ebml-0.1.0.0: src/Codec/EBML.hs
{- | This module is intended to be imported qualified:
> import qualified Codec.EBML as EBML
Decode a webm file with:
> EBML.decodeWebMFile "path/file.webm"
Split a webm stream segments with:
> let streamReader = EBML.newStreamReader
> buf <- acquire data
> EBML.feedReader buf streamReader
References:
- EBML specification introduction: https://matroska-org.github.io/libebml/specs.html
- Document layout: https://www.matroska.org/technical/diagram.html
- The matroska schema: https://github.com/ietf-wg-cellar/matroska-specification/blob/master/ebml_matroska.xml
- The matroska schema doc: https://www.matroska.org/technical/elements.html
- The webm guidelines: https://www.webmproject.org/docs/container/
- The MSE byte stream format spec: https://w3c.github.io/media-source/index.html#byte-stream-format-specs
- The MSE byte stream format for webm: https://w3c.github.io/mse-byte-stream-format-webm/
-}
module Codec.EBML (
-- * WebM decoder
decodeWebM,
WebMDocument (..),
WebMCluster (..),
-- * Raw EBML decoder
decodeEBMLDocument,
webmSchemas,
-- * EBML stream reader
module Codec.EBML.Stream,
-- * EBML data types
EBMLDocument (..),
EBMLElement (..),
EBMLValue (..),
EBMLElementHeader (..),
EBMLID (..),
-- * EBML schema data types
EBMLSchema (..),
-- * Helpers
decodeEBMLFile,
decodeWebMFile,
prettyEBMLDocument,
-- * Low-level API, mostly for testing
EBMLSchemas,
compileSchemas,
getDocument,
getElementHeader,
getElementID,
getDataSize,
getElement,
) where
import Data.Binary.Get (runGetOrFail)
import Data.ByteString.Lazy qualified as LBS
import Data.Text (Text)
import Data.Text qualified as Text
import Codec.EBML.Element
import Codec.EBML.Get
import Codec.EBML.Header
import Codec.EBML.Pretty
import Codec.EBML.Schema
import Codec.EBML.Stream
import Codec.EBML.WebM
-- | Lazy decode a 'WebMDocument'.
decodeWebM :: LBS.ByteString -> Either Text WebMDocument
decodeWebM lbs = decodeWebMDocument =<< decodeEBMLDocument webmSchemas lbs
-- | The webm document schemas.
webmSchemas :: [EBMLSchema]
webmSchemas = schemaHeader
-- | Lazy decode a 'EBMLDocument'.
decodeEBMLDocument :: [EBMLSchema] -> LBS.ByteString -> Either Text EBMLDocument
decodeEBMLDocument schemas lbs = case runGetOrFail (getDocument (compileSchemas schemas)) lbs of
Left (_, _, err) -> Left (Text.pack err)
Right ("", _, x) -> Right x
Right (_rest, l, _) -> Left ("Left over data at " <> Text.pack (show l))
-- | Decode a raw EBML file.
decodeEBMLFile :: [EBMLSchema] -> FilePath -> IO (Either Text EBMLDocument)
decodeEBMLFile schemas fp = decodeEBMLDocument schemas <$> LBS.readFile fp
-- | Decode a webm file.
decodeWebMFile :: FilePath -> IO (Either Text WebMDocument)
decodeWebMFile fp = do
ebml <- decodeEBMLFile webmSchemas fp
pure $ decodeWebMDocument =<< ebml