ffmpeg-light 0.10.0 → 0.11.0
raw patch · 9 files changed
+95/−116 lines, 9 filesdep ~basedep ~transformers
Dependency ranges changed: base, transformers
Files
- CHANGELOG.md +6/−0
- demo/Main.hs +3/−2
- ffmpeg-light.cabal +7/−6
- src/Codec/FFmpeg.hs +14/−6
- src/Codec/FFmpeg/Decode.hs +27/−21
- src/Codec/FFmpeg/Enums.hsc +13/−8
- src/Codec/FFmpeg/Probe.hsc +14/−4
- src/Codec/FFmpeg/Types.hsc +11/−2
- src/nameCompat.h +0/−67
CHANGELOG.md view
@@ -1,3 +1,9 @@+# 0.11.0++* Query stream duration (Matthias Treydte)+* Initial support for verbosity control; defaults to quiet+ * Can be changed with the new `setLogLevel` function+ # 0.10. 0 * Fix encoder bug that created a single black frame at the start of
demo/Main.hs view
@@ -66,8 +66,9 @@ testCamera :: IO () testCamera =- do initFFmpeg- (getFrame, cleanup) <- imageReader (Camera "0:0")+ do initFFmpeg -- Defaults to quiet (minimal) logging+ -- setLogLevel avLogInfo -- Restore standard ffmpeg logging+ (getFrame, cleanup) <- imageReader (Camera "0:0" defaultCameraConfig) frame1 <- getFrame case frame1 of img@(Just (Image w h _)) ->
ffmpeg-light.cabal view
@@ -1,5 +1,5 @@ name: ffmpeg-light-version: 0.10.0+version: 0.11.0 synopsis: Minimal bindings to the FFmpeg library. description: Stream frames from an encoded video, or stream frames to@@ -15,17 +15,18 @@ > go = do (getFrame, cleanup) <- imageReader "myVideo.mov" > (fmap ImageRGB8 <$> getFrame) <* cleanup .- Tested on OS X 10.11.2 with <http://www.ffmpeg.org FFmpeg> 2.8.3- installed via <http://brew.sh homebrew>.+ Tested with FFmpeg 2.7 - 3.0 license: BSD3 license-file: LICENSE author: Anthony Cowley maintainer: acowley@gmail.com copyright: Copyright (C) 2014 Anthony Cowley+homepage: http://github.com/acowley/ffmpeg-light+bug-reports: http://github.com/acowley/ffmpeg-light/issues category: Codec build-type: Simple-extra-source-files: src/hscMacros.h, src/nameCompat.h, CHANGELOG.md+extra-source-files: src/hscMacros.h, CHANGELOG.md cabal-version: >=1.10 source-repository head@@ -55,11 +56,11 @@ Codec.FFmpeg.Internal.Debug, Codec.FFmpeg.Internal.Linear build-tools: hsc2hs- build-depends: base >=4.6 && < 5,+ build-depends: base >=4.6 && < 4.10, either, exceptions, vector >= 0.10.9 && < 0.12,- transformers >= 0.4.1 && < 0.5,+ transformers >= 0.4.1 && < 0.6, mtl >= 2.2.1 && < 2.3, JuicyPixels >= 3.1 && < 3.3 pkgconfig-depends: libavutil, libavformat, libavcodec, libswscale, libavdevice
src/Codec/FFmpeg.hs view
@@ -2,7 +2,7 @@ -- | Interface to initialize FFmpeg, decode video files, encode video -- files, and convert decoded image frames to JuicyPixels images. module Codec.FFmpeg (-- * Initialization- initFFmpeg, + initFFmpeg, setLogLevel, -- * Decoding imageReader, imageReaderTime, imageReaderT, imageReaderTimeT,@@ -16,14 +16,22 @@ import Codec.FFmpeg.Enums import Codec.FFmpeg.Juicy import Codec.FFmpeg.Types+import Foreign.C.Types (CInt(..)) foreign import ccall "av_register_all" av_register_all :: IO () foreign import ccall "avdevice_register_all" avdevice_register_all :: IO () --- foreign import ccall "avcodec_register_all" avcodec_register_all :: IO ()+-- foreign import ccall "avcodec_register_all" avcodec_register_all :: IO ( --- | Initialize FFmpeg by registering all known codecs. This /must/--- be called before using other FFmpeg functions.-initFFmpeg :: IO ()-initFFmpeg = av_register_all >> avdevice_register_all+foreign import ccall "av_log_set_level" av_log_set_level :: CInt -> IO () +-- | Log output is sent to stderr.+setLogLevel :: LogLevel -> IO ()+setLogLevel (LogLevel l) = av_log_set_level l++-- | Initialize FFmpeg by registering all known codecs. This /must/ be+-- called before using other FFmpeg functions. The debug level is+-- initially set to @quiet@. If you would like the standard ffmpeg+-- debug level, call @setLogLevel avLogInfo@ after @initFFmpeg@.+initFFmpeg :: IO ()+initFFmpeg = av_register_all >> avdevice_register_all >> setLogLevel avLogQuiet
src/Codec/FFmpeg/Decode.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ForeignFunctionInterface, FlexibleContexts #-}+{-# LANGUAGE ForeignFunctionInterface, FlexibleContexts, RecordWildCards #-} -- | Video decoding API. Includes FFI declarations for the underlying -- FFmpeg functions, wrappers for these functions that wrap error -- condition checking, and high level Haskellized interfaces.@@ -9,7 +9,7 @@ import Codec.FFmpeg.Types import Control.Applicative import Control.Arrow (first)-import Control.Monad (when)+import Control.Monad (when, void) import Control.Monad.Error.Class import Control.Monad.IO.Class import Control.Monad.Trans.Maybe@@ -23,11 +23,11 @@ -- * FFI Declarations -foreign import ccall "avformat_open_input" +foreign import ccall "avformat_open_input" avformat_open_input :: Ptr AVFormatContext -> CString -> Ptr () -> Ptr AVDictionary -> IO CInt -foreign import ccall "avformat_find_stream_info" +foreign import ccall "avformat_find_stream_info" avformat_find_stream_info :: AVFormatContext -> Ptr () -> IO CInt foreign import ccall "av_find_best_stream"@@ -40,9 +40,6 @@ foreign import ccall "avcodec_find_decoder_by_name" avcodec_find_decoder_by_name :: CString -> IO AVCodec -foreign import ccall "avcodec_get_frame_defaults"- avcodec_get_frame_defaults :: AVFrame -> IO ()- foreign import ccall "avpicture_get_size" avpicture_get_size :: AVPixelFormat -> CInt -> CInt -> IO CInt @@ -71,33 +68,42 @@ -- * FFmpeg Decoding Interface -- | Open the first video input device enumerated by FFMPEG.-openCamera :: (MonadIO m, MonadError String m) => String -> m AVFormatContext-openCamera cam =+openCamera :: (MonadIO m, MonadError String m) => String -> CameraConfig -> m AVFormatContext+openCamera cam cfg = wrapIOError . alloca $ \ctx -> withCString cam $ \cstr -> do avPtr <- mallocAVFormatContext setupCamera avPtr cam poke ctx avPtr r <- alloca $ \dict -> do- dictSet dict "framerate" "30"+ setConfig dict cfg avformat_open_input ctx cstr nullPtr dict when (r /= 0) (fail $ "ffmpeg failed opening file: " ++ show r) peek ctx where+ run :: (a -> IO b) -> Maybe a -> IO ()+ run _ Nothing = return ()+ run f (Just x) = void (f x)++ setConfig :: Ptr AVDictionary -> CameraConfig -> IO ()+ setConfig dict (CameraConfig {..}) =+ do run (dictSet dict "framerate" . show) framerate+ run (\(w,h) -> dictSet dict "video_size" (show w ++ "x" ++ show h)) resolution+ setupCamera :: AVFormatContext -> String -> IO ()- setupCamera avfc c = do- setCamera avfc- setFilename avfc c+ setupCamera avfc c =+ do setCamera avfc+ setFilename avfc c openInput :: (MonadIO m, MonadError String m) => InputSource -> m AVFormatContext openInput ipt = case ipt of File fileName -> openFile fileName- Camera cam -> openCamera cam+ Camera cam cf -> openCamera cam cf -- | Open an input media file. openFile :: (MonadIO m, MonadError String m) => String -> m AVFormatContext-openFile filename = +openFile filename = wrapIOError . alloca $ \ctx -> withCString filename $ \cstr -> do poke (castPtr ctx) nullPtr@@ -112,7 +118,7 @@ -- | Find a codec given by name. findDecoder :: (MonadIO m, MonadError String m) => String -> m AVCodec-findDecoder name = +findDecoder name = do r <- liftIO $ withCString name avcodec_find_decoder_by_name when (getPtr r == nullPtr) (throwError $ "Unsupported codec: " ++ show name)@@ -121,7 +127,7 @@ -- | Read packets of a media file to get stream information. This is -- useful for file formats with no headers such as MPEG. checkStreams :: (MonadIO m, MonadError String m) => AVFormatContext -> m ()-checkStreams ctx = +checkStreams ctx = do r <- liftIO $ avformat_find_stream_info ctx nullPtr when (r < 0) (throwError "Couldn't find stream information") @@ -154,7 +160,7 @@ -- 'AVCodec'. **NOTE**: This function is not thread safe! openCodec :: (MonadIO m, MonadError String m) => AVCodecContext -> AVCodec -> m AVDictionary-openCodec ctx cod = +openCodec ctx cod = wrapIOError . alloca $ \dict -> do poke dict (AVDictionary nullPtr) r <- open_codec ctx cod dict@@ -177,7 +183,7 @@ prepareReader inputContext vidStreamIndex dstFmt ctx -- | Read RGB frames with the result in the 'MaybeT' transformer.--- +-- -- > frameReaderT = fmap (first MaybeT) . frameReader frameReaderT :: (Functor m, MonadIO m, MonadError String m) => InputSource -> m (MaybeT IO AVFrame, IO ())@@ -197,7 +203,7 @@ (reader, cleanup) <- prepareReader inputContext vidStreamIndex dstFmt ctx AVRational num den <- liftIO $ getTimeBase vidStream let (numl, dend) = (fromIntegral num, fromIntegral den)- frameTime' frame = + frameTime' frame = do n <- getPts frame return $ fromIntegral (n * numl) / dend readTS = do frame <- reader@@ -209,7 +215,7 @@ -- | Read time stamped RGB frames with the result in the 'MaybeT' -- transformer.--- +-- -- > frameReaderT = fmap (first MaybeT) . frameReader frameReaderTimeT :: (Functor m, MonadIO m, MonadError String m) => InputSource -> m (MaybeT IO (AVFrame, Double), IO ())
src/Codec/FFmpeg/Enums.hsc view
@@ -11,14 +11,6 @@ #include <libavutil/mathematics.h> #include <libswscale/swscale.h> -#ifndef PIX_FMT_RGBA64--- WARNING: Fragile! This pixel format is not defined in older--- versions. Note that many FFI calls will fail at runtime with older--- versions, so all this does is let us the haskell code.-#warning "This version of libav/ffmpeg is too old. It is not likely to work."-#include "nameCompat.h"-#endif- newtype AVMediaType = AVMediaType CInt deriving (Eq, Storable) #enum AVMediaType,AVMediaType \ , AVMEDIA_TYPE_VIDEO\@@ -220,3 +212,16 @@ #enum PacketFlag, PacketFlag \ , AV_PKT_FLAG_KEY\ , AV_PKT_FLAG_CORRUPT++newtype LogLevel = LogLevel CInt deriving (Eq, Bits, Storable)+#enum LogLevel, LogLevel \+ , AV_LOG_QUIET\+ , AV_LOG_PANIC\+ , AV_LOG_FATAL\+ , AV_LOG_ERROR\+ , AV_LOG_WARNING\+ , AV_LOG_INFO\+ , AV_LOG_VERBOSE\+ , AV_LOG_DEBUG\+ , AV_LOG_TRACE\+ , AV_LOG_MAX_OFFSET
src/Codec/FFmpeg/Probe.hsc view
@@ -6,13 +6,13 @@ module Codec.FFmpeg.Probe ( -- * Files- withAvFile, nbStreams, formatName, formatMetadata,+ withAvFile, nbStreams, formatName, formatMetadata, duration, -- * Streams AvStreamT, withStream, codecContext, codecName, codecMediaTypeName, streamBitrate, streamMetadata,- codec,- + codec, streamImageSize,+ -- * Dictionaries dictFoldM_ ) where@@ -21,6 +21,7 @@ import Control.Monad.Catch ( MonadMask, finally ) import Control.Monad.Reader import Control.Monad.Trans.Either+import Data.Int ( Int64 ) import Foreign.C.String ( CString, peekCString, withCString ) import Foreign.C.Types ( CInt(..) ) import Foreign.Marshal.Utils ( with )@@ -66,6 +67,9 @@ (#peek AVInputFormat, name) >>= peekCString +duration :: MonadIO m => AvFormat m Int64+duration = ask >>= \ctx -> liftIO $ (#peek AVFormatContext, duration) (getPtr ctx)+ formatMetadata :: MonadIO m => AvFormat m AVDictionary formatMetadata = ask >>= liftIO . (#peek AVFormatContext, metadata) . getPtr @@ -116,6 +120,13 @@ streamBitrate :: MonadIO m => AVCodecContext -> AvStreamT m Int streamBitrate cctx = liftIO $ getBitRate cctx >>= return . fromIntegral +-- |+-- Gives the (width, height) of a video stream in pixels, not accounting for the pixel aspect ratio.+streamImageSize :: MonadIO m => AVCodecContext -> AvStreamT m (Int, Int)+streamImageSize cctx = liftIO $ (,)+ <$> liftM fromIntegral (getWidth cctx)+ <*> liftM fromIntegral (getHeight cctx)+ streamMetadata :: MonadIO m => AvStreamT m AVDictionary streamMetadata = ask >>= liftIO . (#peek AVStream, metadata) . getPtr @@ -163,4 +174,3 @@ foreign import ccall "av_dict_get" av_dict_get :: AVDictionary -> CString -> Ptr () -> CInt -> IO (Ptr ())-
src/Codec/FFmpeg/Types.hsc view
@@ -216,7 +216,16 @@ (#poke AVFrac, den) ptr d -- | The input source can be a file or a camera. When using 'Camera',--- frequently in the form @Camera "0:0"@, the first input video device+-- frequently in the form @Camera "0:0" defaultCameraConfig@, the first input video device -- enumerated by libavdevice is selected.-data InputSource = File FilePath | Camera String+data InputSource = File FilePath | Camera String CameraConfig deriving (Eq, Ord, Show, Read)++data CameraConfig =+ CameraConfig { framerate :: Maybe Int+ , resolution :: Maybe (Int,Int)+ }+ deriving (Eq,Ord,Show,Read)++defaultCameraConfig :: CameraConfig+defaultCameraConfig = CameraConfig (Just 30) Nothing
− src/nameCompat.h
@@ -1,67 +0,0 @@-/* Older versions of libav (and perhaps ffmpeg) used a different- naming scheme for constants. Since distributions like Ubuntu 12.04- are locked down with these old versions, we hack in support for the- newer constant names. */--#define AV_PIX_FMT_NONE PIX_FMT_NONE-#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24-#define AV_PIX_FMT_RGBA PIX_FMT_RGBA-#define AV_PIX_FMT_BGRA PIX_FMT_BGRA-#define AV_PIX_FMT_Y400A PIX_FMT_Y400A-#define AV_PIX_FMT_RGB32 PIX_FMT_RGB32-#define AV_PIX_FMT_RGB32_1 PIX_FMT_RGB32_1-#define AV_PIX_FMT_BGR32 PIX_FMT_BGR32-#define AV_PIX_FMT_BGR32_1 PIX_FMT_BGR32_1-#define AV_PIX_FMT_RGB8 -1-#define AV_PIX_FMT_BGR8 -1-#define AV_PIX_FMT_RGB4_BYTE -1-#define AV_PIX_FMT_BGR4_BYTE -1-#define AV_PIX_FMT_GRAY8 PIX_FMT_GRAY8-#define AV_PIX_FMT_GRAY16 PIX_FMT_GRAY16-#define AV_PIX_FMT_GRAY8A -1-#define AV_PIX_FMT_RGB565 PIX_FMT_RGB565-#define AV_PIX_FMT_RGB555 PIX_FMT_RGB555-#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P-#define AV_PIX_FMT_YUV420P9 PIX_FMT_YUV420P9-#define AV_PIX_FMT_YUV420P10 PIX_FMT_YUV420P10-#define AV_PIX_FMT_YUV420P12 -1-#define AV_PIX_FMT_YUV422P12 -1-#define AV_PIX_FMT_YUV444P12 -1-#define AV_PIX_FMT_YUV420P14 -1-#define AV_PIX_FMT_YUV422P14 -1-#define AV_PIX_FMT_YUV444P14 -1-#define AV_PIX_FMT_YUV420P16 PIX_FMT_YUV420P16-#define AV_PIX_FMT_YUV422P16 PIX_FMT_YUV422P16-#define AV_PIX_FMT_YUV444P16 PIX_FMT_YUV444P16-#define AV_PIX_FMT_RGBA64 -1-#define AV_PIX_FMT_BGRA64 -1-#define AV_PIX_FMT_PAL8 PIX_FMT_PAL8--#define AV_CODEC_ID_H264 CODEC_ID_H264-#define AV_CODEC_ID_THEORA CODEC_ID_THEORA-#define AV_CODEC_ID_MPEG4 CODEC_ID_MPEG4-#define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO-#define AV_CODEC_ID_GIF CODEC_ID_GIF-#define AV_CODEC_ID_AAC CODEC_ID_AAC-#define AV_CODEC_ID_MP3 CODEC_ID_MP3-#define AV_CODEC_ID_DTS CODEC_ID_DTS-#define AV_CODEC_ID_HEVC -1-#define AV_CODEC_ID_VC1 -1-#define AV_CODEC_ID_RAWVIDEO CODEC_ID_RAWVIDEO--#define FF_PROFILE_AAC_HE -1-#define FF_PROFILE_AAC_HE_V2 -1-#define FF_PROFILE_AAC_LD -1-#define FF_PROFILE_AAC_ELD -1-#define FF_PROFILE_MPEG2_AAC_LOW -1-#define FF_PROFILE_MPEG2_AAC_HE -1--#define AVIO_FLAG_DIRECT -1--#define AV_ROUND_PASS_MINMAX -1--#define CODEC_FLAG_UNALIGNED -1-#define CODEC_FLAG_OUTPUT_CORRUPT -1--#define AVFMT_ALLOW_FLUSH -1-#define AVFMT_TS_NONSTRICT -1