2016-06-30 6 views
3

У меня есть медиа-поток с соответствующим именованным каналом. Программа считывает данные из каналов и обрабатывает кадры с помощью processFrame.Haskell: Выполнение действия ввода-вывода только в том случае, если прошло определенное время с момента последнего его выполнения.

module Main where 
import Codec.FFmpeg 
import Codec.FFmpeg.Decode 
import Control.Monad.Except (runExceptT) 

main :: IO() 
main = do 
    initFFmpeg 
    -- get IO reader 
    eResult <- runExceptT $ frameReader avPixFmtRgb24 (File "pipe") 
    case eResult of 
     Left err -> do print "couldn't establish frameReader\n" 
         print err 
     Right (getMaybeFrame, cleanup) -> do 
      -- read and process frames until av_read_frame returns no frames 
      loopWhileTrue (getAndProcessFrame getMaybeFrame) 
      cleanup 
      where 
      loopWhileTrue f = do result <- f 
           case result of 
            True -> loopWhileTrue f 
            False -> return() 
     where 
     getAndProcessFrame gMF = do 
      maybeFrame <- gMF 
      case maybeFrame of 
       Just frame -> do tc <- timeCondition 
           if tc 
           then do processFrame frame 
           else return() 
           return True 
       Nothing -> return False 
     timeCondition = return True 

processFrame :: AVFrame -> IO() 
processFrame frame = do isKeyFrame <- getKeyFrame frame 
         if isKeyFrame 
         then do pts <- getPts frame 
           print pts 
         else return() 

мне нужно выполнить processFrame только один раз в минуту, минуя все остальные кадры.

Этот код не имеет надлежащего времени, только timeCondition заглушки. Я планировал написать правильную функцию timeCondition, которая возвращает True, когда определенное время прошло с последних processFrame, в противном случае False. Но это выглядит слишком настойчивым, и неясно, как использовать Monads/MVars для этого. Каков правильный способ разработки такой программы в Haskell?

+0

Либо главное loopWhileTrue немного более сложным, отслеживание в последний раз кадр был обработан, или передать в MVar к getAndProcessFrame затем 'processFrame', который содержит в последний раз. Проверьте текущее время на этот последний раз на каждом кадре и условно продолжите или выйдите раньше. –

+1

Наиболее очевидным улучшением структуры кода было бы сделать 'loopWhileTrue' связывание на верхнем уровне вместо того, чтобы закопать его в выражении' case' внутри блока 'do'. Кроме того, вы можете написать его 'loopWhileTrue f = do {result <- f; когда result $ loopWhileTrue f} ', или даже' loopWhileTrue f = fix $ \ m -> do {result <- f; когда результат m} '. Они будут давать сигнатуры типов 'loopWhileTrue :: Monad m => m Bool -> m()'. – dfeuer

+0

Нет ли способа спать нить ни на минуту? (в 'loopWhileTrue') – Alec

ответ

2

Возьмите отметку времени, когда шаг обработки завершится с getCurrentTime и проденьте его обратно через ваш цикл, тогда timeCondition - это всего лишь некоторые математические значения времени.

import Data.Time.Clock 

-- | Returns `True` when 60 seconds have passed from the given value. 
-- Not respectful of leap seconds. 
isAMinuteSince :: UTCTime -> IO Bool 
isAMinuteSince timestamp = do 
    now <- getCurrentTime 
    return $ diffUTCTime now timestamp >= 60 
Смежные вопросы