isobmff-builder 0.2.0.3 → 0.3.0.0
raw patch · 13 files changed
+816/−284 lines, 13 filesdep +binarydep +hspecdep +isobmff-builderPVP ok
version bump matches the API change (PVP)
Dependencies added: binary, hspec, isobmff-builder, singletons, vector-sized
API changes (from Hackage documentation)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: (^-) :: (IsBoxType t, IsBoxContent (Boxes t ts)) => ParentBox t -> Boxes t ts -> Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: BoxFlags :: Integer -> BoxFlags bits
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: BoxVersion :: Word8 -> BoxVersion
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: Extend :: a -> b -> Extend a b
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: FullBoxHeader :: BoxVersion -> (BoxFlags 24) -> FullBoxHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: UnverifiedBoxes :: (Boxes t ts) -> UnverifiedBoxes t ts
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:-] :: IsBoxType t => Boxes c ts -> Box t -> Boxes c (t : ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Box] :: (IsBoxType t, IsBoxContent c) => BoxType -> c -> Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [ParentBox] :: (IsBoxType t, IsBoxContent c) => BoxType -> c -> ParentBox t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: box :: forall t c. (IsBoxType t, IsBoxContent c) => c -> Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: boxFlagBitMask :: KnownNat bits => BoxFlags bits -> Integer
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: boxes :: (IsBoxType t, IsBoxContent (Boxes t ts)) => ParentBox t -> Boxes t ts -> Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: class BoxRules t => IsBoxType (t :: k)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: cropBits :: KnownNat bits => BoxFlags bits -> BoxFlags bits
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Box (b :: t)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Extend a b
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data FullBoxHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data ParentBox (b :: t)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: emptyBox :: forall t. (IsBoxType t) => Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: emptyParentBox :: forall t. (IsBoxType t) => ParentBox t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: fullBox :: (IsBoxType t, IsBoxContent c) => BoxVersion -> BoxFlags 24 -> c -> Box t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: infixr 1 ^-
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules t, GHC.TypeLits.KnownSymbol t) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent p, Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent c) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Extend p c)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.Box.FullBoxHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance GHC.TypeLits.KnownNat bits => Data.Bits.Bits (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxFlags bits)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance GHC.TypeLits.KnownNat bits => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxFlags bits)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall k (bits :: k). GHC.Classes.Eq (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxFlags bits)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall k (bits :: k). GHC.Num.Num (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxFlags bits)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall k (bits :: k). GHC.Show.Show (Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxFlags bits)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall t (t1 :: t). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Box t1)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall x (t :: x) (bs :: [x]). (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType t, Data.ByteString.IsoBaseFileFormat.Boxes.Box.ValidBoxes t bs) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Boxes t bs)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall x (t :: x) (bs :: [x]). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.UnverifiedBoxes t bs)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: newtype BoxFlags bits
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: newtype BoxVersion
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: newtype UnverifiedBoxes t ts
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: parentBox :: forall t c. (IsBoxType t, IsBoxContent c) => c -> ParentBox t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: toBoxType :: IsBoxType t => proxy t -> BoxType
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: type FullBox t = Extend FullBoxHeader t
- Data.ByteString.IsoBaseFileFormat.Boxes.FileType: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules "ftyp"
- Data.ByteString.IsoBaseFileFormat.Boxes.FileType: type FileTypeBox = Box "ftyp"
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: MediaData :: ByteString -> MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules "mdat"
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: newtype MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: type MediaDataBox = Box "mdat"
- Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules "moov"
- Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type MovieBox = Box "moov"
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: ProgressiveDownloadInformation :: Word32 -> Word32 -> ProgressiveDownloadInformation
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: [pdinDelay] :: ProgressiveDownloadInformation -> Word32
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: [pdinRate] :: ProgressiveDownloadInformation -> Word32
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: data ProgressiveDownloadInformation
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules "pdin"
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation.ProgressiveDownloadInformation
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: progressiveDownloadInformationBox :: ProgressiveDownloadInformation -> ProgressiveDownloadInformationBox
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: type ProgressiveDownloadInformationBox = Box "pdin"
- Data.ByteString.IsoBaseFileFormat.Boxes.Skip: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules "skip"
- Data.ByteString.IsoBaseFileFormat.Boxes.Skip: type SkipBox = Box "skip"
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:.] :: Boxes ts -> Box' t -> Boxes (t : ts)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Box'] :: (IsBoxType' b, ValidBoxes b ts) => BoxContent b -> Boxes ts -> Box' b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: class (IsBoxContent (BoxContent t), BoxRules t) => IsBoxType' t where type BoxContent t type BoxContent t = () where {
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: closedBox :: (IsBoxType' t, ValidBoxes t '[]) => BoxContent t -> Box' t
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: containerBox :: (IsBoxType' t, ValidBoxes t ts, BoxContent t ~ ()) => Boxes ts -> Box' t
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Box' b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.Internal.ByteString
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall k (bs :: [k]). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Boxes bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance forall k (cnt :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Box' cnt)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: mediaFile :: Boxes ts -> Builder
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: toBoxType' :: IsBoxType' t => proxy t -> BoxType
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type BoxContent t = ();
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: (<+>) :: a -> b -> Extend a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: Extend :: a -> b -> Extend a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: Scalar :: scalartype -> Scalar scalartype
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: [Constant] :: Constant o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: [Custom] :: o -> Template o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: [Default] :: Template o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: [ScalarArray] :: Vector n o -> ScalarArray label n o
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: class FromTypeLit o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: data Constant o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: data Extend a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: data Template o v
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: fromList :: forall label n o. (KnownSymbol label, KnownNat n) => [o] -> ScalarArray label n o
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: fromTypeLit :: FromTypeLit o v => proxy o v -> o
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i16 :: Int16 -> I16 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i16Arr :: (KnownNat size, KnownSymbol label) => [Int16] -> I16Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i32 :: Int32 -> I32 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i32Arr :: (KnownNat size, KnownSymbol label) => [Int32] -> I32Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i64 :: Int64 -> I64 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i64Arr :: (KnownNat size, KnownSymbol label) => [Int64] -> I64Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i8 :: Int8 -> I8 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: i8Arr :: (KnownNat size, KnownSymbol label) => [Int8] -> I8Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent p, Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent c) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Extend p c)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (arr :: [GHC.Types.Nat]) o (len :: GHC.Types.Nat) (label :: k). (Data.Singletons.SingI arr, GHC.Num.Num o, Data.Singletons.SingKind [GHC.Types.Nat], GHC.TypeLits.KnownNat len, len ~ Data.Singletons.Prelude.List.Length arr) => Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.FromTypeLit (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.ScalarArray label len o) arr
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Int.Int16 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Int.Int32 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Int.Int64 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Int.Int8 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Word.Word16 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Word.Word32 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Word.Word64 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (label :: k). Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar GHC.Word.Word8 label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k (scalar :: GHC.Types.Nat) o (label :: k). (GHC.TypeLits.KnownNat scalar, GHC.Num.Num o) => Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.FromTypeLit (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar o label) scalar
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k o (label :: k) (len :: GHC.Types.Nat). (GHC.Num.Num o, Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar o label), GHC.TypeLits.KnownNat len) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.ScalarArray label len o)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k o (v :: k). (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent o, Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.FromTypeLit o v) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Constant o v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall k o (v :: k). (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent o, Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.FromTypeLit o v) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Template o v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall scalartype k (label :: k). GHC.Classes.Eq scalartype => GHC.Classes.Eq (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar scalartype label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall scalartype k (label :: k). GHC.Classes.Ord scalartype => GHC.Classes.Ord (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar scalartype label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall scalartype k (label :: k). GHC.Num.Num scalartype => GHC.Num.Num (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar scalartype label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall scalartype k (label :: k). GHC.Read.Read scalartype => GHC.Read.Read (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar scalartype label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance forall scalartype k (label :: k). GHC.Show.Show scalartype => GHC.Show.Show (Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.Scalar scalartype label)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: newtype Scalar scalartype (label :: k)
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: newtype ScalarArray (label :: k) (len :: Nat) o
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type (:+) a b = Extend a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I16 label = Scalar Int16 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I16Arr label size = ScalarArray label size Int16
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I32 label = Scalar Int32 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I32Arr label size = ScalarArray label size Int32
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I64 label = Scalar Int64 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I64Arr label size = ScalarArray label size Int64
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I8 label = Scalar Int8 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type I8Arr label size = ScalarArray label size Int8
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U16 label = Scalar Word16 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U16Arr label size = ScalarArray label size Word16
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U32 label = Scalar Word32 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U32Arr label size = ScalarArray label size Word32
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U64 label = Scalar Word64 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U64Arr label size = ScalarArray label size Word64
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U8 label = Scalar Word8 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U8Arr label size = ScalarArray label size Word8
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u16 :: Word16 -> U16 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u16Arr :: (KnownNat size, KnownSymbol label) => [Word16] -> U16Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u32 :: Word32 -> U32 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u32Arr :: (KnownNat size, KnownSymbol label) => [Word32] -> U32Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u64 :: Word64 -> U64 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u64Arr :: (KnownNat size, KnownSymbol label) => [Word64] -> U64Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u8 :: Word8 -> U8 label
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: u8Arr :: (KnownNat size, KnownSymbol label) => [Word8] -> U8Arr label size
+ Data.ByteString.IsoBaseFileFormat.Boxes.FileType: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules Data.ByteString.IsoBaseFileFormat.Boxes.FileType.FileType
+ Data.ByteString.IsoBaseFileFormat.Boxes.FileType: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' Data.ByteString.IsoBaseFileFormat.Boxes.FileType.FileType
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: BoxFlags :: Integer -> BoxFlags bits
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: [V0] :: IsBoxContent v0 => v0 -> Versioned v0 v1 0
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: [V1] :: IsBoxContent v1 => v1 -> Versioned v0 v1 1
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: closedFullBox :: (IsBoxType' t, ValidBoxes t '[], BoxContent t ~ FullBox version c) => BoxVersion version -> BoxFlags 24 -> c -> Box' t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: data FullBox version t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: data Versioned v0 v1 (version :: Nat)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: fullBox :: (IsBoxType' t, ValidBoxes t ts, BoxContent t ~ FullBox version c) => BoxVersion version -> BoxFlags 24 -> c -> Boxes ts -> Box' t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance (GHC.TypeLits.KnownNat version, Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent t) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.FullBox version t)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.Versioned v0 v1 version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance GHC.TypeLits.KnownNat bits => Data.Bits.Bits (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.BoxFlags bits)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance GHC.TypeLits.KnownNat bits => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.BoxFlags bits)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance forall k (bits :: k). GHC.Classes.Eq (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.BoxFlags bits)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance forall k (bits :: k). GHC.Num.Num (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.BoxFlags bits)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance forall k (bits :: k). GHC.Show.Show (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.BoxFlags bits)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: newtype BoxFlags bits
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: type BoxVersion v = Template (U8 "fullbox-version") v
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: data MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: [MovieHeader] :: KnownNat version => ((((((Versioned MovieHeaderTimesV0 MovieHeaderTimesV1 version :+ Template (I32 "rate") 65536) :+ Template (I16 "volume") 256) :+ Constant (I16 "reserved") 0) :+ Constant (I32Arr "reserved" 2) '[0, 0]) :+ Constant (I32Arr "matrix" 9) '[65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]) :+ Template (U32Arr "pre_defined" 6) '[0, 0, 0, 0, 0, 0]) :+ U32 "next_track_ID" -> MovieHeader version
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: [TrackHeader] :: (((((((Versioned TrackHeaderTimesV0 TrackHeaderTimesV1 version :+ Constant (I32Arr "reserved" 2) '[0, 0]) :+ Template (I16 "layer") 0) :+ Template (I16 "alternate_group") 0) :+ Template (I16 "volume") 256) :+ Constant (I16 "reserved") 0) :+ Template (I32Arr "matrix" 9) '[65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]) :+ I32 "width") :+ I32 "height" -> TrackHeader version
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: data Movie (version :: Nat)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: data MovieHeader (version :: Nat)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: data Track (version :: Nat)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: data TrackHeader (version :: Nat)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.Movie version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.Track version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.Movie version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.Track version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance GHC.TypeLits.KnownNat version => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: instance GHC.TypeLits.KnownNat version => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' (Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox.TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: movieHeaderBox :: KnownNat version => MovieHeader version -> Box' (MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: track :: ValidBoxes (Track version) ts => Boxes ts -> Box' (Track version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: trackHeader :: KnownNat version => TrackHeader version -> Box' (TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type MovieHeaderTimes uint = ((uint "creation_time" :+ uint "modification_time") :+ U32 "timescale") :+ uint "duration"
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type MovieHeaderTimesV0 = MovieHeaderTimes (Scalar Word32)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type MovieHeaderTimesV1 = MovieHeaderTimes (Scalar Word64)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type TrackHeaderTimes uint = (((uint "creation_time" :+ uint "modification_time") :+ U32 "track_ID") :+ Constant (U32 "reserved") 0) :+ uint "duration"
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type TrackHeaderTimesV0 = TrackHeaderTimes (Scalar Word32)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: type TrackHeaderTimesV1 = TrackHeaderTimes (Scalar Word64)
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: data ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation.ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation.ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: pdinBox :: ProgressiveDownloadContent -> Box' ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: type ProgressiveDownloadContent = U32 "rate" :+ U32 "delay"
+ Data.ByteString.IsoBaseFileFormat.Boxes.Skip: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.BoxRules Data.ByteString.IsoBaseFileFormat.Boxes.Skip.Skip
+ Data.ByteString.IsoBaseFileFormat.Boxes.Skip: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType' Data.ByteString.IsoBaseFileFormat.Boxes.Skip.Skip
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Nested] :: IsBoxType t => Box t -> Boxes c '[t]
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Nested] :: Boxes '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Boxes (cont :: x) (boxTypes :: [x])
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Boxes (boxTypes :: [k])
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: type ValidBoxes t ts = (AllAllowedIn t ts ~ True, HasAllRequiredBoxes t (RequiredNestedBoxes t) ts ~ True, CheckTopLevelOk t ~ True)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type ValidBoxes t ts = (AllAllowedIn t ts ~ True, HasAllRequiredBoxes t (RequiredNestedBoxes t) ts ~ True)
- Data.ByteString.IsoBaseFileFormat.Boxes.FileType: fileTypeBox :: FileType -> FileTypeBox
+ Data.ByteString.IsoBaseFileFormat.Boxes.FileType: fileTypeBox :: FileType -> Box' FileType
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: mediaDataBox :: MediaData -> MediaDataBox
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: mediaDataBox :: ByteString -> Box' MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: movieBox :: ParentBox "moov"
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox: movieBox :: ValidBoxes (Movie version) ts => Boxes ts -> Box' (Movie version)
- Data.ByteString.IsoBaseFileFormat.Boxes.Skip: skipBox :: Skip -> SkipBox
+ Data.ByteString.IsoBaseFileFormat.Boxes.Skip: skipBox :: Skip -> Box' Skip
Files
- isobmff-builder.cabal +51/−1
- spec/BoxFieldsSpec.hs +76/−0
- spec/BoxSpec.hs +57/−0
- spec/Spec.hs +1/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs +96/−220
- src/Data/ByteString/IsoBaseFileFormat/Boxes/BoxFields.hs +239/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs +9/−5
- src/Data/ByteString/IsoBaseFileFormat/Boxes/FullBox.hs +99/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs +9/−12
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieBox.hs +146/−22
- src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs +12/−13
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs +11/−10
- src/Data/ByteString/IsoBaseFileFormat/Builder.hs +10/−1
isobmff-builder.cabal view
@@ -1,5 +1,5 @@ name: isobmff-builder-version: 0.2.0.3+version: 0.3.0.0 synopsis: A (bytestring-) builder for the ISO-14496-12 base media file format description: Please see README.md homepage: https://github.com/sheyll/isobmff-builder#readme@@ -17,7 +17,9 @@ hs-source-dirs: src exposed-modules: Data.ByteString.IsoBaseFileFormat.Builder , Data.ByteString.IsoBaseFileFormat.Boxes.Box+ , Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields , Data.ByteString.IsoBaseFileFormat.Boxes.FileType+ , Data.ByteString.IsoBaseFileFormat.Boxes.FullBox , Data.ByteString.IsoBaseFileFormat.Boxes.MediaData , Data.ByteString.IsoBaseFileFormat.Boxes.Skip , Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation@@ -25,7 +27,11 @@ build-depends: base >= 4.9 && < 5 , bytestring >= 0.10.8.1 , type-list >= 0.5.0.0+ -- , mtl+ , vector-sized >= 0.3.2.0+ , singletons >= 2.2 default-language: Haskell2010+ ghc-options: -Wall -funbox-strict-fields -fno-warn-unused-do-bind default-extensions: ConstraintKinds , CPP , DataKinds@@ -52,6 +58,50 @@ , TypeInType , TypeOperators , TypeSynonymInstances++test-suite spec+ type: exitcode-stdio-1.0+ ghc-options: -Wall+ hs-source-dirs: spec+ default-language: Haskell2010+ main-is: Spec.hs+ other-modules: BoxFieldsSpec+ , BoxSpec+ build-depends: base >= 4.9 && < 5+ , bytestring >= 0.10.8.1+ , hspec+ , isobmff-builder+ , binary+ default-language: Haskell2010+ default-extensions: ConstraintKinds+ , CPP+ , DataKinds+ , DefaultSignatures+ , DeriveDataTypeable+ , DeriveFunctor+ , DeriveGeneric+ , FlexibleInstances+ , FlexibleContexts+ , FunctionalDependencies+ , GADTs+ , GeneralizedNewtypeDeriving+ , KindSignatures+ , MultiParamTypeClasses+ , OverloadedStrings+ , QuasiQuotes+ , RecordWildCards+ , RankNTypes+ , ScopedTypeVariables+ , StandaloneDeriving+ , TemplateHaskell+ , TupleSections+ , TypeFamilies+ , TypeInType+ , TypeOperators+ , TypeSynonymInstances+ ghc-options: -Wall -O0 -j +RTS -A256m -n2m -RTS+ -fwarn-unused-binds -fno-warn-unused-do-bind -fno-warn-missing-signatures+ source-repository head type: git location: https://github.com/githubuser/isobmff-builder
+ spec/BoxFieldsSpec.hs view
@@ -0,0 +1,76 @@+module BoxFieldsSpec (spec) where++import Test.Hspec+import Data.ByteString.IsoBaseFileFormat.Builder+-- import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as BL+-- import qualified Data.Binary.Get as Binary+import Control.Exception (evaluate)++-- import qualified Data.ByteString.Builder as B import qualified Data.ByteString.Lazy as BL import+-- qualified Data.Binary.Get as Binary++spec :: Spec+spec =+ describe "Scalar, Constant, Template and ScalarArry composition" $+ describe "IsBoxContent instances" $+ do describe "example1" $+ do it "boxSize reports the correct size" $+ boxSize example1 `shouldBe` (1 + 1 + (3 * 8) + (7 * 8))+ it "crashes during rendering because of the invalid number of array elements for \"baz\"" $+ evaluate (renderBox example1') `shouldThrow` anyException+ describe "example2" $+ do it "boxSize reports the correct size" $+ boxSize example2 `shouldBe` (2 * 4 + 2 + 2 + 2 + 2 + 9 * 4 + 4 + 4)+ it "it renders the expected content" $+ renderBox example2 `shouldBe` (BL.pack [0,0,0,0,+ 0,0,0,0,+ 0,65,+ 0,66,+ 1,0,+ 0,0,+ 0,0,0,67,+ 0,0,0,68,+ 0,0,0,69,+ 0,0,0,70,+ 0,0,0,71,+ 0,0,0,72,+ 0,0,0,73,+ 0,0,0,74,+ 0,0,0,75,+ 0,0,0,76,+ 0,0,0,77])++renderBox :: IsBoxContent c => c -> BL.ByteString+renderBox = toLazyByteString . boxBuilder++type ExampleContent = Scalar Word8 "bla" :+ Constant (Scalar Word8 "blub") 123 :+ Template (ScalarArray "foos" 3 Int64) '[1, 2, 3] :+ ScalarArray "baz" 7 Word64++type ExampleContentShort = U8 "bla" :+ Constant (U8 "blub") 123 :+ Template (I64Arr "foos" 3) '[1, 2, 3] :+ U64Arr "baz" 7++example1 :: ExampleContent+example1 = Scalar 100 <+> Constant <+> Default <+> u64Arr [1,2,3]++example1' :: ExampleContentShort+example1' = example1++type Example2 isAudio =+ Constant (I32Arr "reserved" 2) '[0, 0]+ :+ Template (I16 "layer") 0+ :+ Template (I16 "alternate_group") 0+ :+ Template (I16 "volume") (If isAudio 256 0)+ :+ Constant (I16 "reserved") 0+ :+ Template (I32Arr "matrix" 9) '[65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]+ :+ I32 "width"+ :+ I32 "height"++example2 :: Example2 'True+example2 =+ Constant <+>+ Custom 65 <+>+ Custom 66 <+>+ Default <+>+ Constant <+>+ Custom (i32Arr [67 .. 75]) <+>+ i32 76 <+>+ i32 77
+ spec/BoxSpec.hs view
@@ -0,0 +1,57 @@+module BoxSpec (spec) where++import Test.Hspec+import Data.ByteString.IsoBaseFileFormat.Builder+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Binary.Get as Binary++spec :: Spec+spec =+ do describe "IsBoxContent instances" $+ do describe "()" $+ do describe "boxSize" $ it "returns 0" $ boxSize () `shouldBe` 0+ describe "boxBuilder" $+ it "emits no data" $+ BL.length (B.toLazyByteString (boxBuilder ())) `shouldBe` 0+ describe "Box" $+ do describe "boxSize" $+ it "returns the header size if the content is empty" $+ boxSize testBox1 `shouldBe` (4 + 4)+ describe "Boxes" $+ do describe "boxSize" $+ do describe "a box with one nested box" $+ do it "returns the sum of both boxSizes" $+ boxSize (testParentBox1 $ Nested :. testBox1) `shouldBe`+ (2 * boxSize testBox1)+ it "returns the same value as written by boxBuilder" $+ let b = testParentBox1 $ Nested :. testBox1+ writtenSize =+ let out = toLazyByteString (boxBuilder b)+ getSize = Binary.runGet Binary.getWord32be+ in BoxSize $ fromIntegral $ getSize out+ reportedSize = boxSize b+ in writtenSize `shouldBe` reportedSize+++data TestBox1++instance BoxRules TestBox1 where+ type RestrictedTo TestBox1 = 'Nothing++instance IsBoxType' TestBox1 where+ toBoxType' _ = StdType "tst1"++testBox1 :: Box' TestBox1+testBox1 = closedBox ()+++data TestParentBox1++instance BoxRules TestParentBox1++instance IsBoxType' TestParentBox1 where+ toBoxType' _ = StdType "par1"++testParentBox1 :: (ValidBoxes TestParentBox1 ts) => Boxes ts -> Box' TestParentBox1+testParentBox1 = containerBox
+ spec/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs view
@@ -20,16 +20,20 @@ import GHC.TypeLits as X import Data.String import Data.Type.Equality- import Data.Type.List import Data.Type.Bool-import Data.Type.Equality-import GHC.Exts+import qualified Data.ByteString as B -- * Basic Types and classes +-- | Base class for all (abstract/phantom/normal-) types that represent boxes+class (IsBoxContent (BoxContent t), BoxRules t) => IsBoxType' t where+ type BoxContent t+ type BoxContent t = ()+ toBoxType' :: proxy t -> BoxType+ -- | A class that describes (on the type level) how a box can be nested into--- other boxes (see 'Boxes').+-- other boxes (see 'Boxes). class BoxRules (t :: k) where -- | List of boxes that this box can be nested into. type RestrictedTo t :: Maybe [k]@@ -43,18 +47,11 @@ type RequiredNestedBoxes t = '[] -- | Describes how many times a box should be present in a container (-box). type GetCardinality t (c :: k) :: Cardinality- type GetCardinality t any = ExactlyOnce+ type GetCardinality t any = 'ExactlyOnce -- | Describes how many times a box should be present in a container. data Cardinality = AtMostOnce | ExactlyOnce | OnceOrMore --- | Convert type level box types to values-class BoxRules t => IsBoxType (t :: k) where- toBoxType :: proxy t -> BoxType--instance (BoxRules t, KnownSymbol t) => IsBoxType t where- toBoxType _ = StdType (fromString (symbolVal (Proxy :: Proxy t)))- -- | Types that go into a box. A box content is a piece of data that can be -- reused in different instances of 'IsBox'. It has no 'BoxType' and hence -- defines no box.@@ -62,49 +59,56 @@ boxSize :: a -> BoxSize boxBuilder :: a -> Builder --- | An empty box content can by represented by @()@ (i.e. /unit/).-instance IsBoxContent () where- boxSize _ = 0- boxBuilder _ = mempty+-- * Data types --- | Box content composed of box contents @a@ and @b@.-data Extend a b =- Extend a- b+-- | A type that wraps the contents of a box and the box type.+data Box' b where+ Box' :: (IsBoxType' b, ValidBoxes b ts) => BoxContent b -> Boxes ts -> Box' b -instance (IsBoxContent p,IsBoxContent c) => IsBoxContent (Extend p c) where- boxSize (Extend p c) = boxSize p + boxSize c- boxBuilder (Extend p c) = boxBuilder p <> boxBuilder c+instance IsBoxContent (Box' cnt) where+ boxBuilder b@(Box' cnt nested) = sB <> tB <> sExtB <> tExtB <> cntB <> nestedB+ where s = boxSize b+ t = toBoxType' b+ sB = boxBuilder s+ sExtB = boxBuilder (BoxSizeExtension s)+ tB = boxBuilder t+ tExtB = boxBuilder (BoxTypeExtension t)+ cntB = boxBuilder cnt+ nestedB = boxBuilder nested --- * Boxes+ boxSize b@(Box' cnt nested) = sPayload + boxSize (BoxSizeExtension sPayload)+ where sPayload = boxSize (BoxSize undefined)+ + boxSize t+ + boxSize cnt+ + boxSize (BoxTypeExtension t)+ + boxSize nested+ t = toBoxType' b --- | Create a 'Box' from any 'IsBoxContent' with a type.-box :: forall t c.- (IsBoxType t,IsBoxContent c)- => c -> Box t-box cnt = Box (toBoxType (Proxy :: Proxy t)) cnt+-- | A heterogenous collection of boxes.+data Boxes (boxTypes :: [k]) where+ Nested :: Boxes '[]+ (:.) :: Boxes ts -> Box' t -> Boxes (t ': ts) --- | An /empty/ box. This is for boxes without any extra /fields/. Although it is--- called /emptyBox/ it might still contain nested boxes.-emptyBox :: forall t . (IsBoxType t) => Box t-emptyBox = box ()+infixl 2 :. --- | A type that wraps the contents of a box and the box type.-data Box (b :: t) where- Box :: (IsBoxType t,IsBoxContent c) => BoxType -> c -> Box t+instance IsBoxContent (Boxes bs) where+ boxSize Nested = 0+ boxSize (bs :. b) = boxSize bs + boxSize b+ boxBuilder Nested = mempty+ boxBuilder (bs :. b) = boxBuilder bs <> boxBuilder b -instance IsBoxContent (Box t) where- boxBuilder b@(Box t cnt) = sFix <> tFix <> sExt <> tExt <> boxBuilder cnt- where s = boxSize b- sFix = boxBuilder s- sExt = boxBuilder (BoxSizeExtension s)- tFix = boxBuilder t- tExt = boxBuilder (BoxTypeExtension t)- boxSize b@(Box t cnt) = sPayload + boxSize (BoxSizeExtension sPayload)- where sPayload =- boxSize sPayload + boxSize t + boxSize cnt +- boxSize (BoxTypeExtension t)+-- | A box that contains no nested boxes.+closedBox :: (IsBoxType' t, ValidBoxes t '[]) => BoxContent t -> Box' t+closedBox c = Box' c Nested +-- | A box that contains no fields, but nested boxes.+containerBox :: (IsBoxType' t, ValidBoxes t ts, BoxContent t ~ ()) => Boxes ts -> Box' t+containerBox = Box' ()++-- | A complete media file, consisting of top-level boxes.+mediaFile :: Boxes ts -> Builder+mediaFile = boxBuilder+ -- * Box Size and Type -- | The size of the box. If the size is limited to a (fixed) value, it can be@@ -121,7 +125,7 @@ boxBuilder UnlimitedSize = word32BE 0 boxBuilder (BoxSize n) = word32BE $- if n < 2 ^ 32+ if n < (4294967296 :: Word64) then fromIntegral n else 1 @@ -149,13 +153,13 @@ instance IsBoxContent BoxSizeExtension where boxBuilder (BoxSizeExtension UnlimitedSize) = mempty boxBuilder (BoxSizeExtension (BoxSize n)) =- if n < 2 ^ 32+ if n < 4294967296 then mempty else word64BE n boxSize (BoxSizeExtension UnlimitedSize) = 0 boxSize (BoxSizeExtension (BoxSize n)) = BoxSize $- if n < 2 ^ 32+ if n < 4294967296 then 0 else 8 @@ -194,7 +198,7 @@ boxBuilder t = case t of StdType x -> boxBuilder x- CustomBoxType u -> boxBuilder (FourCc ('u','u','i','d'))+ CustomBoxType _ -> boxBuilder (FourCc ('u','u','i','d')) -- | When using custom types extra data must be written after the extra size -- information. Since the box type and the optional custom box type are not@@ -213,82 +217,14 @@ -- * Type-safe box composition --- | A 'ParentBox' is a 'Box' but without it's children. It has no--- 'IsBoxContent' instance, and it must be converted to a real 'Box' using--- 'boxes'. This is to prevent creation of boxes with invalid children.-data ParentBox (b :: t) where- ParentBox :: (IsBoxType t,IsBoxContent c) => BoxType -> c -> ParentBox t --- | A parent box. Similar to 'box' but for 'ParentBox'es.-parentBox :: forall t c . (IsBoxType t, IsBoxContent c) => c -> ParentBox t-parentBox = toParentBox . box- where toParentBox :: IsBoxType s => Box s -> ParentBox s- toParentBox (Box t c) = ParentBox t c---- | A 'ParentBox' without /fields/.-emptyParentBox :: forall t . (IsBoxType t) => ParentBox t-emptyParentBox = parentBox ()---- | A box that containing nested boxes. The nesting is validated at compile--- time using 'BoxRules'. -boxes :: (IsBoxType t,IsBoxContent (Boxes t ts))- => ParentBox t -> Boxes t ts -> Box t-boxes p = box . Extend (toBox p)- where- toBox :: IsBoxType t => ParentBox t -> Box t- toBox (ParentBox t c) = Box t c---- | An operator for starting a 'Boxes' from the parent box.------ Example:--- > xxx :: Box "moov"--- > xxx = movieBox--- > ^- Nested (movieHeaderBox (MovieHeader ...))--- > :- (trackBox--- > ^- Nested (trackHeaderBox (TrackHeader ...))--- > :- trackReferenceBox (TrackReference ...)--- > :- trackGroupingIndication (TrackGroupingInd ...))----(^-) :: (IsBoxType t,IsBoxContent (Boxes t ts))- => ParentBox t -> Boxes t ts -> Box t-parent ^- nested = parent ^- nested--infixr 1 ^----- | A heterogenous collection of child boxes for a parent box wiht type @cont@.-data Boxes (cont :: x) (boxTypes :: [x]) where- Nested :: IsBoxType t => Box t -> Boxes c '[t]- (:-) :: IsBoxType t => Boxes c ts -> Box t -> Boxes c (t ': ts)--infixl 2 :----- | To be nested into a box, 'Boxes' must be an instance of 'IsBoxContent'.--- This instance concatenates all nested boxes.-instance (IsBoxType t,ValidBoxes t bs) => IsBoxContent (Boxes t bs) where- boxSize bs = boxSize (UnverifiedBoxes bs)- boxBuilder bs = boxBuilder (UnverifiedBoxes bs)---- | An internal wrapper type around 'Boxes' for the 'IsBoxContent' instance.--- Since the 'IsBoxContent' instance recursivly deconstructs a 'Boxes' the--- constraints for the validity 'ValidBoxes' cannot be asserted. To circumvent--- this the 'IsBoxContent' instance for 'Boxes' delegates to the instance of--- 'UnverifiedBoxes', which has no 'ValidBoxes' constraint in the instance head.-newtype UnverifiedBoxes t ts = UnverifiedBoxes (Boxes t ts)--instance IsBoxContent (UnverifiedBoxes t bs) where- boxSize (UnverifiedBoxes (Nested b)) = boxSize b- boxSize (UnverifiedBoxes (bs :- b)) = boxSize (UnverifiedBoxes bs) + boxSize b- boxBuilder (UnverifiedBoxes (Nested b)) = boxBuilder b- boxBuilder (UnverifiedBoxes (bs :- b)) = boxBuilder (UnverifiedBoxes bs) <> boxBuilder b- -- * Type level consistency checks -- | A type-level check that uses 'BoxRules' to check that the contained boxes -- are standard conform. type ValidBoxes t ts = ( AllAllowedIn t ts ~ 'True- , HasAllRequiredBoxes t (RequiredNestedBoxes t) ts ~ 'True- , CheckTopLevelOk t ~ 'True)+ , HasAllRequiredBoxes t (RequiredNestedBoxes t) ts ~ 'True ) -- | A type function to check that all nested boxes are allowed in the -- container.@@ -307,18 +243,18 @@ -- | The custom (type-) error message for 'AllAllowedIn'. type NotAllowedMsg c t =- Text "Boxes of type: "- :<>: ShowType c- :<>: Text " may not contain boxes of type "- :<>: ShowType t- :$$: Text "Valid containers for "- :<>: ShowType t- :<>: Text " boxes are: "- :$$: ShowType (RestrictedTo t)- :$$: ShowType t- :<>: If (IsTopLevelBox c)- (Text " boxes may appear top-level in a file.")- (Text " boxes must be nested.")+ 'Text "Boxes of type: "+ ':<>: 'ShowType c+ ':<>: 'Text " may not contain boxes of type "+ ':<>: 'ShowType t+ ':$$: 'Text "Valid containers for "+ ':<>: 'ShowType t+ ':<>: 'Text " boxes are: "+ ':$$: 'ShowType (RestrictedTo t)+ ':$$: 'ShowType t+ ':<>: If (IsTopLevelBox c)+ ('Text " boxes may appear top-level in a file.")+ ('Text " boxes must be nested.") -- | Check that all required boxes have been nested.@@ -332,103 +268,43 @@ type IsSubSet base sub = Intersection base sub == sub --- | The custom (type-) error message for 'HasAllRequiredBoxes'.+-- | The custom (type-) error message for 'HasAllRequiredBoxes. type MissingRequired c r nested =- Text "Boxes of type: "- :<>: ShowType c- :<>: Text " require these nested boxes: "- :<>: ShowType (RequiredNestedBoxes c)- :$$: Text "but only these box types were nested: "- :<>: ShowType nested- :$$: Text "e.g. this type is missing: "- :<>: ShowType r+ 'Text "Boxes of type: "+ ':<>: 'ShowType c+ ':<>: 'Text " require these nested boxes: "+ ':<>: 'ShowType (RequiredNestedBoxes c)+ ':$$: 'Text "but only these box types were nested: "+ ':<>: 'ShowType nested+ ':$$: 'Text "e.g. this type is missing: "+ ':<>: 'ShowType r +-- | Check that all boxes may appear top-level.+type family CheckAllTopLevelOk (ts :: [k]) :: Bool where+ CheckAllTopLevelOk '[] = 'True+ CheckAllTopLevelOk (t ': rest) = CheckTopLevelOk t && CheckAllTopLevelOk rest+ -- | Check that the box may appear top-level. type family CheckTopLevelOk (t :: k) :: Bool where CheckTopLevelOk t = IsTopLevelBox t || TypeError (NotTopLevenError t) + -- | The custom (type-) error message indicating that a box may not appear -- top-level. type NotTopLevenError c =- Text "Boxes of type "- :<>: ShowType c- :<>: Text " MUST be nested inside boxes of these types: "- :$$: ShowType (RestrictedTo c)---- * Full Boxes---- | A `Box` with /version/ and /branding/ information-type FullBox t = Extend FullBoxHeader t---- | Create a 'FullBox' from a 'FourCc' 'StdType' and the nested box content.-fullBox- :: (IsBoxType t, IsBoxContent c)- => BoxVersion -> BoxFlags 24 -> c -> Box t-fullBox ver fs cnt = box (Extend (FullBoxHeader ver fs) cnt)---- | The additional header with /version/ and /branding/ information-data FullBoxHeader =- FullBoxHeader BoxVersion- (BoxFlags 24)--instance IsBoxContent FullBoxHeader where- boxSize (FullBoxHeader _ f) = 1 + boxSize f- boxBuilder (FullBoxHeader (BoxVersion v) f) = word8 v <> boxBuilder f---- | The box version (in a 'FullBox') is a single byte-newtype BoxVersion =- BoxVersion Word8---- | In addition to a 'BoxVersion' there can be 24 bits for custom flags etc in--- a 'FullBox'.-newtype BoxFlags bits =- BoxFlags Integer- deriving (Eq,Show,Num)---- | Internal function that creates a bit mask with all bits in a 'BoxFlags' set--- to 1.-boxFlagBitMask :: KnownNat bits- => BoxFlags bits -> Integer-boxFlagBitMask px = 2 ^ natVal px - 1+ 'Text "Boxes of type "+ ':<>: 'ShowType c+ ':<>: 'Text " MUST be nested inside boxes of these types: "+ ':$$: 'ShowType (RestrictedTo c) --- | Internal function that masks-out all bits higher than 'bits'.-cropBits :: KnownNat bits- => BoxFlags bits -> BoxFlags bits-cropBits f@(BoxFlags b) = BoxFlags (b .&. boxFlagBitMask f)+-- * 'IsBoxContent' instances --- | Get the number of bytes required to store a number of bits.-instance KnownNat bits => IsBoxContent (BoxFlags bits) where- boxSize f =- let minBytes = fromInteger $ natVal f `div` 8- modBytes = fromInteger $ natVal f `mod` 8- in BoxSize $ minBytes + signum modBytes- boxBuilder f@(BoxFlags b) =- let bytes =- let (BoxSize bytes') = boxSize f- in fromIntegral bytes'- wordSeq n- | n <= bytes =- word8 (fromIntegral (shiftR b ((bytes - n) * 8) .&. 255)) <>- wordSeq (n + 1)- | otherwise = mempty- in wordSeq 1+-- | An empty box content can by represented by @()@ (i.e. /unit/).+instance IsBoxContent () where+ boxSize _ = 0+ boxBuilder _ = mempty -instance KnownNat bits => Bits (BoxFlags bits) where- (.&.) lf@(BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r- (.|.) lf@(BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r- xor (BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ xor l r- complement (BoxFlags x) = cropBits $ BoxFlags $ complement x- shift (BoxFlags x) = cropBits . BoxFlags . shift x- rotateL = error "TODO rotateL"- rotateR = error "TODO rotateR"- bitSize = fromInteger . natVal- bitSizeMaybe = Just . fromInteger . natVal- isSigned _ = False- testBit f n =- let (BoxFlags b) = cropBits f- in testBit b n- bit = cropBits . BoxFlags . bit- popCount f =- let (BoxFlags b) = cropBits f- in popCount b- zeroBits = BoxFlags 0+-- | Trivial instance for 'ByteString'+instance IsBoxContent B.ByteString where+ boxSize = fromIntegral . B.length+ boxBuilder = byteString
+ src/Data/ByteString/IsoBaseFileFormat/Boxes/BoxFields.hs view
@@ -0,0 +1,239 @@+-- | Mini EDSL for labelled box fields. The boxfields can be 'Scalar' or+-- 'ScalarArray's.+module Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields+ where++import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.Int+import Data.Maybe+import Text.Printf+import Data.Singletons+import Data.Singletons.Prelude.List+import qualified Data.Vector.Sized as Vec++-- * Scalar box fields++type U64 label = Scalar Word64 label++type I64 label = Scalar Int64 label++u64 :: Word64 -> U64 label+u64 = Scalar++i64 :: Int64 -> I64 label+i64 = Scalar++type U32 label = Scalar Word32 label++type I32 label = Scalar Int32 label++u32 :: Word32 -> U32 label+u32 = Scalar++i32 :: Int32 -> I32 label+i32 = Scalar++type U16 label = Scalar Word16 label++type I16 label = Scalar Int16 label++u16 :: Word16 -> U16 label+u16 = Scalar++i16 :: Int16 -> I16 label+i16 = Scalar++type U8 label = Scalar Word8 label++type I8 label = Scalar Int8 label++u8 :: Word8 -> U8 label+u8 = Scalar++i8 :: Int8 -> I8 label+i8 = Scalar++-- | A numeric box field with a type level label. Note that it has a 'Num'+-- instance. Use the type aliases above, e.g.+-- 'U8','I8','U16','I16','U32','I32','U64','I64' from above. Use either the+-- smart constructors, e.g. 'u8','i8','u16','i16','u32','i32','u64','i64' or the+-- 'Num' instance, whereas the constructors might give a bit more safety.+newtype Scalar scalartype (label :: k) =+ Scalar scalartype deriving (Show, Read, Ord, Eq, Num)++instance IsBoxContent (Scalar Word8 label) where+ boxSize _ = 1+ boxBuilder (Scalar v) = word8 v++instance IsBoxContent (Scalar Word16 label) where+ boxSize _ = 2+ boxBuilder (Scalar v) = word16BE v++instance IsBoxContent (Scalar Word32 label) where+ boxSize _ = 4+ boxBuilder (Scalar v) = word32BE v++instance IsBoxContent (Scalar Word64 label) where+ boxSize _ = 8+ boxBuilder (Scalar v) = word64BE v++instance IsBoxContent (Scalar Int8 label) where+ boxSize _ = 1+ boxBuilder (Scalar v) = int8 v++instance IsBoxContent (Scalar Int16 label) where+ boxSize _ = 2+ boxBuilder (Scalar v) = int16BE v++instance IsBoxContent (Scalar Int32 label) where+ boxSize _ = 4+ boxBuilder (Scalar v) = int32BE v++instance IsBoxContent (Scalar Int64 label) where+ boxSize _ = 8+ boxBuilder (Scalar v) = int64BE v++instance (KnownNat scalar,Num o) => FromTypeLit (Scalar o label) scalar where+ fromTypeLit _ = Scalar $ fromIntegral $ natVal (Proxy :: Proxy scalar)++-- * Array fields++type U64Arr label size = ScalarArray label size Word64++u64Arr :: (KnownNat size,KnownSymbol label)+ => [Word64] -> U64Arr label size+u64Arr = fromList++type I64Arr label size = ScalarArray label size Int64++i64Arr :: (KnownNat size,KnownSymbol label)+ => [Int64] -> I64Arr label size+i64Arr = fromList++type U32Arr label size = ScalarArray label size Word32++u32Arr :: (KnownNat size,KnownSymbol label)+ => [Word32] -> U32Arr label size+u32Arr = fromList++type I32Arr label size = ScalarArray label size Int32++i32Arr :: (KnownNat size,KnownSymbol label)+ => [Int32] -> I32Arr label size+i32Arr = fromList++type U16Arr label size = ScalarArray label size Word16++u16Arr :: (KnownNat size,KnownSymbol label)+ => [Word16] -> U16Arr label size+u16Arr = fromList++type I16Arr label size = ScalarArray label size Int16++i16Arr :: (KnownNat size,KnownSymbol label)+ => [Int16] -> I16Arr label size+i16Arr = fromList++type U8Arr label size = ScalarArray label size Word8++u8Arr :: (KnownNat size,KnownSymbol label)+ => [Word8] -> U8Arr label size+u8Arr = fromList++type I8Arr label size = ScalarArray label size Int8++i8Arr :: (KnownNat size,KnownSymbol label)+ => [Int8] -> I8Arr label size+i8Arr = fromList++-- | A box field that is an array of 'Scalar's with a type level label. Use the+-- type aliases, e.g.+-- 'U8Arr','I8Arr','U16Arr','I16Arr','U32Arr','I32Arr','U64Arr','I64Arr' from+-- above. Use the smart constructors, e.g.+-- 'u8Arr','i8Arr','u16Arr','i16Arr','u32Arr','i32Arr','u64Arr','i64Arr' .+newtype ScalarArray (label :: k) (len :: Nat) o where+ ScalarArray :: Vec.Vector n o -> ScalarArray label n o++instance (Num o,IsBoxContent (Scalar o label),KnownNat (len :: Nat)) => IsBoxContent (ScalarArray label len o) where+ boxSize (ScalarArray vec) =+ fromIntegral (Vec.length vec) * boxSize (Scalar 0 :: Scalar o label)+ boxBuilder (ScalarArray vec) =+ Vec.foldl' mappend+ mempty+ (Vec.map (boxBuilder . mkScalar) vec)+ where mkScalar :: o -> Scalar o label+ mkScalar = Scalar++-- | Internal function+fromList :: forall label n o.+ (KnownSymbol label,KnownNat n)+ => [o] -> ScalarArray label n o+fromList l =+ ScalarArray $+ case Vec.fromList l of+ Nothing ->+ error $+ printf "Invalid number of array elements for array %s. Got length: %d elments, expected %d."+ (show (symbolVal (Proxy :: Proxy label)))+ (length l)+ (natVal (Proxy :: Proxy n))+ Just v -> v++-- * Constant fields++-- | Wrapper around a field, e.g. a 'Scalar' or 'ScalarArray', with a type level+-- value. The wrapped content must implement 'FromTypeLit'.+data Constant o v where+ Constant :: Constant o v++instance (IsBoxContent o,FromTypeLit o v) => IsBoxContent (Constant o v) where+ boxSize = boxSize . fromTypeLit+ boxBuilder = boxBuilder . fromTypeLit++-- * Template Fields++-- | Fields with default values that can be overriden with custom value. Like+-- 'Constant' this is a wrapper around a field, e.g. a 'Scalar' or+-- 'ScalarArray', with a type level default value. The wrapped content must+-- implement 'FromTypeLit'.+data Template o v where+ Default :: Template o v+ Custom :: o -> Template o v++instance (IsBoxContent o,FromTypeLit o v) => IsBoxContent (Template o v) where+ boxSize = boxSize . fromTypeLit+ boxBuilder d@Default = boxBuilder $ fromTypeLit d+ boxBuilder (Custom o) = boxBuilder o++-- * Conversion from type-level numbers and lists to values++-- | Types that can be constructed from type level value representations.+class FromTypeLit o v where+ fromTypeLit :: proxy o v -> o++instance (SingI arr,Num o,SingKind [Nat],KnownNat len,len ~ Length arr) => FromTypeLit (ScalarArray label len o) (arr :: [Nat]) where+ fromTypeLit _ =+ let s = sing :: Sing arr+ vs :: [Integer]+ vs = fromSing s+ vs' :: [o]+ vs' = fromIntegral <$> vs+ in ScalarArray (fromJust (Vec.fromList vs'))++-- * Box concatenation++-- | Box content composition+data Extend a b =+ Extend a+ b++-- | An operator for 'Extend'.+type a :+ b = Extend a b++-- | An operator for 'Extend'.+(<+>) :: a -> b -> Extend a b+(<+>) = Extend++instance (IsBoxContent p,IsBoxContent c) => IsBoxContent (Extend p c) where+ boxSize (Extend p c) = boxSize p + boxSize c+ boxBuilder (Extend p c) = boxBuilder p <> boxBuilder c
src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs view
@@ -3,14 +3,17 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Box -- | File Type Box-type FileTypeBox = Box "ftyp" -instance BoxRules "ftyp"+instance BoxRules FileType +instance IsBoxType' FileType where+ type BoxContent FileType = FileType+ toBoxType' _ = StdType "ftyp"+ -- | Create a 'FileTypeBox' from a major brand, a minor version and a list of -- compatible brands-fileTypeBox :: FileType -> FileTypeBox-fileTypeBox = box+fileTypeBox :: FileType -> Box' FileType+fileTypeBox = closedBox -- | Contents of a 'ftyp' box are some 'FourCc' /brands/ and a version. data FileType =@@ -19,6 +22,7 @@ ,compatibleBrands :: [FourCc]} instance IsBoxContent FileType where- boxSize (FileType maj ver comps) = boxSize maj + 4 + sum (boxSize <$> comps)+ boxSize (FileType maj _ver comps) =+ boxSize maj + 4 + sum (boxSize <$> comps) boxBuilder (FileType maj ver comps) = boxBuilder maj <> word32BE ver <> mconcat (boxBuilder <$> comps)
+ src/Data/ByteString/IsoBaseFileFormat/Boxes/FullBox.hs view
@@ -0,0 +1,99 @@+-- | Full Boxes+module Data.ByteString.IsoBaseFileFormat.Boxes.FullBox+ (FullBox(), fullBox, closedFullBox, BoxVersion, BoxFlags(..), Versioned(..)) where++import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields++-- | A 'FullBox' contains an extra version and a flags field. In this+-- implementation it is wrapped around the rest of the box content. This+-- enforces that the 'FullBox' header fields are always at the beginning - at+-- least as long as this module hides the 'FullBox' constructor ;)+data FullBox version t where+ FullBox ::+ BoxVersion version -> BoxFlags 24 -> t -> FullBox version t++instance (KnownNat version,IsBoxContent t) => IsBoxContent (FullBox version t) where+ boxSize (FullBox _ f c) = 1 + boxSize f + boxSize c+ boxBuilder (FullBox v f c) = boxBuilder v <> boxBuilder f <> boxBuilder c++-- | Create a 'FullBox' from a 'BoxVersion' and 'BoxFlags'+fullBox+ :: (IsBoxType' t,ValidBoxes t ts,BoxContent t ~ FullBox version c)+ => BoxVersion version -> BoxFlags 24 -> c -> Boxes ts -> Box' t+fullBox version fs cnt = Box' (FullBox version fs cnt)++-- | Create a 'FullBox' from a 'BoxVersion' and 'BoxFlags' without nested boxes.+closedFullBox+ :: (IsBoxType' t,ValidBoxes t '[],BoxContent t ~ FullBox version c)+ => BoxVersion version -> BoxFlags 24 -> c -> Box' t+closedFullBox version fs cnt = closedBox (FullBox version fs cnt)++-- | The box version (in a 'FullBox') is a single byte+type BoxVersion v = Template (U8 "fullbox-version") v++-- | Two alternative representations based on a /version/ index.+-- Use this for box content that can be either 32 or 64 bit.+data Versioned v0 v1 (version :: Nat) where+ V0 :: IsBoxContent v0 => v0 -> Versioned v0 v1 0+ V1 :: IsBoxContent v1 => v1 -> Versioned v0 v1 1++instance IsBoxContent (Versioned v0 v1 version) where+ boxSize (V0 c) = boxSize c+ boxSize (V1 c) = boxSize c+ boxBuilder (V0 c) = boxBuilder c+ boxBuilder (V1 c) = boxBuilder c++-- | In addition to a 'BoxVersion' there can be 24 bits for custom flags etc in+-- a 'FullBox'.+newtype BoxFlags bits =+ BoxFlags Integer+ deriving (Eq,Show,Num)++-- | Internal function that creates a bit mask with all bits in a 'BoxFlags' set+-- to 1.+boxFlagBitMask :: KnownNat bits+ => BoxFlags bits -> Integer+boxFlagBitMask px = 2 ^ natVal px - 1++-- | Internal function that masks-out all bits higher than 'bits'.+cropBits :: KnownNat bits+ => BoxFlags bits -> BoxFlags bits+cropBits f@(BoxFlags b) = BoxFlags (b .&. boxFlagBitMask f)++-- | Get the number of bytes required to store a number of bits.+instance KnownNat bits => IsBoxContent (BoxFlags bits) where+ boxSize f =+ let minBytes = fromInteger $ natVal f `div` 8+ modBytes = fromInteger $ natVal f `mod` 8+ in BoxSize $ minBytes + signum modBytes+ boxBuilder f@(BoxFlags b) =+ let bytes =+ let (BoxSize bytes') = boxSize f+ in fromIntegral bytes'+ wordSeq n+ | n <= bytes =+ word8 (fromIntegral (shiftR b ((bytes - n) * 8) .&. 255)) <>+ wordSeq (n + 1)+ | otherwise = mempty+ in wordSeq 1++instance KnownNat bits => Bits (BoxFlags bits) where+ (.&.) (BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r+ (.|.) (BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r+ xor (BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ xor l r+ complement (BoxFlags x) = cropBits $ BoxFlags $ complement x+ shift (BoxFlags x) = cropBits . BoxFlags . shift x+ rotateL = error "TODO rotateL"+ rotateR = error "TODO rotateR"+ bitSize = fromInteger . natVal+ bitSizeMaybe = Just . fromInteger . natVal+ isSigned _ = False+ testBit f n =+ let (BoxFlags b) = cropBits f+ in testBit b n+ bit = cropBits . BoxFlags . bit+ popCount f =+ let (BoxFlags b) = cropBits f+ in popCount b+ zeroBits = BoxFlags 0
src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs view
@@ -4,18 +4,15 @@ import qualified Data.ByteString as B -- | Media data box-type MediaDataBox = Box "mdat"--instance BoxRules "mdat"+data MediaData --- | Create a 'MediaDataBox' from a strict 'ByteString'-mediaDataBox :: MediaData -> MediaDataBox-mediaDataBox = box+instance BoxRules MediaData --- | Contents of a 'mdat' box are just bytes from a strict 'ByteString'-newtype MediaData =- MediaData B.ByteString+instance IsBoxType' MediaData where+ -- | Contents of a 'mdat' box are just bytes from a strict 'ByteString'+ type BoxContent MediaData = B.ByteString+ toBoxType' _ = StdType "mdat" -instance IsBoxContent MediaData where- boxSize (MediaData bs) = fromIntegral $ B.length bs- boxBuilder (MediaData bs) = byteString bs+-- | Create a 'MediaDataBox' from a strict 'ByteString'+mediaDataBox :: B.ByteString -> Box' MediaData+mediaDataBox = closedBox
src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieBox.hs view
@@ -1,32 +1,156 @@+{-# LANGUAGE UndecidableInstances #-}+ -- | Meta data for a presentation of a /movie/. module Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox where import Data.ByteString.IsoBaseFileFormat.Boxes.Box--- Uncomment this to see what the custom compiler errors look like:+import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields+import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox++-- | Compose a set of boxes into a 'MovieBox' ---import Data.ByteString.IsoBaseFileFormat.Boxes.Skip+-- Example:+--+-- > xxx :: Box' Movie+-- > xxx = movieBox $+-- > Nested (movieHeaderBox (...))+-- > :. (trackBox $+-- > Nested (trackHeaderBox (TrackHeader ...))+-- > :. trackReferenceBox (TrackReference ...)+-- > :. trackGroupingIndication (TrackGroupingInd ...))+--+movieBox :: ValidBoxes (Movie version) ts+ => Boxes ts -> Box' (Movie version)+movieBox = containerBox --- xxx :: Box "moov"--- xxx = movieBox--- (movieBoxContainer :- skipBox (Skip 100))--- | The metadata for a presentation, a single 'MovieBox' which occurs only once+-- | The metadata for a presentation, a single 'Movie' which occurs only once -- and top-level. It is pretty empty on it's own, but it contains nested boxes -- with all the relevant meta data.-type MovieBox = Box "moov"+data Movie (version :: Nat) -instance BoxRules "moov" where- type RequiredNestedBoxes "moov" = '["mvhd", "trak"]+instance IsBoxType' (Movie version) where+ toBoxType' _ = StdType "moov" --- | A movie parent box. Combine with the nested 'Boxes' using 'boxes' or '(^-)'------ Example:--- > xxx :: Box "moov"--- > xxx = movieBox--- > ^- Nested (movieHeaderBox (MovieHeader ...))--- > :- (trackBox--- > ^- Nested (trackHeaderBox (TrackHeader ...))--- > :- trackReferenceBox (TrackReference ...)--- > :- trackGroupingIndication (TrackGroupingInd ...))----movieBox :: ParentBox "moov"-movieBox = emptyParentBox+instance BoxRules (Movie version) where+ type RequiredNestedBoxes (Movie version) = '[MovieHeader version]++-- * @mvhd@ Box++-- | Construct a 'MovieHeader' box.+movieHeaderBox+ :: KnownNat version+ => MovieHeader version -> Box' (MovieHeader version)+movieHeaderBox = closedFullBox Default 0++-- | Movie meta data, indexed by a version.+data MovieHeader (version :: Nat) where+ MovieHeader ::+ KnownNat version =>+ Versioned MovieHeaderTimesV0+ MovieHeaderTimesV1+ version+ :+ Template (I32 "rate") 0x00010000+ :+ Template (I16 "volume") 0x0100+ :+ Constant (I16 "reserved") 0+ :+ Constant (I32Arr "reserved" 2) '[0,0]+ :+ Constant (I32Arr "matrix" 9)+ '[65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]+ :+ Template (U32Arr "pre_defined" 6) '[0,0,0,0,0,0]+ :+ U32 "next_track_ID"+ -> MovieHeader version++-- | Time and timing information about a movie (32bit version).+type MovieHeaderTimesV0 = MovieHeaderTimes (Scalar Word32)++-- | Time and timing information about a movie (64bit version).+type MovieHeaderTimesV1 = MovieHeaderTimes (Scalar Word64)++-- | Time and timing information about a movie.+type MovieHeaderTimes uint =+ uint "creation_time"+ :+ uint "modification_time"+ :+ U32 "timescale"+ :+ uint "duration"++instance IsBoxContent (MovieHeader version) where+ boxSize (MovieHeader c) = boxSize c+ boxBuilder (MovieHeader c) = boxBuilder c++instance KnownNat version => IsBoxType' (MovieHeader version) where+ toBoxType' _ = StdType "mvhd"+ type BoxContent (MovieHeader version) = FullBox version (MovieHeader version)++instance BoxRules (MovieHeader version) where+ type IsTopLevelBox (MovieHeader version) = 'False+ type GetCardinality (MovieHeader version) any = 'ExactlyOnce+ type RestrictedTo (MovieHeader version) = 'Just '[Movie version]++-- * @trak@ Box++-- | Compose a 'Track' box from the given boxes.+track :: ValidBoxes (Track version) ts+ => Boxes ts -> Box' (Track version)+track = containerBox++-- | Container box for tracks.+data Track (version :: Nat)++instance IsBoxType' (Track version) where+ toBoxType' _ = StdType "trak"++instance BoxRules (Track version) where+ type IsTopLevelBox (Track version) = 'False+ type GetCardinality (Track version) any = 'ExactlyOnce+ type RestrictedTo (Track version) = 'Just '[Movie version]++-- * @tkhd@ Box+++-- | Create a 'TrackHeader' box.+trackHeader+ :: KnownNat version => TrackHeader version -> Box' (TrackHeader version)+trackHeader = closedFullBox Default 0++-- | Track meta data, indexed by a version.+data TrackHeader (version :: Nat) where+ TrackHeader ::+ Versioned TrackHeaderTimesV0+ TrackHeaderTimesV1+ version+ :+ Constant (I32Arr "reserved" 2) '[0, 0]+ :+ Template (I16 "layer") 0+ :+ Template (I16 "alternate_group") 0+ :+ Template (I16 "volume") 256+ :+ Constant (I16 "reserved") 0+ :+ Template (I32Arr "matrix" 9)+ '[65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]+ :+ I32 "width"+ :+ I32 "height"+ -> TrackHeader version++-- | Time and timing information about a track (32bit version).+type TrackHeaderTimesV0 = TrackHeaderTimes (Scalar Word32)++-- | Time and timing information about a track (64bit version).+type TrackHeaderTimesV1 = TrackHeaderTimes (Scalar Word64)++-- | Time and timing information about a track.+type TrackHeaderTimes uint =+ uint "creation_time"+ :+ uint "modification_time"+ :+ U32 "track_ID"+ :+ Constant (U32 "reserved") 0+ :+ uint "duration"++instance IsBoxContent (TrackHeader version) where+ boxSize (TrackHeader c) = boxSize c+ boxBuilder (TrackHeader c) = boxBuilder c++instance KnownNat version => IsBoxType' (TrackHeader version) where+ type BoxContent (TrackHeader version) = FullBox version (TrackHeader version)+ toBoxType' _ = StdType "tkhd"++instance BoxRules (TrackHeader version) where+ type IsTopLevelBox (TrackHeader version) = 'False+ type GetCardinality (TrackHeader version) any = 'ExactlyOnce+ type RestrictedTo (TrackHeader version) = 'Just '[Track version]
src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs view
@@ -2,24 +2,23 @@ where import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields+import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox -- | A Box with progressive download information-type ProgressiveDownloadInformationBox = Box "pdin"+data ProgressiveDownload -instance BoxRules "pdin"+instance BoxRules ProgressiveDownload --- | Create a 'pdin' box-progressiveDownloadInformationBox- :: ProgressiveDownloadInformation -> ProgressiveDownloadInformationBox-progressiveDownloadInformationBox = fullBox (BoxVersion 0) zeroBits+instance IsBoxType' ProgressiveDownload where+ type BoxContent ProgressiveDownload = FullBox 0 ProgressiveDownloadContent+ toBoxType' _ = StdType "pdin" -- | Information for progressive media data download/playback encompasses the -- delay for initial playback and expected download bit rate.-data ProgressiveDownloadInformation =- ProgressiveDownloadInformation {pdinRate :: Word32 -- ^ Effective download bitrate in byte/sec- ,pdinDelay :: Word32 -- ^ Delay in milli seconds- }+type ProgressiveDownloadContent = U32 "rate" :+ U32 "delay" -instance IsBoxContent ProgressiveDownloadInformation where- boxSize _ = 8- boxBuilder pdin = word32BE (pdinRate pdin) <> word32BE (pdinDelay pdin)+-- | Construct a @pdin@ box.+pdinBox+ :: ProgressiveDownloadContent -> Box' ProgressiveDownload+pdinBox = closedFullBox Default 0
src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs view
@@ -1,20 +1,21 @@+-- | A filler box with a specific size. module Data.ByteString.IsoBaseFileFormat.Boxes.Skip where import Data.ByteString.IsoBaseFileFormat.Boxes.Box --- | A filler box, the contents are skipped-type SkipBox = Box "skip"+-- | Contents of a 'skip' box are just any number of filler bytes.+newtype Skip = Skip Int -instance BoxRules "skip" where- type RestrictedTo "skip" = 'Nothing+instance IsBoxType' Skip where+ type BoxContent Skip = Skip+ toBoxType' _ = StdType "skip" --- | Create a 'SkipBox' with a given size.-skipBox :: Skip -> SkipBox-skipBox = box+instance BoxRules Skip where+ type RestrictedTo Skip = 'Nothing --- | Contents of a 'skip' box are just any number of filler bytes.-newtype Skip =- Skip Int+-- | Create a 'Skip' with a given size.+skipBox :: Skip -> Box' Skip+skipBox = closedBox instance IsBoxContent Skip where boxSize (Skip bs) = fromIntegral bs
src/Data/ByteString/IsoBaseFileFormat/Builder.hs view
@@ -1,11 +1,20 @@ -- | This module re-exports all modules needed to build /ISOBMFF/ documents. module Data.ByteString.IsoBaseFileFormat.Builder- (module Data.ByteString.IsoBaseFileFormat.Builder, module X)+ (module X) where import Data.ByteString.IsoBaseFileFormat.Boxes.Box as X+import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields as X import Data.ByteString.IsoBaseFileFormat.Boxes.FileType as X+import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox as X import Data.ByteString.IsoBaseFileFormat.Boxes.MediaData as X import Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox as X import Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation as X import Data.ByteString.IsoBaseFileFormat.Boxes.Skip as X++import Data.Int as X+import Data.Kind as X (Type, Constraint)+import Data.Maybe as X+import Data.Type.Bool as X+import Data.Type.Equality as X+import Text.Printf as X