{-# LINE 1 "src/Store/AV.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable, EmptyDataDecls, OverloadedStrings, NegativeLiterals, GeneralizedNewtypeDeriving #-}
{-# LINE 2 "src/Store/AV.hsc" #-}
module Store.AV
  ( AVError(..)
  , avErrorString
  , AV
  , initAV
  , AVMediaType(..)
  , AVProbe(..)
  , avProbe
  , avProbeLength
  , avProbeHas
  , avFrame
  ) where

import Control.Applicative ((<|>))
import Control.Arrow (first)
import Control.Concurrent.MVar (MVar, newMVar, takeMVar, putMVar)
import Control.Exception (Exception, throwIO, bracket, bracket_, finally, onException)
import Control.Monad ((<=<), void, when, forM, forM_)
import qualified Data.ByteString as BS
import Data.Int (Int32, Int64)
import Data.Maybe (isNothing)
import Data.Ratio (Ratio, (%), numerator, denominator)
import Data.Time.Clock (DiffTime)
import Data.Time.Format (parseTimeM, defaultTimeLocale)
import Data.Time.LocalTime (ZonedTime)
import Data.Typeable (Typeable)
import Data.Word (Word16, Word32)
import Foreign.C.Error (throwErrnoIfNull)
import Foreign.C.String (CString, CStringLen, peekCAString, withCAString)
import Foreign.C.Types (CInt(..), CUInt(..), CSize(..))
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Marshal.Utils (with, maybePeek)
import Foreign.Ptr (Ptr, FunPtr, nullPtr, plusPtr, castPtr)
import Foreign.StablePtr
import Foreign.Storable
import System.IO.Unsafe (unsafeDupablePerformIO)

import Ops
import Files
import Model.Offset


{-# LINE 44 "src/Store/AV.hsc" #-}

type AVLockOp = Word32
{-# LINE 46 "src/Store/AV.hsc" #-}
type AVLockmgr a = Ptr (Ptr a) -> AVLockOp -> IO CInt
type AVPixelFormat = Int32
{-# LINE 48 "src/Store/AV.hsc" #-}
type AVCodecID = Word32
{-# LINE 49 "src/Store/AV.hsc" #-}

data AVDictionary
data AVDictionaryEntry
data AVInputFormat
data AVFrame
data AVPacket
data AVCodec
data AVCodecContext
data AVStream
data AVFormatContext
data AVIOContext
data AVOutputFormat

foreign import ccall unsafe "libavutil/error.h av_strerror"
  avStrerror :: CInt -> CString -> CSize -> IO CInt

foreign import ccall unsafe "libavutil/mem.h av_free"
  avFree :: Ptr a -> IO ()

foreign import ccall unsafe "libavutil/dict.h av_dict_get"
  avDictGet :: Ptr AVDictionary -> CString -> Ptr AVDictionaryEntry -> CInt -> IO (Ptr AVDictionaryEntry)

foreign import ccall unsafe "libavutil/dict.h av_dict_set"
  avDictSet :: Ptr (Ptr AVDictionary) -> CString -> CString -> CInt -> IO CInt

foreign import ccall unsafe "libavutil/dict.h av_dict_free"
  avDictFree :: Ptr (Ptr AVDictionary) -> IO ()

foreign import ccall unsafe "libavutil/frame.h av_frame_alloc"
  avFrameAlloc :: IO (Ptr AVFrame)

foreign import ccall unsafe "libavutil/frame.h av_frame_free"
  avFrameFree :: Ptr (Ptr AVFrame) -> IO ()

foreign import ccall unsafe "libavutil/frame.h av_frame_unref"
  avFrameUnref :: Ptr AVFrame -> IO ()

foreign import ccall unsafe "libavutil/frame.h av_frame_get_best_effort_timestamp"
  avFrameGetBestEffortTimestamp :: Ptr AVFrame -> IO Int64

foreign import ccall "libavcodec/avcodec.h av_lockmgr_register"
  avLockmgrRegister :: FunPtr (AVLockmgr a) -> IO CInt

foreign import ccall "wrapper"
  mkAVLockmgr :: AVLockmgr a -> IO (FunPtr (AVLockmgr a))

foreign import ccall unsafe "libavcodec/avcodec.h avcodec_get_name"
  avcodecGetName :: AVCodecID -> IO CString

foreign import ccall unsafe "libavcodec/avcodec.h av_init_packet"
  avInitPacket :: Ptr AVPacket -> IO ()

foreign import ccall unsafe "libavcodec/avcodec.h av_free_packet"
  avFreePacket :: Ptr AVPacket -> IO ()

foreign import ccall "libavcodec/avcodec.h avcodec_open2"
  avcodecOpen2 :: Ptr AVCodecContext -> Ptr AVCodec -> Ptr (Ptr AVDictionary) -> IO CInt

foreign import ccall "libavcodec/avcodec.h avcodec_close"
  avcodecClose :: Ptr AVCodecContext -> IO CInt

foreign import ccall "libavcodec/avcodec.h avcodec_decode_video2"
  avcodecDecodeVideo2 :: Ptr AVCodecContext -> Ptr AVFrame -> Ptr CInt -> Ptr AVPacket -> IO CInt

foreign import ccall "libavcodec/avcodec.h avcodec_encode_video2"
  avcodecEncodeVideo2 :: Ptr AVCodecContext -> Ptr AVPacket -> Ptr AVFrame -> Ptr CInt -> IO CInt

foreign import ccall "libavcodec/avcodec.h avcodec_find_encoder"
  avcodecFindEncoder :: AVCodecID -> IO (Ptr AVCodec)

foreign import ccall "libavcodec/avcodec.h avcodec_find_best_pix_fmt_of_list"
  avcodecFindBestPixFmtOfList :: Ptr AVPixelFormat -> AVPixelFormat -> CInt -> Ptr CInt -> IO AVPixelFormat

foreign import ccall unsafe "libavformat/avio.h avio_open_dyn_buf"
  avioOpenDynBuf :: Ptr (Ptr AVIOContext) -> IO CInt

foreign import ccall unsafe "libavformat/avio.h avio_close_dyn_buf"
  avioCloseDynBuf :: Ptr AVIOContext -> Ptr CString -> IO CInt

foreign import ccall "libavformat/avformat.h av_register_all"
  avRegisterAll :: IO ()

foreign import ccall "libavformat/avformat.h avformat_open_input"
  avformatOpenInput :: Ptr (Ptr AVFormatContext) -> CString -> Ptr AVInputFormat -> Ptr (Ptr AVDictionary) -> IO CInt

foreign import ccall "libavformat/avformat.h avformat_close_input"
  avformatCloseInput :: Ptr (Ptr AVFormatContext) -> IO ()

foreign import ccall "libavformat/avformat.h avformat_find_stream_info"
  avformatFindStreamInfo :: Ptr AVFormatContext -> Ptr (Ptr AVDictionary) -> IO CInt

foreign import ccall unsafe "libavformat/avformat.h av_find_input_format"
  avFindInputFormat :: CString -> IO (Ptr AVInputFormat)

foreign import ccall "libavformat/avformat.h av_find_best_stream"
  avFindBestStream :: Ptr AVFormatContext -> Int32 -> CInt -> CInt -> Ptr (Ptr AVCodec) -> CInt -> IO CInt
{-# LINE 145 "src/Store/AV.hsc" #-}

foreign import ccall "libavformat/avformat.h avformat_seek_file"
  avformatSeekFile :: Ptr AVFormatContext -> CInt -> Int64 -> Int64 -> Int64 -> CInt -> IO CInt

foreign import ccall "libavformat/avformat.h av_read_frame"
  avReadFrame :: Ptr AVFormatContext -> Ptr AVPacket -> IO CInt

foreign import ccall "libavformat/avformat.h avformat_alloc_output_context2"
  avformatAllocOutputContext2 :: Ptr (Ptr AVFormatContext) -> Ptr AVOutputFormat -> CString -> CString -> IO CInt

foreign import ccall "libavformat/avformat.h avformat_free_context"
  avformatFreeContext :: Ptr AVFormatContext -> IO ()

foreign import ccall "libavformat/avformat.h avformat_new_stream"
  avformatNewStream :: Ptr AVFormatContext -> Ptr AVCodec -> IO (Ptr AVStream)

foreign import ccall "libavformat/avformat.h avformat_write_header"
  avformatWriteHeader :: Ptr AVFormatContext -> Ptr (Ptr AVDictionary) -> IO CInt

foreign import ccall "libavformat/avformat.h av_write_frame"
  avWriteFrame :: Ptr AVFormatContext -> Ptr AVPacket -> IO CInt

foreign import ccall "libavformat/avformat.h av_write_trailer"
  avWriteTrailer :: Ptr AVFormatContext -> IO CInt


newtype AVRational = AVRational (Ratio CInt) deriving (Eq, Ord, Num, Fractional, Real, RealFrac)

instance Storable AVRational where
  sizeOf _ = (8)
{-# LINE 175 "src/Store/AV.hsc" #-}
  alignment (AVRational x) = alignment $ numerator x
  peek p = do
    num <- (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 178 "src/Store/AV.hsc" #-}
    den <- (\hsc_ptr -> peekByteOff hsc_ptr 4) p
{-# LINE 179 "src/Store/AV.hsc" #-}
    return $ AVRational $ num % den
  poke p (AVRational x) = do
    (\hsc_ptr -> pokeByteOff hsc_ptr 0) p (numerator x)
{-# LINE 182 "src/Store/AV.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 4) p (denominator x)
{-# LINE 183 "src/Store/AV.hsc" #-}


avShowError :: CInt -> String
avShowError e = unsafeDupablePerformIO $
  allocaBytes len $ \p -> do
    _ <- avStrerror e p (fromIntegral len)
    peekCAString p
  where len = 256

data AVError = AVError
  { avErrorCode :: CInt
  , avErrorFunction :: String
  , avErrorFile :: Maybe RawFilePath
  } deriving (Typeable)

instance Exception AVError

avErrorString :: AVError -> String
avErrorString = avShowError . avErrorCode

instance Show AVError where
  showsPrec p (AVError e c f) = showParen (p > 10) $
    showString "AVError "
    . showString c
    . maybe id (((' ' :) .) . shows) f
    . if e == 0 then id else
      showString ": " . showString (avShowError e)

data ErrorFile
  = NoFile
  | FileName !RawFilePath
  | FileContext !(Ptr AVFormatContext)

errorFile :: ErrorFile -> IO (Maybe RawFilePath)
errorFile NoFile = return Nothing
errorFile (FileName f) = return $ Just f
errorFile (FileContext a) =
  (n /= nullPtr) `thenReturn` (BS.packCString n)
  where n = (\hsc_ptr -> hsc_ptr `plusPtr` 56) a
{-# LINE 222 "src/Store/AV.hsc" #-}

throwAVError :: CInt -> String -> ErrorFile -> IO a
throwAVError e c f = throwIO . AVError e c =<< errorFile f

throwAVErrorIf :: Integral a => String -> ErrorFile -> IO a -> IO a
throwAVErrorIf c f g = do
  r <- g
  when (r < 0) $
    throwAVError (fromIntegral r) c f
  return r

throwAVErrorIf_ :: Integral a => String -> ErrorFile -> IO a -> IO ()
throwAVErrorIf_ c f = void . throwAVErrorIf c f

throwAVErrorIfNull :: String -> ErrorFile -> IO (Ptr a) -> IO (Ptr a)
throwAVErrorIfNull c f g = do
  r <- g
  when (r == nullPtr) $
    throwAVError 0 c f
  return r


withAVDictionary :: (Ptr (Ptr AVDictionary) -> IO a) -> IO a
withAVDictionary f = with nullPtr $ \d ->
  f d `finally` avDictFree d

getAVDictionary :: Ptr AVDictionary -> String -> IO (Maybe String)
getAVDictionary dict key =
  withCAString key $ \ckey ->
    maybePeek (peekCAString <=< (\hsc_ptr -> peekByteOff hsc_ptr 8)) =<< avDictGet dict ckey nullPtr 0
{-# LINE 252 "src/Store/AV.hsc" #-}

setAVDictionary :: Ptr (Ptr AVDictionary) -> String -> String -> IO ()
setAVDictionary dict key val =
  withCAString key $ \ckey ->
  withCAString val $ \cval ->
  throwAVErrorIf_ "av_dict_set" NoFile $ avDictSet dict ckey cval 0

closeAVIODynBuf :: Ptr AVIOContext -> (CStringLen -> IO a) -> IO a
closeAVIODynBuf c g =
  with nullPtr $ \p ->
    bracket
      (do
        l <- avioCloseDynBuf c p
        b <- peek p
        return (b, fromIntegral l))
      (avFree . fst)
      g

withAVIODynBuf :: ErrorFile -> Ptr (Ptr AVIOContext) -> IO a -> IO (BS.ByteString, a)
withAVIODynBuf ec pb g = do
  throwAVErrorIf_ "avio_open_dyn_buf" ec $
    avioOpenDynBuf pb
  buf <- peek pb
  r <- g `onException`
    closeAVIODynBuf buf return
  b <- closeAVIODynBuf buf BS.packCStringLen
  return (b, r)

withAVFrame :: (Ptr AVFrame -> IO a) -> IO a
withAVFrame =
  bracket
    (throwErrnoIfNull "av_frame_alloc" avFrameAlloc)
    (`with` avFrameFree)

withAVInput :: RawFilePath -> Maybe String -> (Ptr AVFormatContext -> IO a) -> IO a
withAVInput f fmt g =
  BS.useAsCString f $ \cf ->
  with nullPtr $ \a ->
  bracket_
    (do
      avfmt <- maybe (return nullPtr) (`withCAString` avFindInputFormat) fmt
      throwAVErrorIf "avformat_open_input" (FileName f) $
        avformatOpenInput a cf avfmt nullPtr)
    (avformatCloseInput a)
    (g =<< peek a)

findAVStreamInfo :: Ptr AVFormatContext -> IO ()
findAVStreamInfo a = throwAVErrorIf_ "avformat_find_stream_info" (FileContext a) $
  avformatFindStreamInfo a nullPtr

withAVOutput :: Maybe RawFilePath -> String -> (Ptr AVFormatContext -> IO a) -> IO (Maybe BS.ByteString, a)
withAVOutput f fmt g =
  maybe ($ nullPtr) BS.useAsCString f $ \cf ->
  withCAString fmt $ \cfmt ->
  with nullPtr $ \a ->
    bracket_
      (throwAVErrorIf_ "avformat_alloc_output_context2" (maybe NoFile FileName f) $
        avformatAllocOutputContext2 a nullPtr cfmt cf)
      (avformatFreeContext =<< peek a)
      (do
        c <- peek a
        case f of
          Just _ -> (,) Nothing <$> g c
          Nothing -> first Just <$>
            withAVIODynBuf (FileContext c) ((\hsc_ptr -> hsc_ptr `plusPtr` 32) c)
{-# LINE 317 "src/Store/AV.hsc" #-}
              (g c))

withAVCodec :: Ptr AVFormatContext -> Ptr AVStream -> Ptr AVCodec -> Ptr (Ptr AVDictionary) -> IO a -> IO a
withAVCodec a s c o =
  bracket_
    (do
      sc <- (\hsc_ptr -> peekByteOff hsc_ptr 8) s
{-# LINE 324 "src/Store/AV.hsc" #-}
      throwAVErrorIf_ "avcodec_open2" (FileContext a) $
        avcodecOpen2 sc c o)
    (do
      sc <- (\hsc_ptr -> peekByteOff hsc_ptr 8) s
{-# LINE 328 "src/Store/AV.hsc" #-}
      avcodecClose sc)

withAVPacket :: (Ptr AVPacket -> IO a) -> IO a
withAVPacket f = allocaBytes (88) $ \p -> do
{-# LINE 332 "src/Store/AV.hsc" #-}
  bracket_
    (avInitPacket p)
    (avFreePacket p)
    (do
      (\hsc_ptr -> pokeByteOff hsc_ptr 24) p nullPtr
{-# LINE 337 "src/Store/AV.hsc" #-}
      (\hsc_ptr -> pokeByteOff hsc_ptr 32) p (0 :: CInt)
{-# LINE 338 "src/Store/AV.hsc" #-}
      f p)


avLockmgr :: AVLockmgr ()
avLockmgr p o
  | o == 0 = (<$) 0 $
{-# LINE 344 "src/Store/AV.hsc" #-}
    poke p . castStablePtrToPtr =<< newStablePtr =<< newMVar ()
  | o == 1 = (<$) 0 $
{-# LINE 346 "src/Store/AV.hsc" #-}
    takeMVar =<< deRefStablePtr =<< s
  | o == 2 = (<$) 0 $
{-# LINE 348 "src/Store/AV.hsc" #-}
    (`putMVar` ()) =<< deRefStablePtr =<< s
  | o == 3 = (<$) 0 $
{-# LINE 350 "src/Store/AV.hsc" #-}
    freeStablePtr =<< s
  | otherwise = return (-1)
  where
  s = castPtrToStablePtr <$> peek p
  s :: IO (StablePtr (MVar ()))

data AV = AV 

initAV :: IO AV
initAV = do
  avRegisterAll
  mgr <- mkAVLockmgr avLockmgr
  throwAVErrorIf_ "av_lockmgr_register" NoFile $ avLockmgrRegister mgr
  -- leak mgr
  return AV

data AVMediaType
  = AVMediaTypeUnknown
  | AVMediaTypeVideo
  | AVMediaTypeAudio
  | AVMediaTypeData
  | AVMediaTypeSubtitle
  | AVMediaTypeAttachment
  deriving (Eq, Show, Enum, Bounded)

instance Storable AVMediaType where
  sizeOf _ = sizeOf (undefined :: Int32)
{-# LINE 377 "src/Store/AV.hsc" #-}
  alignment _ = alignment (undefined :: Int32)
{-# LINE 378 "src/Store/AV.hsc" #-}
  peek p = do
    v <- peek (castPtr p :: Ptr Int32)
{-# LINE 380 "src/Store/AV.hsc" #-}
    return $ case v of 
      0      -> AVMediaTypeVideo
{-# LINE 382 "src/Store/AV.hsc" #-}
      1      -> AVMediaTypeAudio
{-# LINE 383 "src/Store/AV.hsc" #-}
      2       -> AVMediaTypeData
{-# LINE 384 "src/Store/AV.hsc" #-}
      3   -> AVMediaTypeSubtitle
{-# LINE 385 "src/Store/AV.hsc" #-}
      4 -> AVMediaTypeAttachment
{-# LINE 386 "src/Store/AV.hsc" #-}
      _ -> AVMediaTypeUnknown
  poke p v = poke (castPtr p :: Ptr Int32) $ case v of
{-# LINE 388 "src/Store/AV.hsc" #-}
    AVMediaTypeUnknown    -> -1
{-# LINE 389 "src/Store/AV.hsc" #-}
    AVMediaTypeVideo      -> 0
{-# LINE 390 "src/Store/AV.hsc" #-}
    AVMediaTypeAudio      -> 1
{-# LINE 391 "src/Store/AV.hsc" #-}
    AVMediaTypeData       -> 2
{-# LINE 392 "src/Store/AV.hsc" #-}
    AVMediaTypeSubtitle   -> 3
{-# LINE 393 "src/Store/AV.hsc" #-}
    AVMediaTypeAttachment -> 4
{-# LINE 394 "src/Store/AV.hsc" #-}

data AVProbe = AVProbe
  { avProbeFormat :: BS.ByteString
  , avProbeDuration :: DiffTime
  , avProbeStreams :: [(AVMediaType, BS.ByteString)]
  , avProbeDate :: Maybe ZonedTime
  }

avProbeHas :: AVMediaType -> AVProbe -> Bool
avProbeHas t = any ((t ==) . fst) . avProbeStreams

avProbeLength :: AVProbe -> Maybe Offset
avProbeLength AVProbe{ avProbeDuration = o } = (o > 0) `thenUse` (diffTimeOffset o)

avTime :: Int64 -> DiffTime
avTime t = realToFrac $ t % 1000000
{-# LINE 410 "src/Store/AV.hsc" #-}

avProbe :: RawFilePath -> AV -> IO AVProbe
avProbe f AV = withAVInput f Nothing $ \ic -> do
  findAVStreamInfo ic
  meta <- (\hsc_ptr -> peekByteOff hsc_ptr 1192) ic
{-# LINE 415 "src/Store/AV.hsc" #-}
  AVProbe
    <$> (BS.packCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 0) =<< (\hsc_ptr -> peekByteOff hsc_ptr 8) ic)
{-# LINE 417 "src/Store/AV.hsc" #-}
    <*> (avTime <$> (\hsc_ptr -> peekByteOff hsc_ptr 1088) ic)
{-# LINE 418 "src/Store/AV.hsc" #-}
    <*> do
      nb :: CUInt <- (\hsc_ptr -> peekByteOff hsc_ptr 44) ic
{-# LINE 420 "src/Store/AV.hsc" #-}
      ss <- (\hsc_ptr -> peekByteOff hsc_ptr 48) ic
{-# LINE 421 "src/Store/AV.hsc" #-}
      forM [0..pred (fromIntegral nb)] $ \i -> do
        c <- (\hsc_ptr -> peekByteOff hsc_ptr 8) =<< peekElemOff ss i
{-# LINE 423 "src/Store/AV.hsc" #-}
        t <- (\hsc_ptr -> peekByteOff hsc_ptr 12) c
{-# LINE 424 "src/Store/AV.hsc" #-}
        n <- BS.packCString =<< avcodecGetName =<< (\hsc_ptr -> peekByteOff hsc_ptr 56) c
{-# LINE 425 "src/Store/AV.hsc" #-}
        return (t, n)
    <*> ((=<<) (\t -> parseTimeM True defaultTimeLocale "%F %T%Z" t <|> parseTimeM True defaultTimeLocale "%F %T %Z" t) <$>
      ((`orElseM` getAVDictionary meta "creation_time") =<< getAVDictionary meta "date"))


avSeekStream :: Ptr AVFormatContext -> Ptr AVStream -> Ptr AVFrame -> Maybe DiffTime -> IO ()
avSeekStream ctx s frame offset = do
  off <- forM offset $ \o -> do
    den :: CInt <- (\hsc_ptr -> peekByteOff hsc_ptr 52) s
{-# LINE 434 "src/Store/AV.hsc" #-}
    num :: CInt <- (\hsc_ptr -> peekByteOff hsc_ptr 48) s
{-# LINE 435 "src/Store/AV.hsc" #-}
    let off = floor $ o * (fromIntegral den) / (fromIntegral num)
    throwAVErrorIf_ "avformat_seek_file" (FileContext ctx) $
      avformatSeekFile ctx 0 (-9223372036854775808) off off 0
{-# LINE 438 "src/Store/AV.hsc" #-}
    return off
  si :: CInt <- (\hsc_ptr -> peekByteOff hsc_ptr 0) s
{-# LINE 440 "src/Store/AV.hsc" #-}
  codec <- (\hsc_ptr -> peekByteOff hsc_ptr 8) s
{-# LINE 441 "src/Store/AV.hsc" #-}
  let
    seek = withAVPacket $ \pkt -> do
      avFrameUnref frame
      throwAVErrorIf_ "av_read_frame" (FileContext ctx) $
        avReadFrame ctx pkt
      psi <- (\hsc_ptr -> peekByteOff hsc_ptr 36) pkt
{-# LINE 447 "src/Store/AV.hsc" #-}
      if psi /= si then seek else with 0 $ \gpp -> do
        throwAVErrorIf_ "avcodec_decode_video2" (FileContext ctx) $
          avcodecDecodeVideo2 codec frame gpp pkt
        gp <- peek gpp
        if gp == 0 then seek else do
          pts <- avFrameGetBestEffortTimestamp frame
          if any (pts <) off then seek else
            (\hsc_ptr -> pokeByteOff hsc_ptr 136) frame pts -- done
{-# LINE 455 "src/Store/AV.hsc" #-}
  seek


foreign import ccall unsafe "av.h avFrame_initialize_stream"
  avFrameInitializeStream :: Ptr AVStream -> Ptr AVFormatContext -> Ptr AVStream -> Ptr AVFrame -> CInt -> CInt -> IO ()

foreign import ccall "av.h avFrame_rescale"
  avFrameRescale :: Ptr AVCodecContext -> Ptr AVFrame -> IO CInt

avFrame :: RawFilePath -> Maybe DiffTime -> Maybe Word16 -> Maybe Word16 -> Maybe RawFilePath -> AV -> IO (Maybe BS.ByteString)
avFrame infile offset width height outfile AV =
  withAVInput infile (isimg `thenUse` "image2") $ \inctx ->
  with nullPtr $ \icodecp ->
  withAVDictionary $ \opts -> do
  when isimg $
    (\hsc_ptr -> pokeByteOff hsc_ptr 1160) inctx (8 :: AVCodecID)
{-# LINE 471 "src/Store/AV.hsc" #-}
  findAVStreamInfo inctx

  si <- throwAVErrorIf "av_find_best_stream" (FileContext inctx) $
    avFindBestStream inctx 0 (-1) (-1) icodecp 0
{-# LINE 475 "src/Store/AV.hsc" #-}
  nb :: CUInt <- (\hsc_ptr -> peekByteOff hsc_ptr 44) inctx
{-# LINE 476 "src/Store/AV.hsc" #-}
  isl <- (\hsc_ptr -> peekByteOff hsc_ptr 48) inctx
{-# LINE 477 "src/Store/AV.hsc" #-}
  forM_ [0..pred (fromIntegral nb)] $ \i ->
    when (i /= si) $ do
      is <- peekElemOff isl (fromIntegral i)
      (\hsc_ptr -> pokeByteOff hsc_ptr 84) is (48 :: Int32)
{-# LINE 481 "src/Store/AV.hsc" #-}
  is <- peekElemOff isl (fromIntegral si)

  setAVDictionary opts "threads" "1"
  icodec <- peek icodecp
  withAVCodec inctx is icodec opts $ withAVFrame $ \frame -> do
    avSeekStream inctx is frame offset
    ffmt <- (\hsc_ptr -> peekByteOff hsc_ptr 116) frame
{-# LINE 488 "src/Store/AV.hsc" #-}
    fwidth :: CInt <- (\hsc_ptr -> peekByteOff hsc_ptr 104) frame
{-# LINE 489 "src/Store/AV.hsc" #-}
    fheight :: CInt <- (\hsc_ptr -> peekByteOff hsc_ptr 108) frame
{-# LINE 490 "src/Store/AV.hsc" #-}
    fmap fst $ withAVOutput outfile (maybe "image2pipe" (const "image2") outfile) $ \outctx -> do
      ocodec <- throwAVErrorIfNull "avcodec_find_encoder(AV_CODEC_ID_MJPEG)" (FileContext outctx) $
        avcodecFindEncoder 8
{-# LINE 493 "src/Store/AV.hsc" #-}
      os <- throwAVErrorIfNull "avformat_new_stream" (FileContext outctx) $
        avformatNewStream outctx ocodec
      oc :: Ptr AVCodecContext <- (\hsc_ptr -> peekByteOff hsc_ptr 8) os
{-# LINE 496 "src/Store/AV.hsc" #-}
      avFrameInitializeStream os inctx is frame (maybe (-1) fromIntegral width) (maybe (-1) fromIntegral height)
      owidth <- (\hsc_ptr -> peekByteOff hsc_ptr 156) oc
{-# LINE 498 "src/Store/AV.hsc" #-}
      oheight <- (\hsc_ptr -> peekByteOff hsc_ptr 160) oc
{-# LINE 499 "src/Store/AV.hsc" #-}
      fmts <- (\hsc_ptr -> peekByteOff hsc_ptr 40) ocodec
{-# LINE 500 "src/Store/AV.hsc" #-}
      fmt <- throwAVErrorIf "avcodec_find_best_pix_fmt_of_list" (FileContext outctx) $
        avcodecFindBestPixFmtOfList fmts ffmt 0 nullPtr
      (\hsc_ptr -> pokeByteOff hsc_ptr 176) oc fmt
{-# LINE 503 "src/Store/AV.hsc" #-}
      when (fmt /= ffmt || owidth /= fwidth || oheight /= fheight) $
        throwAVErrorIf_ "av_frame_get_buffer" (FileContext outctx) $
          avFrameRescale oc frame

      setAVDictionary opts "threads" "1"
      withAVCodec outctx os ocodec opts $
        withAVPacket $ \pkt -> with 0 $ \gpp -> do
          throwAVErrorIf_ "avformat_write_header" (FileContext outctx) $
            avformatWriteHeader outctx nullPtr
          throwAVErrorIf_ "avcodec_encode_video2" (FileContext outctx) $
            avcodecEncodeVideo2 oc pkt frame gpp
          gp <- peek gpp
          when (gp == 0) $
            throwAVError 0 "avcodec_encode_video2 packet" (FileContext outctx)
          throwAVErrorIf_ "av_write_frame" (FileContext outctx) $
            avWriteFrame outctx pkt
          throwAVErrorIf_ "av_write_trailer" (FileContext outctx) $
            avWriteTrailer outctx
  where
  isimg = isNothing offset