Haskell - Преобразование нескольких изображений в видеофайл - функция frameWriter ffmpeg-lights не работает

ситуация
В настоящее время я работаю над приложением для обработки изображений, которое использует ffmpeg-light для извлечения всех кадров данного видеофайла, чтобы впоследствии программа могла применять оттенки серого, а также алгоритмы обнаружения краев для каждого из кадров.

С помощью дружественных стековых потоков мне удалось настроить метод, позволяющий конвертировать несколько изображений в один видеофайл с помощью ffmpeg-lights' frameWriter функция.

проблема
Приложение работает нормально до момента, когда оно попадает в frameWriterфункция, и я не знаю почему, так как нет ошибок или сообщений об исключениях. (ОС: Win 10 64bit)

Что я пробовал?
Я старался..
- разные версии ffmpeg (от 3.2 до 3.4).
- ffmpeg.exe с помощью командной строки, чтобы проверить, отсутствуют ли какие-либо кодеки, но любое преобразование, которое я пробовал, работало.
- разные комбинации EncodingParams: например.. ширина EncodingParams высота fps (Nothing) (Nothing) "средний"

Вопрос
К сожалению, ничего из вышеперечисленного не сработало, и в Интернете не хватает информации для этого конкретного случая. Может быть, я пропустил что-то важное (например, флаги GHC или что-то) или сделал большую ошибку в моем коде. Вот почему я должен спросить вас: есть ли у вас какие-либо предложения / советы для меня?

Пакеты Haskell
- ffmpeg-light-0.12.0
- JuicyPixels-3.2.8.3

Код

{--------------------------------------------------------------------------------------------
 Applies "juicyToFFmpeg'" and "getFPS" to a list of images and saves the output-video
 to a user defined location.
---------------------------------------------------------------------------------------------}     
saveVideo :: String -> [Image PixelYA8] -> Int -> IO ()
saveVideo path imgs fps = do
         -- program stops after hitting next line --
         frame <- frameWriter ep path
         ------------------------------------------------
         Prelude.mapM_ (frame . Just) ffmpegImgs 
         frame Nothing
         where ep = EncodingParams width height fps (Just avCodecIdMpeg4) (Just avPixFmtGray8a) "medium"
               width      = toCInt $ imageWidth  $ head imgs
               height     = toCInt $ imageHeight $ head imgs
               ffmpegImgs = juicyToFFmpeg' imgs
               toCInt x   = fromIntegral x :: CInt

{--------------------------------------------------------------------------------------------
 Converts a single image from JuicyPixel-format to ffmpeg-light-format. 
---------------------------------------------------------------------------------------------}      
juicyToFFmpeg :: Image PixelYA8 -> (AVPixelFormat, V2 CInt, Vector CUChar)
juicyToFFmpeg img = (avPixFmtGray8a, V2 (toCInt width) (toCInt height), ffmpegData)
                  where toCInt   x   = fromIntegral x :: CInt
                        toCUChar x   = fromIntegral x :: CUChar
                        width        = imageWidth img
                        height       = imageHeight img
                        ffmpegData   = VS.map toCUChar (imageData img)

{--------------------------------------------------------------------------------------------
 Converts a list of images from JuicyPixel-format to ffmpeg-light-format. 
---------------------------------------------------------------------------------------------}                        
juicyToFFmpeg' :: [Image PixelYA8] -> [(AVPixelFormat, V2 CInt, Vector CUChar)]
juicyToFFmpeg' imgs = Prelude.foldr (\i acc -> acc++[juicyToFFmpeg i]) [] imgs

{--------------------------------------------------------------------------------------------
 Simply calculates the FPS for image-to-video conversion.
 -> frame :: (Double, DynamicImage) where Double is a timestamp of when it got extracted 
---------------------------------------------------------------------------------------------}
getFPS :: [(Double, DynamicImage)] -> Int
getFPS frames = div (ceiling $ lastTimestamp - firstTimestamp) frameCount :: Int
              where firstTimestamp = fst $ head frames
                    lastTimestamp  = fst $ last frames
                    frameCount     = length frames

1 ответ

Я подозреваю, что проблема связана с окружением Windows и использованием ffmpeg из Haskell (т.е. ffmpeg-simple)

Мне удалось успешно скомпилировать и запустить ваш модуль в Ubuntu 16.04, хотя я получил ошибку времени выполнения от ffmpeg:

$ ./main
[NULL @ 0x1ea6900] Unable to find a suitable output format for 'foo.avi'
main: Couldn't allocate output format context
CallStack (from HasCallStack):
  error, called at src/Codec/FFmpeg/Encode.hs:214:17 in ffmpeg-light-
0.12.0-DYHyy7pUAhZ7WHcd6Y2mLO:Codec.FFmpeg.Encode

Кажется, что вышеупомянутая ошибка может быть исправлена ​​с помощью настройки некоторых аргументов ffmpeg, но, поскольку это не та проблема, с которой вы сталкиваетесь, я решил не идти дальше с ее отладкой.

На всякий случай мой main:

main :: IO ()
main = do
  Right (ImageYA8 img) <- readPng "foo_ya.png"
  saveVideo "foo.avi" (replicate 10 img) 10

Я запустил то же самое на Windows 7 64-битной и, похоже, я не смог полностью удовлетворить зависимости.

Компиляция и установка зависимостей в Windows:

> stack exec -- pacman -Syu
> stack exec -- pacman -S mingw-w64-x86_64-gtk3
> stack exec -- pacman -S mingw-w64-x86_64-pkg-config
> stack exec -- pacman -S mingw-w64-x86_64-ffmpeg
> stack --install-ghc --resolver lts-9.10 exec --package vector --package JuicyPixels --package ffmpeg-light -- ghc main.hs -O2 -threaded
> stack exec -- main.exe

Приводит к ошибке всплывающего окна при запуске в cmd (ps просто выходит)

Не удалось найти точку входа в процедуру inflateValidate в библиотеке динамических ссылок zlib1.dll

Я не специалист по разработке под Windows, поэтому чувствую, что что-то упустил. Надеюсь, моя попытка будет хоть немного полезной.

Другие вопросы по тегам