isobmff-builder 0.9.0.0 → 0.10.0.0
raw patch · 31 files changed
+898/−715 lines, 31 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.ByteString.IsoBaseFileFormat.Boxes: [MediaFile] :: (ValidTopLevel brand ts) => Boxes brand ts -> MediaFile brand
- Data.ByteString.IsoBaseFileFormat.Boxes: data MediaFile brand
- Data.ByteString.IsoBaseFileFormat.Boxes: packMediaFile :: MediaFile brand -> ByteString
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: class (IsBoxContent (BoxContent t)) => IsBoxType t where type BoxContent t type BoxContent t = () where {
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: closedBox :: (IsBoxType t, IsBrandConform brand (Just t) '[]) => BoxContent t -> Box brand t
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Box brand cnt)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Boxes brand bs)
- Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: (:+) :: a -> b -> (:+) a b
- Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: data (:+) a b
- 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 (p Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.:+ c)
- Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: instance (Data.Default.Class.Default a, Data.Default.Class.Default b) => Data.Default.Class.Default (a Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields.:+ b)
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: OnceMandatory :: Type -> BoxForrest -> BoxTree
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: OnceOptional :: Type -> BoxForrest -> BoxTree
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: SomeMandatory :: Type -> BoxForrest -> BoxTree
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: SomeOptional :: Type -> BoxForrest -> BoxTree
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: class KnownNat (GetVersion brand) => IsBrand brand where type BoxLayout brand :: BoxForrest type GetVersion brand :: Nat type BoxLayout brand = '[] type GetVersion brand = 0 where {
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: data BoxTree
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type BoxForrest = [BoxTree]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type BoxLayout brand = '[];
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type GetVersion brand = 0;
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type OM b bs = OnceMandatory b bs
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type OM_ b = OnceMandatory b '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type OO b bs = OnceOptional b bs
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type OO_ b = OnceOptional b '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type SM b bs = SomeMandatory b bs
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type SM_ b = SomeMandatory b '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type SO b bs = SomeOptional b bs
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type SO_ b = SomeOptional b '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type ValidBox b t = IsBrandConform b (Just t) '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type ValidContainerBox b t ts = IsBrandConform b (Just t) ts
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type ValidTopLevel b ts = IsBrandConform b Nothing ts
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: type family GetVersion brand :: Nat;
- Data.ByteString.IsoBaseFileFormat.Boxes.Brand: }
- Data.ByteString.IsoBaseFileFormat.Boxes.FileType: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.FileType.FileType
- Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: closedFullBox :: (IsBoxType t, ValidBox brand t, BoxContent t ~ FullBox version c) => BoxVersion version -> BoxFlags 24 -> c -> Box brand 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: type BoxVersion v = Template (U8 "fullbox-version") v
- Data.ByteString.IsoBaseFileFormat.Boxes.Handler: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.Handler.Handler
- Data.ByteString.IsoBaseFileFormat.Boxes.Media: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.Media.Media
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: data MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader: instance GHC.TypeLits.KnownNat v => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType (Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader.MediaHeader v)
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation.MediaInformation
- Data.ByteString.IsoBaseFileFormat.Boxes.Movie: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.Movie.Movie
- Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader: instance GHC.TypeLits.KnownNat version => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType (Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader.MovieHeader version)
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation.ProgressiveDownload
- Data.ByteString.IsoBaseFileFormat.Boxes.Skip: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.Skip.Skip
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [NullMediaHeader] :: SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: data SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: specificMediaHeader :: ValidBox brand SpecificMediaHeader => SpecificMediaHeader -> Box brand SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.Track: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType Data.ByteString.IsoBaseFileFormat.Boxes.Track.Track
- Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader: instance GHC.TypeLits.KnownNat version => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxType (Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader.TrackHeader version)
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: SingleTrackInit :: MovieHeader 0 -> TrackHeader 0 -> MediaHeader 0 -> Handler -> SpecificMediaHeader -> SingleTrackInit
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_xmhd] :: SingleTrackInit -> SpecificMediaHeader
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: data SingleTrackInit
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: instance GHC.TypeLits.KnownNat v => Data.ByteString.IsoBaseFileFormat.Boxes.Brand.IsBrand (Data.ByteString.IsoBaseFileFormat.Brands.Dash.Dash v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: (:+) :: a -> b -> (:+) a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [ContainerBox] :: IsBox b => BoxContent b -> Boxes bs -> ContainerBox b bs
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: class (KnownSymbol (BoxTypeSymbol t), IsBoxContent (BoxContent t)) => IsBox t where type BoxContent t type BoxContent t = t toBoxType _ = parseBoxType (Proxy :: Proxy (BoxTypeSymbol t)) where {
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data (:+) a b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data ContainerBox b (bs :: [Type])
+ 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 (p Data.ByteString.IsoBaseFileFormat.Boxes.Box.:+ c)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance (Data.Default.Class.Default a, Data.Default.Class.Default b) => Data.Default.Class.Default (a Data.ByteString.IsoBaseFileFormat.Boxes.Box.:+ b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox b => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Box b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox b => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.Box.ContainerBox b bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Box cnt)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.Boxes bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Box.ContainerBox b bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent a => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (GHC.Base.Maybe a)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: parseBoxType :: KnownSymbol t => proxy t -> BoxType
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type OM b bs = ContainerBox b bs
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type OM_ b = Box b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type OO b bs = OnceOptionalX (ContainerBox b bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type OO_ b = OnceOptionalX (Box b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type SM b bs = SomeMandatoryX (ContainerBox b bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type SM_ b = SomeMandatoryX (Box b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type SO b bs = SomeOptionalX (ContainerBox b bs)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type SO_ b = SomeOptionalX (Box b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: typeListLength :: forall a proxy (ts :: [k]). (KnownNat (Length ts), Num a) => proxy ts -> a
+ Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields: type U32U64 c = SelectByVersion c (Scalar Word32) (Scalar Word64)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation: data DataInformation
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation: dataInformation :: Boxes ts -> Box (ContainerBox DataInformation ts)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation.DataInformation
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: data DataEntryUrl
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: data DataEntryUrn
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: data DataReference
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: dataEntryUrl :: Bool -> Maybe Text -> Box (FullBox DataEntryUrl 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: dataEntryUrn :: Bool -> Text -> Text -> Box (FullBox DataEntryUrn 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: dataReference :: KnownNat (Length ts) => Boxes ts -> Box (ContainerBox (FullBox DataReference 0) ts)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataEntryUrl
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataEntryUrn
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataReference
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataEntryUrl
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataEntryUrn
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataReference
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataEntryUrl
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.DataReference.DataReference
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: localMediaDataEntryUrl :: Box (FullBox DataEntryUrl 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.DataReference: localMediaDataReference :: Box (ContainerBox (FullBox DataReference 0) '[Box (FullBox DataEntryUrl 0)])
+ Data.ByteString.IsoBaseFileFormat.Boxes.FileType: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.FileType.FileType
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox t, GHC.TypeLits.KnownNat v) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.FullBox t v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: instance (GHC.TypeLits.KnownNat v, Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox t) => Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.FullBox.FullBox t v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Handler: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.Handler.Handler
+ Data.ByteString.IsoBaseFileFormat.Boxes.Media: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.Media.Media
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: MediaData :: ByteString -> MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: instance GHC.Show.Show Data.ByteString.IsoBaseFileFormat.Boxes.MediaData.MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: newtype MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader.MediaHeader v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation.MediaInformation
+ Data.ByteString.IsoBaseFileFormat.Boxes.Movie: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.Movie.Movie
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader.MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation.ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.Skip: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.Skip.Skip
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: NullMediaHeader :: NullMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: data NullMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: hintMediaHeader :: HintMediaHeader -> Box (FullBox HintMediaHeader 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.HintMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.NullMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.SoundMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.VideoMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.HintMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.NullMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.SoundMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.VideoMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.HintMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.NullMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.SoundMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: instance Data.Default.Class.Default Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader.VideoMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: newtype HintMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: newtype SoundMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: newtype VideoMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: nullMediaHeader :: Box (FullBox NullMediaHeader 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: soundMediaHeader :: SoundMediaHeader -> Box (FullBox SoundMediaHeader 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: videoMediaHeader :: VideoMediaHeader -> Box (FullBox VideoMediaHeader 0)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Track: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox Data.ByteString.IsoBaseFileFormat.Boxes.Track.Track
+ Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBox (Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader.TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: [OnV0] :: forall (v :: Nat ~> Type). IsBoxContent (v @@ 0) => v @@ 0 -> ApplyVersioned v
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: [OnV1] :: forall (v :: Nat ~> Type). IsBoxContent (v @@ 1) => v @@ 1 -> ApplyVersioned v
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: data ApplyVersioned (v' :: Nat ~> Type)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: data SelectByVersion :: (a -> Type) -> a -> a -> Nat ~> Type
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (b 0), Data.Default.Class.Default (b 0)) => Data.Default.Class.Default (Data.ByteString.IsoBaseFileFormat.Boxes.Versioned.VersionedBox b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: instance (Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (b Data.Singletons.@@ 0), Data.Default.Class.Default (b Data.Singletons.@@ 0)) => Data.Default.Class.Default (Data.ByteString.IsoBaseFileFormat.Boxes.Versioned.ApplyVersioned b)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Versioned.ApplyVersioned c)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Versioned: instance Data.ByteString.IsoBaseFileFormat.Boxes.Box.IsBoxContent (Data.ByteString.IsoBaseFileFormat.Boxes.Versioned.VersionedBox c)
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: SingleAudioTrackInit :: MovieHeader 0 -> TrackHeader 0 -> MediaHeader 0 -> Handler -> SoundMediaHeader -> SingleAudioTrackInit
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_smhd] :: SingleAudioTrackInit -> SoundMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: data SingleAudioTrackInit
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: instance Data.ByteString.IsoBaseFileFormat.Brands.Types.IsBrand (Data.ByteString.IsoBaseFileFormat.Brands.Dash.Dash v)
+ Data.ByteString.IsoBaseFileFormat.Brands.Types: class IsBrand brand where type BoxLayout brand mediaBuilder _ t = boxBuilder t where {
+ Data.ByteString.IsoBaseFileFormat.Brands.Types: mediaBuilder :: forall t proxy. (IsBrand brand, IsBoxContent t, IsRuleConform t (BoxLayout brand) ~ True) => proxy brand -> t -> Builder
+ Data.ByteString.IsoBaseFileFormat.Brands.Types: type family BoxLayout brand;
+ Data.ByteString.IsoBaseFileFormat.Brands.Types: }
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data IsRuleConform0 :: k ~> (l ~> Bool)
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data IsRuleConform1 :: k -> l ~> Bool
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data MatchSymbol :: Symbol -> Type
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data OnceOptionalX t
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data OneOf :: [Type] -> Type
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data SomeMandatoryX t
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data SomeOptionalX t
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data ToSymbol0 :: Type ~> Symbol
+ Data.ByteString.IsoBaseFileFormat.Util.TypeLayout: data TopLevel :: Type -> Type
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: ($:) :: (Boxes brand '[l] -> r) -> Box brand l -> r
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: ($:) :: (Boxes '[Box l] -> r) -> Box l -> r
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:.] :: Box brand l -> Boxes brand r -> Boxes brand (l : r)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:.] :: Box l -> Boxes r -> Boxes (Box l : r)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:<>] :: Boxes brand l -> Boxes brand r -> Boxes brand (l :++ r)
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:<>] :: Boxes l -> Boxes r -> Boxes (l :++ r)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:|] :: Box brand l -> Box brand r -> Boxes brand '[l, r]
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [:|] :: Box l -> Box r -> Boxes '[Box l, Box r]
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Box] :: (IsBoxType b, IsBrandConform brand (Just b) ts) => BoxContent b -> Boxes brand ts -> Box brand b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [Box] :: (IsBox b) => BoxContent b -> Box b
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: [NoBoxes] :: Boxes brand '[]
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: [NoBoxes] :: Boxes '[]
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: containerBox :: (IsBoxType t, IsBrandConform brand (Just t) ts, BoxContent t ~ ()) => Boxes brand ts -> Box brand t
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: containerBox :: (IsBox t) => BoxContent t -> Boxes ts -> Box (ContainerBox t ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Box brand b
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Box b
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Boxes brand (boxTypes :: [Type])
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: data Boxes (boxTypes :: [Type])
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: singletonBox :: Box brand l -> Boxes brand '[l]
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: singletonBox :: Box l -> Boxes '[Box l]
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: toBoxType :: IsBoxType t => proxy t -> BoxContent t -> BoxType
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: toBoxType :: IsBox t => proxy t -> BoxType
- Data.ByteString.IsoBaseFileFormat.Boxes.Box: type BoxContent t = ();
+ Data.ByteString.IsoBaseFileFormat.Boxes.Box: type BoxContent t = t;
- Data.ByteString.IsoBaseFileFormat.Boxes.FileType: fileTypeBox :: (ValidBox b FileType) => FileType -> Box b FileType
+ Data.ByteString.IsoBaseFileFormat.Boxes.FileType: fileTypeBox :: FileType -> Box FileType
- Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: [FullBox] :: BoxVersion version -> BoxFlags 24 -> t -> FullBox version t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: [FullBox] :: (KnownNat version, IsBox t) => BoxFlags 24 -> BoxContent t -> FullBox t version
- Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: data FullBox version t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: data FullBox t (version :: Nat)
- Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: fullBox :: (IsBoxType t, ValidContainerBox brand t ts, BoxContent t ~ FullBox version c) => BoxVersion version -> BoxFlags 24 -> c -> Boxes brand ts -> Box brand t
+ Data.ByteString.IsoBaseFileFormat.Boxes.FullBox: fullBox :: (KnownNat v, IsBox t) => BoxFlags 24 -> BoxContent t -> Box (FullBox t v)
- Data.ByteString.IsoBaseFileFormat.Boxes.Handler: handler :: (ValidBox brand Handler) => Handler -> Box brand Handler
+ Data.ByteString.IsoBaseFileFormat.Boxes.Handler: handler :: Handler -> Box (FullBox Handler 0)
- Data.ByteString.IsoBaseFileFormat.Boxes.Media: media :: ValidContainerBox brand Media ts => Boxes brand ts -> Box brand Media
+ Data.ByteString.IsoBaseFileFormat.Boxes.Media: media :: Boxes ts -> Box (ContainerBox Media ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: mediaData :: ValidBox b MediaData => ByteString -> Box b MediaData
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaData: mediaData :: MediaData -> Box MediaData
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader: mediaHeader :: (KnownNat v, ValidBox brand (MediaHeader v)) => MediaHeader v -> Box brand (MediaHeader v)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaHeader: mediaHeader :: (KnownNat v) => MediaHeader v -> Box (FullBox (MediaHeader v) v)
- Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation: mediaInformation :: ValidContainerBox brand MediaInformation ts => Boxes brand ts -> Box brand MediaInformation
+ Data.ByteString.IsoBaseFileFormat.Boxes.MediaInformation: mediaInformation :: Boxes ts -> Box (ContainerBox MediaInformation ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.Movie: movie :: (ValidContainerBox brand Movie ts) => Boxes brand ts -> Box brand Movie
+ Data.ByteString.IsoBaseFileFormat.Boxes.Movie: movie :: Boxes ts -> Box (ContainerBox Movie ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader: movieHeader :: (KnownNat version, ValidBox brand (MovieHeader version)) => MovieHeader version -> Box brand (MovieHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.MovieHeader: movieHeader :: (KnownNat version) => MovieHeader version -> Box (FullBox (MovieHeader version) version)
- Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: pdinBox :: ValidBox brand ProgressiveDownload => ProgressiveDownloadContent -> Box brand ProgressiveDownload
+ Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation: pdinBox :: ProgressiveDownloadContent -> Box (FullBox ProgressiveDownload 0)
- Data.ByteString.IsoBaseFileFormat.Boxes.Skip: skipBox :: ValidBox brand Skip => Skip -> Box brand Skip
+ Data.ByteString.IsoBaseFileFormat.Boxes.Skip: skipBox :: Skip -> Box Skip
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [HintMediaHeader] :: U16 "maxPDUsize" :+ (U16 "avgPDUsize" :+ (U16 "maxbitrate" :+ (U16 "avgbitrate" :+ U32 "reserved"))) -> SpecificMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [HintMediaHeader] :: U16 "maxPDUsize" :+ (U16 "avgPDUsize" :+ (U16 "maxbitrate" :+ (U16 "avgbitrate" :+ U32 "reserved"))) -> HintMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [SoundMediaHeader] :: Template (I16 "balance") 0 :+ Constant (U16Arr "opcolor" 3) '[0, 0, 0] -> SpecificMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [SoundMediaHeader] :: Template (I16 "balance") 0 :+ Constant (U16 "reserved") 0 -> SoundMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [VideoMediaHeader] :: Template (U16 "graphicsmode") 0 :+ Template (U16 "reserved") 0 -> SpecificMediaHeader
+ Data.ByteString.IsoBaseFileFormat.Boxes.SpecificMediaHeader: [VideoMediaHeader] :: Template (U16 "graphicsmode") 0 :+ Template (U16Arr "opcolor" 3) '[0, 0, 0] -> VideoMediaHeader
- Data.ByteString.IsoBaseFileFormat.Boxes.Track: track :: (ValidContainerBox brand Track ts) => Boxes brand ts -> Box brand Track
+ Data.ByteString.IsoBaseFileFormat.Boxes.Track: track :: Boxes ts -> Box (ContainerBox Track ts)
- Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader: trackHeader :: (ValidBox brand (TrackHeader version), version ~ GetVersion brand) => TrackHeader version -> Box brand (TrackHeader version)
+ Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader: trackHeader :: KnownNat version => TrackHeader version -> Box (FullBox (TrackHeader version) version)
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_hdlr] :: SingleTrackInit -> Handler
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_hdlr] :: SingleAudioTrackInit -> Handler
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_mdhd] :: SingleTrackInit -> MediaHeader 0
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_mdhd] :: SingleAudioTrackInit -> MediaHeader 0
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_mvhd] :: SingleTrackInit -> MovieHeader 0
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_mvhd] :: SingleAudioTrackInit -> MovieHeader 0
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_tkhd] :: SingleTrackInit -> TrackHeader 0
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: [_tkhd] :: SingleAudioTrackInit -> TrackHeader 0
- Data.ByteString.IsoBaseFileFormat.Brands.Dash: mkSingleTrackInit :: SingleTrackInit -> MediaFile (Dash 0)
+ Data.ByteString.IsoBaseFileFormat.Brands.Dash: mkSingleTrackInit :: SingleAudioTrackInit -> Builder
Files
- isobmff-builder.cabal +8/−2
- spec/BoxFieldsSpec.hs +1/−18
- spec/BoxSpec.hs +44/−17
- spec/BrandTypeSpec.hs +70/−0
- spec/DashSpec.hs +47/−254
- spec/DataReferenceSpec.hs +25/−0
- spec/TypeLayoutSpec.hs +144/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes.hs +3/−12
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs +121/−32
- src/Data/ByteString/IsoBaseFileFormat/Boxes/BoxFields.hs +6/−12
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Brand.hs +0/−217
- src/Data/ByteString/IsoBaseFileFormat/Boxes/DataInformation.hs +18/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes/DataReference.hs +79/−0
- src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs +4/−5
- src/Data/ByteString/IsoBaseFileFormat/Boxes/FullBox.hs +21/−21
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Handler.hs +7/−7
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Media.hs +6/−5
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs +8/−6
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaHeader.hs +6/−6
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaInformation.hs +8/−7
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Movie.hs +6/−5
- src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieHeader.hs +6/−6
- src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs +6/−6
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs +5/−4
- src/Data/ByteString/IsoBaseFileFormat/Boxes/SpecificMediaHeader.hs +59/−31
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Track.hs +6/−5
- src/Data/ByteString/IsoBaseFileFormat/Boxes/TrackHeader.hs +6/−6
- src/Data/ByteString/IsoBaseFileFormat/Boxes/Versioned.hs +40/−1
- src/Data/ByteString/IsoBaseFileFormat/Brands/Dash.hs +62/−30
- src/Data/ByteString/IsoBaseFileFormat/Brands/Types.hs +16/−0
- src/Data/ByteString/IsoBaseFileFormat/Util/TypeLayout.hs +60/−0
isobmff-builder.cabal view
@@ -1,5 +1,5 @@ name: isobmff-builder-version: 0.9.0.0+version: 0.10.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@@ -18,7 +18,8 @@ exposed-modules: Data.ByteString.IsoBaseFileFormat.Boxes , Data.ByteString.IsoBaseFileFormat.Boxes.Box , Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields- , Data.ByteString.IsoBaseFileFormat.Boxes.Brand+ , Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation+ , Data.ByteString.IsoBaseFileFormat.Boxes.DataReference , Data.ByteString.IsoBaseFileFormat.Boxes.FileType , Data.ByteString.IsoBaseFileFormat.Boxes.FullBox , Data.ByteString.IsoBaseFileFormat.Boxes.Handler@@ -37,6 +38,8 @@ , Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader , Data.ByteString.IsoBaseFileFormat.Boxes.Versioned , Data.ByteString.IsoBaseFileFormat.Brands.Dash+ , Data.ByteString.IsoBaseFileFormat.Brands.Types+ , Data.ByteString.IsoBaseFileFormat.Util.TypeLayout build-depends: base >= 4.9 && < 5 , bytestring >= 0.10.8.1 && < 0.11 , type-list >= 0.5.0.0 && < 0.6@@ -83,7 +86,10 @@ main-is: Spec.hs other-modules: BoxFieldsSpec , BoxSpec+ , BrandTypeSpec+ , DataReferenceSpec , DashSpec+ , TypeLayoutSpec build-depends: base >= 4.9 && < 5 , bytestring >= 0.10.8.1 , hspec
spec/BoxFieldsSpec.hs view
@@ -12,24 +12,7 @@ -- qualified Data.Binary.Get as Binary spec :: Spec spec =- do describe "boxSize of Data.Text.Text" $- it "returns string length + 1 (for the null termination byte)" $ do- boxSize (T.pack "") `shouldBe` 1- boxSize (T.pack "Hello!") `shouldBe` 7- describe "boxBuilder of Data.Text.Text" $ do- it "appends the null termination byte" $- let expected = [72,101,108,108,111,32,119,111,114,108,100,33,0]- actual = BL.unpack $ toLazyByteString $ boxBuilder (T.pack "Hello world!")- in actual `shouldBe` expected- it "appends the null termination byte" $- let expected = [72,101,108,108,111,32,119,111,114,108,100,33,0]- actual = BL.unpack $ toLazyByteString $ boxBuilder (T.pack "Hello world!")- in actual `shouldBe` expected- it "replaces embeded NULL characters with a space (0x20)" $- let expected = [72,101,108,108,111,32,119,111,114,108,100,33,0]- actual = BL.unpack $ toLazyByteString $ boxBuilder (T.pack "Hello\0world!")- in actual `shouldBe` expected- describe "mkLanguage" $+ do describe "mkLanguage" $ do it "throws runtime exceptions when the code is too short or too long" $ do evaluate (mkLanguage "") `shouldThrow` anyException evaluate (mkLanguage "a") `shouldThrow` anyException
spec/BoxSpec.hs view
@@ -2,15 +2,45 @@ import Test.Hspec import Data.ByteString.IsoBaseFileFormat.Boxes- import qualified Data.ByteString.Builder as B import qualified Data.ByteString.Lazy as BL import qualified Data.Binary.Get as Binary+import qualified Data.Text as T spec :: Spec spec = do describe "IsBoxContent instances" $- do describe "()" $+ do describe "IsBoxContent Data.Text.Text" $+ do describe "boxSize" $+ it "returns string length + 1 (for the null termination byte)" $+ do boxSize (T.pack "") `shouldBe` 1+ boxSize (T.pack "Hello!") `shouldBe` 7+ describe "boxBuilder of Data.Text.Text" $+ do it "appends the null termination byte" $+ let expected =+ [72,101,108,108,111,32,119,111,114,108,100,33,0]+ actual =+ BL.unpack $+ toLazyByteString $+ boxBuilder (T.pack "Hello world!")+ in actual `shouldBe` expected+ it "appends the null termination byte" $+ let expected =+ [72,101,108,108,111,32,119,111,114,108,100,33,0]+ actual =+ BL.unpack $+ toLazyByteString $+ boxBuilder (T.pack "Hello world!")+ in actual `shouldBe` expected+ it "replaces embeded NULL characters with a space (0x20)" $+ let expected =+ [72,101,108,108,111,32,119,111,114,108,100,33,0]+ actual =+ BL.unpack $+ toLazyByteString $+ boxBuilder (T.pack "Hello\0world!")+ in actual `shouldBe` expected+ describe "()" $ do describe "boxSize" $ it "returns 0" $ boxSize () `shouldBe` 0 describe "boxBuilder" $ it "emits no data" $@@ -34,26 +64,23 @@ reportedSize = boxSize b in writtenSize `shouldBe` reportedSize -data TestBrand--instance IsBrand TestBrand where- type BoxLayout TestBrand =- '[ 'OnceMandatory TestParentBox1 '[ 'SomeOptional TestBox1 '[]] ]- data TestBox1 -instance IsBoxType TestBox1 where- toBoxType _ _ = StdType "tst1"+instance IsBox TestBox1 where+ type BoxContent TestBox1 = () -testBox1 :: Box TestBrand TestBox1-testBox1 = closedBox ()+type instance BoxTypeSymbol TestBox1 = "tst1" +testBox1 :: Box TestBox1+testBox1 = Box ()+ data TestParentBox1 -instance IsBoxType TestParentBox1 where- toBoxType _ _ = StdType "par1"+instance IsBox TestParentBox1 where+ type BoxContent TestParentBox1 = () +type instance BoxTypeSymbol TestParentBox1 = "par1"+ testParentBox1- :: ValidContainerBox TestBrand TestParentBox1 ts- => Boxes TestBrand ts -> Box TestBrand TestParentBox1-testParentBox1 = containerBox+ :: Boxes ts -> Box (ContainerBox TestParentBox1 ts)+testParentBox1 = containerBox ()
+ spec/BrandTypeSpec.hs view
@@ -0,0 +1,70 @@+module BrandTypeSpec+ (spec)+ where++import Test.Hspec+import Data.ByteString.IsoBaseFileFormat.Boxes+import Data.ByteString.IsoBaseFileFormat.Brands.Types+import Data.ByteString.Lazy (unpack)++spec :: Spec+spec =+ describe "mediaBuilder" $+ do describe "Empty BoxLayout" $+ it "accepts valid box content types" $+ let test =+ mediaBuilder (Proxy :: Proxy TestBrandEmpty)+ NoBoxes+ in printBuilder test+ describe "Single Box BoxLayout" $+ it "accepts valid box content types" $+ let test =+ mediaBuilder (Proxy :: Proxy TestBrandSingle)+ (singletonBox testBox1)+ in printBuilder test+ describe "Multiple nested Boxes BoxLayout" $+ it "accepts valid box content types" $+ let test =+ mediaBuilder (Proxy :: Proxy TestBrandNested)+ (singletonBox (testParentBox1 $: testBox1))+ in printBuilder test++printBuilder :: Builder -> IO ()+printBuilder b =+ putStrLn $ unlines $ (" "++) <$> lines (show (unpack (toLazyByteString b)))++data TestBox1++instance IsBox TestBox1 where+ type BoxContent TestBox1 = ()++type instance BoxTypeSymbol TestBox1 = "tst1"++testBox1 :: Box TestBox1+testBox1 = Box ()++data TestParentBox1++instance IsBox TestParentBox1 where+ type BoxContent TestParentBox1 = ()++type instance BoxTypeSymbol TestParentBox1 = "par1"++testParentBox1+ :: Boxes ts -> Box (ContainerBox TestParentBox1 ts)+testParentBox1 = containerBox ()++data TestBrandEmpty++instance IsBrand TestBrandEmpty where+ type BoxLayout TestBrandEmpty = Boxes '[]++data TestBrandSingle++instance IsBrand TestBrandSingle where+ type BoxLayout TestBrandSingle = Boxes '[OM_ TestBox1]++data TestBrandNested++instance IsBrand TestBrandNested where+ type BoxLayout TestBrandNested = Boxes '[OM TestParentBox1 '[OM_ TestBox1]]
spec/DashSpec.hs view
@@ -8,7 +8,7 @@ spec :: Spec spec =- do describe "minimalIsobmff version 0" $+ do describe "SingleAudioTrackInit version 0" $ do it "renders some output at all" $ do createionTime <- mp4CurrentTime let ct :: Word32@@ -21,272 +21,65 @@ cts = fromIntegral <$> [ct3,ct2,ct1,ct0] let args = exampleSingleTrackInit createionTime doc = mkSingleTrackInit args- rendered = BL.unpack $ packMediaFile doc+ rendered = BL.unpack $ toLazyByteString $ doc expected =- [0- ,0- ,0- ,32- ,102- ,116- ,121- ,112- ,105- ,115- ,111- ,53- ,0- ,0- ,0- ,0- ,105- ,115- ,111- ,109- ,105- ,115- ,111- ,53- ,100- ,97- ,115- ,104- ,109- ,112- ,52- ,50- ,0- ,0- ,1- ,73 -- Here- ,109- ,111- ,111- ,118- ,0- ,0- ,0- ,108- ,109- ,118- ,104- ,100- ,0- ,0- ,0- ,0] ++- cts ++- [0- ,0- ,0- ,0- ,0- ,1- ,95- ,144- ,0- ,1- ,95- ,144- ,0- ,1- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,64- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,255- ,255- ,255- ,255- ,0- ,0- ,0- ,213 -- Here- ,116- ,114- ,97- ,107- ,0- ,0- ,0- ,92- ,116- ,107- ,104- ,100- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,1- ,95- ,144- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,1- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,64- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0- ,0,0,0,113 -- HERE+ [+ -- ftyp box+ 0,0,0,28,102,116,121,112,100,97,115,104,0,0,0,0+ ,105,115,111,109,105,115,111,53,109,112,52,50,0,0+ -- moov box+ ,1 ,105 ,109 ,111 ,111 ,118+ -- mvhd box+ ,0 ,0 ,0 ,108 ,109 ,118 ,104 ,100 ,0 ,0 ,0 ,0]+ ++ cts ++ [0 ,0 ,0 ,0 ,0+ ,1 ,95 ,144 ,0 ,1 ,95 ,144 ,0 ,1 ,0 ,0 ,1 ,0 ,0 ,0+ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,0 ,0 ,0 ,0 ,0 ,64 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,255 ,255 ,255 ,255+ -- trak box+ ,0 ,0 ,0 ,245+ ,116 ,114 ,97 ,107+ -- tkhd box+ ,0 ,0 ,0 ,92+ ,116 ,107 ,104 ,100+ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1 ,95 ,144 ,0 ,0+ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0+ ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ ,0 ,64 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0+ -- mdia box+ ,0,0,0,145 ,109,100,105,97 ,0,0,0,32,109,100,104,100,0,0,0,0 ,0,0,0,0,0,0,0,0,0,1,95,144,0,0,0,0,16,181,0,0- ,0,0,0,45 -- HERE+ -- hdlr box+ ,0,0,0,45 ,104,100,108,114 ,0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0 ,72,101,108,108,111,32,119,111,114,108,100,33,0- ,0,0,0,28 -- HERE+ ,0,0,0,60 ,109,105,110,102- ,0,0,0,20 -- HERE- ,115,109,104,100,0,0,0,0,0,0,0,0,0,0,0,0]+ ,0,0,0,16+ ,115,109,104,100,0,0,0,0,0,0,0,0+ ,0,0,0,36+ ,100,105,110,102+ ,0,0,0,28+ ,100,114,101,102+ ,0,0,0,0,0,0,0,1+ ,0,0,0,12+ ,117,114,110,32+ ,0,0,0,1] -- BL.writeFile "/tmp/xxx.mp4" (BL.pack rendered) rendered `shouldBe` expected -exampleSingleTrackInit :: U32 "creation_time" -> SingleTrackInit+exampleSingleTrackInit :: U32 "creation_time" -> SingleAudioTrackInit exampleSingleTrackInit creationTime =- SingleTrackInit (MovieHeader $+ SingleAudioTrackInit+ (MovieHeader $ V0 (creationTime :+ 0 :+ Default :+ durationFromSeconds Default 1) :+ def) (TrackHeader $
+ spec/DataReferenceSpec.hs view
@@ -0,0 +1,25 @@+module DataReferenceSpec (spec) where++import Test.Hspec+import Data.ByteString.IsoBaseFileFormat.Boxes++import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Binary.Get as Binary+import qualified Data.Text as T++spec :: Spec+spec = return ()+-- describe "IsBoxContent" $ do+-- describe "LocalMediaEntry" $ do+-- describe "boxSize" $ do+-- it "returns 0" $+-- let actual = boxSize (localMediaDataReference :: DRef)+-- -- dref: size+fourcc+fullbox+entries -> 4 * 4bytes+-- expected = 4 + 4 + 4 + 4 + (4 + 4 + boxSize ("xxxx" :+ FullBox Default 0 () :: DEntryLocal))+-- in actual `shouldBe` expected+--+-- -- type DRef = Box (Dash 0) DataReference+-- type DEntryLocal = FourCc :+ FullBox 0 ()+-- type DEntryUrl = FourCc :+ FullBox 0 (T.Text)+-- type DEntryUrn = FourCc :+ FullBox 0 (T.Text :+ T.Text)
+ spec/TypeLayoutSpec.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+module TypeLayoutSpec (spec) where++import Test.Hspec+import GHC.TypeLits ()+import Data.ByteString.IsoBaseFileFormat.Util.TypeLayout+import Data.ByteString.IsoBaseFileFormat.Boxes.Box++spec :: Spec+spec =+ describe "IsRuleConform" $ do+ describe "TopLevel" $ do+ it "validates TopLevel Boxes" $ test1 `shouldBe` ()+ describe "ContainerBoxes" $ do+ describe "OnceOptional" $ do+ it "validates empty containters" $ test2a `shouldBe` ()+ it "validates a singleton container" $ test2b `shouldBe` ()+ describe "SomeOptional" $ do+ it "validates empty containters" $ test3a `shouldBe` ()+ it "validates a singleton container" $ test3b `shouldBe` ()+ it "validates a multi-element container" $ test3c `shouldBe` ()+ describe "(implied) mandatory" $ do+ it "validates a singleton container" $ test4 `shouldBe` ()+ describe "SomeMandatory" $ do+ it "validates a singleton container" $ test5a `shouldBe` ()+ it "validates a multi-element container" $ test5b `shouldBe` ()+ it "validates a Mix of SomeMandatory, OnceOptional, SomeOptional" $ do+ test6a `shouldBe` ()+ test6b `shouldBe` ()+ test6c `shouldBe` ()+ test6d `shouldBe` ()+ it "validates deeply nested container" $ do+ test7a `shouldBe` ()+ test7b `shouldBe` ()+ test7c `shouldBe` ()++----+data Foo+type instance ToSymbol Foo = "foo "+data Fov+type instance ToSymbol Fov = "fov "+data Bar+type instance ToSymbol Bar = "bar "+data Baz+type instance ToSymbol Baz = "baz "+----+type TestRule1 = TopLevel (MatchSymbol "foo ")+type TestType1 = Foo+test1 :: (IsRuleConform TestType1 TestRule1 ~ 'True) => ()+test1 = ()+----+type TestRule2 = TopLevel (ContainerBox Foo '[OnceOptionalX (MatchSymbol "bar ")])+type TestType2a = Box (ContainerBox Foo '[])+test2a :: (IsRuleConform TestType2a TestRule2 ~ 'True) => ()+test2a = ()+--+type TestType2b = Box (ContainerBox Foo '[Bar])+test2b :: (IsRuleConform TestType2b TestRule2 ~ 'True) => ()+test2b = ()+----+type TestRule3 = TopLevel (ContainerBox Foo '[SomeOptionalX (MatchSymbol "bar ")])+type TestType3a = Box (ContainerBox Foo '[])+test3a :: (IsRuleConform TestType3a TestRule3 ~ 'True) => ()+test3a = ()+--+type TestType3b = Box (ContainerBox Foo '[Bar])+test3b :: (IsRuleConform TestType3b TestRule3 ~ 'True) => ()+test3b = ()+--+type TestType3c = Box (ContainerBox Foo '[Bar,Bar])+test3c :: (IsRuleConform TestType3c TestRule3 ~ 'True) => ()+test3c = ()+----+type TestRule4 = TopLevel (ContainerBox Foo '[MatchSymbol "bar "])+type TestType4 = Box (ContainerBox Foo '[Bar])+test4 :: (IsRuleConform TestType4 TestRule4 ~ 'True) => ()+test4 = ()+----+type TestRule5 = TopLevel (ContainerBox Foo '[SomeMandatoryX (MatchSymbol "bar ")])+type TestType5a = Box (ContainerBox Foo '[Bar])+test5a :: (IsRuleConform TestType5a TestRule5 ~ 'True) => ()+test5a = ()+type TestType5b = Box (ContainerBox Foo '[Bar, Bar])+test5b :: (IsRuleConform TestType5b TestRule5 ~ 'True) => ()+test5b = ()+----+type TestRule6 =+ (ContainerBox Foo+ '[ OnceOptionalX (MatchSymbol "baz ")+ , SomeMandatoryX (MatchSymbol "bar ")+ , SomeOptionalX (MatchSymbol "fov ")+ , MatchSymbol "foo "])+type TestType6a =+ Box (ContainerBox Foo '[Baz,Bar,Bar,Bar,Fov,Fov,Foo])+test6a :: (IsRuleConform TestType6a TestRule6 ~ 'True) => ()+test6a = ()+type TestType6b =+ Box (ContainerBox Foo '[Bar,Bar,Bar,Fov,Fov,Foo])+test6b :: (IsRuleConform TestType6b TestRule6 ~ 'True) => ()+test6b = ()+type TestType6c =+ Box (ContainerBox Foo '[Bar,Fov,Fov,Foo])+test6c :: (IsRuleConform TestType6c TestRule6 ~ 'True) => ()+test6c = ()+type TestType6d = Box (ContainerBox Foo '[Bar,Foo])+test6d :: (IsRuleConform TestType6d TestRule6 ~ 'True) => ()+test6d = ()+----+type TestRule7 =+ TopLevel (ContainerBox Foo+ '[ SomeOptionalX (ContainerBox Fov+ '[ OnceOptionalX (ContainerBox Baz+ '[MatchSymbol "foo "])+ , SomeMandatoryX (MatchSymbol "bar ")+ ])])+type TestType7a = Box (ContainerBox Foo '[ ])+test7a :: (IsRuleConform TestType7a TestRule7 ~ 'True) => ()+test7a = ()+type TestType7b = Box (ContainerBox Foo+ '[ Box (ContainerBox Fov+ '[Box (ContainerBox Baz+ '[Foo])+ , Bar])])+test7b :: (IsRuleConform TestType7b TestRule7 ~ 'True) => ()+test7b = ()+type TestType7c = Box (ContainerBox Foo+ '[ Box (ContainerBox Fov+ '[ Box (ContainerBox Baz+ '[Foo])+ , Bar+ , Bar+ , Bar+ ])+ , Box (ContainerBox Fov+ '[ Box (ContainerBox Baz+ '[Foo])+ , Bar+ , Bar+ , Bar+ ])+ ])+test7c :: (IsRuleConform TestType7c TestRule7 ~ 'True) => ()+test7c = ()
src/Data/ByteString/IsoBaseFileFormat/Boxes.hs view
@@ -1,10 +1,12 @@ -- | This module re-exports all modules needed to build /ISOBMFF/ documents. module Data.ByteString.IsoBaseFileFormat.Boxes- (module Data.ByteString.IsoBaseFileFormat.Boxes, 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.DataInformation as X+import Data.ByteString.IsoBaseFileFormat.Boxes.DataReference as X import Data.ByteString.IsoBaseFileFormat.Boxes.FileType as X import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox as X import Data.ByteString.IsoBaseFileFormat.Boxes.Handler as X@@ -22,7 +24,6 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Track as X import Data.ByteString.IsoBaseFileFormat.Boxes.TrackHeader as X import Data.ByteString.IsoBaseFileFormat.Boxes.Versioned as X-import qualified Data.ByteString.Lazy as BL import Data.Int as X import Data.Kind as X (Type, Constraint)@@ -31,13 +32,3 @@ import Data.Type.Equality as X import Text.Printf as X import Data.Default as X---- * MediaFiles---- | The toplevel container for all boxes of a media file.-data MediaFile brand where- MediaFile :: (ValidTopLevel brand ts) => Boxes brand ts -> MediaFile brand---- | Generate a lazy 'ByteString' with the contents of a 'MediaFile'-packMediaFile :: MediaFile brand -> BL.ByteString-packMediaFile (MediaFile bs) = toLazyByteString (boxBuilder bs)
src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs view
@@ -12,7 +12,7 @@ (module Data.ByteString.IsoBaseFileFormat.Boxes.Box, module X) where -import Data.ByteString.IsoBaseFileFormat.Boxes.Brand as X+import Data.ByteString.IsoBaseFileFormat.Util.TypeLayout as X import Data.Bits as X import Data.ByteString.Builder as X import Data.Monoid as X@@ -21,6 +21,10 @@ import Data.Kind import GHC.TypeLits as X import Data.String+import Data.Default+import Data.Singletons.Prelude.List (Length)+import Data.Type.Equality+import Data.Type.Bool import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Singletons.Prelude.List ((:++))@@ -28,11 +32,18 @@ -- * Box Type Classes -- | Base class for all (abstract/phantom/normal-) types that represent boxes-class (IsBoxContent (BoxContent t)) => IsBoxType t where+class (KnownSymbol (BoxTypeSymbol t), IsBoxContent (BoxContent t)) => IsBox t where type BoxContent t- type BoxContent t = ()- toBoxType :: proxy t -> BoxContent t -> BoxType+ type BoxContent t = t+ toBoxType :: proxy t -> BoxType+ toBoxType _ = parseBoxType (Proxy :: Proxy (BoxTypeSymbol t)) +-- | A type family used by the type-level consistency checks. It is required+-- that an instance of this type family exists for every 'IsBox' instance.+-- This family could not be associative since it is used by type families that+-- cannot have type class constraints.+type family BoxTypeSymbol t :: Symbol+ -- | 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.@@ -41,36 +52,55 @@ boxBuilder :: a -> Builder -- * Data types++ -- | A type that wraps the contents of a box and the box type.-data Box brand b where+data Box b where Box ::- (IsBoxType b, IsBrandConform brand ('Just b) ts) =>- BoxContent b -> Boxes brand ts -> Box brand b+ (IsBox b) =>+ BoxContent b -> Box b -instance IsBoxContent (Box brand cnt) where- boxBuilder b@(Box cnt nested) = sB <> tB <> sExtB <> tExtB <> cntB <> nestedB+instance IsBox b => IsBox (Box b) where+ type BoxContent (Box b) = BoxContent b+ toBoxType _ = toBoxType (Proxy :: Proxy b)++type instance BoxTypeSymbol (Box b) = BoxTypeSymbol b++instance IsBoxContent (Box cnt) where+ boxBuilder b@(Box cnt) = sB <> tB <> sExtB <> tExtB <> cntB where s = boxSize b- t = toBoxType b cnt+ t = toBoxType b sB = boxBuilder s sExtB = boxBuilder (BoxSizeExtension s) tB = boxBuilder t tExtB = boxBuilder (BoxTypeExtension t) cntB = boxBuilder cnt- nestedB = boxBuilder nested- boxSize b@(Box cnt nested) = sPayload + boxSize (BoxSizeExtension sPayload)+ boxSize b@(Box cnt) = sPayload + boxSize (BoxSizeExtension sPayload) where sPayload = boxSize (BoxSize undefined) + boxSize t + boxSize cnt +- boxSize (BoxTypeExtension t) +- boxSize nested- t = toBoxType b cnt+ boxSize (BoxTypeExtension t)+ t = toBoxType b +-- | Compose 'BoxContent' and 'Boxes' under the Constraint that they are+-- composable.+data ContainerBox b (bs :: [Type]) where+ ContainerBox :: IsBox b => BoxContent b -> Boxes bs -> ContainerBox b bs++instance (IsBox b) => IsBox (ContainerBox b bs)++type instance BoxTypeSymbol (ContainerBox b bs) = BoxTypeSymbol b++instance IsBoxContent (ContainerBox b bs) where+ boxSize (ContainerBox c bs) = boxSize (c :+ bs)+ boxBuilder (ContainerBox c bs) = boxBuilder (c :+ bs)+ -- | A heterogenous collection of boxes.-data Boxes brand (boxTypes :: [Type]) where- NoBoxes :: Boxes brand '[]- (:.) :: Box brand l -> Boxes brand r -> Boxes brand (l ': r)- -- | Create a 'Boxes' collection from two 'Box'es- (:|) :: Box brand l -> Box brand r -> Boxes brand '[l, r]- (:<>) :: Boxes brand l -> Boxes brand r -> Boxes brand (l :++ r)+data Boxes (boxTypes :: [Type]) where+ NoBoxes :: Boxes '[]+ (:.) :: Box l -> Boxes r -> Boxes (Box l ': r)+ -- | Create a 'Boxes' collection from two 'Box'es+ (:<>) :: Boxes l -> Boxes r -> Boxes (l :++ r)+ (:|) :: Box l -> Box r -> Boxes '[Box l, Box r] infixr 1 :<> infixr 2 :.@@ -78,15 +108,19 @@ infixr 3 $: -- | Apply a function to a 'Boxes' collection containing only a single 'Box'.-($:) :: (Boxes brand '[l] -> r) -> Box brand l -> r+($:) :: (Boxes '[Box l] -> r) -> Box l -> r ($:) f = f . singletonBox -- | Create a 'Boxes' collection with a single 'Box'.-singletonBox :: Box brand l -> Boxes brand '[l]+singletonBox :: Box l -> Boxes '[Box l] singletonBox b = b :. NoBoxes +-- | Get the elements in a type level array+typeListLength :: forall a proxy (ts :: [k]) . (KnownNat (Length ts), Num a)+ => proxy ts -> a+typeListLength _ = fromIntegral (natVal (Proxy :: Proxy (Length ts))) -instance IsBoxContent (Boxes brand bs) where+instance IsBoxContent (Boxes bs) where boxSize NoBoxes = 0 boxSize (l :. r) = boxSize l + boxSize r boxSize (l :| r) = boxSize l + boxSize r@@ -96,15 +130,10 @@ boxBuilder (l :| r) = boxBuilder l <> boxBuilder r boxBuilder (l :<> r) = boxBuilder l <> boxBuilder r --- | A box that contains no nested boxes.-closedBox :: (IsBoxType t, IsBrandConform brand ('Just t) '[])- => BoxContent t -> Box brand t-closedBox c = Box c NoBoxes- -- | A box that contains no fields, but nested boxes.-containerBox :: (IsBoxType t,IsBrandConform brand ('Just t) ts,BoxContent t ~ ())- => Boxes brand ts -> Box brand t-containerBox = Box ()+containerBox :: (IsBox t)+ => BoxContent t -> Boxes ts -> Box (ContainerBox t ts)+containerBox c bs = Box (ContainerBox c bs) -- * Box Size and Type -- | The size of the box. If the size is limited to a (fixed) value, it can be@@ -170,6 +199,12 @@ CustomBoxType String deriving (Show,Eq) +-- | Create a box type from a 'Symbol'. Parse the symbol value, if it's a four+-- charachter code, then return that as 'StdType' otherwise parse a UUID (TODO)+-- and return a 'CustomBoxType'.+parseBoxType :: KnownSymbol t => proxy t -> BoxType+parseBoxType px = StdType (fromString (symbolVal px))+ -- | A type containin a printable four letter character code. newtype FourCc = FourCc (Char,Char,Char,Char)@@ -230,3 +265,57 @@ boxSize = (1+) . fromIntegral . T.length boxBuilder txt = boxBuilder (T.encodeUtf8 txtNoNulls) <> word8 0 where txtNoNulls = T.map (\c -> if c == '\0' then ' ' else c) txt++-- | This instance writes zero bytes for 'Nothing' and delegates on 'Just'.+instance IsBoxContent a => IsBoxContent (Maybe a) where+ boxSize = maybe 0 boxSize+ boxBuilder = maybe mempty boxBuilder++-- * Box concatenation++-- | Box content composition+data a :+ b = a :+ b++infixr 3 :+++instance (IsBoxContent p,IsBoxContent c) => IsBoxContent (p :+ c) where+ boxSize (p :+ c) = boxSize p + boxSize c+ boxBuilder (p :+ c) = boxBuilder p <> boxBuilder c++instance (Default a, Default b) => Default (a :+ b) where+ def = def :+ def++-- * Type Layout Rule Matchers++-- | Mandatory, container box, exactly one+type OM b bs = ContainerBox b bs+-- | Optional, container box, zero or one+type OO b bs = OnceOptionalX (ContainerBox b bs)+-- | Mandatory, container box, one or more+type SM b bs = SomeMandatoryX (ContainerBox b bs)+-- | Optional, container box, zero or more+type SO b bs = SomeOptionalX (ContainerBox b bs)++-- | Mandatory, exactly one, no children+type OM_ b = Box b+-- | Optional, zero or one, no children+type OO_ b = OnceOptionalX (Box b)+-- | Mandatory, one or more, no children+type SM_ b = SomeMandatoryX (Box b)+-- | Optional, zero or more, no children+type SO_ b = SomeOptionalX (Box b)++----+type instance IsRuleConform (Box b) (Box r) = BoxTypeSymbol b == BoxTypeSymbol r+----+type instance IsRuleConform (Boxes bs) (Boxes rs) = IsRuleConform bs rs -- TODO+----+type instance IsRuleConform (Box b) (ContainerBox b' rules)+ = IsContainerBox b+ && IsRuleConform (Box b) (Box b')+ && IsRuleConform (ChildBoxes b) (Boxes rules)+type family IsContainerBox t :: Bool where+ IsContainerBox (ContainerBox a as) = 'True+ IsContainerBox b = 'False+type family ChildBoxes c where+ ChildBoxes (ContainerBox a as) = Boxes as
src/Data/ByteString/IsoBaseFileFormat/Boxes/BoxFields.hs view
@@ -4,6 +4,7 @@ where import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.ByteString.IsoBaseFileFormat.Boxes.Versioned import Data.Default import Data.Int import Data.Maybe@@ -246,16 +247,9 @@ instance KnownSymbol str => FromTypeLit T.Text (str :: Symbol) where fromTypeLit = T.pack . symbolVal --- * Box concatenation---- | Box content composition-data a :+ b = a :+ b--infixr 3 :+--instance (IsBoxContent p,IsBoxContent c) => IsBoxContent (p :+ c) where- boxSize (p :+ c) = boxSize p + boxSize c- boxBuilder (p :+ c) = boxBuilder p <> boxBuilder c+-- * Versioned support -instance (Default a, Default b) => Default (a :+ b) where- def = def :+ def+-- | A utility for 'Versioned' to apply a type constructor to either a+-- @('Scalar' Word32)@ or a @('Scalar' Word64)@ depending on the type level+-- version. This uses 'SelectByVersion'. +type U32U64 c = SelectByVersion c (Scalar Word32) (Scalar Word64)
− src/Data/ByteString/IsoBaseFileFormat/Boxes/Brand.hs
@@ -1,217 +0,0 @@--- | Brand/Box-validation-{-# LANGUAGE UndecidableInstances #-}-module Data.ByteString.IsoBaseFileFormat.Boxes.Brand- (IsBrand(..), ValidBox, ValidContainerBox, ValidTopLevel,- IsBrandConform, BoxTree(..), BoxForrest,- OM,OM_,OO,OO_,SM,SM_,SO,SO_)- where--import Data.Kind-import Data.Type.Bool-import GHC.TypeLits--- import GHC.Exts-import Data.Singletons (Apply, type (~>))-import Data.Singletons.Prelude.List as S (Map, (:++))-import Data.Type.List (Find)---- | A class that describes (on the type level) how a box can be nested into--- other boxes (see 'Boxes).-class KnownNat (GetVersion brand) => IsBrand brand where- type BoxLayout brand :: BoxForrest- type BoxLayout brand = '[]- type GetVersion brand :: Nat- type GetVersion brand = 0---- | Mandatory, container box, exactly one-type OM b bs = 'OnceMandatory b bs--- | Optional, container box, zero or one-type OO b bs = 'OnceOptional b bs--- | Mandatory, container box, one or more-type SM b bs = 'SomeMandatory b bs--- | Optional, container box, zero or more-type SO b bs = 'SomeOptional b bs---- | Mandatory, exactly one, no children-type OM_ b = 'OnceMandatory b '[]--- | Optional, zero or one, no children-type OO_ b = 'OnceOptional b '[]--- | Mandatory, one or more, no children-type SM_ b = 'SomeMandatory b '[]--- | Optional, zero or more, no children-type SO_ b = 'SomeOptional b '[]---- | Boxes that valid according to the box structure defined in a 'IsBrand'--- instance, i.e. where 'IsBrandConform' holds.-type family- IsBrandConform (b :: Type) (parent :: Maybe Type) (ts :: [Type]) :: Constraint where- IsBrandConform b 'Nothing ts =- IsBrandConformImpl b (TopLevel b) ts (BoxLayout b)- IsBrandConform b ('Just parent) ts =- IsBrandConformImpl b parent ts (LookUpSubtrees parent (BoxLayout b))---- | Convenience wrapper around @(IsBrandConform b ('Just t) '[])@-type ValidBox b t = IsBrandConform b ('Just t) '[]---- | Convenience wrapper around @(IsBrandConform b ('Just t) ts)@-type ValidContainerBox b t ts = IsBrandConform b ('Just t) ts---- | Convenience wrapper around @(IsBrandConform b 'Nothing ts)@-type ValidTopLevel b ts = IsBrandConform b 'Nothing ts----- | Define the cardinality and valid child boxes of a box.-data BoxTree- = OnceOptional Type- BoxForrest- | OnceMandatory Type- BoxForrest- | SomeOptional Type- BoxForrest- | SomeMandatory Type- BoxForrest---- | A list of 'BoxTree's-type BoxForrest = [BoxTree]---- * Implementation---- | A type for marking top-level boxes in TypeError messages, in the--- 'IsBrandConformImpl' constraint.-data TopLevel :: t -> Type---type family- LookUpSubtrees t (trees :: BoxForrest) :: BoxForrest where- LookUpSubtrees t '[] = '[]- LookUpSubtrees t ('OnceOptional t sub ': rest) = sub- LookUpSubtrees t ('OnceOptional u sub ': rest) = LookUpSubtrees t (sub :++ rest)- LookUpSubtrees t ('OnceMandatory t sub ': rest) = sub- LookUpSubtrees t ('OnceMandatory u sub ': rest) = LookUpSubtrees t (sub :++ rest)- LookUpSubtrees t ('SomeOptional t sub ': rest) = sub- LookUpSubtrees t ('SomeOptional u sub ': rest) = LookUpSubtrees t (sub :++ rest)- LookUpSubtrees t ('SomeMandatory t sub ': rest) = sub- LookUpSubtrees t ('SomeMandatory u sub ': rest) = LookUpSubtrees t (sub :++ rest)---- | A constraint that is solved if all 'Box'es layed out in accordance with the--- 'BoxLayout' if an 'IsBrand' instance.-type IsBrandConformImpl b (info :: Type) (ts :: [Type]) (boxForrest :: BoxForrest) =- ( IsBrand b- , ReportIt '[AllRequiredBoxes- boxForrest- ts]- , ReportIt '[OnlyValidBoxes info- boxForrest- ts]- , ReportIt (Map (RuleAppliesFun info ts)- boxForrest))--type family- ReportIt (es :: [Maybe ErrorMessage]) :: Constraint where- ReportIt '[] = ()- ReportIt ('Nothing ': rest) = ReportIt rest- ReportIt ('Just e ': rest) = TypeError e--type family- AllRequiredBoxes (f :: BoxForrest) (ts :: [t]) :: Maybe ErrorMessage where- AllRequiredBoxes '[] children = 'Nothing-- AllRequiredBoxes ('OnceMandatory c sub ': rules) '[] =- 'Just ('Text "OnceMandatory box '"- ':<>: 'ShowType c ':<>: 'Text "' missing, or out of order.")- AllRequiredBoxes ('SomeMandatory c sub ': rules) '[] =- 'Just ('Text "SomeMandatory box '"- ':<>: 'ShowType c ':<>: 'Text "' missing, or out of order.")-- AllRequiredBoxes ('OnceMandatory c sub ': rules) (c ': children) =- AllRequiredBoxes rules children- AllRequiredBoxes ('SomeMandatory c sub ': rules) (c ': children) =- AllRequiredBoxes rules (RemoveNext c children)-- AllRequiredBoxes ('OnceMandatory c sub ': rules) children =- AllRequiredBoxes rules children- AllRequiredBoxes ('SomeMandatory c sub ': rules) children =- AllRequiredBoxes rules children-- AllRequiredBoxes ('OnceOptional c sub ': rules) (c ': children) =- AllRequiredBoxes rules children- AllRequiredBoxes ('OnceOptional c sub ': rules) children =- AllRequiredBoxes rules children- AllRequiredBoxes ('SomeOptional c sub ': rules) children =- AllRequiredBoxes rules (RemoveNext c children)--type family- OnlyValidBoxes (r :: t) (f :: BoxForrest) (ts :: [t]) :: Maybe ErrorMessage where- OnlyValidBoxes r rules (c ': children) =- If (Find c (ExtractBoxes rules))- (OnlyValidBoxes r rules children)- ('Just ('Text "Invalid box '" ':<>: 'ShowType c- ':<>: 'Text "' in box '" ':<>: 'ShowType r ':<>: 'Text "'"))- OnlyValidBoxes r rules '[] = 'Nothing--type family- ExtractBoxes (f :: BoxForrest) :: [t] where- ExtractBoxes '[] = '[]- ExtractBoxes ('OnceMandatory c sub ': rules) =- c ': ExtractBoxes rules- ExtractBoxes ('SomeMandatory c sub ': rules) =- c ': ExtractBoxes rules- ExtractBoxes ('OnceOptional c sub ': rules) =- c ': ExtractBoxes rules- ExtractBoxes ('SomeOptional c sub ': rules) =- c ': ExtractBoxes rules--type family- RemoveNext (t :: k) (ts :: [k]) :: [k] where- RemoveNext t (t ': ts) = RemoveNext t ts- RemoveNext t ts = ts--data RuleAppliesFun :: t -> [t] -> BoxTree ~> Maybe ErrorMessage--type instance Apply (RuleAppliesFun parent childBoxes) rules =- RuleApplies parent childBoxes rules--type family- RuleApplies (parent :: t) (childBoxes :: [t]) (rules :: BoxTree) :: Maybe ErrorMessage where- -- Zero or more- RuleApplies parent children ('SomeOptional other sub) =- 'Nothing- -- zero or one- RuleApplies parent (child ': others) ('OnceOptional child sub) =- If (Find child others)- ('Just ('Text "It is not allowed to have more than one '"- ':<>: 'ShowType child- ':<>: 'Text "' in '"- ':<>: 'ShowType parent- ':<>: 'Text "'."))- 'Nothing- RuleApplies parent (notChild ': others) ('OnceOptional child sub) =- RuleApplies parent others ('OnceOptional child sub)- RuleApplies parent '[] ('OnceOptional child sub) = 'Nothing- -- exactly one- RuleApplies parent (child ': others) ('OnceMandatory child sub) =- If (Find child others)- ('Just ('Text "It is not allowed to have more than one '"- ':<>: 'ShowType child- ':<>: 'Text "' in '"- ':<>: 'ShowType parent- ':<>: 'Text "'."))- 'Nothing- RuleApplies parent (notChild ': others) ('OnceMandatory child sub) =- RuleApplies parent others ('OnceMandatory child sub)- RuleApplies parent '[] ('OnceMandatory child sub) =- 'Just ('Text "Need exactly one '"- ':<>: 'ShowType child- ':<>: 'Text "' in '"- ':<>: 'ShowType parent- ':<>: 'Text "'.")- -- OnceMandatory or more- RuleApplies parent (child ': others) ('SomeMandatory child sub) =- 'Nothing- RuleApplies parent (notChild ': others) ('SomeMandatory child sub) =- RuleApplies parent others ('SomeMandatory child sub)- RuleApplies parent '[] ('SomeMandatory child sub) =- 'Just ('Text "Need at least one '"- ':<>: 'ShowType child- ':<>: 'Text "' in '"- ':<>: 'ShowType parent- ':<>: 'Text "'.")
+ src/Data/ByteString/IsoBaseFileFormat/Boxes/DataInformation.hs view
@@ -0,0 +1,18 @@+-- | Data information container declare the location of media information of a+-- 'Track' the actual location are stored in 'DataReference's.+module Data.ByteString.IsoBaseFileFormat.Boxes.DataInformation where++import Data.ByteString.IsoBaseFileFormat.Boxes.Box++-- | Data information box phantom type.+data DataInformation++-- | Compose a 'DataInformation' box.+dataInformation+ :: Boxes ts -> Box (ContainerBox DataInformation ts)+dataInformation = containerBox ()++instance IsBox DataInformation where+ type BoxContent DataInformation = ()++type instance BoxTypeSymbol DataInformation = "dinf"
+ src/Data/ByteString/IsoBaseFileFormat/Boxes/DataReference.hs view
@@ -0,0 +1,79 @@+-- | A table of data references (URL/URNs). This tables is referred to by the+-- 'SampleDescription' this supports splitting a file over several files. When a+-- media file is split for transportation, this still counts as being in the+-- same file as the.+module Data.ByteString.IsoBaseFileFormat.Boxes.DataReference+ (DataReference()+ ,DataEntryUrl()+ ,DataEntryUrn()+ ,dataReference+ ,localMediaDataReference+ ,localMediaDataEntryUrl+ ,dataEntryUrl+ ,dataEntryUrn+ )+ where++import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox+import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields+ hiding (Default)+import qualified Data.Text as T+import Data.Singletons.Prelude.List (Length)+import Data.Default++-- | A container for 'DataEntryUrl's and 'DataEntryUrn's+newtype DataReference =+ DataReference (U32 "entry_count")+ deriving (Default,IsBoxContent)++-- | A container for a URL+newtype DataEntryUrl =+ DataEntryUrl (Maybe T.Text)+ deriving (Default,IsBoxContent)++-- | A container for a URN and optionally a URL+newtype DataEntryUrn =+ DataEntryUrn (T.Text :+ T.Text)+ deriving (IsBoxContent)++-- | Create a 'DataReference' box.+dataReference+ :: KnownNat (Length ts)+ => Boxes ts -> Box (ContainerBox (FullBox DataReference 0) ts)+dataReference bs =+ containerBox (FullBox 0 $ DataReference (typeListLength bs))+ bs++-- | Create a 'DataReference' box with a single local media entry.+localMediaDataReference+ :: Box (ContainerBox (FullBox DataReference 0) '[Box (FullBox DataEntryUrl 0)])+localMediaDataReference = dataReference (singletonBox localMediaDataEntryUrl)++-- | Create a 'DataEntryUrl' box for local media entry with the flag set and+-- empty content.+localMediaDataEntryUrl+ :: Box (FullBox DataEntryUrl 0)+localMediaDataEntryUrl = dataEntryUrl True Nothing++-- | Create a 'DataEntryUrl' box. The flag determines if the url is local, i.e.+-- the media data is in the same file.+dataEntryUrl+ :: Bool -> Maybe T.Text -> Box (FullBox DataEntryUrl 0)+dataEntryUrl isLocal Nothing = Box (FullBox (fromIntegral $ fromEnum isLocal) $ DataEntryUrl Nothing)+dataEntryUrl isLocal murl = Box (FullBox (fromIntegral $ fromEnum isLocal) $ DataEntryUrl murl)++-- | Create a 'DataEntryUrn' box. The flag determines if the url is local, i.e.+-- the media data is in the same file.+dataEntryUrn+ :: Bool -> T.Text -> T.Text -> Box (FullBox DataEntryUrn 0)+dataEntryUrn isLocal urn url = Box (FullBox (fromIntegral $ fromEnum isLocal) $ DataEntryUrn $ urn :+ url)++instance IsBox DataReference+type instance BoxTypeSymbol DataReference = "dref"++instance IsBox DataEntryUrn+type instance BoxTypeSymbol DataEntryUrn = "urn "++instance IsBox DataEntryUrl+type instance BoxTypeSymbol DataEntryUrl = "urn "
src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs view
@@ -3,15 +3,14 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Box -- | File Type Box-instance IsBoxType FileType where+instance IsBox FileType where type BoxContent FileType = FileType- toBoxType _ _ = StdType "ftyp"+type instance BoxTypeSymbol FileType = "ftyp" -- | Create a 'FileTypeBox' from a major brand, a minor version and a list of -- compatible brands-fileTypeBox :: (ValidBox b FileType)- => FileType -> Box b FileType-fileTypeBox = closedBox+fileTypeBox :: FileType -> Box FileType+fileTypeBox = Box -- | Contents of a 'ftyp' box are some 'FourCc' /brands/ and a version. data FileType =
src/Data/ByteString/IsoBaseFileFormat/Boxes/FullBox.hs view
@@ -1,39 +1,39 @@ -- | Full Boxes module Data.ByteString.IsoBaseFileFormat.Boxes.FullBox- (FullBox(..), fullBox, closedFullBox, BoxVersion, BoxFlags(..))+ (FullBox(..), fullBox, BoxFlags(..)) 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+data FullBox t (version :: Nat) where+ FullBox :: (KnownNat version, IsBox t)+ => BoxFlags 24+ -> BoxContent t+ -> FullBox t version -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+instance (KnownNat v, IsBox t) => IsBox (FullBox t v) where+ type BoxContent (FullBox t v) = FullBox t v --- | Create a 'FullBox' from a 'BoxVersion' and 'BoxFlags'-fullBox- :: (IsBoxType t,ValidContainerBox brand t ts,BoxContent t ~ FullBox version c)- => BoxVersion version -> BoxFlags 24 -> c -> Boxes brand ts -> Box brand t-fullBox version fs cnt = Box (FullBox version fs cnt)+type instance BoxTypeSymbol (FullBox t v) = BoxTypeSymbol t --- | Create a 'FullBox' from a 'BoxVersion' and 'BoxFlags' without nested boxes.-closedFullBox- :: (IsBoxType t,ValidBox brand t,BoxContent t ~ FullBox version c)- => BoxVersion version -> BoxFlags 24 -> c -> Box brand t-closedFullBox version fs cnt = closedBox (FullBox version fs cnt)+instance (IsBox t, KnownNat v) => IsBoxContent (FullBox t v) where+ boxSize (FullBox f c) = 1 + boxSize f + boxSize c+ boxBuilder (FullBox f c) =+ word8 (fromIntegral (natVal (Proxy :: Proxy v)))+ <> boxBuilder f+ <> boxBuilder c --- | The box version (in a 'FullBox') is a single byte-type BoxVersion v = Template (U8 "fullbox-version") v+-- | Create a 'FullBox' from a 'BoxVersion' and 'BoxFlags'+fullBox+ :: (KnownNat v, IsBox t)+ => BoxFlags 24 -> BoxContent t -> Box (FullBox t v)+fullBox f c = Box (FullBox f c) --- | In addition to a 'BoxVersion' there can be 24 bits for custom flags etc in+-- | In addition to a version there can be 24 bits for custom flags etc in -- a 'FullBox'. newtype BoxFlags bits = BoxFlags Integer
src/Data/ByteString/IsoBaseFileFormat/Boxes/Handler.hs view
@@ -26,15 +26,15 @@ | TimedMetadataTrack | AuxilliaryVideoTrack --- | Create a 'MediaDataBox' from a strict 'ByteString'+-- | Create a 'Handler' box. handler- :: (ValidBox brand Handler)- => Handler -> Box brand Handler-handler = closedFullBox Default 0+ :: Handler -> Box (FullBox Handler 0)+handler = fullBox 0 -instance IsBoxType Handler where- type BoxContent Handler = FullBox 0 Handler- toBoxType _ _ = StdType "hdlr"+instance IsBox Handler where+ type BoxContent Handler = Handler++type instance BoxTypeSymbol Handler = "hdlr" instance Default HandlerType where def = AudioTrack
src/Data/ByteString/IsoBaseFileFormat/Boxes/Media.hs view
@@ -6,10 +6,11 @@ -- | Media data box data Media -instance IsBoxType Media where- toBoxType _ _ = StdType "mdia"+instance IsBox Media where+ type BoxContent Media = () +type instance BoxTypeSymbol Media = "mdia"+ -- | Create a 'MediaDataBox' from a strict 'ByteString'-media :: ValidContainerBox brand Media ts- => Boxes brand ts -> Box brand Media-media = containerBox+media :: Boxes ts -> Box (ContainerBox Media ts)+media = containerBox ()
src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs view
@@ -5,13 +5,15 @@ import qualified Data.ByteString as B -- | Media data box phantom type-data MediaData+newtype MediaData = MediaData B.ByteString+ deriving (Show, IsBoxContent) -instance IsBoxType MediaData where+instance IsBox MediaData where -- | Contents of a 'mdat' box are just bytes from a strict 'ByteString'- type BoxContent MediaData = B.ByteString- toBoxType _ _ = StdType "mdat"+ type BoxContent MediaData = MediaData +type instance BoxTypeSymbol MediaData = "mdat"+ -- | Create a 'MediaDataBox' from a strict 'ByteString'-mediaData :: ValidBox b MediaData => B.ByteString -> Box b MediaData-mediaData = closedBox+mediaData :: MediaData -> Box MediaData+mediaData = Box
src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaHeader.hs view
@@ -16,13 +16,13 @@ -- | Create a 'MediaHeader' box. mediaHeader- :: (KnownNat v, ValidBox brand (MediaHeader v))- => MediaHeader v -> Box brand (MediaHeader v)-mediaHeader = closedFullBox Default 0+ :: (KnownNat v)+ => MediaHeader v -> Box (FullBox (MediaHeader v) v)+mediaHeader = fullBox 0 -instance (KnownNat v) => IsBoxType (MediaHeader v) where- type BoxContent (MediaHeader v) = FullBox v (MediaHeader v)- toBoxType _ _ = StdType "mdhd"+instance IsBox (MediaHeader v)++type instance BoxTypeSymbol (MediaHeader v) = "mdhd" instance IsBoxContent (MediaHeader v) where boxSize (MediaHeader c) = boxSize c
src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaInformation.hs view
@@ -4,14 +4,15 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Box --- | Media information box phantom type.+-- | Media information box type. data MediaInformation --- | Create a 'MediaInformation' from a strict 'ByteString'+-- | Compose a 'MediaInformation' box. mediaInformation- :: ValidContainerBox brand MediaInformation ts- => Boxes brand ts -> Box brand MediaInformation-mediaInformation = containerBox+ :: Boxes ts -> Box (ContainerBox MediaInformation ts)+mediaInformation = containerBox () -instance IsBoxType MediaInformation where- toBoxType _ _ = StdType "minf"+instance IsBox MediaInformation where+ type BoxContent MediaInformation = ()++type instance BoxTypeSymbol MediaInformation = "minf"
src/Data/ByteString/IsoBaseFileFormat/Boxes/Movie.hs view
@@ -4,14 +4,15 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Box -- | Compose a set of boxes into a 'Movie'-movie :: (ValidContainerBox brand Movie ts)- => Boxes brand ts -> Box brand Movie-movie = containerBox+movie :: Boxes ts -> Box (ContainerBox Movie ts)+movie = containerBox () -- | 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. data Movie -instance IsBoxType Movie where- toBoxType _ _ = StdType "moov"+instance IsBox Movie where+ type BoxContent Movie = ()++type instance BoxTypeSymbol Movie = "moov"
src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieHeader.hs view
@@ -10,9 +10,9 @@ -- | Construct a 'MovieHeader' box. movieHeader- :: (KnownNat version, ValidBox brand (MovieHeader version))- => MovieHeader version -> Box brand (MovieHeader version)-movieHeader = closedFullBox Default 0+ :: (KnownNat version)+ => MovieHeader version -> Box (FullBox (MovieHeader version) version)+movieHeader = fullBox 0 -- | Movie meta data, indexed by a version. --@@ -61,6 +61,6 @@ 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 IsBox (MovieHeader version)++type instance BoxTypeSymbol (MovieHeader v) = "mvhd"
src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs view
@@ -8,16 +8,16 @@ -- | A Box with progressive download information data ProgressiveDownload -instance IsBoxType ProgressiveDownload where- type BoxContent ProgressiveDownload = FullBox 0 ProgressiveDownloadContent- toBoxType _ _ = StdType "pdin"+instance IsBox ProgressiveDownload where+ type BoxContent ProgressiveDownload = ProgressiveDownloadContent +type instance BoxTypeSymbol ProgressiveDownload = "pdin"+ -- | Information for progressive media data download/playback encompasses the -- delay for initial playback and expected download bit rate. type ProgressiveDownloadContent = U32 "rate" :+ U32 "delay" -- | Construct a @pdin@ box. pdinBox- :: ValidBox brand ProgressiveDownload- => ProgressiveDownloadContent -> Box brand ProgressiveDownload-pdinBox = closedFullBox Default 0+ :: ProgressiveDownloadContent -> Box (FullBox ProgressiveDownload 0)+pdinBox = fullBox 0
src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs view
@@ -6,13 +6,14 @@ -- | Contents of a 'skip' box are just any number of filler bytes. newtype Skip = Skip Int -instance IsBoxType Skip where+instance IsBox Skip where type BoxContent Skip = Skip- toBoxType _ _ = StdType "skip" +type instance BoxTypeSymbol Skip = "skip"+ -- | Create a 'Skip' with a given size.-skipBox :: ValidBox brand Skip => Skip -> Box brand Skip-skipBox = closedBox+skipBox :: Skip -> Box Skip+skipBox = Box instance IsBoxContent Skip where boxSize (Skip bs) = fromIntegral bs
src/Data/ByteString/IsoBaseFileFormat/Boxes/SpecificMediaHeader.hs view
@@ -4,48 +4,76 @@ import Data.ByteString.IsoBaseFileFormat.Boxes.Box import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields import Data.ByteString.IsoBaseFileFormat.Boxes.FullBox+import Data.Default --- | Media header data box. The actual box type is determined by the claused--- used to construct the record.-data SpecificMediaHeader where+-- * Videos++-- | Video header data box.+newtype VideoMediaHeader where VideoMediaHeader :: Template (U16 "graphicsmode") 0- :+ Template (U16 "reserved") 0- -> SpecificMediaHeader+ :+ Template (U16Arr "opcolor" 3) '[0,0,0]+ -> VideoMediaHeader+ deriving (Default, IsBoxContent)++-- | Create a video media header data box.+videoMediaHeader :: VideoMediaHeader -> Box (FullBox VideoMediaHeader 0)+videoMediaHeader = fullBox 1++instance IsBox VideoMediaHeader+type instance BoxTypeSymbol VideoMediaHeader = "vmhd"++-- * Sounds++-- | Sound header data box.+newtype SoundMediaHeader where SoundMediaHeader :: Template (I16 "balance") 0- :+ Constant (U16Arr "opcolor" 3) '[0,0,0]- -> SpecificMediaHeader+ :+ Constant (U16 "reserved") 0+ -> SoundMediaHeader+ deriving (Default, IsBoxContent)++-- | Create a sound media header data box.+soundMediaHeader :: SoundMediaHeader -> Box (FullBox SoundMediaHeader 0)+soundMediaHeader = fullBox 0++instance IsBox SoundMediaHeader+type instance BoxTypeSymbol SoundMediaHeader = "smhd"++-- * Hints++-- | Hint data box.+newtype HintMediaHeader where HintMediaHeader :: U16 "maxPDUsize" :+ U16 "avgPDUsize" :+ U16 "maxbitrate" :+ U16 "avgbitrate" :+ U32 "reserved"- -> SpecificMediaHeader- NullMediaHeader- :: SpecificMediaHeader+ -> HintMediaHeader+ deriving (Default, IsBoxContent) --- | Create a 'SpecificMediaHeader' box.-specificMediaHeader- :: ValidBox brand SpecificMediaHeader- => SpecificMediaHeader -> Box brand SpecificMediaHeader-specificMediaHeader h@(VideoMediaHeader _) = closedFullBox Default 1 h-specificMediaHeader h = closedFullBox Default 0 h+-- | Create a hint media header data box.+hintMediaHeader :: HintMediaHeader -> Box (FullBox HintMediaHeader 0)+hintMediaHeader = fullBox 0 -instance IsBoxType SpecificMediaHeader where- type BoxContent SpecificMediaHeader = FullBox 0 SpecificMediaHeader- toBoxType _ (FullBox _ _ (VideoMediaHeader _)) = StdType "vmhd"- toBoxType _ (FullBox _ _ (SoundMediaHeader _)) = StdType "smhd"- toBoxType _ (FullBox _ _ (HintMediaHeader _)) = StdType "hmhd"- toBoxType _ (FullBox _ _ NullMediaHeader) = StdType "nmhd"+instance IsBox HintMediaHeader+type instance BoxTypeSymbol HintMediaHeader = "hmhd" -instance IsBoxContent SpecificMediaHeader where- boxSize (VideoMediaHeader c) = boxSize c- boxSize (SoundMediaHeader c) = boxSize c- boxSize (HintMediaHeader c) = boxSize c- boxSize NullMediaHeader = boxSize ()- boxBuilder (VideoMediaHeader c) = boxBuilder c- boxBuilder (SoundMediaHeader c) = boxBuilder c- boxBuilder (HintMediaHeader c) = boxBuilder c- boxBuilder NullMediaHeader = boxBuilder ()+-- * Dummy/Null media++-- | Null header data box.+data NullMediaHeader = NullMediaHeader++-- | Create a null media header data box.+nullMediaHeader :: Box (FullBox NullMediaHeader 0)+nullMediaHeader = fullBox 0 NullMediaHeader++instance IsBox NullMediaHeader+type instance BoxTypeSymbol NullMediaHeader = "nmhd"++instance Default NullMediaHeader where+ def = NullMediaHeader+instance IsBoxContent NullMediaHeader where+ boxSize _ = 0+ boxBuilder _ = mempty
src/Data/ByteString/IsoBaseFileFormat/Boxes/Track.hs view
@@ -6,12 +6,13 @@ -- * @trak@ Box -- | Compose a 'Track' box from the given boxes. track- :: (ValidContainerBox brand Track ts)- => Boxes brand ts -> Box brand Track-track = containerBox+ :: Boxes ts -> Box (ContainerBox Track ts)+track = containerBox () -- | Container box for tracks. data Track -instance IsBoxType Track where- toBoxType _ _ = StdType "trak"+instance IsBox Track where+ type BoxContent Track = ()++type instance BoxTypeSymbol Track = "trak"
src/Data/ByteString/IsoBaseFileFormat/Boxes/TrackHeader.hs view
@@ -9,9 +9,9 @@ -- * @tkhd@ Box -- | Create a 'TrackHeader' box. trackHeader- :: (ValidBox brand (TrackHeader version), version ~ GetVersion brand)- => TrackHeader version -> Box brand (TrackHeader version)-trackHeader = closedFullBox Default 0+ :: KnownNat version+ => TrackHeader version -> Box (FullBox (TrackHeader version) version)+trackHeader = fullBox 0 -- | Track meta data, indexed by a version. data TrackHeader (version :: Nat) where@@ -46,6 +46,6 @@ 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 IsBox (TrackHeader version)++type instance BoxTypeSymbol (TrackHeader version) = "tkhd"
src/Data/ByteString/IsoBaseFileFormat/Boxes/Versioned.hs view
@@ -1,10 +1,13 @@+{-# LANGUAGE UndecidableInstances #-} -- | A binary version 0/1 field with seperate content for each version. module Data.ByteString.IsoBaseFileFormat.Boxes.Versioned- (Versioned(..))+ (Versioned(..), ApplyVersioned(..), SelectByVersion) where import Data.ByteString.IsoBaseFileFormat.Boxes.Box import Data.Default+import Data.Kind+import Data.Singletons -- | Two alternative representations based on a /version/ index. -- Use this for box content that can be either 32 or 64 bit.@@ -20,3 +23,39 @@ boxSize (V1 c) = boxSize c boxBuilder (V0 c) = boxBuilder c boxBuilder (V1 c) = boxBuilder c++data VersionedBox c where+ BoxV0 :: forall (v :: Nat -> Type). IsBoxContent (v 0) => v 0 -> VersionedBox v+ BoxV1 :: forall (v :: Nat -> Type). IsBoxContent (v 1) => v 1 -> VersionedBox v++instance (IsBoxContent (b 0), Default (b 0)) => Default (VersionedBox b) where+ def = BoxV0 def++instance IsBoxContent (VersionedBox c) where+ boxSize (BoxV0 c) = boxSize c+ boxSize (BoxV1 c) = boxSize c+ boxBuilder (BoxV0 c) = boxBuilder c+ boxBuilder (BoxV1 c) = boxBuilder c++-- * Versions based on type level arrows++-- | Two alternative representations based on a /version/ index.+-- Use this for box content that can be either 32 or 64 bit.+data ApplyVersioned (v' :: Nat ~> Type) where+ OnV0 :: forall (v :: Nat ~> Type). IsBoxContent (v @@ 0) => v @@ 0 -> ApplyVersioned v+ OnV1 :: forall (v :: Nat ~> Type). IsBoxContent (v @@ 1) => v @@ 1 -> ApplyVersioned v++instance (IsBoxContent (b @@ 0), Default (b @@ 0)) => Default (ApplyVersioned b) where+ def = OnV0 def++instance IsBoxContent (ApplyVersioned c) where+ boxSize (OnV0 c) = boxSize c+ boxSize (OnV1 c) = boxSize c+ boxBuilder (OnV0 c) = boxBuilder c+ boxBuilder (OnV1 c) = boxBuilder c++-- | A type level arrow that applys the type constructor to one of the two+-- versions depending on the /version/ parameter.+data SelectByVersion :: (a -> Type) -> a -> a -> Nat ~> Type+type instance Apply (SelectByVersion f v0 v1) 0 = f v0+type instance Apply (SelectByVersion f v0 v1) 1 = f v1
src/Data/ByteString/IsoBaseFileFormat/Brands/Dash.hs view
@@ -1,32 +1,64 @@+{-# LANGUAGE UndecidableInstances #-} -- | Predefined Box composition matching the @dash@ brand. TODO this is an -- incomplete, special-purpose variant of this brand, serving my personal, -- educational, current need. -- This is a convenient way of building documents of that kind. module Data.ByteString.IsoBaseFileFormat.Brands.Dash- (Dash, SingleTrackInit(..), mkSingleTrackInit, module X) where+ (Dash, SingleAudioTrackInit(..), mkSingleTrackInit, module X) where -import Data.ByteString.IsoBaseFileFormat.Boxes as X+import Data.ByteString.IsoBaseFileFormat.Brands.Types+import Data.ByteString.IsoBaseFileFormat.Boxes as X hiding (All) import Data.Kind (Type, Constraint) import Control.Lens+import Data.Promotion.Prelude.List+import Data.Singletons -- | A phantom type to indicate this branding. Version can be 0 or 1 it is used -- in some boxes to switch between 32/64 bits. data Dash (version :: Nat) +-- | A constant to indicate the 'Dash' brand with version 0+dash :: Proxy (Dash 0)+dash = Proxy+ -- | A 'BoxLayout' which contains the stuff needed for the 'dash' brand. -- TODO incomplete-instance KnownNat v => IsBrand (Dash v) where- type GetVersion (Dash v) = v+instance IsBrand (Dash v) where type BoxLayout (Dash v) =- '[OM_ FileType,- OM Movie- '[OM_ (MovieHeader v),- SM Track- '[OM_ (TrackHeader v),- OM Media- '[OM_ (MediaHeader v), OM_ Handler,- OM MediaInformation '[OO_ SpecificMediaHeader]]]],- SO_ Skip]+ Boxes+ '[ OM_ FileType+ , OM Movie+ '[ OM_ (MovieHeader v)+ , SM Track+ '[ OM_ (TrackHeader v)+ , OM Media+ '[ OM_ (MediaHeader v)+ , OM_ Handler+ , OM MediaInformation+ '[ OneOf '[ OM_ VideoMediaHeader+ , OM_ SoundMediaHeader+ , OM_ HintMediaHeader+ , OM_ NullMediaHeader]+ , OM DataInformation+ '[ OM DataReference+ '[ OneOf '[ OM_ DataEntryUrl+ , OM_ DataEntryUrn]+ , SomeOptionalX+ (OneOf '[ OM_ DataEntryUrl+ , OM_ DataEntryUrn])]]+ -- , OM (SampleTable v) -- TODO+ -- '[ OM_ (SampleDescriptions v)+ -- , OM_ (TimeToSample v)+ -- , OM_ (SampleToChunk v)+ -- , OO_ (SampleSizes v)+ -- , OM_ (SampleChunkOffset v)+ -- ]+ ]+ ]+ ]+ ]+ , SO_ Skip+ ] -- Missing Boxes -- START 17:47:@@ -58,23 +90,23 @@ -- trun -- | A record which contains the stuff needed for a single track initialization -- document according to the 'Dash' brand. TODO incomplete-data SingleTrackInit =- SingleTrackInit {_mvhd :: MovieHeader 0- ,_tkhd :: TrackHeader 0- ,_mdhd :: MediaHeader 0- ,_hdlr :: Handler- ,_xmhd :: SpecificMediaHeader}+data SingleAudioTrackInit =+ SingleAudioTrackInit {_mvhd :: MovieHeader 0+ ,_tkhd :: TrackHeader 0+ ,_mdhd :: MediaHeader 0+ ,_hdlr :: Handler+ ,_smhd :: SoundMediaHeader} -makeLenses ''SingleTrackInit+makeLenses ''SingleAudioTrackInit --- | Convert a 'SingleTrackInit' record to a generic 'Boxes' collection.+-- | Convert a 'SingleAudioTrackInit' record to a generic 'Boxes' collection. mkSingleTrackInit- :: SingleTrackInit -> MediaFile (Dash 0)-mkSingleTrackInit doc =- MediaFile $- fileTypeBox (FileType "iso5" 0 ["isom","iso5","dash","mp42"]) :|- movie (movieHeader (doc ^. mvhd) :|- track (trackHeader (doc ^. tkhd) :|- media (mediaHeader (doc ^. mdhd) :. handler (doc ^. hdlr) :|- mediaInformation $:- specificMediaHeader (doc ^. xmhd))))+ :: SingleAudioTrackInit -> Builder+mkSingleTrackInit doc = mediaBuilder dash $+ fileTypeBox (FileType "dash" 0 ["isom","iso5","mp42"])+ :|+ movie (movieHeader (doc ^. mvhd) :|+ track (trackHeader (doc ^. tkhd) :|+ media (mediaHeader (doc ^. mdhd) :. handler (doc ^. hdlr) :|+ mediaInformation+ (soundMediaHeader (doc ^. smhd) :| dataInformation $: localMediaDataReference ))))
+ src/Data/ByteString/IsoBaseFileFormat/Brands/Types.hs view
@@ -0,0 +1,16 @@+-- | Brand/Box-validation+module Data.ByteString.IsoBaseFileFormat.Brands.Types+ where++import Data.ByteString.IsoBaseFileFormat.Boxes.Box+import Data.ByteString.IsoBaseFileFormat.Util.TypeLayout ()++-- | A class that describes (on the type level) how a box can be nested into+-- other boxes (see 'Boxes).+class IsBrand brand where+ -- | The layout that an IsBoxContent instance has to have, before 'packMedia' accepts it+ type BoxLayout brand+ mediaBuilder+ :: forall t proxy . (IsBoxContent t, IsRuleConform t (BoxLayout brand) ~ 'True)+ => proxy brand -> t -> Builder+ mediaBuilder _ t = boxBuilder t
+ src/Data/ByteString/IsoBaseFileFormat/Util/TypeLayout.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE UndecidableInstances #-}++module Data.ByteString.IsoBaseFileFormat.Util.TypeLayout where++import Data.Kind+import Data.Type.Bool+import Data.Singletons (Apply, type (~>))+import Data.Type.Equality+import GHC.TypeLits++----+type family IsRuleConform (b :: k) (r :: l) :: Bool+data IsRuleConform0 :: k ~> l ~> Bool+type instance Apply IsRuleConform0 ts = IsRuleConform1 ts+data IsRuleConform1 :: k -> l ~> Bool+type instance Apply (IsRuleConform1 ts) rule = IsRuleConform ts rule+----+data TopLevel :: Type -> Type+type instance IsRuleConform t (TopLevel rule) = IsRuleConform t rule+----+data OneOf :: [Type] -> Type+type instance IsRuleConform t (OneOf '[]) = 'False+type instance IsRuleConform t (OneOf (r ': rs)) =+ IsRuleConform t r || IsRuleConform t (OneOf rs)+----+data MatchSymbol :: Symbol -> Type+type instance IsRuleConform b (MatchSymbol fourcc) = ToSymbol b == fourcc+type family ToSymbol t :: Symbol+data ToSymbol0 :: Type ~> Symbol+type instance Apply ToSymbol0 t = ToSymbol t+----+data OnceOptionalX t+data SomeOptionalX t+data SomeMandatoryX t+type instance IsRuleConform (bs :: [Type]) (sq :: [Type]) = IsSequence bs sq+type family+ IsSequence (bs :: [k]) (rs :: [j]) :: Bool+ where+ IsSequence '[] '[] = 'True+ IsSequence (b ': bs) '[] = 'False+ --+ IsSequence '[] (OnceOptionalX r ': rs) = IsSequence '[] rs+ IsSequence (b ': bs) (OnceOptionalX r ': rs) =+ If (IsRuleConform b r)+ (IsSequence bs rs)+ (IsSequence (b ': bs) rs)+ --+ IsSequence '[] (SomeOptionalX r ': rs) = IsSequence '[] rs+ IsSequence (b ': bs) (SomeOptionalX r ': rs) =+ If (IsRuleConform b r)+ (IsSequence bs (SomeOptionalX r ': rs))+ (IsSequence (b ': bs) rs )+ --+ IsSequence '[] (SomeMandatoryX r ': rs) = 'False+ IsSequence (b ': bs) (SomeMandatoryX r ': rs) =+ IsRuleConform b r && IsSequence bs (SomeOptionalX r ': rs)+ --+ IsSequence '[] (r ': rs) = 'False+ IsSequence (b ': bs) (r ': rs) =+ IsRuleConform b r && IsSequence bs rs