From cc69250bbe9aa95b2405512ef03e8d3dbaa38246 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 08:18:28 +0000 Subject: [chore]: Bump github.com/abema/go-mp4 from 0.11.0 to 0.12.0 (#2075) --- vendor/github.com/abema/go-mp4/box_types.go | 2846 -------------------- vendor/github.com/abema/go-mp4/box_types_3gpp.go | 24 + vendor/github.com/abema/go-mp4/box_types_av1.go | 44 + .../abema/go-mp4/box_types_iso14496_12.go | 2454 +++++++++++++++++ .../abema/go-mp4/box_types_iso14496_14.go | 126 + .../abema/go-mp4/box_types_iso23001_7.go | 108 + .../github.com/abema/go-mp4/box_types_metadata.go | 172 ++ vendor/github.com/abema/go-mp4/box_types_opus.go | 54 + 8 files changed, 2982 insertions(+), 2846 deletions(-) delete mode 100644 vendor/github.com/abema/go-mp4/box_types.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_3gpp.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_av1.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_iso14496_12.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_iso14496_14.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_iso23001_7.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_metadata.go create mode 100644 vendor/github.com/abema/go-mp4/box_types_opus.go (limited to 'vendor/github.com') diff --git a/vendor/github.com/abema/go-mp4/box_types.go b/vendor/github.com/abema/go-mp4/box_types.go deleted file mode 100644 index dc4231e3a..000000000 --- a/vendor/github.com/abema/go-mp4/box_types.go +++ /dev/null @@ -1,2846 +0,0 @@ -package mp4 - -import ( - "bytes" - "errors" - "fmt" - "io" - - "github.com/abema/go-mp4/bitio" - "github.com/abema/go-mp4/util" - "github.com/google/uuid" -) - -/*************************** btrt ****************************/ - -func BoxTypeBtrt() BoxType { return StrToBoxType("btrt") } - -func init() { - AddBoxDef(&Btrt{}, 0) -} - -type Btrt struct { - Box - BufferSizeDB uint32 `mp4:"0,size=32"` - MaxBitrate uint32 `mp4:"1,size=32"` - AvgBitrate uint32 `mp4:"2,size=32"` -} - -// GetType returns the BoxType -func (*Btrt) GetType() BoxType { - return BoxTypeBtrt() -} - -/*************************** co64 ****************************/ - -func BoxTypeCo64() BoxType { return StrToBoxType("co64") } - -func init() { - AddBoxDef(&Co64{}, 0) -} - -type Co64 struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - ChunkOffset []uint64 `mp4:"2,size=64,len=dynamic"` -} - -// GetType returns the BoxType -func (*Co64) GetType() BoxType { - return BoxTypeCo64() -} - -// GetFieldLength returns length of dynamic field -func (co64 *Co64) GetFieldLength(name string, ctx Context) uint { - switch name { - case "ChunkOffset": - return uint(co64.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=co64 fieldName=%s", name)) -} - -/*************************** colr ****************************/ - -func BoxTypeColr() BoxType { return StrToBoxType("colr") } - -func init() { - AddBoxDef(&Colr{}) -} - -type Colr struct { - Box - ColourType [4]byte `mp4:"0,size=8,string"` - ColourPrimaries uint16 `mp4:"1,size=16,opt=dynamic"` - TransferCharacteristics uint16 `mp4:"2,size=16,opt=dynamic"` - MatrixCoefficients uint16 `mp4:"3,size=16,opt=dynamic"` - FullRangeFlag bool `mp4:"4,size=1,opt=dynamic"` - Reserved uint8 `mp4:"5,size=7,opt=dynamic"` - Profile []byte `mp4:"6,size=8,opt=dynamic"` - Unknown []byte `mp4:"7,size=8,opt=dynamic"` -} - -func (colr *Colr) IsOptFieldEnabled(name string, ctx Context) bool { - switch colr.ColourType { - case [4]byte{'n', 'c', 'l', 'x'}: - switch name { - case "ColourType", - "ColourPrimaries", - "TransferCharacteristics", - "MatrixCoefficients", - "FullRangeFlag", - "Reserved": - return true - default: - return false - } - case [4]byte{'r', 'I', 'C', 'C'}, [4]byte{'p', 'r', 'o', 'f'}: - return name == "Profile" - default: - return name == "Unknown" - } -} - -// GetType returns the BoxType -func (*Colr) GetType() BoxType { - return BoxTypeColr() -} - -/*************************** cslg ****************************/ - -func BoxTypeCslg() BoxType { return StrToBoxType("cslg") } - -func init() { - AddBoxDef(&Cslg{}, 0, 1) -} - -type Cslg struct { - FullBox `mp4:"0,extend"` - CompositionToDTSShiftV0 int32 `mp4:"1,size=32,ver=0"` - LeastDecodeToDisplayDeltaV0 int32 `mp4:"2,size=32,ver=0"` - GreatestDecodeToDisplayDeltaV0 int32 `mp4:"3,size=32,ver=0"` - CompositionStartTimeV0 int32 `mp4:"4,size=32,ver=0"` - CompositionEndTimeV0 int32 `mp4:"5,size=32,ver=0"` - CompositionToDTSShiftV1 int64 `mp4:"6,size=64,nver=0"` - LeastDecodeToDisplayDeltaV1 int64 `mp4:"7,size=64,nver=0"` - GreatestDecodeToDisplayDeltaV1 int64 `mp4:"8,size=64,nver=0"` - CompositionStartTimeV1 int64 `mp4:"9,size=64,nver=0"` - CompositionEndTimeV1 int64 `mp4:"10,size=64,nver=0"` -} - -// GetType returns the BoxType -func (*Cslg) GetType() BoxType { - return BoxTypeCslg() -} - -func (cslg *Cslg) GetCompositionToDTSShift() int64 { - switch cslg.GetVersion() { - case 0: - return int64(cslg.CompositionToDTSShiftV0) - case 1: - return cslg.CompositionToDTSShiftV1 - default: - return 0 - } -} - -func (cslg *Cslg) GetLeastDecodeToDisplayDelta() int64 { - switch cslg.GetVersion() { - case 0: - return int64(cslg.LeastDecodeToDisplayDeltaV0) - case 1: - return cslg.LeastDecodeToDisplayDeltaV1 - default: - return 0 - } -} - -func (cslg *Cslg) GetGreatestDecodeToDisplayDelta() int64 { - switch cslg.GetVersion() { - case 0: - return int64(cslg.GreatestDecodeToDisplayDeltaV0) - case 1: - return cslg.GreatestDecodeToDisplayDeltaV1 - default: - return 0 - } -} - -func (cslg *Cslg) GetCompositionStartTime() int64 { - switch cslg.GetVersion() { - case 0: - return int64(cslg.CompositionStartTimeV0) - case 1: - return cslg.CompositionStartTimeV1 - default: - return 0 - } -} - -func (cslg *Cslg) GetCompositionEndTime() int64 { - switch cslg.GetVersion() { - case 0: - return int64(cslg.CompositionEndTimeV0) - case 1: - return cslg.CompositionEndTimeV1 - default: - return 0 - } -} - -/*************************** ctts ****************************/ - -func BoxTypeCtts() BoxType { return StrToBoxType("ctts") } - -func init() { - AddBoxDef(&Ctts{}, 0, 1) -} - -type Ctts struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - Entries []CttsEntry `mp4:"2,len=dynamic,size=64"` -} - -type CttsEntry struct { - SampleCount uint32 `mp4:"0,size=32"` - SampleOffsetV0 uint32 `mp4:"1,size=32,ver=0"` - SampleOffsetV1 int32 `mp4:"2,size=32,ver=1"` -} - -// GetType returns the BoxType -func (*Ctts) GetType() BoxType { - return BoxTypeCtts() -} - -// GetFieldLength returns length of dynamic field -func (ctts *Ctts) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(ctts.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=ctts fieldName=%s", name)) -} - -func (ctts *Ctts) GetSampleOffset(index int) int64 { - switch ctts.GetVersion() { - case 0: - return int64(ctts.Entries[index].SampleOffsetV0) - case 1: - return int64(ctts.Entries[index].SampleOffsetV1) - default: - return 0 - } -} - -/*************************** dinf ****************************/ - -func BoxTypeDinf() BoxType { return StrToBoxType("dinf") } - -func init() { - AddBoxDef(&Dinf{}) -} - -// Dinf is ISOBMFF dinf box type -type Dinf struct { - Box -} - -// GetType returns the BoxType -func (*Dinf) GetType() BoxType { - return BoxTypeDinf() -} - -/*************************** dref ****************************/ - -func BoxTypeDref() BoxType { return StrToBoxType("dref") } -func BoxTypeUrl() BoxType { return StrToBoxType("url ") } -func BoxTypeUrn() BoxType { return StrToBoxType("urn ") } - -func init() { - AddBoxDef(&Dref{}, 0) - AddBoxDef(&Url{}, 0) - AddBoxDef(&Urn{}, 0) -} - -// Dref is ISOBMFF dref box type -type Dref struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Dref) GetType() BoxType { - return BoxTypeDref() -} - -type Url struct { - FullBox `mp4:"0,extend"` - Location string `mp4:"1,string,nopt=0x000001"` -} - -func (*Url) GetType() BoxType { - return BoxTypeUrl() -} - -const UrlSelfContained = 0x000001 - -type Urn struct { - FullBox `mp4:"0,extend"` - Name string `mp4:"1,string,nopt=0x000001"` - Location string `mp4:"2,string,nopt=0x000001"` -} - -func (*Urn) GetType() BoxType { - return BoxTypeUrn() -} - -const UrnSelfContained = 0x000001 - -/*************************** edts ****************************/ - -func BoxTypeEdts() BoxType { return StrToBoxType("edts") } - -func init() { - AddBoxDef(&Edts{}) -} - -// Edts is ISOBMFF edts box type -type Edts struct { - Box -} - -// GetType returns the BoxType -func (*Edts) GetType() BoxType { - return BoxTypeEdts() -} - -/*************************** elst ****************************/ - -func BoxTypeElst() BoxType { return StrToBoxType("elst") } - -func init() { - AddBoxDef(&Elst{}, 0, 1) -} - -// Elst is ISOBMFF elst box type -type Elst struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - Entries []ElstEntry `mp4:"2,len=dynamic,size=dynamic"` -} - -type ElstEntry struct { - SegmentDurationV0 uint32 `mp4:"0,size=32,ver=0"` - MediaTimeV0 int32 `mp4:"1,size=32,ver=0"` - SegmentDurationV1 uint64 `mp4:"2,size=64,ver=1"` - MediaTimeV1 int64 `mp4:"3,size=64,ver=1"` - MediaRateInteger int16 `mp4:"4,size=16"` - MediaRateFraction int16 `mp4:"5,size=16,const=0"` -} - -// GetType returns the BoxType -func (*Elst) GetType() BoxType { - return BoxTypeElst() -} - -// GetFieldSize returns size of dynamic field -func (elst *Elst) GetFieldSize(name string, ctx Context) uint { - switch name { - case "Entries": - switch elst.GetVersion() { - case 0: - return 0 + - /* segmentDurationV0 */ 32 + - /* mediaTimeV0 */ 32 + - /* mediaRateInteger */ 16 + - /* mediaRateFraction */ 16 - case 1: - return 0 + - /* segmentDurationV1 */ 64 + - /* mediaTimeV1 */ 64 + - /* mediaRateInteger */ 16 + - /* mediaRateFraction */ 16 - } - } - panic(fmt.Errorf("invalid name of dynamic-size field: boxType=elst fieldName=%s", name)) -} - -// GetFieldLength returns length of dynamic field -func (elst *Elst) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(elst.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=elst fieldName=%s", name)) -} - -func (elst *Elst) GetSegmentDuration(index int) uint64 { - switch elst.GetVersion() { - case 0: - return uint64(elst.Entries[index].SegmentDurationV0) - case 1: - return elst.Entries[index].SegmentDurationV1 - default: - return 0 - } -} - -func (elst *Elst) GetMediaTime(index int) int64 { - switch elst.GetVersion() { - case 0: - return int64(elst.Entries[index].MediaTimeV0) - case 1: - return elst.Entries[index].MediaTimeV1 - default: - return 0 - } -} - -/*************************** emsg ****************************/ - -func BoxTypeEmsg() BoxType { return StrToBoxType("emsg") } - -func init() { - AddBoxDef(&Emsg{}, 0, 1) -} - -// Emsg is ISOBMFF emsg box type -type Emsg struct { - FullBox `mp4:"0,extend"` - SchemeIdUri string `mp4:"1,string"` - Value string `mp4:"2,string"` - Timescale uint32 `mp4:"3,size=32"` - PresentationTimeDelta uint32 `mp4:"4,size=32,ver=0"` - PresentationTime uint64 `mp4:"5,size=64,ver=1"` - EventDuration uint32 `mp4:"6,size=32"` - Id uint32 `mp4:"7,size=32"` - MessageData []byte `mp4:"8,size=8,string"` -} - -func (emsg *Emsg) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { - if emsg.GetVersion() == 0 { - return - } - switch name { - case "SchemeIdUri", "Value": - override = true - return - case "MessageData": - emsg.SchemeIdUri, err = util.ReadString(r) - if err != nil { - return - } - emsg.Value, err = util.ReadString(r) - if err != nil { - return - } - rbits += uint64(len(emsg.SchemeIdUri)+len(emsg.Value)+2) * 8 - return - default: - return - } -} - -func (emsg *Emsg) OnWriteField(name string, w bitio.Writer, ctx Context) (wbits uint64, override bool, err error) { - if emsg.GetVersion() == 0 { - return - } - switch name { - case "SchemeIdUri", "Value": - override = true - return - case "MessageData": - if err = util.WriteString(w, emsg.SchemeIdUri); err != nil { - return - } - if err = util.WriteString(w, emsg.Value); err != nil { - return - } - wbits += uint64(len(emsg.SchemeIdUri)+len(emsg.Value)+2) * 8 - return - default: - return - } -} - -// GetType returns the BoxType -func (*Emsg) GetType() BoxType { - return BoxTypeEmsg() -} - -/*************************** esds ****************************/ - -// https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html - -func BoxTypeEsds() BoxType { return StrToBoxType("esds") } - -func init() { - AddBoxDef(&Esds{}, 0) -} - -const ( - ESDescrTag = 0x03 - DecoderConfigDescrTag = 0x04 - DecSpecificInfoTag = 0x05 - SLConfigDescrTag = 0x06 -) - -// Esds is ES descripter box -type Esds struct { - FullBox `mp4:"0,extend"` - Descriptors []Descriptor `mp4:"1,array"` -} - -// GetType returns the BoxType -func (*Esds) GetType() BoxType { - return BoxTypeEsds() -} - -type Descriptor struct { - BaseCustomFieldObject - Tag int8 `mp4:"0,size=8"` // must be 0x03 - Size uint32 `mp4:"1,varint"` - ESDescriptor *ESDescriptor `mp4:"2,extend,opt=dynamic"` - DecoderConfigDescriptor *DecoderConfigDescriptor `mp4:"3,extend,opt=dynamic"` - Data []byte `mp4:"4,size=8,opt=dynamic,len=dynamic"` -} - -// GetFieldLength returns length of dynamic field -func (ds *Descriptor) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Data": - return uint(ds.Size) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=esds fieldName=%s", name)) -} - -func (ds *Descriptor) IsOptFieldEnabled(name string, ctx Context) bool { - switch ds.Tag { - case ESDescrTag: - return name == "ESDescriptor" - case DecoderConfigDescrTag: - return name == "DecoderConfigDescriptor" - default: - return name == "Data" - } -} - -// StringifyField returns field value as string -func (ds *Descriptor) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "Tag": - switch ds.Tag { - case ESDescrTag: - return "ESDescr", true - case DecoderConfigDescrTag: - return "DecoderConfigDescr", true - case DecSpecificInfoTag: - return "DecSpecificInfo", true - case SLConfigDescrTag: - return "SLConfigDescr", true - default: - return "", false - } - default: - return "", false - } -} - -type ESDescriptor struct { - BaseCustomFieldObject - ESID uint16 `mp4:"0,size=16"` - StreamDependenceFlag bool `mp4:"1,size=1"` - UrlFlag bool `mp4:"2,size=1"` - OcrStreamFlag bool `mp4:"3,size=1"` - StreamPriority int8 `mp4:"4,size=5"` - DependsOnESID uint16 `mp4:"5,size=16,opt=dynamic"` - URLLength uint8 `mp4:"6,size=8,opt=dynamic"` - URLString []byte `mp4:"7,size=8,len=dynamic,opt=dynamic,string"` - OCRESID uint16 `mp4:"8,size=16,opt=dynamic"` -} - -func (esds *ESDescriptor) GetFieldLength(name string, ctx Context) uint { - switch name { - case "URLString": - return uint(esds.URLLength) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=ESDescriptor fieldName=%s", name)) -} - -func (esds *ESDescriptor) IsOptFieldEnabled(name string, ctx Context) bool { - switch name { - case "DependsOnESID": - return esds.StreamDependenceFlag - case "URLLength", "URLString": - return esds.UrlFlag - case "OCRESID": - return esds.OcrStreamFlag - default: - return false - } -} - -type DecoderConfigDescriptor struct { - BaseCustomFieldObject - ObjectTypeIndication byte `mp4:"0,size=8"` - StreamType int8 `mp4:"1,size=6"` - UpStream bool `mp4:"2,size=1"` - Reserved bool `mp4:"3,size=1"` - BufferSizeDB uint32 `mp4:"4,size=24"` - MaxBitrate uint32 `mp4:"5,size=32"` - AvgBitrate uint32 `mp4:"6,size=32"` -} - -/*************************** fiel ****************************/ - -func BoxTypeFiel() BoxType { return StrToBoxType("fiel") } - -func init() { - AddBoxDef(&Fiel{}) -} - -type Fiel struct { - Box - FieldCount uint8 `mp4:"0,size=8"` - FieldOrdering uint8 `mp4:"1,size=8"` -} - -func (Fiel) GetType() BoxType { - return BoxTypeFiel() -} - -/************************ free, skip *************************/ - -func BoxTypeFree() BoxType { return StrToBoxType("free") } -func BoxTypeSkip() BoxType { return StrToBoxType("skip") } - -func init() { - AddBoxDef(&Free{}) - AddBoxDef(&Skip{}) -} - -type FreeSpace struct { - Box - Data []uint8 `mp4:"0,size=8"` -} - -type Free FreeSpace - -func (*Free) GetType() BoxType { - return BoxTypeFree() -} - -type Skip FreeSpace - -func (*Skip) GetType() BoxType { - return BoxTypeSkip() -} - -/*************************** frma ****************************/ - -func BoxTypeFrma() BoxType { return StrToBoxType("frma") } - -func init() { - AddBoxDef(&Frma{}) -} - -// Frma is ISOBMFF frma box type -type Frma struct { - Box - DataFormat [4]byte `mp4:"0,size=8,string"` -} - -// GetType returns the BoxType -func (*Frma) GetType() BoxType { - return BoxTypeFrma() -} - -/*************************** ftyp ****************************/ - -func BoxTypeFtyp() BoxType { return StrToBoxType("ftyp") } - -func init() { - AddBoxDef(&Ftyp{}) -} - -func BrandQT() [4]byte { return [4]byte{'q', 't', ' ', ' '} } -func BrandISOM() [4]byte { return [4]byte{'i', 's', 'o', 'm'} } -func BrandISO2() [4]byte { return [4]byte{'i', 's', 'o', '2'} } -func BrandISO3() [4]byte { return [4]byte{'i', 's', 'o', '3'} } -func BrandISO4() [4]byte { return [4]byte{'i', 's', 'o', '4'} } -func BrandISO5() [4]byte { return [4]byte{'i', 's', 'o', '5'} } -func BrandISO6() [4]byte { return [4]byte{'i', 's', 'o', '6'} } -func BrandISO7() [4]byte { return [4]byte{'i', 's', 'o', '7'} } -func BrandISO8() [4]byte { return [4]byte{'i', 's', 'o', '8'} } -func BrandISO9() [4]byte { return [4]byte{'i', 's', 'o', '9'} } -func BrandAVC1() [4]byte { return [4]byte{'a', 'v', 'c', '1'} } -func BrandMP41() [4]byte { return [4]byte{'m', 'p', '4', '1'} } -func BrandMP71() [4]byte { return [4]byte{'m', 'p', '7', '1'} } - -// Ftyp is ISOBMFF ftyp box type -type Ftyp struct { - Box - MajorBrand [4]byte `mp4:"0,size=8,string"` - MinorVersion uint32 `mp4:"1,size=32"` - CompatibleBrands []CompatibleBrandElem `mp4:"2,size=32"` // reach to end of the box -} - -type CompatibleBrandElem struct { - CompatibleBrand [4]byte `mp4:"0,size=8,string"` -} - -func (ftyp *Ftyp) AddCompatibleBrand(cb [4]byte) { - if !ftyp.HasCompatibleBrand(cb) { - ftyp.CompatibleBrands = append(ftyp.CompatibleBrands, CompatibleBrandElem{ - CompatibleBrand: cb, - }) - } -} - -func (ftyp *Ftyp) RemoveCompatibleBrand(cb [4]byte) { - for i := 0; i < len(ftyp.CompatibleBrands); { - if ftyp.CompatibleBrands[i].CompatibleBrand != cb { - i++ - continue - } - ftyp.CompatibleBrands[i] = ftyp.CompatibleBrands[len(ftyp.CompatibleBrands)-1] - ftyp.CompatibleBrands = ftyp.CompatibleBrands[:len(ftyp.CompatibleBrands)-1] - } -} - -func (ftyp *Ftyp) HasCompatibleBrand(cb [4]byte) bool { - for i := range ftyp.CompatibleBrands { - if ftyp.CompatibleBrands[i].CompatibleBrand == cb { - return true - } - } - return false -} - -// GetType returns the BoxType -func (*Ftyp) GetType() BoxType { - return BoxTypeFtyp() -} - -/*************************** hdlr ****************************/ - -func BoxTypeHdlr() BoxType { return StrToBoxType("hdlr") } - -func init() { - AddBoxDef(&Hdlr{}, 0) -} - -// Hdlr is ISOBMFF hdlr box type -type Hdlr struct { - FullBox `mp4:"0,extend"` - // Predefined corresponds to component_type of QuickTime. - // pre_defined of ISO-14496 has always zero, - // however component_type has "mhlr" or "dhlr". - PreDefined uint32 `mp4:"1,size=32"` - HandlerType [4]byte `mp4:"2,size=8,string"` - Reserved [3]uint32 `mp4:"3,size=32,const=0"` - Name string `mp4:"4,string"` -} - -// GetType returns the BoxType -func (*Hdlr) GetType() BoxType { - return BoxTypeHdlr() -} - -func (hdlr *Hdlr) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { - switch name { - case "Name": - return hdlr.OnReadName(r, leftBits, ctx) - default: - return 0, false, nil - } -} - -func (hdlr *Hdlr) OnReadName(r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { - size := leftBits / 8 - if size == 0 { - hdlr.Name = "" - return 0, true, nil - } - - buf := make([]byte, size) - if _, err := io.ReadFull(r, buf); err != nil { - return 0, false, err - } - - plen := buf[0] - if hdlr.PreDefined != 0 && size >= 2 && size == uint64(plen+1) { - // Pascal-style String - hdlr.Name = string(buf[1 : plen+1]) - } else { - // C-style String - clen := 0 - for _, c := range buf { - if c == 0x00 { - break - } - clen++ - } - hdlr.Name = string(buf[:clen]) - } - return leftBits, true, nil -} - -/*************************** hvcC ****************************/ - -func BoxTypeHvcC() BoxType { return StrToBoxType("hvcC") } - -func init() { - AddBoxDef(&HvcC{}) -} - -type HEVCNalu struct { - BaseCustomFieldObject - Length uint16 `mp4:"0,size=16"` - NALUnit []byte `mp4:"1,size=8,len=dynamic"` -} - -func (s HEVCNalu) GetFieldLength(name string, ctx Context) uint { - switch name { - case "NALUnit": - return uint(s.Length) - } - return 0 -} - -type HEVCNaluArray struct { - BaseCustomFieldObject - Completeness bool `mp4:"0,size=1"` - Reserved bool `mp4:"1,size=1"` - NaluType uint8 `mp4:"2,size=6"` - NumNalus uint16 `mp4:"3,size=16"` - Nalus []HEVCNalu `mp4:"4,len=dynamic"` -} - -func (a HEVCNaluArray) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Nalus": - return uint(a.NumNalus) - } - return 0 -} - -type HvcC struct { - Box - ConfigurationVersion uint8 `mp4:"0,size=8"` - GeneralProfileSpace uint8 `mp4:"1,size=2"` - GeneralTierFlag bool `mp4:"2,size=1"` - GeneralProfileIdc uint8 `mp4:"3,size=5"` - GeneralProfileCompatibility [32]bool `mp4:"4,size=1"` - GeneralConstraintIndicator [6]uint8 `mp4:"5,size=8"` - GeneralLevelIdc uint8 `mp4:"6,size=8"` - Reserved1 uint8 `mp4:"7,size=4,const=15"` - MinSpatialSegmentationIdc uint16 `mp4:"8,size=12"` - Reserved2 uint8 `mp4:"9,size=6,const=63"` - ParallelismType uint8 `mp4:"10,size=2"` - Reserved3 uint8 `mp4:"11,size=6,const=63"` - ChromaFormatIdc uint8 `mp4:"12,size=2"` - Reserved4 uint8 `mp4:"13,size=5,const=31"` - BitDepthLumaMinus8 uint8 `mp4:"14,size=3"` - Reserved5 uint8 `mp4:"15,size=5,const=31"` - BitDepthChromaMinus8 uint8 `mp4:"16,size=3"` - AvgFrameRate uint16 `mp4:"17,size=16"` - ConstantFrameRate uint8 `mp4:"18,size=2"` - NumTemporalLayers uint8 `mp4:"19,size=2"` - TemporalIdNested uint8 `mp4:"20,size=2"` - LengthSizeMinusOne uint8 `mp4:"21,size=2"` - NumOfNaluArrays uint8 `mp4:"22,size=8"` - NaluArrays []HEVCNaluArray `mp4:"23,len=dynamic"` -} - -func (HvcC) GetType() BoxType { - return BoxTypeHvcC() -} - -func (hvcc HvcC) GetFieldLength(name string, ctx Context) uint { - switch name { - case "NaluArrays": - return uint(hvcc.NumOfNaluArrays) - } - return 0 -} - -/*************************** ilst ****************************/ - -func BoxTypeIlst() BoxType { return StrToBoxType("ilst") } -func BoxTypeData() BoxType { return StrToBoxType("data") } - -var ilstMetaBoxTypes = []BoxType{ - StrToBoxType("----"), - StrToBoxType("aART"), - StrToBoxType("akID"), - StrToBoxType("apID"), - StrToBoxType("atID"), - StrToBoxType("cmID"), - StrToBoxType("cnID"), - StrToBoxType("covr"), - StrToBoxType("cpil"), - StrToBoxType("cprt"), - StrToBoxType("desc"), - StrToBoxType("disk"), - StrToBoxType("egid"), - StrToBoxType("geID"), - StrToBoxType("gnre"), - StrToBoxType("pcst"), - StrToBoxType("pgap"), - StrToBoxType("plID"), - StrToBoxType("purd"), - StrToBoxType("purl"), - StrToBoxType("rtng"), - StrToBoxType("sfID"), - StrToBoxType("soaa"), - StrToBoxType("soal"), - StrToBoxType("soar"), - StrToBoxType("soco"), - StrToBoxType("sonm"), - StrToBoxType("sosn"), - StrToBoxType("stik"), - StrToBoxType("tmpo"), - StrToBoxType("trkn"), - StrToBoxType("tven"), - StrToBoxType("tves"), - StrToBoxType("tvnn"), - StrToBoxType("tvsh"), - StrToBoxType("tvsn"), - {0xA9, 'A', 'R', 'T'}, - {0xA9, 'a', 'l', 'b'}, - {0xA9, 'c', 'm', 't'}, - {0xA9, 'c', 'o', 'm'}, - {0xA9, 'd', 'a', 'y'}, - {0xA9, 'g', 'e', 'n'}, - {0xA9, 'g', 'r', 'p'}, - {0xA9, 'n', 'a', 'm'}, - {0xA9, 't', 'o', 'o'}, - {0xA9, 'w', 'r', 't'}, -} - -func IsIlstMetaBoxType(boxType BoxType) bool { - for _, bt := range ilstMetaBoxTypes { - if boxType == bt { - return true - } - } - return false -} - -func init() { - AddBoxDef(&Ilst{}) - AddBoxDefEx(&Data{}, isUnderIlstMeta) - for _, bt := range ilstMetaBoxTypes { - AddAnyTypeBoxDefEx(&IlstMetaContainer{}, bt, isIlstMetaContainer) - } - AddAnyTypeBoxDefEx(&StringData{}, StrToBoxType("mean"), isUnderIlstFreeFormat) - AddAnyTypeBoxDefEx(&StringData{}, StrToBoxType("name"), isUnderIlstFreeFormat) -} - -type Ilst struct { - Box -} - -// GetType returns the BoxType -func (*Ilst) GetType() BoxType { - return BoxTypeIlst() -} - -type IlstMetaContainer struct { - AnyTypeBox -} - -func isIlstMetaContainer(ctx Context) bool { - return ctx.UnderIlst && !ctx.UnderIlstMeta -} - -const ( - DataTypeBinary = 0 - DataTypeStringUTF8 = 1 - DataTypeStringUTF16 = 2 - DataTypeStringMac = 3 - DataTypeStringJPEG = 14 - DataTypeSignedIntBigEndian = 21 - DataTypeFloat32BigEndian = 22 - DataTypeFloat64BigEndian = 23 -) - -type Data struct { - Box - DataType uint32 `mp4:"0,size=32"` - DataLang uint32 `mp4:"1,size=32"` - Data []byte `mp4:"2,size=8"` -} - -// GetType returns the BoxType -func (*Data) GetType() BoxType { - return BoxTypeData() -} - -func isUnderIlstMeta(ctx Context) bool { - return ctx.UnderIlstMeta -} - -// StringifyField returns field value as string -func (data *Data) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "DataType": - switch data.DataType { - case DataTypeBinary: - return "BINARY", true - case DataTypeStringUTF8: - return "UTF8", true - case DataTypeStringUTF16: - return "UTF16", true - case DataTypeStringMac: - return "MAC_STR", true - case DataTypeStringJPEG: - return "JPEG", true - case DataTypeSignedIntBigEndian: - return "INT", true - case DataTypeFloat32BigEndian: - return "FLOAT32", true - case DataTypeFloat64BigEndian: - return "FLOAT64", true - } - case "Data": - switch data.DataType { - case DataTypeStringUTF8: - return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(data.Data))), true - } - } - return "", false -} - -type StringData struct { - AnyTypeBox - Data []byte `mp4:"0,size=8"` -} - -// StringifyField returns field value as string -func (sd *StringData) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - if name == "Data" { - return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(sd.Data))), true - } - return "", false -} - -func isUnderIlstFreeFormat(ctx Context) bool { - return ctx.UnderIlstFreeMeta -} - -/*************************** mdat ****************************/ - -func BoxTypeMdat() BoxType { return StrToBoxType("mdat") } - -func init() { - AddBoxDef(&Mdat{}) -} - -// Mdat is ISOBMFF mdat box type -type Mdat struct { - Box - Data []byte `mp4:"0,size=8"` -} - -// GetType returns the BoxType -func (*Mdat) GetType() BoxType { - return BoxTypeMdat() -} - -/*************************** mdhd ****************************/ - -func BoxTypeMdhd() BoxType { return StrToBoxType("mdhd") } - -func init() { - AddBoxDef(&Mdhd{}, 0, 1) -} - -// Mdhd is ISOBMFF mdhd box type -type Mdhd struct { - FullBox `mp4:"0,extend"` - CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` - ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` - CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` - ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` - Timescale uint32 `mp4:"5,size=32"` - DurationV0 uint32 `mp4:"6,size=32,ver=0"` - DurationV1 uint64 `mp4:"7,size=64,ver=1"` - // - Pad bool `mp4:"8,size=1,hidden"` - Language [3]byte `mp4:"9,size=5,iso639-2"` // ISO-639-2/T language code - PreDefined uint16 `mp4:"10,size=16"` -} - -// GetType returns the BoxType -func (*Mdhd) GetType() BoxType { - return BoxTypeMdhd() -} - -func (mdhd *Mdhd) GetCreationTime() uint64 { - switch mdhd.GetVersion() { - case 0: - return uint64(mdhd.CreationTimeV0) - case 1: - return mdhd.CreationTimeV1 - default: - return 0 - } -} - -func (mdhd *Mdhd) GetModificationTime() uint64 { - switch mdhd.GetVersion() { - case 0: - return uint64(mdhd.ModificationTimeV0) - case 1: - return mdhd.ModificationTimeV1 - default: - return 0 - } -} - -func (mdhd *Mdhd) GetDuration() uint64 { - switch mdhd.GetVersion() { - case 0: - return uint64(mdhd.DurationV0) - case 1: - return mdhd.DurationV1 - default: - return 0 - } -} - -/*************************** mdia ****************************/ - -func BoxTypeMdia() BoxType { return StrToBoxType("mdia") } - -func init() { - AddBoxDef(&Mdia{}) -} - -// Mdia is ISOBMFF mdia box type -type Mdia struct { - Box -} - -// GetType returns the BoxType -func (*Mdia) GetType() BoxType { - return BoxTypeMdia() -} - -/*************************** mehd ****************************/ - -func BoxTypeMehd() BoxType { return StrToBoxType("mehd") } - -func init() { - AddBoxDef(&Mehd{}, 0, 1) -} - -// Mehd is ISOBMFF mehd box type -type Mehd struct { - FullBox `mp4:"0,extend"` - FragmentDurationV0 uint32 `mp4:"1,size=32,ver=0"` - FragmentDurationV1 uint64 `mp4:"2,size=64,ver=1"` -} - -// GetType returns the BoxType -func (*Mehd) GetType() BoxType { - return BoxTypeMehd() -} - -func (mdhd *Mehd) GetFragmentDuration() uint64 { - switch mdhd.GetVersion() { - case 0: - return uint64(mdhd.FragmentDurationV0) - case 1: - return mdhd.FragmentDurationV1 - default: - return 0 - } -} - -/*************************** meta ****************************/ - -func BoxTypeMeta() BoxType { return StrToBoxType("meta") } - -func init() { - AddBoxDef(&Meta{}, 0) -} - -// Meta is ISOBMFF meta box type -type Meta struct { - FullBox `mp4:"0,extend"` -} - -// GetType returns the BoxType -func (*Meta) GetType() BoxType { - return BoxTypeMeta() -} - -func (meta *Meta) BeforeUnmarshal(r io.ReadSeeker, size uint64, ctx Context) (n uint64, override bool, err error) { - // for Apple Quick Time - buf := make([]byte, 4) - if _, err := io.ReadFull(r, buf); err != nil { - return 0, false, err - } - if _, err := r.Seek(-int64(len(buf)), io.SeekCurrent); err != nil { - return 0, false, err - } - if buf[0]|buf[1]|buf[2]|buf[3] != 0x00 { - meta.Version = 0 - meta.Flags = [3]byte{0, 0, 0} - return 0, true, nil - } - return 0, false, nil -} - -/*************************** mfhd ****************************/ - -func BoxTypeMfhd() BoxType { return StrToBoxType("mfhd") } - -func init() { - AddBoxDef(&Mfhd{}, 0) -} - -// Mfhd is ISOBMFF mfhd box type -type Mfhd struct { - FullBox `mp4:"0,extend"` - SequenceNumber uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Mfhd) GetType() BoxType { - return BoxTypeMfhd() -} - -/*************************** mfra ****************************/ - -func BoxTypeMfra() BoxType { return StrToBoxType("mfra") } - -func init() { - AddBoxDef(&Mfra{}) -} - -// Mfra is ISOBMFF mfra box type -type Mfra struct { - Box -} - -// GetType returns the BoxType -func (*Mfra) GetType() BoxType { - return BoxTypeMfra() -} - -/*************************** mfro ****************************/ - -func BoxTypeMfro() BoxType { return StrToBoxType("mfro") } - -func init() { - AddBoxDef(&Mfro{}, 0) -} - -// Mfro is ISOBMFF mfro box type -type Mfro struct { - FullBox `mp4:"0,extend"` - Size uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Mfro) GetType() BoxType { - return BoxTypeMfro() -} - -/*************************** minf ****************************/ - -func BoxTypeMinf() BoxType { return StrToBoxType("minf") } - -func init() { - AddBoxDef(&Minf{}) -} - -// Minf is ISOBMFF minf box type -type Minf struct { - Box -} - -// GetType returns the BoxType -func (*Minf) GetType() BoxType { - return BoxTypeMinf() -} - -/*************************** moof ****************************/ - -func BoxTypeMoof() BoxType { return StrToBoxType("moof") } - -func init() { - AddBoxDef(&Moof{}) -} - -// Moof is ISOBMFF moof box type -type Moof struct { - Box -} - -// GetType returns the BoxType -func (*Moof) GetType() BoxType { - return BoxTypeMoof() -} - -/*************************** moov ****************************/ - -func BoxTypeMoov() BoxType { return StrToBoxType("moov") } - -func init() { - AddBoxDef(&Moov{}) -} - -// Moov is ISOBMFF moov box type -type Moov struct { - Box -} - -// GetType returns the BoxType -func (*Moov) GetType() BoxType { - return BoxTypeMoov() -} - -/*************************** mvex ****************************/ - -func BoxTypeMvex() BoxType { return StrToBoxType("mvex") } - -func init() { - AddBoxDef(&Mvex{}) -} - -// Mvex is ISOBMFF mvex box type -type Mvex struct { - Box -} - -// GetType returns the BoxType -func (*Mvex) GetType() BoxType { - return BoxTypeMvex() -} - -/*************************** mvhd ****************************/ - -func BoxTypeMvhd() BoxType { return StrToBoxType("mvhd") } - -func init() { - AddBoxDef(&Mvhd{}, 0, 1) -} - -// Mvhd is ISOBMFF mvhd box type -type Mvhd struct { - FullBox `mp4:"0,extend"` - CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` - ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` - CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` - ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` - Timescale uint32 `mp4:"5,size=32"` - DurationV0 uint32 `mp4:"6,size=32,ver=0"` - DurationV1 uint64 `mp4:"7,size=64,ver=1"` - Rate int32 `mp4:"8,size=32"` // fixed-point 16.16 - template=0x00010000 - Volume int16 `mp4:"9,size=16"` // template=0x0100 - Reserved int16 `mp4:"10,size=16,const=0"` - Reserved2 [2]uint32 `mp4:"11,size=32,const=0"` - Matrix [9]int32 `mp4:"12,size=32,hex"` // template={ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } - PreDefined [6]int32 `mp4:"13,size=32"` - NextTrackID uint32 `mp4:"14,size=32"` -} - -// GetType returns the BoxType -func (*Mvhd) GetType() BoxType { - return BoxTypeMvhd() -} - -// StringifyField returns field value as string -func (mvhd *Mvhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "Rate": - return util.FormatSignedFixedFloat1616(mvhd.Rate), true - default: - return "", false - } -} - -func (mvhd *Mvhd) GetCreationTime() uint64 { - switch mvhd.GetVersion() { - case 0: - return uint64(mvhd.CreationTimeV0) - case 1: - return mvhd.CreationTimeV1 - default: - return 0 - } -} - -func (mvhd *Mvhd) GetModificationTime() uint64 { - switch mvhd.GetVersion() { - case 0: - return uint64(mvhd.ModificationTimeV0) - case 1: - return mvhd.ModificationTimeV1 - default: - return 0 - } -} - -func (mvhd *Mvhd) GetDuration() uint64 { - switch mvhd.GetVersion() { - case 0: - return uint64(mvhd.DurationV0) - case 1: - return mvhd.DurationV1 - default: - return 0 - } -} - -// GetRate returns value of rate as float64 -func (mvhd *Mvhd) GetRate() float64 { - return float64(mvhd.Rate) / (1 << 16) -} - -// GetRateInt returns value of rate as int16 -func (mvhd *Mvhd) GetRateInt() int16 { - return int16(mvhd.Rate >> 16) -} - -/*************************** pssh ****************************/ - -func BoxTypePssh() BoxType { return StrToBoxType("pssh") } - -func init() { - AddBoxDef(&Pssh{}, 0, 1) -} - -// Pssh is ISOBMFF pssh box type -type Pssh struct { - FullBox `mp4:"0,extend"` - SystemID [16]byte `mp4:"1,size=8,uuid"` - KIDCount uint32 `mp4:"2,size=32,nver=0"` - KIDs []PsshKID `mp4:"3,nver=0,len=dynamic,size=128"` - DataSize int32 `mp4:"4,size=32"` - Data []byte `mp4:"5,size=8,len=dynamic"` -} - -type PsshKID struct { - KID [16]byte `mp4:"0,size=8,uuid"` -} - -// GetFieldLength returns length of dynamic field -func (pssh *Pssh) GetFieldLength(name string, ctx Context) uint { - switch name { - case "KIDs": - return uint(pssh.KIDCount) - case "Data": - return uint(pssh.DataSize) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=pssh fieldName=%s", name)) -} - -// StringifyField returns field value as string -func (pssh *Pssh) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "KIDs": - buf := bytes.NewBuffer(nil) - buf.WriteString("[") - for i, e := range pssh.KIDs { - if i != 0 { - buf.WriteString(", ") - } - buf.WriteString(uuid.UUID(e.KID).String()) - } - buf.WriteString("]") - return buf.String(), true - - default: - return "", false - } -} - -// GetType returns the BoxType -func (*Pssh) GetType() BoxType { - return BoxTypePssh() -} - -/*************************** saio ****************************/ - -func BoxTypeSaio() BoxType { return StrToBoxType("saio") } - -func init() { - AddBoxDef(&Saio{}, 0, 1) -} - -type Saio struct { - FullBox `mp4:"0,extend"` - AuxInfoType [4]byte `mp4:"1,size=8,opt=0x000001,string"` - AuxInfoTypeParameter uint32 `mp4:"2,size=32,opt=0x000001,hex"` - EntryCount uint32 `mp4:"3,size=32"` - OffsetV0 []uint32 `mp4:"4,size=32,ver=0,len=dynamic"` - OffsetV1 []uint64 `mp4:"5,size=64,nver=0,len=dynamic"` -} - -func (saio *Saio) GetFieldLength(name string, ctx Context) uint { - switch name { - case "OffsetV0", "OffsetV1": - return uint(saio.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=saio fieldName=%s", name)) -} - -func (*Saio) GetType() BoxType { - return BoxTypeSaio() -} - -func (saio *Saio) GetOffset(index int) uint64 { - switch saio.GetVersion() { - case 0: - return uint64(saio.OffsetV0[index]) - case 1: - return saio.OffsetV1[index] - default: - return 0 - } -} - -/*************************** saiz ****************************/ - -func BoxTypeSaiz() BoxType { return StrToBoxType("saiz") } - -func init() { - AddBoxDef(&Saiz{}, 0) -} - -type Saiz struct { - FullBox `mp4:"0,extend"` - AuxInfoType [4]byte `mp4:"1,size=8,opt=0x000001,string"` - AuxInfoTypeParameter uint32 `mp4:"2,size=32,opt=0x000001,hex"` - DefaultSampleInfoSize uint8 `mp4:"3,size=8,dec"` - SampleCount uint32 `mp4:"4,size=32"` - SampleInfoSize []uint8 `mp4:"5,size=8,opt=dynamic,len=dynamic,dec"` -} - -func (saiz *Saiz) IsOptFieldEnabled(name string, ctx Context) bool { - switch name { - case "SampleInfoSize": - return saiz.DefaultSampleInfoSize == 0 - } - return false -} - -func (saiz *Saiz) GetFieldLength(name string, ctx Context) uint { - switch name { - case "SampleInfoSize": - return uint(saiz.SampleCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=saiz fieldName=%s", name)) -} - -func (*Saiz) GetType() BoxType { - return BoxTypeSaiz() -} - -/*********************** SampleEntry *************************/ - -func BoxTypeAvc1() BoxType { return StrToBoxType("avc1") } -func BoxTypeEncv() BoxType { return StrToBoxType("encv") } -func BoxTypeHev1() BoxType { return StrToBoxType("hev1") } -func BoxTypeHvc1() BoxType { return StrToBoxType("hvc1") } -func BoxTypeMp4a() BoxType { return StrToBoxType("mp4a") } -func BoxTypeEnca() BoxType { return StrToBoxType("enca") } -func BoxTypeAvcC() BoxType { return StrToBoxType("avcC") } -func BoxTypePasp() BoxType { return StrToBoxType("pasp") } - -func init() { - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeAvc1()) - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeEncv()) - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeHev1()) - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeHvc1()) - AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeMp4a()) - AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeEnca()) - AddAnyTypeBoxDef(&AVCDecoderConfiguration{}, BoxTypeAvcC()) - AddAnyTypeBoxDef(&PixelAspectRatioBox{}, BoxTypePasp()) -} - -type SampleEntry struct { - AnyTypeBox - Reserved [6]uint8 `mp4:"0,size=8,const=0"` - DataReferenceIndex uint16 `mp4:"1,size=16"` -} - -type VisualSampleEntry struct { - SampleEntry `mp4:"0,extend"` - PreDefined uint16 `mp4:"1,size=16"` - Reserved uint16 `mp4:"2,size=16,const=0"` - PreDefined2 [3]uint32 `mp4:"3,size=32"` - Width uint16 `mp4:"4,size=16"` - Height uint16 `mp4:"5,size=16"` - Horizresolution uint32 `mp4:"6,size=32"` - Vertresolution uint32 `mp4:"7,size=32"` - Reserved2 uint32 `mp4:"8,size=32,const=0"` - FrameCount uint16 `mp4:"9,size=16"` - Compressorname [32]byte `mp4:"10,size=8"` - Depth uint16 `mp4:"11,size=16"` - PreDefined3 int16 `mp4:"12,size=16"` -} - -// StringifyField returns field value as string -func (vse *VisualSampleEntry) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "Compressorname": - if vse.Compressorname[0] <= 31 { - return `"` + util.EscapeUnprintables(string(vse.Compressorname[1:vse.Compressorname[0]+1])) + `"`, true - } - return "", false - default: - return "", false - } -} - -type AudioSampleEntry struct { - SampleEntry `mp4:"0,extend,opt=dynamic"` - EntryVersion uint16 `mp4:"1,size=16,opt=dynamic"` - Reserved [3]uint16 `mp4:"2,size=16,opt=dynamic,const=0"` - ChannelCount uint16 `mp4:"3,size=16,opt=dynamic"` - SampleSize uint16 `mp4:"4,size=16,opt=dynamic"` - PreDefined uint16 `mp4:"5,size=16,opt=dynamic"` - Reserved2 uint16 `mp4:"6,size=16,opt=dynamic,const=0"` - SampleRate uint32 `mp4:"7,size=32,opt=dynamic"` - QuickTimeData []byte `mp4:"8,size=8,opt=dynamic,len=dynamic"` -} - -func (ase *AudioSampleEntry) IsOptFieldEnabled(name string, ctx Context) bool { - if name == "QuickTimeData" { - return ctx.IsQuickTimeCompatible && (ctx.UnderWave || ase.EntryVersion == 1 || ase.EntryVersion == 2) - } - if ctx.IsQuickTimeCompatible && ctx.UnderWave { - return false - } - return true -} - -func (ase *AudioSampleEntry) GetFieldLength(name string, ctx Context) uint { - if name == "QuickTimeData" && ctx.IsQuickTimeCompatible { - if ctx.UnderWave { - return LengthUnlimited - } else if ase.EntryVersion == 1 { - return 16 - } else if ase.EntryVersion == 2 { - return 36 - } - } - return 0 -} - -const ( - AVCBaselineProfile uint8 = 66 // 0x42 - AVCMainProfile uint8 = 77 // 0x4d - AVCExtendedProfile uint8 = 88 // 0x58 - AVCHighProfile uint8 = 100 // 0x64 - AVCHigh10Profile uint8 = 110 // 0x6e - AVCHigh422Profile uint8 = 122 // 0x7a -) - -type AVCDecoderConfiguration struct { - AnyTypeBox - ConfigurationVersion uint8 `mp4:"0,size=8"` - Profile uint8 `mp4:"1,size=8"` - ProfileCompatibility uint8 `mp4:"2,size=8"` - Level uint8 `mp4:"3,size=8"` - Reserved uint8 `mp4:"4,size=6,const=63"` - LengthSizeMinusOne uint8 `mp4:"5,size=2"` - Reserved2 uint8 `mp4:"6,size=3,const=7"` - NumOfSequenceParameterSets uint8 `mp4:"7,size=5"` - SequenceParameterSets []AVCParameterSet `mp4:"8,len=dynamic"` - NumOfPictureParameterSets uint8 `mp4:"9,size=8"` - PictureParameterSets []AVCParameterSet `mp4:"10,len=dynamic"` - HighProfileFieldsEnabled bool `mp4:"11,hidden"` - Reserved3 uint8 `mp4:"12,size=6,opt=dynamic,const=63"` - ChromaFormat uint8 `mp4:"13,size=2,opt=dynamic"` - Reserved4 uint8 `mp4:"14,size=5,opt=dynamic,const=31"` - BitDepthLumaMinus8 uint8 `mp4:"15,size=3,opt=dynamic"` - Reserved5 uint8 `mp4:"16,size=5,opt=dynamic,const=31"` - BitDepthChromaMinus8 uint8 `mp4:"17,size=3,opt=dynamic"` - NumOfSequenceParameterSetExt uint8 `mp4:"18,size=8,opt=dynamic"` - SequenceParameterSetsExt []AVCParameterSet `mp4:"19,len=dynamic,opt=dynamic"` -} - -func (avcc *AVCDecoderConfiguration) GetFieldLength(name string, ctx Context) uint { - switch name { - case "SequenceParameterSets": - return uint(avcc.NumOfSequenceParameterSets) - case "PictureParameterSets": - return uint(avcc.NumOfPictureParameterSets) - case "SequenceParameterSetsExt": - return uint(avcc.NumOfSequenceParameterSetExt) - } - return 0 -} - -func (avcc *AVCDecoderConfiguration) IsOptFieldEnabled(name string, ctx Context) bool { - switch name { - case "Reserved3", - "ChromaFormat", - "Reserved4", - "BitDepthLumaMinus8", - "Reserved5", - "BitDepthChromaMinus8", - "NumOfSequenceParameterSetExt", - "SequenceParameterSetsExt": - return avcc.HighProfileFieldsEnabled - } - return false -} - -func (avcc *AVCDecoderConfiguration) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { - if name == "HighProfileFieldsEnabled" { - avcc.HighProfileFieldsEnabled = leftBits >= 32 && - (avcc.Profile == AVCHighProfile || - avcc.Profile == AVCHigh10Profile || - avcc.Profile == AVCHigh422Profile || - avcc.Profile == 144) - return 0, true, nil - } - return 0, false, nil -} - -func (avcc *AVCDecoderConfiguration) OnWriteField(name string, w bitio.Writer, ctx Context) (wbits uint64, override bool, err error) { - if name == "HighProfileFieldsEnabled" { - if avcc.HighProfileFieldsEnabled && - avcc.Profile != AVCHighProfile && - avcc.Profile != AVCHigh10Profile && - avcc.Profile != AVCHigh422Profile && - avcc.Profile != 144 { - return 0, false, errors.New("each values of Profile and HighProfileFieldsEnabled are inconsistent") - } - return 0, true, nil - } - return 0, false, nil -} - -type AVCParameterSet struct { - BaseCustomFieldObject - Length uint16 `mp4:"0,size=16"` - NALUnit []byte `mp4:"1,size=8,len=dynamic"` -} - -func (s *AVCParameterSet) GetFieldLength(name string, ctx Context) uint { - switch name { - case "NALUnit": - return uint(s.Length) - } - return 0 -} - -type PixelAspectRatioBox struct { - AnyTypeBox - HSpacing uint32 `mp4:"0,size=32"` - VSpacing uint32 `mp4:"1,size=32"` -} - -/*************************** sbgp ****************************/ - -func BoxTypeSbgp() BoxType { return StrToBoxType("sbgp") } - -func init() { - AddBoxDef(&Sbgp{}, 0, 1) -} - -type Sbgp struct { - FullBox `mp4:"0,extend"` - GroupingType uint32 `mp4:"1,size=32"` - GroupingTypeParameter uint32 `mp4:"2,size=32,ver=1"` - EntryCount uint32 `mp4:"3,size=32"` - Entries []SbgpEntry `mp4:"4,len=dynamic,size=64"` -} - -type SbgpEntry struct { - SampleCount uint32 `mp4:"0,size=32"` - GroupDescriptionIndex uint32 `mp4:"1,size=32"` -} - -func (sbgp *Sbgp) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(sbgp.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=sbgp fieldName=%s", name)) -} - -func (*Sbgp) GetType() BoxType { - return BoxTypeSbgp() -} - -/*************************** schi ****************************/ - -func BoxTypeSchi() BoxType { return StrToBoxType("schi") } - -func init() { - AddBoxDef(&Schi{}) -} - -type Schi struct { - Box -} - -func (*Schi) GetType() BoxType { - return BoxTypeSchi() -} - -/*************************** schm ****************************/ - -func BoxTypeSchm() BoxType { return StrToBoxType("schm") } - -func init() { - AddBoxDef(&Schm{}, 0) -} - -type Schm struct { - FullBox `mp4:"0,extend"` - SchemeType [4]byte `mp4:"1,size=8,string"` - SchemeVersion uint32 `mp4:"2,size=32,hex"` - SchemeUri []byte `mp4:"3,size=8,opt=0x000001,string"` -} - -func (*Schm) GetType() BoxType { - return BoxTypeSchm() -} - -/*************************** sdtp ****************************/ - -func BoxTypeSdtp() BoxType { return StrToBoxType("sdtp") } - -func init() { - AddBoxDef(&Sdtp{}, 0) -} - -type Sdtp struct { - FullBox `mp4:"0,extend"` - Samples []SdtpSampleElem `mp4:"1,size=8"` -} - -type SdtpSampleElem struct { - IsLeading uint8 `mp4:"0,size=2"` - SampleDependsOn uint8 `mp4:"1,size=2"` - SampleIsDependedOn uint8 `mp4:"2,size=2"` - SampleHasRedundancy uint8 `mp4:"3,size=2"` -} - -func (*Sdtp) GetType() BoxType { - return BoxTypeSdtp() -} - -/*************************** sgpd ****************************/ - -func BoxTypeSgpd() BoxType { return StrToBoxType("sgpd") } - -func init() { - AddBoxDef(&Sgpd{}, 1, 2) // version 0 is deprecated by ISO/IEC 14496-12 -} - -type Sgpd struct { - FullBox `mp4:"0,extend"` - GroupingType [4]byte `mp4:"1,size=8,string"` - DefaultLength uint32 `mp4:"2,size=32,ver=1"` - DefaultSampleDescriptionIndex uint32 `mp4:"3,size=32,ver=2"` - EntryCount uint32 `mp4:"4,size=32"` - RollDistances []int16 `mp4:"5,size=16,opt=dynamic"` - RollDistancesL []RollDistanceWithLength `mp4:"6,size=16,opt=dynamic"` - AlternativeStartupEntries []AlternativeStartupEntry `mp4:"7,size=dynamic,len=dynamic,opt=dynamic"` - AlternativeStartupEntriesL []AlternativeStartupEntryL `mp4:"8,len=dynamic,opt=dynamic"` - VisualRandomAccessEntries []VisualRandomAccessEntry `mp4:"9,len=dynamic,opt=dynamic"` - VisualRandomAccessEntriesL []VisualRandomAccessEntryL `mp4:"10,len=dynamic,opt=dynamic"` - TemporalLevelEntries []TemporalLevelEntry `mp4:"11,len=dynamic,opt=dynamic"` - TemporalLevelEntriesL []TemporalLevelEntryL `mp4:"12,len=dynamic,opt=dynamic"` - Unsupported []byte `mp4:"13,size=8,opt=dynamic"` -} - -type RollDistanceWithLength struct { - DescriptionLength uint32 `mp4:"0,size=32"` - RollDistance int16 `mp4:"1,size=16"` -} - -type AlternativeStartupEntry struct { - BaseCustomFieldObject - RollCount uint16 `mp4:"0,size=16"` - FirstOutputSample uint16 `mp4:"1,size=16"` - SampleOffset []uint32 `mp4:"2,size=32,len=dynamic"` - Opts []AlternativeStartupEntryOpt `mp4:"3,size=32"` -} - -type AlternativeStartupEntryL struct { - DescriptionLength uint32 `mp4:"0,size=32"` - AlternativeStartupEntry `mp4:"1,extend,size=dynamic"` -} - -type AlternativeStartupEntryOpt struct { - NumOutputSamples uint16 `mp4:"0,size=16"` - NumTotalSamples uint16 `mp4:"1,size=16"` -} - -type VisualRandomAccessEntry struct { - NumLeadingSamplesKnown bool `mp4:"0,size=1"` - NumLeadingSamples uint8 `mp4:"1,size=7"` -} - -type VisualRandomAccessEntryL struct { - DescriptionLength uint32 `mp4:"0,size=32"` - VisualRandomAccessEntry `mp4:"1,extend"` -} - -type TemporalLevelEntry struct { - LevelIndependentlyDecodable bool `mp4:"0,size=1"` - Reserved uint8 `mp4:"1,size=7,const=0"` -} - -type TemporalLevelEntryL struct { - DescriptionLength uint32 `mp4:"0,size=32"` - TemporalLevelEntry `mp4:"1,extend"` -} - -func (sgpd *Sgpd) GetFieldSize(name string, ctx Context) uint { - switch name { - case "AlternativeStartupEntries": - return uint(sgpd.DefaultLength * 8) - } - return 0 -} - -func (sgpd *Sgpd) GetFieldLength(name string, ctx Context) uint { - switch name { - case "RollDistances", "RollDistancesL", - "AlternativeStartupEntries", "AlternativeStartupEntriesL", - "VisualRandomAccessEntries", "VisualRandomAccessEntriesL", - "TemporalLevelEntries", "TemporalLevelEntriesL": - return uint(sgpd.EntryCount) - } - return 0 -} - -func (sgpd *Sgpd) IsOptFieldEnabled(name string, ctx Context) bool { - noDefaultLength := sgpd.Version == 1 && sgpd.DefaultLength == 0 - rollDistances := sgpd.GroupingType == [4]byte{'r', 'o', 'l', 'l'} || - sgpd.GroupingType == [4]byte{'p', 'r', 'o', 'l'} - alternativeStartupEntries := sgpd.GroupingType == [4]byte{'a', 'l', 's', 't'} - visualRandomAccessEntries := sgpd.GroupingType == [4]byte{'r', 'a', 'p', ' '} - temporalLevelEntries := sgpd.GroupingType == [4]byte{'t', 'e', 'l', 'e'} - switch name { - case "RollDistances": - return rollDistances && !noDefaultLength - case "RollDistancesL": - return rollDistances && noDefaultLength - case "AlternativeStartupEntries": - return alternativeStartupEntries && !noDefaultLength - case "AlternativeStartupEntriesL": - return alternativeStartupEntries && noDefaultLength - case "VisualRandomAccessEntries": - return visualRandomAccessEntries && !noDefaultLength - case "VisualRandomAccessEntriesL": - return visualRandomAccessEntries && noDefaultLength - case "TemporalLevelEntries": - return temporalLevelEntries && !noDefaultLength - case "TemporalLevelEntriesL": - return temporalLevelEntries && noDefaultLength - case "Unsupported": - return !rollDistances && - !alternativeStartupEntries && - !visualRandomAccessEntries && - !temporalLevelEntries - default: - return false - } -} - -func (*Sgpd) GetType() BoxType { - return BoxTypeSgpd() -} - -func (entry *AlternativeStartupEntry) GetFieldLength(name string, ctx Context) uint { - switch name { - case "SampleOffset": - return uint(entry.RollCount) - } - return 0 -} - -func (entry *AlternativeStartupEntryL) GetFieldSize(name string, ctx Context) uint { - switch name { - case "AlternativeStartupEntry": - return uint(entry.DescriptionLength * 8) - } - return 0 -} - -/*************************** sidx ****************************/ - -func BoxTypeSidx() BoxType { return StrToBoxType("sidx") } - -func init() { - AddBoxDef(&Sidx{}, 0, 1) -} - -type Sidx struct { - FullBox `mp4:"0,extend"` - ReferenceID uint32 `mp4:"1,size=32"` - Timescale uint32 `mp4:"2,size=32"` - EarliestPresentationTimeV0 uint32 `mp4:"3,size=32,ver=0"` - FirstOffsetV0 uint32 `mp4:"4,size=32,ver=0"` - EarliestPresentationTimeV1 uint64 `mp4:"5,size=64,nver=0"` - FirstOffsetV1 uint64 `mp4:"6,size=64,nver=0"` - Reserved uint16 `mp4:"7,size=16,const=0"` - ReferenceCount uint16 `mp4:"8,size=16"` - References []SidxReference `mp4:"9,size=96,len=dynamic"` -} - -type SidxReference struct { - ReferenceType bool `mp4:"0,size=1"` - ReferencedSize uint32 `mp4:"1,size=31"` - SubsegmentDuration uint32 `mp4:"2,size=32"` - StartsWithSAP bool `mp4:"3,size=1"` - SAPType uint32 `mp4:"4,size=3"` - SAPDeltaTime uint32 `mp4:"5,size=28"` -} - -func (*Sidx) GetType() BoxType { - return BoxTypeSidx() -} - -func (sidx *Sidx) GetFieldLength(name string, ctx Context) uint { - switch name { - case "References": - return uint(sidx.ReferenceCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=sidx fieldName=%s", name)) -} - -func (sidx *Sidx) GetEarliestPresentationTime() uint64 { - switch sidx.GetVersion() { - case 0: - return uint64(sidx.EarliestPresentationTimeV0) - case 1: - return sidx.EarliestPresentationTimeV1 - default: - return 0 - } -} - -func (sidx *Sidx) GetFirstOffset() uint64 { - switch sidx.GetVersion() { - case 0: - return uint64(sidx.FirstOffsetV0) - case 1: - return sidx.FirstOffsetV1 - default: - return 0 - } -} - -/*************************** sinf ****************************/ - -func BoxTypeSinf() BoxType { return StrToBoxType("sinf") } - -func init() { - AddBoxDef(&Sinf{}) -} - -type Sinf struct { - Box -} - -func (*Sinf) GetType() BoxType { - return BoxTypeSinf() -} - -/*************************** smhd ****************************/ - -func BoxTypeSmhd() BoxType { return StrToBoxType("smhd") } - -func init() { - AddBoxDef(&Smhd{}, 0) -} - -type Smhd struct { - FullBox `mp4:"0,extend"` - Balance int16 `mp4:"1,size=16"` // fixed-point 8.8 template=0 - Reserved uint16 `mp4:"2,size=16,const=0"` -} - -func (*Smhd) GetType() BoxType { - return BoxTypeSmhd() -} - -// StringifyField returns field value as string -func (smhd *Smhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "Balance": - return util.FormatSignedFixedFloat88(smhd.Balance), true - default: - return "", false - } -} - -// GetBalance returns value of width as float32 -func (smhd *Smhd) GetBalance() float32 { - return float32(smhd.Balance) / (1 << 8) -} - -// GetBalanceInt returns value of width as int8 -func (smhd *Smhd) GetBalanceInt() int8 { - return int8(smhd.Balance >> 8) -} - -/*************************** stbl ****************************/ - -func BoxTypeStbl() BoxType { return StrToBoxType("stbl") } - -func init() { - AddBoxDef(&Stbl{}) -} - -// Stbl is ISOBMFF stbl box type -type Stbl struct { - Box -} - -// GetType returns the BoxType -func (*Stbl) GetType() BoxType { - return BoxTypeStbl() -} - -/*************************** stco ****************************/ - -func BoxTypeStco() BoxType { return StrToBoxType("stco") } - -func init() { - AddBoxDef(&Stco{}, 0) -} - -// Stco is ISOBMFF stco box type -type Stco struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - ChunkOffset []uint32 `mp4:"2,size=32,len=dynamic"` -} - -// GetType returns the BoxType -func (*Stco) GetType() BoxType { - return BoxTypeStco() -} - -// GetFieldLength returns length of dynamic field -func (stco *Stco) GetFieldLength(name string, ctx Context) uint { - switch name { - case "ChunkOffset": - return uint(stco.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stco fieldName=%s", name)) -} - -/*************************** stsc ****************************/ - -func BoxTypeStsc() BoxType { return StrToBoxType("stsc") } - -func init() { - AddBoxDef(&Stsc{}, 0) -} - -// Stsc is ISOBMFF stsc box type -type Stsc struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - Entries []StscEntry `mp4:"2,len=dynamic,size=96"` -} - -type StscEntry struct { - FirstChunk uint32 `mp4:"0,size=32"` - SamplesPerChunk uint32 `mp4:"1,size=32"` - SampleDescriptionIndex uint32 `mp4:"2,size=32"` -} - -// GetType returns the BoxType -func (*Stsc) GetType() BoxType { - return BoxTypeStsc() -} - -// GetFieldLength returns length of dynamic field -func (stsc *Stsc) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(stsc.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stsc fieldName=%s", name)) -} - -/*************************** stsd ****************************/ - -func BoxTypeStsd() BoxType { return StrToBoxType("stsd") } - -func init() { - AddBoxDef(&Stsd{}, 0) -} - -// Stsd is ISOBMFF stsd box type -type Stsd struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Stsd) GetType() BoxType { - return BoxTypeStsd() -} - -/*************************** stss ****************************/ - -func BoxTypeStss() BoxType { return StrToBoxType("stss") } - -func init() { - AddBoxDef(&Stss{}, 0) -} - -type Stss struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - SampleNumber []uint32 `mp4:"2,len=dynamic,size=32"` -} - -// GetType returns the BoxType -func (*Stss) GetType() BoxType { - return BoxTypeStss() -} - -// GetFieldLength returns length of dynamic field -func (stss *Stss) GetFieldLength(name string, ctx Context) uint { - switch name { - case "SampleNumber": - return uint(stss.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stss fieldName=%s", name)) -} - -/*************************** stsz ****************************/ - -func BoxTypeStsz() BoxType { return StrToBoxType("stsz") } - -func init() { - AddBoxDef(&Stsz{}, 0) -} - -// Stsz is ISOBMFF stsz box type -type Stsz struct { - FullBox `mp4:"0,extend"` - SampleSize uint32 `mp4:"1,size=32"` - SampleCount uint32 `mp4:"2,size=32"` - EntrySize []uint32 `mp4:"3,size=32,len=dynamic"` -} - -// GetType returns the BoxType -func (*Stsz) GetType() BoxType { - return BoxTypeStsz() -} - -// GetFieldLength returns length of dynamic field -func (stsz *Stsz) GetFieldLength(name string, ctx Context) uint { - switch name { - case "EntrySize": - if stsz.SampleSize == 0 { - return uint(stsz.SampleCount) - } - return 0 - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stsz fieldName=%s", name)) -} - -/*************************** stts ****************************/ - -func BoxTypeStts() BoxType { return StrToBoxType("stts") } - -func init() { - AddBoxDef(&Stts{}, 0) -} - -// Stts is ISOBMFF stts box type -type Stts struct { - FullBox `mp4:"0,extend"` - EntryCount uint32 `mp4:"1,size=32"` - Entries []SttsEntry `mp4:"2,len=dynamic,size=64"` -} - -type SttsEntry struct { - SampleCount uint32 `mp4:"0,size=32"` - SampleDelta uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Stts) GetType() BoxType { - return BoxTypeStts() -} - -// GetFieldLength returns length of dynamic field -func (stts *Stts) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(stts.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stts fieldName=%s", name)) -} - -/*************************** styp ****************************/ - -func BoxTypeStyp() BoxType { return StrToBoxType("styp") } - -func init() { - AddBoxDef(&Styp{}) -} - -type Styp struct { - Box - MajorBrand [4]byte `mp4:"0,size=8,string"` - MinorVersion uint32 `mp4:"1,size=32"` - CompatibleBrands []CompatibleBrandElem `mp4:"2,size=32"` // reach to end of the box -} - -func (*Styp) GetType() BoxType { - return BoxTypeStyp() -} - -/*************************** tenc ****************************/ - -func BoxTypeTenc() BoxType { return StrToBoxType("tenc") } - -func init() { - AddBoxDef(&Tenc{}, 0, 1) -} - -// Tenc is ISOBMFF tenc box type -type Tenc struct { - FullBox `mp4:"0,extend"` - Reserved uint8 `mp4:"1,size=8,dec"` - DefaultCryptByteBlock uint8 `mp4:"2,size=4,dec"` // always 0 on version 0 - DefaultSkipByteBlock uint8 `mp4:"3,size=4,dec"` // always 0 on version 0 - DefaultIsProtected uint8 `mp4:"4,size=8,dec"` - DefaultPerSampleIVSize uint8 `mp4:"5,size=8,dec"` - DefaultKID [16]byte `mp4:"6,size=8,uuid"` - DefaultConstantIVSize uint8 `mp4:"7,size=8,opt=dynamic,dec"` - DefaultConstantIV []byte `mp4:"8,size=8,opt=dynamic,len=dynamic"` -} - -func (tenc *Tenc) IsOptFieldEnabled(name string, ctx Context) bool { - switch name { - case "DefaultConstantIVSize", "DefaultConstantIV": - return tenc.DefaultIsProtected == 1 && tenc.DefaultPerSampleIVSize == 0 - } - return false -} - -func (tenc *Tenc) GetFieldLength(name string, ctx Context) uint { - switch name { - case "DefaultConstantIV": - return uint(tenc.DefaultConstantIVSize) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=tenc fieldName=%s", name)) -} - -// GetType returns the BoxType -func (*Tenc) GetType() BoxType { - return BoxTypeTenc() -} - -/*************************** tfdt ****************************/ - -func BoxTypeTfdt() BoxType { return StrToBoxType("tfdt") } - -func init() { - AddBoxDef(&Tfdt{}, 0, 1) -} - -// Tfdt is ISOBMFF tfdt box type -type Tfdt struct { - FullBox `mp4:"0,extend"` - BaseMediaDecodeTimeV0 uint32 `mp4:"1,size=32,ver=0"` - BaseMediaDecodeTimeV1 uint64 `mp4:"2,size=64,ver=1"` -} - -// GetType returns the BoxType -func (*Tfdt) GetType() BoxType { - return BoxTypeTfdt() -} - -func (tfdt *Tfdt) GetBaseMediaDecodeTime() uint64 { - switch tfdt.GetVersion() { - case 0: - return uint64(tfdt.BaseMediaDecodeTimeV0) - case 1: - return tfdt.BaseMediaDecodeTimeV1 - default: - return 0 - } -} - -/*************************** tfhd ****************************/ - -func BoxTypeTfhd() BoxType { return StrToBoxType("tfhd") } - -func init() { - AddBoxDef(&Tfhd{}, 0) -} - -// Tfhd is ISOBMFF tfhd box type -type Tfhd struct { - FullBox `mp4:"0,extend"` - TrackID uint32 `mp4:"1,size=32"` - - // optional - BaseDataOffset uint64 `mp4:"2,size=64,opt=0x000001"` - SampleDescriptionIndex uint32 `mp4:"3,size=32,opt=0x000002"` - DefaultSampleDuration uint32 `mp4:"4,size=32,opt=0x000008"` - DefaultSampleSize uint32 `mp4:"5,size=32,opt=0x000010"` - DefaultSampleFlags uint32 `mp4:"6,size=32,opt=0x000020,hex"` -} - -const ( - TfhdBaseDataOffsetPresent = 0x000001 - TfhdSampleDescriptionIndexPresent = 0x000002 - TfhdDefaultSampleDurationPresent = 0x000008 - TfhdDefaultSampleSizePresent = 0x000010 - TfhdDefaultSampleFlagsPresent = 0x000020 - TfhdDurationIsEmpty = 0x010000 - TfhdDefaultBaseIsMoof = 0x020000 -) - -// GetType returns the BoxType -func (*Tfhd) GetType() BoxType { - return BoxTypeTfhd() -} - -/*************************** tfra ****************************/ - -func BoxTypeTfra() BoxType { return StrToBoxType("tfra") } - -func init() { - AddBoxDef(&Tfra{}, 0, 1) -} - -// Tfra is ISOBMFF tfra box type -type Tfra struct { - FullBox `mp4:"0,extend"` - TrackID uint32 `mp4:"1,size=32"` - Reserved uint32 `mp4:"2,size=26,const=0"` - LengthSizeOfTrafNum byte `mp4:"3,size=2"` - LengthSizeOfTrunNum byte `mp4:"4,size=2"` - LengthSizeOfSampleNum byte `mp4:"5,size=2"` - NumberOfEntry uint32 `mp4:"6,size=32"` - Entries []TfraEntry `mp4:"7,len=dynamic,size=dynamic"` -} - -type TfraEntry struct { - TimeV0 uint32 `mp4:"0,size=32,ver=0"` - MoofOffsetV0 uint32 `mp4:"1,size=32,ver=0"` - TimeV1 uint64 `mp4:"2,size=64,ver=1"` - MoofOffsetV1 uint64 `mp4:"3,size=64,ver=1"` - TrafNumber uint32 `mp4:"4,size=dynamic"` - TrunNumber uint32 `mp4:"5,size=dynamic"` - SampleNumber uint32 `mp4:"6,size=dynamic"` -} - -// GetType returns the BoxType -func (*Tfra) GetType() BoxType { - return BoxTypeTfra() -} - -// GetFieldSize returns size of dynamic field -func (tfra *Tfra) GetFieldSize(name string, ctx Context) uint { - switch name { - case "TrafNumber": - return (uint(tfra.LengthSizeOfTrafNum) + 1) * 8 - case "TrunNumber": - return (uint(tfra.LengthSizeOfTrunNum) + 1) * 8 - case "SampleNumber": - return (uint(tfra.LengthSizeOfSampleNum) + 1) * 8 - case "Entries": - switch tfra.GetVersion() { - case 0: - return 0 + - /* TimeV0 */ 32 + - /* MoofOffsetV0 */ 32 + - /* TrafNumber */ (uint(tfra.LengthSizeOfTrafNum)+1)*8 + - /* TrunNumber */ (uint(tfra.LengthSizeOfTrunNum)+1)*8 + - /* SampleNumber */ (uint(tfra.LengthSizeOfSampleNum)+1)*8 - case 1: - return 0 + - /* TimeV1 */ 64 + - /* MoofOffsetV1 */ 64 + - /* TrafNumber */ (uint(tfra.LengthSizeOfTrafNum)+1)*8 + - /* TrunNumber */ (uint(tfra.LengthSizeOfTrunNum)+1)*8 + - /* SampleNumber */ (uint(tfra.LengthSizeOfSampleNum)+1)*8 - } - } - panic(fmt.Errorf("invalid name of dynamic-size field: boxType=tfra fieldName=%s", name)) -} - -// GetFieldLength returns length of dynamic field -func (tfra *Tfra) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(tfra.NumberOfEntry) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=tfra fieldName=%s", name)) -} - -func (tfra *Tfra) GetTime(index int) uint64 { - switch tfra.GetVersion() { - case 0: - return uint64(tfra.Entries[index].TimeV0) - case 1: - return tfra.Entries[index].TimeV1 - default: - return 0 - } -} - -func (tfra *Tfra) GetMoofOffset(index int) uint64 { - switch tfra.GetVersion() { - case 0: - return uint64(tfra.Entries[index].MoofOffsetV0) - case 1: - return tfra.Entries[index].MoofOffsetV1 - default: - return 0 - } -} - -/*************************** tkhd ****************************/ - -func BoxTypeTkhd() BoxType { return StrToBoxType("tkhd") } - -func init() { - AddBoxDef(&Tkhd{}, 0, 1) -} - -// Tkhd is ISOBMFF tkhd box type -type Tkhd struct { - FullBox `mp4:"0,extend"` - CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` - ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` - CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` - ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` - TrackID uint32 `mp4:"5,size=32"` - Reserved0 uint32 `mp4:"6,size=32,const=0"` - DurationV0 uint32 `mp4:"7,size=32,ver=0"` - DurationV1 uint64 `mp4:"8,size=64,ver=1"` - // - Reserved1 [2]uint32 `mp4:"9,size=32,const=0"` - Layer int16 `mp4:"10,size=16"` // template=0 - AlternateGroup int16 `mp4:"11,size=16"` // template=0 - Volume int16 `mp4:"12,size=16"` // template={if track_is_audio 0x0100 else 0} - Reserved2 uint16 `mp4:"13,size=16,const=0"` - Matrix [9]int32 `mp4:"14,size=32,hex"` // template={ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 }; - Width uint32 `mp4:"15,size=32"` // fixed-point 16.16 - Height uint32 `mp4:"16,size=32"` // fixed-point 16.16 -} - -// GetType returns the BoxType -func (*Tkhd) GetType() BoxType { - return BoxTypeTkhd() -} - -// StringifyField returns field value as string -func (tkhd *Tkhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "Width": - return util.FormatUnsignedFixedFloat1616(tkhd.Width), true - case "Height": - return util.FormatUnsignedFixedFloat1616(tkhd.Height), true - default: - return "", false - } -} - -func (tkhd *Tkhd) GetCreationTime() uint64 { - switch tkhd.GetVersion() { - case 0: - return uint64(tkhd.CreationTimeV0) - case 1: - return tkhd.CreationTimeV1 - default: - return 0 - } -} - -func (tkhd *Tkhd) GetModificationTime() uint64 { - switch tkhd.GetVersion() { - case 0: - return uint64(tkhd.ModificationTimeV0) - case 1: - return tkhd.ModificationTimeV1 - default: - return 0 - } -} - -func (tkhd *Tkhd) GetDuration() uint64 { - switch tkhd.GetVersion() { - case 0: - return uint64(tkhd.DurationV0) - case 1: - return tkhd.DurationV1 - default: - return 0 - } -} - -// GetWidth returns value of width as float64 -func (tkhd *Tkhd) GetWidth() float64 { - return float64(tkhd.Width) / (1 << 16) -} - -// GetWidthInt returns value of width as uint16 -func (tkhd *Tkhd) GetWidthInt() uint16 { - return uint16(tkhd.Width >> 16) -} - -// GetHeight returns value of height as float64 -func (tkhd *Tkhd) GetHeight() float64 { - return float64(tkhd.Height) / (1 << 16) -} - -// GetHeightInt returns value of height as uint16 -func (tkhd *Tkhd) GetHeightInt() uint16 { - return uint16(tkhd.Height >> 16) -} - -/*************************** traf ****************************/ - -func BoxTypeTraf() BoxType { return StrToBoxType("traf") } - -func init() { - AddBoxDef(&Traf{}) -} - -// Traf is ISOBMFF traf box type -type Traf struct { - Box -} - -// GetType returns the BoxType -func (*Traf) GetType() BoxType { - return BoxTypeTraf() -} - -/*************************** trak ****************************/ - -func BoxTypeTrak() BoxType { return StrToBoxType("trak") } - -func init() { - AddBoxDef(&Trak{}) -} - -// Trak is ISOBMFF trak box type -type Trak struct { - Box -} - -// GetType returns the BoxType -func (*Trak) GetType() BoxType { - return BoxTypeTrak() -} - -/*************************** trep ****************************/ - -func BoxTypeTrep() BoxType { return StrToBoxType("trep") } - -func init() { - AddBoxDef(&Trep{}, 0) -} - -// Trep is ISOBMFF trep box type -type Trep struct { - FullBox `mp4:"0,extend"` - TrackID uint32 `mp4:"1,size=32"` -} - -// GetType returns the BoxType -func (*Trep) GetType() BoxType { - return BoxTypeTrep() -} - -/*************************** trex ****************************/ - -func BoxTypeTrex() BoxType { return StrToBoxType("trex") } - -func init() { - AddBoxDef(&Trex{}, 0) -} - -// Trex is ISOBMFF trex box type -type Trex struct { - FullBox `mp4:"0,extend"` - TrackID uint32 `mp4:"1,size=32"` - DefaultSampleDescriptionIndex uint32 `mp4:"2,size=32"` - DefaultSampleDuration uint32 `mp4:"3,size=32"` - DefaultSampleSize uint32 `mp4:"4,size=32"` - DefaultSampleFlags uint32 `mp4:"5,size=32,hex"` -} - -// GetType returns the BoxType -func (*Trex) GetType() BoxType { - return BoxTypeTrex() -} - -/*************************** trun ****************************/ - -func BoxTypeTrun() BoxType { return StrToBoxType("trun") } - -func init() { - AddBoxDef(&Trun{}, 0, 1) -} - -// Trun is ISOBMFF trun box type -type Trun struct { - FullBox `mp4:"0,extend"` - SampleCount uint32 `mp4:"1,size=32"` - - // optional fields - DataOffset int32 `mp4:"2,size=32,opt=0x000001"` - FirstSampleFlags uint32 `mp4:"3,size=32,opt=0x000004,hex"` - Entries []TrunEntry `mp4:"4,len=dynamic,size=dynamic"` -} - -type TrunEntry struct { - SampleDuration uint32 `mp4:"0,size=32,opt=0x000100"` - SampleSize uint32 `mp4:"1,size=32,opt=0x000200"` - SampleFlags uint32 `mp4:"2,size=32,opt=0x000400,hex"` - SampleCompositionTimeOffsetV0 uint32 `mp4:"3,size=32,opt=0x000800,ver=0"` - SampleCompositionTimeOffsetV1 int32 `mp4:"4,size=32,opt=0x000800,nver=0"` -} - -// GetType returns the BoxType -func (*Trun) GetType() BoxType { - return BoxTypeTrun() -} - -// GetFieldSize returns size of dynamic field -func (trun *Trun) GetFieldSize(name string, ctx Context) uint { - switch name { - case "Entries": - var size uint - flags := trun.GetFlags() - if flags&0x100 != 0 { - size += 32 // SampleDuration - } - if flags&0x200 != 0 { - size += 32 // SampleSize - } - if flags&0x400 != 0 { - size += 32 // SampleFlags - } - if flags&0x800 != 0 { - size += 32 // SampleCompositionTimeOffsetV0 or V1 - } - return size - } - panic(fmt.Errorf("invalid name of dynamic-size field: boxType=trun fieldName=%s", name)) -} - -// GetFieldLength returns length of dynamic field -func (trun *Trun) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(trun.SampleCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=trun fieldName=%s", name)) -} - -func (trun *Trun) GetSampleCompositionTimeOffset(index int) int64 { - switch trun.GetVersion() { - case 0: - return int64(trun.Entries[index].SampleCompositionTimeOffsetV0) - case 1: - return int64(trun.Entries[index].SampleCompositionTimeOffsetV1) - default: - return 0 - } -} - -/*************************** udta ****************************/ - -func BoxTypeUdta() BoxType { return StrToBoxType("udta") } - -var udta3GppMetaBoxTypes = []BoxType{ - StrToBoxType("titl"), - StrToBoxType("dscp"), - StrToBoxType("cprt"), - StrToBoxType("perf"), - StrToBoxType("auth"), - StrToBoxType("gnre"), -} - -func init() { - AddBoxDef(&Udta{}) - for _, bt := range udta3GppMetaBoxTypes { - AddAnyTypeBoxDefEx(&Udta3GppString{}, bt, isUnderUdta, 0) - } -} - -// Udta is ISOBMFF udta box type -type Udta struct { - Box -} - -// GetType returns the BoxType -func (*Udta) GetType() BoxType { - return BoxTypeUdta() -} - -type Udta3GppString struct { - AnyTypeBox - FullBox `mp4:"0,extend"` - Pad bool `mp4:"1,size=1,hidden"` - Language [3]byte `mp4:"2,size=5,iso639-2"` // ISO-639-2/T language code - Data []byte `mp4:"3,size=8,string"` -} - -func isUnderUdta(ctx Context) bool { - return ctx.UnderUdta -} - -/*************************** vmhd ****************************/ - -func BoxTypeVmhd() BoxType { return StrToBoxType("vmhd") } - -func init() { - AddBoxDef(&Vmhd{}, 0) -} - -// Vmhd is ISOBMFF vmhd box type -type Vmhd struct { - FullBox `mp4:"0,extend"` - Graphicsmode uint16 `mp4:"1,size=16"` // template=0 - Opcolor [3]uint16 `mp4:"2,size=16"` // template={0, 0, 0} -} - -// GetType returns the BoxType -func (*Vmhd) GetType() BoxType { - return BoxTypeVmhd() -} - -/*************************** wave ****************************/ - -func BoxTypeWave() BoxType { return StrToBoxType("wave") } - -func init() { - AddBoxDef(&Wave{}) -} - -// Wave is QuickTime wave box -type Wave struct { - Box -} - -// GetType returns the BoxType -func (*Wave) GetType() BoxType { - return BoxTypeWave() -} diff --git a/vendor/github.com/abema/go-mp4/box_types_3gpp.go b/vendor/github.com/abema/go-mp4/box_types_3gpp.go new file mode 100644 index 000000000..d19640c51 --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_3gpp.go @@ -0,0 +1,24 @@ +package mp4 + +var udta3GppMetaBoxTypes = []BoxType{ + StrToBoxType("titl"), + StrToBoxType("dscp"), + StrToBoxType("cprt"), + StrToBoxType("perf"), + StrToBoxType("auth"), + StrToBoxType("gnre"), +} + +func init() { + for _, bt := range udta3GppMetaBoxTypes { + AddAnyTypeBoxDefEx(&Udta3GppString{}, bt, isUnderUdta, 0) + } +} + +type Udta3GppString struct { + AnyTypeBox + FullBox `mp4:"0,extend"` + Pad bool `mp4:"1,size=1,hidden"` + Language [3]byte `mp4:"2,size=5,iso639-2"` // ISO-639-2/T language code + Data []byte `mp4:"3,size=8,string"` +} diff --git a/vendor/github.com/abema/go-mp4/box_types_av1.go b/vendor/github.com/abema/go-mp4/box_types_av1.go new file mode 100644 index 000000000..7b929e72b --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_av1.go @@ -0,0 +1,44 @@ +package mp4 + +/*************************** av01 ****************************/ + +// https://aomediacodec.github.io/av1-isobmff + +func BoxTypeAv01() BoxType { return StrToBoxType("av01") } + +func init() { + AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeAv01()) +} + +/*************************** av1C ****************************/ + +// https://aomediacodec.github.io/av1-isobmff + +func BoxTypeAv1C() BoxType { return StrToBoxType("av1C") } + +func init() { + AddBoxDef(&Av1C{}) +} + +type Av1C struct { + Box + Marker uint8 `mp4:"0,size=1,const=1"` + Version uint8 `mp4:"1,size=7,const=1"` + SeqProfile uint8 `mp4:"2,size=3"` + SeqLevelIdx0 uint8 `mp4:"3,size=5"` + SeqTier0 uint8 `mp4:"4,size=1"` + HighBitdepth uint8 `mp4:"5,size=1"` + TwelveBit uint8 `mp4:"6,size=1"` + Monochrome uint8 `mp4:"7,size=1"` + ChromaSubsamplingX uint8 `mp4:"8,size=1"` + ChromaSubsamplingY uint8 `mp4:"9,size=1"` + ChromaSamplePosition uint8 `mp4:"10,size=2"` + Reserved uint8 `mp4:"11,size=3,const=0"` + InitialPresentationDelayPresent uint8 `mp4:"12,size=1"` + InitialPresentationDelayMinusOne uint8 `mp4:"13,size=4"` + ConfigOBUs []uint8 `mp4:"14,size=8"` +} + +func (Av1C) GetType() BoxType { + return BoxTypeAv1C() +} diff --git a/vendor/github.com/abema/go-mp4/box_types_iso14496_12.go b/vendor/github.com/abema/go-mp4/box_types_iso14496_12.go new file mode 100644 index 000000000..b3e46fd75 --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_iso14496_12.go @@ -0,0 +1,2454 @@ +package mp4 + +import ( + "errors" + "fmt" + "io" + + "github.com/abema/go-mp4/bitio" + "github.com/abema/go-mp4/util" +) + +/*************************** btrt ****************************/ + +func BoxTypeBtrt() BoxType { return StrToBoxType("btrt") } + +func init() { + AddBoxDef(&Btrt{}, 0) +} + +type Btrt struct { + Box + BufferSizeDB uint32 `mp4:"0,size=32"` + MaxBitrate uint32 `mp4:"1,size=32"` + AvgBitrate uint32 `mp4:"2,size=32"` +} + +// GetType returns the BoxType +func (*Btrt) GetType() BoxType { + return BoxTypeBtrt() +} + +/*************************** co64 ****************************/ + +func BoxTypeCo64() BoxType { return StrToBoxType("co64") } + +func init() { + AddBoxDef(&Co64{}, 0) +} + +type Co64 struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + ChunkOffset []uint64 `mp4:"2,size=64,len=dynamic"` +} + +// GetType returns the BoxType +func (*Co64) GetType() BoxType { + return BoxTypeCo64() +} + +// GetFieldLength returns length of dynamic field +func (co64 *Co64) GetFieldLength(name string, ctx Context) uint { + switch name { + case "ChunkOffset": + return uint(co64.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=co64 fieldName=%s", name)) +} + +/*************************** colr ****************************/ + +func BoxTypeColr() BoxType { return StrToBoxType("colr") } + +func init() { + AddBoxDef(&Colr{}) +} + +type Colr struct { + Box + ColourType [4]byte `mp4:"0,size=8,string"` + ColourPrimaries uint16 `mp4:"1,size=16,opt=dynamic"` + TransferCharacteristics uint16 `mp4:"2,size=16,opt=dynamic"` + MatrixCoefficients uint16 `mp4:"3,size=16,opt=dynamic"` + FullRangeFlag bool `mp4:"4,size=1,opt=dynamic"` + Reserved uint8 `mp4:"5,size=7,opt=dynamic"` + Profile []byte `mp4:"6,size=8,opt=dynamic"` + Unknown []byte `mp4:"7,size=8,opt=dynamic"` +} + +func (colr *Colr) IsOptFieldEnabled(name string, ctx Context) bool { + switch colr.ColourType { + case [4]byte{'n', 'c', 'l', 'x'}: + switch name { + case "ColourType", + "ColourPrimaries", + "TransferCharacteristics", + "MatrixCoefficients", + "FullRangeFlag", + "Reserved": + return true + default: + return false + } + case [4]byte{'r', 'I', 'C', 'C'}, [4]byte{'p', 'r', 'o', 'f'}: + return name == "Profile" + default: + return name == "Unknown" + } +} + +// GetType returns the BoxType +func (*Colr) GetType() BoxType { + return BoxTypeColr() +} + +/*************************** cslg ****************************/ + +func BoxTypeCslg() BoxType { return StrToBoxType("cslg") } + +func init() { + AddBoxDef(&Cslg{}, 0, 1) +} + +type Cslg struct { + FullBox `mp4:"0,extend"` + CompositionToDTSShiftV0 int32 `mp4:"1,size=32,ver=0"` + LeastDecodeToDisplayDeltaV0 int32 `mp4:"2,size=32,ver=0"` + GreatestDecodeToDisplayDeltaV0 int32 `mp4:"3,size=32,ver=0"` + CompositionStartTimeV0 int32 `mp4:"4,size=32,ver=0"` + CompositionEndTimeV0 int32 `mp4:"5,size=32,ver=0"` + CompositionToDTSShiftV1 int64 `mp4:"6,size=64,nver=0"` + LeastDecodeToDisplayDeltaV1 int64 `mp4:"7,size=64,nver=0"` + GreatestDecodeToDisplayDeltaV1 int64 `mp4:"8,size=64,nver=0"` + CompositionStartTimeV1 int64 `mp4:"9,size=64,nver=0"` + CompositionEndTimeV1 int64 `mp4:"10,size=64,nver=0"` +} + +// GetType returns the BoxType +func (*Cslg) GetType() BoxType { + return BoxTypeCslg() +} + +func (cslg *Cslg) GetCompositionToDTSShift() int64 { + switch cslg.GetVersion() { + case 0: + return int64(cslg.CompositionToDTSShiftV0) + case 1: + return cslg.CompositionToDTSShiftV1 + default: + return 0 + } +} + +func (cslg *Cslg) GetLeastDecodeToDisplayDelta() int64 { + switch cslg.GetVersion() { + case 0: + return int64(cslg.LeastDecodeToDisplayDeltaV0) + case 1: + return cslg.LeastDecodeToDisplayDeltaV1 + default: + return 0 + } +} + +func (cslg *Cslg) GetGreatestDecodeToDisplayDelta() int64 { + switch cslg.GetVersion() { + case 0: + return int64(cslg.GreatestDecodeToDisplayDeltaV0) + case 1: + return cslg.GreatestDecodeToDisplayDeltaV1 + default: + return 0 + } +} + +func (cslg *Cslg) GetCompositionStartTime() int64 { + switch cslg.GetVersion() { + case 0: + return int64(cslg.CompositionStartTimeV0) + case 1: + return cslg.CompositionStartTimeV1 + default: + return 0 + } +} + +func (cslg *Cslg) GetCompositionEndTime() int64 { + switch cslg.GetVersion() { + case 0: + return int64(cslg.CompositionEndTimeV0) + case 1: + return cslg.CompositionEndTimeV1 + default: + return 0 + } +} + +/*************************** ctts ****************************/ + +func BoxTypeCtts() BoxType { return StrToBoxType("ctts") } + +func init() { + AddBoxDef(&Ctts{}, 0, 1) +} + +type Ctts struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + Entries []CttsEntry `mp4:"2,len=dynamic,size=64"` +} + +type CttsEntry struct { + SampleCount uint32 `mp4:"0,size=32"` + SampleOffsetV0 uint32 `mp4:"1,size=32,ver=0"` + SampleOffsetV1 int32 `mp4:"2,size=32,ver=1"` +} + +// GetType returns the BoxType +func (*Ctts) GetType() BoxType { + return BoxTypeCtts() +} + +// GetFieldLength returns length of dynamic field +func (ctts *Ctts) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(ctts.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=ctts fieldName=%s", name)) +} + +func (ctts *Ctts) GetSampleOffset(index int) int64 { + switch ctts.GetVersion() { + case 0: + return int64(ctts.Entries[index].SampleOffsetV0) + case 1: + return int64(ctts.Entries[index].SampleOffsetV1) + default: + return 0 + } +} + +/*************************** dinf ****************************/ + +func BoxTypeDinf() BoxType { return StrToBoxType("dinf") } + +func init() { + AddBoxDef(&Dinf{}) +} + +// Dinf is ISOBMFF dinf box type +type Dinf struct { + Box +} + +// GetType returns the BoxType +func (*Dinf) GetType() BoxType { + return BoxTypeDinf() +} + +/*************************** dref ****************************/ + +func BoxTypeDref() BoxType { return StrToBoxType("dref") } +func BoxTypeUrl() BoxType { return StrToBoxType("url ") } +func BoxTypeUrn() BoxType { return StrToBoxType("urn ") } + +func init() { + AddBoxDef(&Dref{}, 0) + AddBoxDef(&Url{}, 0) + AddBoxDef(&Urn{}, 0) +} + +// Dref is ISOBMFF dref box type +type Dref struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Dref) GetType() BoxType { + return BoxTypeDref() +} + +type Url struct { + FullBox `mp4:"0,extend"` + Location string `mp4:"1,string,nopt=0x000001"` +} + +func (*Url) GetType() BoxType { + return BoxTypeUrl() +} + +const UrlSelfContained = 0x000001 + +type Urn struct { + FullBox `mp4:"0,extend"` + Name string `mp4:"1,string,nopt=0x000001"` + Location string `mp4:"2,string,nopt=0x000001"` +} + +func (*Urn) GetType() BoxType { + return BoxTypeUrn() +} + +const UrnSelfContained = 0x000001 + +/*************************** edts ****************************/ + +func BoxTypeEdts() BoxType { return StrToBoxType("edts") } + +func init() { + AddBoxDef(&Edts{}) +} + +// Edts is ISOBMFF edts box type +type Edts struct { + Box +} + +// GetType returns the BoxType +func (*Edts) GetType() BoxType { + return BoxTypeEdts() +} + +/*************************** elst ****************************/ + +func BoxTypeElst() BoxType { return StrToBoxType("elst") } + +func init() { + AddBoxDef(&Elst{}, 0, 1) +} + +// Elst is ISOBMFF elst box type +type Elst struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + Entries []ElstEntry `mp4:"2,len=dynamic,size=dynamic"` +} + +type ElstEntry struct { + SegmentDurationV0 uint32 `mp4:"0,size=32,ver=0"` + MediaTimeV0 int32 `mp4:"1,size=32,ver=0"` + SegmentDurationV1 uint64 `mp4:"2,size=64,ver=1"` + MediaTimeV1 int64 `mp4:"3,size=64,ver=1"` + MediaRateInteger int16 `mp4:"4,size=16"` + MediaRateFraction int16 `mp4:"5,size=16,const=0"` +} + +// GetType returns the BoxType +func (*Elst) GetType() BoxType { + return BoxTypeElst() +} + +// GetFieldSize returns size of dynamic field +func (elst *Elst) GetFieldSize(name string, ctx Context) uint { + switch name { + case "Entries": + switch elst.GetVersion() { + case 0: + return 0 + + /* segmentDurationV0 */ 32 + + /* mediaTimeV0 */ 32 + + /* mediaRateInteger */ 16 + + /* mediaRateFraction */ 16 + case 1: + return 0 + + /* segmentDurationV1 */ 64 + + /* mediaTimeV1 */ 64 + + /* mediaRateInteger */ 16 + + /* mediaRateFraction */ 16 + } + } + panic(fmt.Errorf("invalid name of dynamic-size field: boxType=elst fieldName=%s", name)) +} + +// GetFieldLength returns length of dynamic field +func (elst *Elst) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(elst.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=elst fieldName=%s", name)) +} + +func (elst *Elst) GetSegmentDuration(index int) uint64 { + switch elst.GetVersion() { + case 0: + return uint64(elst.Entries[index].SegmentDurationV0) + case 1: + return elst.Entries[index].SegmentDurationV1 + default: + return 0 + } +} + +func (elst *Elst) GetMediaTime(index int) int64 { + switch elst.GetVersion() { + case 0: + return int64(elst.Entries[index].MediaTimeV0) + case 1: + return elst.Entries[index].MediaTimeV1 + default: + return 0 + } +} + +/*************************** emsg ****************************/ + +func BoxTypeEmsg() BoxType { return StrToBoxType("emsg") } + +func init() { + AddBoxDef(&Emsg{}, 0, 1) +} + +// Emsg is ISOBMFF emsg box type +type Emsg struct { + FullBox `mp4:"0,extend"` + SchemeIdUri string `mp4:"1,string"` + Value string `mp4:"2,string"` + Timescale uint32 `mp4:"3,size=32"` + PresentationTimeDelta uint32 `mp4:"4,size=32,ver=0"` + PresentationTime uint64 `mp4:"5,size=64,ver=1"` + EventDuration uint32 `mp4:"6,size=32"` + Id uint32 `mp4:"7,size=32"` + MessageData []byte `mp4:"8,size=8,string"` +} + +func (emsg *Emsg) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { + if emsg.GetVersion() == 0 { + return + } + switch name { + case "SchemeIdUri", "Value": + override = true + return + case "MessageData": + emsg.SchemeIdUri, err = util.ReadString(r) + if err != nil { + return + } + emsg.Value, err = util.ReadString(r) + if err != nil { + return + } + rbits += uint64(len(emsg.SchemeIdUri)+len(emsg.Value)+2) * 8 + return + default: + return + } +} + +func (emsg *Emsg) OnWriteField(name string, w bitio.Writer, ctx Context) (wbits uint64, override bool, err error) { + if emsg.GetVersion() == 0 { + return + } + switch name { + case "SchemeIdUri", "Value": + override = true + return + case "MessageData": + if err = util.WriteString(w, emsg.SchemeIdUri); err != nil { + return + } + if err = util.WriteString(w, emsg.Value); err != nil { + return + } + wbits += uint64(len(emsg.SchemeIdUri)+len(emsg.Value)+2) * 8 + return + default: + return + } +} + +// GetType returns the BoxType +func (*Emsg) GetType() BoxType { + return BoxTypeEmsg() +} + +/*************************** fiel ****************************/ + +func BoxTypeFiel() BoxType { return StrToBoxType("fiel") } + +func init() { + AddBoxDef(&Fiel{}) +} + +type Fiel struct { + Box + FieldCount uint8 `mp4:"0,size=8"` + FieldOrdering uint8 `mp4:"1,size=8"` +} + +func (Fiel) GetType() BoxType { + return BoxTypeFiel() +} + +/************************ free, skip *************************/ + +func BoxTypeFree() BoxType { return StrToBoxType("free") } +func BoxTypeSkip() BoxType { return StrToBoxType("skip") } + +func init() { + AddBoxDef(&Free{}) + AddBoxDef(&Skip{}) +} + +type FreeSpace struct { + Box + Data []uint8 `mp4:"0,size=8"` +} + +type Free FreeSpace + +func (*Free) GetType() BoxType { + return BoxTypeFree() +} + +type Skip FreeSpace + +func (*Skip) GetType() BoxType { + return BoxTypeSkip() +} + +/*************************** frma ****************************/ + +func BoxTypeFrma() BoxType { return StrToBoxType("frma") } + +func init() { + AddBoxDef(&Frma{}) +} + +// Frma is ISOBMFF frma box type +type Frma struct { + Box + DataFormat [4]byte `mp4:"0,size=8,string"` +} + +// GetType returns the BoxType +func (*Frma) GetType() BoxType { + return BoxTypeFrma() +} + +/*************************** ftyp ****************************/ + +func BoxTypeFtyp() BoxType { return StrToBoxType("ftyp") } + +func init() { + AddBoxDef(&Ftyp{}) +} + +func BrandQT() [4]byte { return [4]byte{'q', 't', ' ', ' '} } +func BrandISOM() [4]byte { return [4]byte{'i', 's', 'o', 'm'} } +func BrandISO2() [4]byte { return [4]byte{'i', 's', 'o', '2'} } +func BrandISO3() [4]byte { return [4]byte{'i', 's', 'o', '3'} } +func BrandISO4() [4]byte { return [4]byte{'i', 's', 'o', '4'} } +func BrandISO5() [4]byte { return [4]byte{'i', 's', 'o', '5'} } +func BrandISO6() [4]byte { return [4]byte{'i', 's', 'o', '6'} } +func BrandISO7() [4]byte { return [4]byte{'i', 's', 'o', '7'} } +func BrandISO8() [4]byte { return [4]byte{'i', 's', 'o', '8'} } +func BrandISO9() [4]byte { return [4]byte{'i', 's', 'o', '9'} } +func BrandAVC1() [4]byte { return [4]byte{'a', 'v', 'c', '1'} } +func BrandMP41() [4]byte { return [4]byte{'m', 'p', '4', '1'} } +func BrandMP71() [4]byte { return [4]byte{'m', 'p', '7', '1'} } + +// Ftyp is ISOBMFF ftyp box type +type Ftyp struct { + Box + MajorBrand [4]byte `mp4:"0,size=8,string"` + MinorVersion uint32 `mp4:"1,size=32"` + CompatibleBrands []CompatibleBrandElem `mp4:"2,size=32"` // reach to end of the box +} + +type CompatibleBrandElem struct { + CompatibleBrand [4]byte `mp4:"0,size=8,string"` +} + +func (ftyp *Ftyp) AddCompatibleBrand(cb [4]byte) { + if !ftyp.HasCompatibleBrand(cb) { + ftyp.CompatibleBrands = append(ftyp.CompatibleBrands, CompatibleBrandElem{ + CompatibleBrand: cb, + }) + } +} + +func (ftyp *Ftyp) RemoveCompatibleBrand(cb [4]byte) { + for i := 0; i < len(ftyp.CompatibleBrands); { + if ftyp.CompatibleBrands[i].CompatibleBrand != cb { + i++ + continue + } + ftyp.CompatibleBrands[i] = ftyp.CompatibleBrands[len(ftyp.CompatibleBrands)-1] + ftyp.CompatibleBrands = ftyp.CompatibleBrands[:len(ftyp.CompatibleBrands)-1] + } +} + +func (ftyp *Ftyp) HasCompatibleBrand(cb [4]byte) bool { + for i := range ftyp.CompatibleBrands { + if ftyp.CompatibleBrands[i].CompatibleBrand == cb { + return true + } + } + return false +} + +// GetType returns the BoxType +func (*Ftyp) GetType() BoxType { + return BoxTypeFtyp() +} + +/*************************** hdlr ****************************/ + +func BoxTypeHdlr() BoxType { return StrToBoxType("hdlr") } + +func init() { + AddBoxDef(&Hdlr{}, 0) +} + +// Hdlr is ISOBMFF hdlr box type +type Hdlr struct { + FullBox `mp4:"0,extend"` + // Predefined corresponds to component_type of QuickTime. + // pre_defined of ISO-14496 has always zero, + // however component_type has "mhlr" or "dhlr". + PreDefined uint32 `mp4:"1,size=32"` + HandlerType [4]byte `mp4:"2,size=8,string"` + Reserved [3]uint32 `mp4:"3,size=32,const=0"` + Name string `mp4:"4,string"` +} + +// GetType returns the BoxType +func (*Hdlr) GetType() BoxType { + return BoxTypeHdlr() +} + +func (hdlr *Hdlr) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { + switch name { + case "Name": + return hdlr.OnReadName(r, leftBits, ctx) + default: + return 0, false, nil + } +} + +func (hdlr *Hdlr) OnReadName(r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { + size := leftBits / 8 + if size == 0 { + hdlr.Name = "" + return 0, true, nil + } + + buf := make([]byte, size) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, false, err + } + + plen := buf[0] + if hdlr.PreDefined != 0 && size >= 2 && size == uint64(plen+1) { + // Pascal-style String + hdlr.Name = string(buf[1 : plen+1]) + } else { + // C-style String + clen := 0 + for _, c := range buf { + if c == 0x00 { + break + } + clen++ + } + hdlr.Name = string(buf[:clen]) + } + return leftBits, true, nil +} + +/*************************** hvcC ****************************/ + +func BoxTypeHvcC() BoxType { return StrToBoxType("hvcC") } + +func init() { + AddBoxDef(&HvcC{}) +} + +type HEVCNalu struct { + BaseCustomFieldObject + Length uint16 `mp4:"0,size=16"` + NALUnit []byte `mp4:"1,size=8,len=dynamic"` +} + +func (s HEVCNalu) GetFieldLength(name string, ctx Context) uint { + switch name { + case "NALUnit": + return uint(s.Length) + } + return 0 +} + +type HEVCNaluArray struct { + BaseCustomFieldObject + Completeness bool `mp4:"0,size=1"` + Reserved bool `mp4:"1,size=1"` + NaluType uint8 `mp4:"2,size=6"` + NumNalus uint16 `mp4:"3,size=16"` + Nalus []HEVCNalu `mp4:"4,len=dynamic"` +} + +func (a HEVCNaluArray) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Nalus": + return uint(a.NumNalus) + } + return 0 +} + +type HvcC struct { + Box + ConfigurationVersion uint8 `mp4:"0,size=8"` + GeneralProfileSpace uint8 `mp4:"1,size=2"` + GeneralTierFlag bool `mp4:"2,size=1"` + GeneralProfileIdc uint8 `mp4:"3,size=5"` + GeneralProfileCompatibility [32]bool `mp4:"4,size=1"` + GeneralConstraintIndicator [6]uint8 `mp4:"5,size=8"` + GeneralLevelIdc uint8 `mp4:"6,size=8"` + Reserved1 uint8 `mp4:"7,size=4,const=15"` + MinSpatialSegmentationIdc uint16 `mp4:"8,size=12"` + Reserved2 uint8 `mp4:"9,size=6,const=63"` + ParallelismType uint8 `mp4:"10,size=2"` + Reserved3 uint8 `mp4:"11,size=6,const=63"` + ChromaFormatIdc uint8 `mp4:"12,size=2"` + Reserved4 uint8 `mp4:"13,size=5,const=31"` + BitDepthLumaMinus8 uint8 `mp4:"14,size=3"` + Reserved5 uint8 `mp4:"15,size=5,const=31"` + BitDepthChromaMinus8 uint8 `mp4:"16,size=3"` + AvgFrameRate uint16 `mp4:"17,size=16"` + ConstantFrameRate uint8 `mp4:"18,size=2"` + NumTemporalLayers uint8 `mp4:"19,size=2"` + TemporalIdNested uint8 `mp4:"20,size=2"` + LengthSizeMinusOne uint8 `mp4:"21,size=2"` + NumOfNaluArrays uint8 `mp4:"22,size=8"` + NaluArrays []HEVCNaluArray `mp4:"23,len=dynamic"` +} + +func (HvcC) GetType() BoxType { + return BoxTypeHvcC() +} + +func (hvcc HvcC) GetFieldLength(name string, ctx Context) uint { + switch name { + case "NaluArrays": + return uint(hvcc.NumOfNaluArrays) + } + return 0 +} + +/*************************** mdat ****************************/ + +func BoxTypeMdat() BoxType { return StrToBoxType("mdat") } + +func init() { + AddBoxDef(&Mdat{}) +} + +// Mdat is ISOBMFF mdat box type +type Mdat struct { + Box + Data []byte `mp4:"0,size=8"` +} + +// GetType returns the BoxType +func (*Mdat) GetType() BoxType { + return BoxTypeMdat() +} + +/*************************** mdhd ****************************/ + +func BoxTypeMdhd() BoxType { return StrToBoxType("mdhd") } + +func init() { + AddBoxDef(&Mdhd{}, 0, 1) +} + +// Mdhd is ISOBMFF mdhd box type +type Mdhd struct { + FullBox `mp4:"0,extend"` + CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` + ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` + CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` + ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` + Timescale uint32 `mp4:"5,size=32"` + DurationV0 uint32 `mp4:"6,size=32,ver=0"` + DurationV1 uint64 `mp4:"7,size=64,ver=1"` + // + Pad bool `mp4:"8,size=1,hidden"` + Language [3]byte `mp4:"9,size=5,iso639-2"` // ISO-639-2/T language code + PreDefined uint16 `mp4:"10,size=16"` +} + +// GetType returns the BoxType +func (*Mdhd) GetType() BoxType { + return BoxTypeMdhd() +} + +func (mdhd *Mdhd) GetCreationTime() uint64 { + switch mdhd.GetVersion() { + case 0: + return uint64(mdhd.CreationTimeV0) + case 1: + return mdhd.CreationTimeV1 + default: + return 0 + } +} + +func (mdhd *Mdhd) GetModificationTime() uint64 { + switch mdhd.GetVersion() { + case 0: + return uint64(mdhd.ModificationTimeV0) + case 1: + return mdhd.ModificationTimeV1 + default: + return 0 + } +} + +func (mdhd *Mdhd) GetDuration() uint64 { + switch mdhd.GetVersion() { + case 0: + return uint64(mdhd.DurationV0) + case 1: + return mdhd.DurationV1 + default: + return 0 + } +} + +/*************************** mdia ****************************/ + +func BoxTypeMdia() BoxType { return StrToBoxType("mdia") } + +func init() { + AddBoxDef(&Mdia{}) +} + +// Mdia is ISOBMFF mdia box type +type Mdia struct { + Box +} + +// GetType returns the BoxType +func (*Mdia) GetType() BoxType { + return BoxTypeMdia() +} + +/*************************** mehd ****************************/ + +func BoxTypeMehd() BoxType { return StrToBoxType("mehd") } + +func init() { + AddBoxDef(&Mehd{}, 0, 1) +} + +// Mehd is ISOBMFF mehd box type +type Mehd struct { + FullBox `mp4:"0,extend"` + FragmentDurationV0 uint32 `mp4:"1,size=32,ver=0"` + FragmentDurationV1 uint64 `mp4:"2,size=64,ver=1"` +} + +// GetType returns the BoxType +func (*Mehd) GetType() BoxType { + return BoxTypeMehd() +} + +func (mdhd *Mehd) GetFragmentDuration() uint64 { + switch mdhd.GetVersion() { + case 0: + return uint64(mdhd.FragmentDurationV0) + case 1: + return mdhd.FragmentDurationV1 + default: + return 0 + } +} + +/*************************** meta ****************************/ + +func BoxTypeMeta() BoxType { return StrToBoxType("meta") } + +func init() { + AddBoxDef(&Meta{}, 0) +} + +// Meta is ISOBMFF meta box type +type Meta struct { + FullBox `mp4:"0,extend"` +} + +// GetType returns the BoxType +func (*Meta) GetType() BoxType { + return BoxTypeMeta() +} + +func (meta *Meta) BeforeUnmarshal(r io.ReadSeeker, size uint64, ctx Context) (n uint64, override bool, err error) { + // for Apple Quick Time + buf := make([]byte, 4) + if _, err := io.ReadFull(r, buf); err != nil { + return 0, false, err + } + if _, err := r.Seek(-int64(len(buf)), io.SeekCurrent); err != nil { + return 0, false, err + } + if buf[0]|buf[1]|buf[2]|buf[3] != 0x00 { + meta.Version = 0 + meta.Flags = [3]byte{0, 0, 0} + return 0, true, nil + } + return 0, false, nil +} + +/*************************** mfhd ****************************/ + +func BoxTypeMfhd() BoxType { return StrToBoxType("mfhd") } + +func init() { + AddBoxDef(&Mfhd{}, 0) +} + +// Mfhd is ISOBMFF mfhd box type +type Mfhd struct { + FullBox `mp4:"0,extend"` + SequenceNumber uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Mfhd) GetType() BoxType { + return BoxTypeMfhd() +} + +/*************************** mfra ****************************/ + +func BoxTypeMfra() BoxType { return StrToBoxType("mfra") } + +func init() { + AddBoxDef(&Mfra{}) +} + +// Mfra is ISOBMFF mfra box type +type Mfra struct { + Box +} + +// GetType returns the BoxType +func (*Mfra) GetType() BoxType { + return BoxTypeMfra() +} + +/*************************** mfro ****************************/ + +func BoxTypeMfro() BoxType { return StrToBoxType("mfro") } + +func init() { + AddBoxDef(&Mfro{}, 0) +} + +// Mfro is ISOBMFF mfro box type +type Mfro struct { + FullBox `mp4:"0,extend"` + Size uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Mfro) GetType() BoxType { + return BoxTypeMfro() +} + +/*************************** minf ****************************/ + +func BoxTypeMinf() BoxType { return StrToBoxType("minf") } + +func init() { + AddBoxDef(&Minf{}) +} + +// Minf is ISOBMFF minf box type +type Minf struct { + Box +} + +// GetType returns the BoxType +func (*Minf) GetType() BoxType { + return BoxTypeMinf() +} + +/*************************** moof ****************************/ + +func BoxTypeMoof() BoxType { return StrToBoxType("moof") } + +func init() { + AddBoxDef(&Moof{}) +} + +// Moof is ISOBMFF moof box type +type Moof struct { + Box +} + +// GetType returns the BoxType +func (*Moof) GetType() BoxType { + return BoxTypeMoof() +} + +/*************************** moov ****************************/ + +func BoxTypeMoov() BoxType { return StrToBoxType("moov") } + +func init() { + AddBoxDef(&Moov{}) +} + +// Moov is ISOBMFF moov box type +type Moov struct { + Box +} + +// GetType returns the BoxType +func (*Moov) GetType() BoxType { + return BoxTypeMoov() +} + +/*************************** mvex ****************************/ + +func BoxTypeMvex() BoxType { return StrToBoxType("mvex") } + +func init() { + AddBoxDef(&Mvex{}) +} + +// Mvex is ISOBMFF mvex box type +type Mvex struct { + Box +} + +// GetType returns the BoxType +func (*Mvex) GetType() BoxType { + return BoxTypeMvex() +} + +/*************************** mvhd ****************************/ + +func BoxTypeMvhd() BoxType { return StrToBoxType("mvhd") } + +func init() { + AddBoxDef(&Mvhd{}, 0, 1) +} + +// Mvhd is ISOBMFF mvhd box type +type Mvhd struct { + FullBox `mp4:"0,extend"` + CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` + ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` + CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` + ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` + Timescale uint32 `mp4:"5,size=32"` + DurationV0 uint32 `mp4:"6,size=32,ver=0"` + DurationV1 uint64 `mp4:"7,size=64,ver=1"` + Rate int32 `mp4:"8,size=32"` // fixed-point 16.16 - template=0x00010000 + Volume int16 `mp4:"9,size=16"` // template=0x0100 + Reserved int16 `mp4:"10,size=16,const=0"` + Reserved2 [2]uint32 `mp4:"11,size=32,const=0"` + Matrix [9]int32 `mp4:"12,size=32,hex"` // template={ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 } + PreDefined [6]int32 `mp4:"13,size=32"` + NextTrackID uint32 `mp4:"14,size=32"` +} + +// GetType returns the BoxType +func (*Mvhd) GetType() BoxType { + return BoxTypeMvhd() +} + +// StringifyField returns field value as string +func (mvhd *Mvhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "Rate": + return util.FormatSignedFixedFloat1616(mvhd.Rate), true + default: + return "", false + } +} + +func (mvhd *Mvhd) GetCreationTime() uint64 { + switch mvhd.GetVersion() { + case 0: + return uint64(mvhd.CreationTimeV0) + case 1: + return mvhd.CreationTimeV1 + default: + return 0 + } +} + +func (mvhd *Mvhd) GetModificationTime() uint64 { + switch mvhd.GetVersion() { + case 0: + return uint64(mvhd.ModificationTimeV0) + case 1: + return mvhd.ModificationTimeV1 + default: + return 0 + } +} + +func (mvhd *Mvhd) GetDuration() uint64 { + switch mvhd.GetVersion() { + case 0: + return uint64(mvhd.DurationV0) + case 1: + return mvhd.DurationV1 + default: + return 0 + } +} + +// GetRate returns value of rate as float64 +func (mvhd *Mvhd) GetRate() float64 { + return float64(mvhd.Rate) / (1 << 16) +} + +// GetRateInt returns value of rate as int16 +func (mvhd *Mvhd) GetRateInt() int16 { + return int16(mvhd.Rate >> 16) +} + +/*************************** saio ****************************/ + +func BoxTypeSaio() BoxType { return StrToBoxType("saio") } + +func init() { + AddBoxDef(&Saio{}, 0, 1) +} + +type Saio struct { + FullBox `mp4:"0,extend"` + AuxInfoType [4]byte `mp4:"1,size=8,opt=0x000001,string"` + AuxInfoTypeParameter uint32 `mp4:"2,size=32,opt=0x000001,hex"` + EntryCount uint32 `mp4:"3,size=32"` + OffsetV0 []uint32 `mp4:"4,size=32,ver=0,len=dynamic"` + OffsetV1 []uint64 `mp4:"5,size=64,nver=0,len=dynamic"` +} + +func (saio *Saio) GetFieldLength(name string, ctx Context) uint { + switch name { + case "OffsetV0", "OffsetV1": + return uint(saio.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=saio fieldName=%s", name)) +} + +func (*Saio) GetType() BoxType { + return BoxTypeSaio() +} + +func (saio *Saio) GetOffset(index int) uint64 { + switch saio.GetVersion() { + case 0: + return uint64(saio.OffsetV0[index]) + case 1: + return saio.OffsetV1[index] + default: + return 0 + } +} + +/*************************** saiz ****************************/ + +func BoxTypeSaiz() BoxType { return StrToBoxType("saiz") } + +func init() { + AddBoxDef(&Saiz{}, 0) +} + +type Saiz struct { + FullBox `mp4:"0,extend"` + AuxInfoType [4]byte `mp4:"1,size=8,opt=0x000001,string"` + AuxInfoTypeParameter uint32 `mp4:"2,size=32,opt=0x000001,hex"` + DefaultSampleInfoSize uint8 `mp4:"3,size=8,dec"` + SampleCount uint32 `mp4:"4,size=32"` + SampleInfoSize []uint8 `mp4:"5,size=8,opt=dynamic,len=dynamic,dec"` +} + +func (saiz *Saiz) IsOptFieldEnabled(name string, ctx Context) bool { + switch name { + case "SampleInfoSize": + return saiz.DefaultSampleInfoSize == 0 + } + return false +} + +func (saiz *Saiz) GetFieldLength(name string, ctx Context) uint { + switch name { + case "SampleInfoSize": + return uint(saiz.SampleCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=saiz fieldName=%s", name)) +} + +func (*Saiz) GetType() BoxType { + return BoxTypeSaiz() +} + +/*********************** SampleEntry *************************/ + +func BoxTypeAvc1() BoxType { return StrToBoxType("avc1") } +func BoxTypeEncv() BoxType { return StrToBoxType("encv") } +func BoxTypeHev1() BoxType { return StrToBoxType("hev1") } +func BoxTypeHvc1() BoxType { return StrToBoxType("hvc1") } +func BoxTypeMp4a() BoxType { return StrToBoxType("mp4a") } +func BoxTypeEnca() BoxType { return StrToBoxType("enca") } +func BoxTypeAvcC() BoxType { return StrToBoxType("avcC") } +func BoxTypePasp() BoxType { return StrToBoxType("pasp") } + +func init() { + AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeAvc1()) + AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeEncv()) + AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeHev1()) + AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeHvc1()) + AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeMp4a()) + AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeEnca()) + AddAnyTypeBoxDef(&AVCDecoderConfiguration{}, BoxTypeAvcC()) + AddAnyTypeBoxDef(&PixelAspectRatioBox{}, BoxTypePasp()) +} + +type SampleEntry struct { + AnyTypeBox + Reserved [6]uint8 `mp4:"0,size=8,const=0"` + DataReferenceIndex uint16 `mp4:"1,size=16"` +} + +type VisualSampleEntry struct { + SampleEntry `mp4:"0,extend"` + PreDefined uint16 `mp4:"1,size=16"` + Reserved uint16 `mp4:"2,size=16,const=0"` + PreDefined2 [3]uint32 `mp4:"3,size=32"` + Width uint16 `mp4:"4,size=16"` + Height uint16 `mp4:"5,size=16"` + Horizresolution uint32 `mp4:"6,size=32"` + Vertresolution uint32 `mp4:"7,size=32"` + Reserved2 uint32 `mp4:"8,size=32,const=0"` + FrameCount uint16 `mp4:"9,size=16"` + Compressorname [32]byte `mp4:"10,size=8"` + Depth uint16 `mp4:"11,size=16"` + PreDefined3 int16 `mp4:"12,size=16"` +} + +// StringifyField returns field value as string +func (vse *VisualSampleEntry) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "Compressorname": + if vse.Compressorname[0] <= 31 { + return `"` + util.EscapeUnprintables(string(vse.Compressorname[1:vse.Compressorname[0]+1])) + `"`, true + } + return "", false + default: + return "", false + } +} + +type AudioSampleEntry struct { + SampleEntry `mp4:"0,extend,opt=dynamic"` + EntryVersion uint16 `mp4:"1,size=16,opt=dynamic"` + Reserved [3]uint16 `mp4:"2,size=16,opt=dynamic,const=0"` + ChannelCount uint16 `mp4:"3,size=16,opt=dynamic"` + SampleSize uint16 `mp4:"4,size=16,opt=dynamic"` + PreDefined uint16 `mp4:"5,size=16,opt=dynamic"` + Reserved2 uint16 `mp4:"6,size=16,opt=dynamic,const=0"` + SampleRate uint32 `mp4:"7,size=32,opt=dynamic"` // fixed-point 16.16 + QuickTimeData []byte `mp4:"8,size=8,opt=dynamic,len=dynamic"` +} + +func (ase *AudioSampleEntry) IsOptFieldEnabled(name string, ctx Context) bool { + if name == "QuickTimeData" { + return ctx.IsQuickTimeCompatible && (ctx.UnderWave || ase.EntryVersion == 1 || ase.EntryVersion == 2) + } + if ctx.IsQuickTimeCompatible && ctx.UnderWave { + return false + } + return true +} + +func (ase *AudioSampleEntry) GetFieldLength(name string, ctx Context) uint { + if name == "QuickTimeData" && ctx.IsQuickTimeCompatible { + if ctx.UnderWave { + return LengthUnlimited + } else if ase.EntryVersion == 1 { + return 16 + } else if ase.EntryVersion == 2 { + return 36 + } + } + return 0 +} + +// StringifyField returns field value as string +func (ase *AudioSampleEntry) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "SampleRate": + return util.FormatUnsignedFixedFloat1616(ase.SampleRate), true + default: + return "", false + } +} + +func (ase *AudioSampleEntry) GetSampleRate() float64 { + return float64(ase.SampleRate) / (1 << 16) +} + +func (ase *AudioSampleEntry) GetSampleRateInt() uint16 { + return uint16(ase.SampleRate >> 16) +} + +const ( + AVCBaselineProfile uint8 = 66 // 0x42 + AVCMainProfile uint8 = 77 // 0x4d + AVCExtendedProfile uint8 = 88 // 0x58 + AVCHighProfile uint8 = 100 // 0x64 + AVCHigh10Profile uint8 = 110 // 0x6e + AVCHigh422Profile uint8 = 122 // 0x7a +) + +type AVCDecoderConfiguration struct { + AnyTypeBox + ConfigurationVersion uint8 `mp4:"0,size=8"` + Profile uint8 `mp4:"1,size=8"` + ProfileCompatibility uint8 `mp4:"2,size=8"` + Level uint8 `mp4:"3,size=8"` + Reserved uint8 `mp4:"4,size=6,const=63"` + LengthSizeMinusOne uint8 `mp4:"5,size=2"` + Reserved2 uint8 `mp4:"6,size=3,const=7"` + NumOfSequenceParameterSets uint8 `mp4:"7,size=5"` + SequenceParameterSets []AVCParameterSet `mp4:"8,len=dynamic"` + NumOfPictureParameterSets uint8 `mp4:"9,size=8"` + PictureParameterSets []AVCParameterSet `mp4:"10,len=dynamic"` + HighProfileFieldsEnabled bool `mp4:"11,hidden"` + Reserved3 uint8 `mp4:"12,size=6,opt=dynamic,const=63"` + ChromaFormat uint8 `mp4:"13,size=2,opt=dynamic"` + Reserved4 uint8 `mp4:"14,size=5,opt=dynamic,const=31"` + BitDepthLumaMinus8 uint8 `mp4:"15,size=3,opt=dynamic"` + Reserved5 uint8 `mp4:"16,size=5,opt=dynamic,const=31"` + BitDepthChromaMinus8 uint8 `mp4:"17,size=3,opt=dynamic"` + NumOfSequenceParameterSetExt uint8 `mp4:"18,size=8,opt=dynamic"` + SequenceParameterSetsExt []AVCParameterSet `mp4:"19,len=dynamic,opt=dynamic"` +} + +func (avcc *AVCDecoderConfiguration) GetFieldLength(name string, ctx Context) uint { + switch name { + case "SequenceParameterSets": + return uint(avcc.NumOfSequenceParameterSets) + case "PictureParameterSets": + return uint(avcc.NumOfPictureParameterSets) + case "SequenceParameterSetsExt": + return uint(avcc.NumOfSequenceParameterSetExt) + } + return 0 +} + +func (avcc *AVCDecoderConfiguration) IsOptFieldEnabled(name string, ctx Context) bool { + switch name { + case "Reserved3", + "ChromaFormat", + "Reserved4", + "BitDepthLumaMinus8", + "Reserved5", + "BitDepthChromaMinus8", + "NumOfSequenceParameterSetExt", + "SequenceParameterSetsExt": + return avcc.HighProfileFieldsEnabled + } + return false +} + +func (avcc *AVCDecoderConfiguration) OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) { + if name == "HighProfileFieldsEnabled" { + avcc.HighProfileFieldsEnabled = leftBits >= 32 && + (avcc.Profile == AVCHighProfile || + avcc.Profile == AVCHigh10Profile || + avcc.Profile == AVCHigh422Profile || + avcc.Profile == 144) + return 0, true, nil + } + return 0, false, nil +} + +func (avcc *AVCDecoderConfiguration) OnWriteField(name string, w bitio.Writer, ctx Context) (wbits uint64, override bool, err error) { + if name == "HighProfileFieldsEnabled" { + if avcc.HighProfileFieldsEnabled && + avcc.Profile != AVCHighProfile && + avcc.Profile != AVCHigh10Profile && + avcc.Profile != AVCHigh422Profile && + avcc.Profile != 144 { + return 0, false, errors.New("each values of Profile and HighProfileFieldsEnabled are inconsistent") + } + return 0, true, nil + } + return 0, false, nil +} + +type AVCParameterSet struct { + BaseCustomFieldObject + Length uint16 `mp4:"0,size=16"` + NALUnit []byte `mp4:"1,size=8,len=dynamic"` +} + +func (s *AVCParameterSet) GetFieldLength(name string, ctx Context) uint { + switch name { + case "NALUnit": + return uint(s.Length) + } + return 0 +} + +type PixelAspectRatioBox struct { + AnyTypeBox + HSpacing uint32 `mp4:"0,size=32"` + VSpacing uint32 `mp4:"1,size=32"` +} + +/*************************** sbgp ****************************/ + +func BoxTypeSbgp() BoxType { return StrToBoxType("sbgp") } + +func init() { + AddBoxDef(&Sbgp{}, 0, 1) +} + +type Sbgp struct { + FullBox `mp4:"0,extend"` + GroupingType uint32 `mp4:"1,size=32"` + GroupingTypeParameter uint32 `mp4:"2,size=32,ver=1"` + EntryCount uint32 `mp4:"3,size=32"` + Entries []SbgpEntry `mp4:"4,len=dynamic,size=64"` +} + +type SbgpEntry struct { + SampleCount uint32 `mp4:"0,size=32"` + GroupDescriptionIndex uint32 `mp4:"1,size=32"` +} + +func (sbgp *Sbgp) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(sbgp.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=sbgp fieldName=%s", name)) +} + +func (*Sbgp) GetType() BoxType { + return BoxTypeSbgp() +} + +/*************************** schi ****************************/ + +func BoxTypeSchi() BoxType { return StrToBoxType("schi") } + +func init() { + AddBoxDef(&Schi{}) +} + +type Schi struct { + Box +} + +func (*Schi) GetType() BoxType { + return BoxTypeSchi() +} + +/*************************** schm ****************************/ + +func BoxTypeSchm() BoxType { return StrToBoxType("schm") } + +func init() { + AddBoxDef(&Schm{}, 0) +} + +type Schm struct { + FullBox `mp4:"0,extend"` + SchemeType [4]byte `mp4:"1,size=8,string"` + SchemeVersion uint32 `mp4:"2,size=32,hex"` + SchemeUri []byte `mp4:"3,size=8,opt=0x000001,string"` +} + +func (*Schm) GetType() BoxType { + return BoxTypeSchm() +} + +/*************************** sdtp ****************************/ + +func BoxTypeSdtp() BoxType { return StrToBoxType("sdtp") } + +func init() { + AddBoxDef(&Sdtp{}, 0) +} + +type Sdtp struct { + FullBox `mp4:"0,extend"` + Samples []SdtpSampleElem `mp4:"1,size=8"` +} + +type SdtpSampleElem struct { + IsLeading uint8 `mp4:"0,size=2"` + SampleDependsOn uint8 `mp4:"1,size=2"` + SampleIsDependedOn uint8 `mp4:"2,size=2"` + SampleHasRedundancy uint8 `mp4:"3,size=2"` +} + +func (*Sdtp) GetType() BoxType { + return BoxTypeSdtp() +} + +/*************************** sgpd ****************************/ + +func BoxTypeSgpd() BoxType { return StrToBoxType("sgpd") } + +func init() { + AddBoxDef(&Sgpd{}, 1, 2) // version 0 is deprecated by ISO/IEC 14496-12 +} + +type Sgpd struct { + FullBox `mp4:"0,extend"` + GroupingType [4]byte `mp4:"1,size=8,string"` + DefaultLength uint32 `mp4:"2,size=32,ver=1"` + DefaultSampleDescriptionIndex uint32 `mp4:"3,size=32,ver=2"` + EntryCount uint32 `mp4:"4,size=32"` + RollDistances []int16 `mp4:"5,size=16,opt=dynamic"` + RollDistancesL []RollDistanceWithLength `mp4:"6,size=16,opt=dynamic"` + AlternativeStartupEntries []AlternativeStartupEntry `mp4:"7,size=dynamic,len=dynamic,opt=dynamic"` + AlternativeStartupEntriesL []AlternativeStartupEntryL `mp4:"8,len=dynamic,opt=dynamic"` + VisualRandomAccessEntries []VisualRandomAccessEntry `mp4:"9,len=dynamic,opt=dynamic"` + VisualRandomAccessEntriesL []VisualRandomAccessEntryL `mp4:"10,len=dynamic,opt=dynamic"` + TemporalLevelEntries []TemporalLevelEntry `mp4:"11,len=dynamic,opt=dynamic"` + TemporalLevelEntriesL []TemporalLevelEntryL `mp4:"12,len=dynamic,opt=dynamic"` + Unsupported []byte `mp4:"13,size=8,opt=dynamic"` +} + +type RollDistanceWithLength struct { + DescriptionLength uint32 `mp4:"0,size=32"` + RollDistance int16 `mp4:"1,size=16"` +} + +type AlternativeStartupEntry struct { + BaseCustomFieldObject + RollCount uint16 `mp4:"0,size=16"` + FirstOutputSample uint16 `mp4:"1,size=16"` + SampleOffset []uint32 `mp4:"2,size=32,len=dynamic"` + Opts []AlternativeStartupEntryOpt `mp4:"3,size=32"` +} + +type AlternativeStartupEntryL struct { + DescriptionLength uint32 `mp4:"0,size=32"` + AlternativeStartupEntry `mp4:"1,extend,size=dynamic"` +} + +type AlternativeStartupEntryOpt struct { + NumOutputSamples uint16 `mp4:"0,size=16"` + NumTotalSamples uint16 `mp4:"1,size=16"` +} + +type VisualRandomAccessEntry struct { + NumLeadingSamplesKnown bool `mp4:"0,size=1"` + NumLeadingSamples uint8 `mp4:"1,size=7"` +} + +type VisualRandomAccessEntryL struct { + DescriptionLength uint32 `mp4:"0,size=32"` + VisualRandomAccessEntry `mp4:"1,extend"` +} + +type TemporalLevelEntry struct { + LevelIndependentlyDecodable bool `mp4:"0,size=1"` + Reserved uint8 `mp4:"1,size=7,const=0"` +} + +type TemporalLevelEntryL struct { + DescriptionLength uint32 `mp4:"0,size=32"` + TemporalLevelEntry `mp4:"1,extend"` +} + +func (sgpd *Sgpd) GetFieldSize(name string, ctx Context) uint { + switch name { + case "AlternativeStartupEntries": + return uint(sgpd.DefaultLength * 8) + } + return 0 +} + +func (sgpd *Sgpd) GetFieldLength(name string, ctx Context) uint { + switch name { + case "RollDistances", "RollDistancesL", + "AlternativeStartupEntries", "AlternativeStartupEntriesL", + "VisualRandomAccessEntries", "VisualRandomAccessEntriesL", + "TemporalLevelEntries", "TemporalLevelEntriesL": + return uint(sgpd.EntryCount) + } + return 0 +} + +func (sgpd *Sgpd) IsOptFieldEnabled(name string, ctx Context) bool { + noDefaultLength := sgpd.Version == 1 && sgpd.DefaultLength == 0 + rollDistances := sgpd.GroupingType == [4]byte{'r', 'o', 'l', 'l'} || + sgpd.GroupingType == [4]byte{'p', 'r', 'o', 'l'} + alternativeStartupEntries := sgpd.GroupingType == [4]byte{'a', 'l', 's', 't'} + visualRandomAccessEntries := sgpd.GroupingType == [4]byte{'r', 'a', 'p', ' '} + temporalLevelEntries := sgpd.GroupingType == [4]byte{'t', 'e', 'l', 'e'} + switch name { + case "RollDistances": + return rollDistances && !noDefaultLength + case "RollDistancesL": + return rollDistances && noDefaultLength + case "AlternativeStartupEntries": + return alternativeStartupEntries && !noDefaultLength + case "AlternativeStartupEntriesL": + return alternativeStartupEntries && noDefaultLength + case "VisualRandomAccessEntries": + return visualRandomAccessEntries && !noDefaultLength + case "VisualRandomAccessEntriesL": + return visualRandomAccessEntries && noDefaultLength + case "TemporalLevelEntries": + return temporalLevelEntries && !noDefaultLength + case "TemporalLevelEntriesL": + return temporalLevelEntries && noDefaultLength + case "Unsupported": + return !rollDistances && + !alternativeStartupEntries && + !visualRandomAccessEntries && + !temporalLevelEntries + default: + return false + } +} + +func (*Sgpd) GetType() BoxType { + return BoxTypeSgpd() +} + +func (entry *AlternativeStartupEntry) GetFieldLength(name string, ctx Context) uint { + switch name { + case "SampleOffset": + return uint(entry.RollCount) + } + return 0 +} + +func (entry *AlternativeStartupEntryL) GetFieldSize(name string, ctx Context) uint { + switch name { + case "AlternativeStartupEntry": + return uint(entry.DescriptionLength * 8) + } + return 0 +} + +/*************************** sidx ****************************/ + +func BoxTypeSidx() BoxType { return StrToBoxType("sidx") } + +func init() { + AddBoxDef(&Sidx{}, 0, 1) +} + +type Sidx struct { + FullBox `mp4:"0,extend"` + ReferenceID uint32 `mp4:"1,size=32"` + Timescale uint32 `mp4:"2,size=32"` + EarliestPresentationTimeV0 uint32 `mp4:"3,size=32,ver=0"` + FirstOffsetV0 uint32 `mp4:"4,size=32,ver=0"` + EarliestPresentationTimeV1 uint64 `mp4:"5,size=64,nver=0"` + FirstOffsetV1 uint64 `mp4:"6,size=64,nver=0"` + Reserved uint16 `mp4:"7,size=16,const=0"` + ReferenceCount uint16 `mp4:"8,size=16"` + References []SidxReference `mp4:"9,size=96,len=dynamic"` +} + +type SidxReference struct { + ReferenceType bool `mp4:"0,size=1"` + ReferencedSize uint32 `mp4:"1,size=31"` + SubsegmentDuration uint32 `mp4:"2,size=32"` + StartsWithSAP bool `mp4:"3,size=1"` + SAPType uint32 `mp4:"4,size=3"` + SAPDeltaTime uint32 `mp4:"5,size=28"` +} + +func (*Sidx) GetType() BoxType { + return BoxTypeSidx() +} + +func (sidx *Sidx) GetFieldLength(name string, ctx Context) uint { + switch name { + case "References": + return uint(sidx.ReferenceCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=sidx fieldName=%s", name)) +} + +func (sidx *Sidx) GetEarliestPresentationTime() uint64 { + switch sidx.GetVersion() { + case 0: + return uint64(sidx.EarliestPresentationTimeV0) + case 1: + return sidx.EarliestPresentationTimeV1 + default: + return 0 + } +} + +func (sidx *Sidx) GetFirstOffset() uint64 { + switch sidx.GetVersion() { + case 0: + return uint64(sidx.FirstOffsetV0) + case 1: + return sidx.FirstOffsetV1 + default: + return 0 + } +} + +/*************************** sinf ****************************/ + +func BoxTypeSinf() BoxType { return StrToBoxType("sinf") } + +func init() { + AddBoxDef(&Sinf{}) +} + +type Sinf struct { + Box +} + +func (*Sinf) GetType() BoxType { + return BoxTypeSinf() +} + +/*************************** smhd ****************************/ + +func BoxTypeSmhd() BoxType { return StrToBoxType("smhd") } + +func init() { + AddBoxDef(&Smhd{}, 0) +} + +type Smhd struct { + FullBox `mp4:"0,extend"` + Balance int16 `mp4:"1,size=16"` // fixed-point 8.8 template=0 + Reserved uint16 `mp4:"2,size=16,const=0"` +} + +func (*Smhd) GetType() BoxType { + return BoxTypeSmhd() +} + +// StringifyField returns field value as string +func (smhd *Smhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "Balance": + return util.FormatSignedFixedFloat88(smhd.Balance), true + default: + return "", false + } +} + +// GetBalance returns value of width as float32 +func (smhd *Smhd) GetBalance() float32 { + return float32(smhd.Balance) / (1 << 8) +} + +// GetBalanceInt returns value of width as int8 +func (smhd *Smhd) GetBalanceInt() int8 { + return int8(smhd.Balance >> 8) +} + +/*************************** stbl ****************************/ + +func BoxTypeStbl() BoxType { return StrToBoxType("stbl") } + +func init() { + AddBoxDef(&Stbl{}) +} + +// Stbl is ISOBMFF stbl box type +type Stbl struct { + Box +} + +// GetType returns the BoxType +func (*Stbl) GetType() BoxType { + return BoxTypeStbl() +} + +/*************************** stco ****************************/ + +func BoxTypeStco() BoxType { return StrToBoxType("stco") } + +func init() { + AddBoxDef(&Stco{}, 0) +} + +// Stco is ISOBMFF stco box type +type Stco struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + ChunkOffset []uint32 `mp4:"2,size=32,len=dynamic"` +} + +// GetType returns the BoxType +func (*Stco) GetType() BoxType { + return BoxTypeStco() +} + +// GetFieldLength returns length of dynamic field +func (stco *Stco) GetFieldLength(name string, ctx Context) uint { + switch name { + case "ChunkOffset": + return uint(stco.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stco fieldName=%s", name)) +} + +/*************************** stsc ****************************/ + +func BoxTypeStsc() BoxType { return StrToBoxType("stsc") } + +func init() { + AddBoxDef(&Stsc{}, 0) +} + +// Stsc is ISOBMFF stsc box type +type Stsc struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + Entries []StscEntry `mp4:"2,len=dynamic,size=96"` +} + +type StscEntry struct { + FirstChunk uint32 `mp4:"0,size=32"` + SamplesPerChunk uint32 `mp4:"1,size=32"` + SampleDescriptionIndex uint32 `mp4:"2,size=32"` +} + +// GetType returns the BoxType +func (*Stsc) GetType() BoxType { + return BoxTypeStsc() +} + +// GetFieldLength returns length of dynamic field +func (stsc *Stsc) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(stsc.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stsc fieldName=%s", name)) +} + +/*************************** stsd ****************************/ + +func BoxTypeStsd() BoxType { return StrToBoxType("stsd") } + +func init() { + AddBoxDef(&Stsd{}, 0) +} + +// Stsd is ISOBMFF stsd box type +type Stsd struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Stsd) GetType() BoxType { + return BoxTypeStsd() +} + +/*************************** stss ****************************/ + +func BoxTypeStss() BoxType { return StrToBoxType("stss") } + +func init() { + AddBoxDef(&Stss{}, 0) +} + +type Stss struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + SampleNumber []uint32 `mp4:"2,len=dynamic,size=32"` +} + +// GetType returns the BoxType +func (*Stss) GetType() BoxType { + return BoxTypeStss() +} + +// GetFieldLength returns length of dynamic field +func (stss *Stss) GetFieldLength(name string, ctx Context) uint { + switch name { + case "SampleNumber": + return uint(stss.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stss fieldName=%s", name)) +} + +/*************************** stsz ****************************/ + +func BoxTypeStsz() BoxType { return StrToBoxType("stsz") } + +func init() { + AddBoxDef(&Stsz{}, 0) +} + +// Stsz is ISOBMFF stsz box type +type Stsz struct { + FullBox `mp4:"0,extend"` + SampleSize uint32 `mp4:"1,size=32"` + SampleCount uint32 `mp4:"2,size=32"` + EntrySize []uint32 `mp4:"3,size=32,len=dynamic"` +} + +// GetType returns the BoxType +func (*Stsz) GetType() BoxType { + return BoxTypeStsz() +} + +// GetFieldLength returns length of dynamic field +func (stsz *Stsz) GetFieldLength(name string, ctx Context) uint { + switch name { + case "EntrySize": + if stsz.SampleSize == 0 { + return uint(stsz.SampleCount) + } + return 0 + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stsz fieldName=%s", name)) +} + +/*************************** stts ****************************/ + +func BoxTypeStts() BoxType { return StrToBoxType("stts") } + +func init() { + AddBoxDef(&Stts{}, 0) +} + +// Stts is ISOBMFF stts box type +type Stts struct { + FullBox `mp4:"0,extend"` + EntryCount uint32 `mp4:"1,size=32"` + Entries []SttsEntry `mp4:"2,len=dynamic,size=64"` +} + +type SttsEntry struct { + SampleCount uint32 `mp4:"0,size=32"` + SampleDelta uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Stts) GetType() BoxType { + return BoxTypeStts() +} + +// GetFieldLength returns length of dynamic field +func (stts *Stts) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(stts.EntryCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=stts fieldName=%s", name)) +} + +/*************************** styp ****************************/ + +func BoxTypeStyp() BoxType { return StrToBoxType("styp") } + +func init() { + AddBoxDef(&Styp{}) +} + +type Styp struct { + Box + MajorBrand [4]byte `mp4:"0,size=8,string"` + MinorVersion uint32 `mp4:"1,size=32"` + CompatibleBrands []CompatibleBrandElem `mp4:"2,size=32"` // reach to end of the box +} + +func (*Styp) GetType() BoxType { + return BoxTypeStyp() +} + +/*************************** tfdt ****************************/ + +func BoxTypeTfdt() BoxType { return StrToBoxType("tfdt") } + +func init() { + AddBoxDef(&Tfdt{}, 0, 1) +} + +// Tfdt is ISOBMFF tfdt box type +type Tfdt struct { + FullBox `mp4:"0,extend"` + BaseMediaDecodeTimeV0 uint32 `mp4:"1,size=32,ver=0"` + BaseMediaDecodeTimeV1 uint64 `mp4:"2,size=64,ver=1"` +} + +// GetType returns the BoxType +func (*Tfdt) GetType() BoxType { + return BoxTypeTfdt() +} + +func (tfdt *Tfdt) GetBaseMediaDecodeTime() uint64 { + switch tfdt.GetVersion() { + case 0: + return uint64(tfdt.BaseMediaDecodeTimeV0) + case 1: + return tfdt.BaseMediaDecodeTimeV1 + default: + return 0 + } +} + +/*************************** tfhd ****************************/ + +func BoxTypeTfhd() BoxType { return StrToBoxType("tfhd") } + +func init() { + AddBoxDef(&Tfhd{}, 0) +} + +// Tfhd is ISOBMFF tfhd box type +type Tfhd struct { + FullBox `mp4:"0,extend"` + TrackID uint32 `mp4:"1,size=32"` + + // optional + BaseDataOffset uint64 `mp4:"2,size=64,opt=0x000001"` + SampleDescriptionIndex uint32 `mp4:"3,size=32,opt=0x000002"` + DefaultSampleDuration uint32 `mp4:"4,size=32,opt=0x000008"` + DefaultSampleSize uint32 `mp4:"5,size=32,opt=0x000010"` + DefaultSampleFlags uint32 `mp4:"6,size=32,opt=0x000020,hex"` +} + +const ( + TfhdBaseDataOffsetPresent = 0x000001 + TfhdSampleDescriptionIndexPresent = 0x000002 + TfhdDefaultSampleDurationPresent = 0x000008 + TfhdDefaultSampleSizePresent = 0x000010 + TfhdDefaultSampleFlagsPresent = 0x000020 + TfhdDurationIsEmpty = 0x010000 + TfhdDefaultBaseIsMoof = 0x020000 +) + +// GetType returns the BoxType +func (*Tfhd) GetType() BoxType { + return BoxTypeTfhd() +} + +/*************************** tfra ****************************/ + +func BoxTypeTfra() BoxType { return StrToBoxType("tfra") } + +func init() { + AddBoxDef(&Tfra{}, 0, 1) +} + +// Tfra is ISOBMFF tfra box type +type Tfra struct { + FullBox `mp4:"0,extend"` + TrackID uint32 `mp4:"1,size=32"` + Reserved uint32 `mp4:"2,size=26,const=0"` + LengthSizeOfTrafNum byte `mp4:"3,size=2"` + LengthSizeOfTrunNum byte `mp4:"4,size=2"` + LengthSizeOfSampleNum byte `mp4:"5,size=2"` + NumberOfEntry uint32 `mp4:"6,size=32"` + Entries []TfraEntry `mp4:"7,len=dynamic,size=dynamic"` +} + +type TfraEntry struct { + TimeV0 uint32 `mp4:"0,size=32,ver=0"` + MoofOffsetV0 uint32 `mp4:"1,size=32,ver=0"` + TimeV1 uint64 `mp4:"2,size=64,ver=1"` + MoofOffsetV1 uint64 `mp4:"3,size=64,ver=1"` + TrafNumber uint32 `mp4:"4,size=dynamic"` + TrunNumber uint32 `mp4:"5,size=dynamic"` + SampleNumber uint32 `mp4:"6,size=dynamic"` +} + +// GetType returns the BoxType +func (*Tfra) GetType() BoxType { + return BoxTypeTfra() +} + +// GetFieldSize returns size of dynamic field +func (tfra *Tfra) GetFieldSize(name string, ctx Context) uint { + switch name { + case "TrafNumber": + return (uint(tfra.LengthSizeOfTrafNum) + 1) * 8 + case "TrunNumber": + return (uint(tfra.LengthSizeOfTrunNum) + 1) * 8 + case "SampleNumber": + return (uint(tfra.LengthSizeOfSampleNum) + 1) * 8 + case "Entries": + switch tfra.GetVersion() { + case 0: + return 0 + + /* TimeV0 */ 32 + + /* MoofOffsetV0 */ 32 + + /* TrafNumber */ (uint(tfra.LengthSizeOfTrafNum)+1)*8 + + /* TrunNumber */ (uint(tfra.LengthSizeOfTrunNum)+1)*8 + + /* SampleNumber */ (uint(tfra.LengthSizeOfSampleNum)+1)*8 + case 1: + return 0 + + /* TimeV1 */ 64 + + /* MoofOffsetV1 */ 64 + + /* TrafNumber */ (uint(tfra.LengthSizeOfTrafNum)+1)*8 + + /* TrunNumber */ (uint(tfra.LengthSizeOfTrunNum)+1)*8 + + /* SampleNumber */ (uint(tfra.LengthSizeOfSampleNum)+1)*8 + } + } + panic(fmt.Errorf("invalid name of dynamic-size field: boxType=tfra fieldName=%s", name)) +} + +// GetFieldLength returns length of dynamic field +func (tfra *Tfra) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(tfra.NumberOfEntry) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=tfra fieldName=%s", name)) +} + +func (tfra *Tfra) GetTime(index int) uint64 { + switch tfra.GetVersion() { + case 0: + return uint64(tfra.Entries[index].TimeV0) + case 1: + return tfra.Entries[index].TimeV1 + default: + return 0 + } +} + +func (tfra *Tfra) GetMoofOffset(index int) uint64 { + switch tfra.GetVersion() { + case 0: + return uint64(tfra.Entries[index].MoofOffsetV0) + case 1: + return tfra.Entries[index].MoofOffsetV1 + default: + return 0 + } +} + +/*************************** tkhd ****************************/ + +func BoxTypeTkhd() BoxType { return StrToBoxType("tkhd") } + +func init() { + AddBoxDef(&Tkhd{}, 0, 1) +} + +// Tkhd is ISOBMFF tkhd box type +type Tkhd struct { + FullBox `mp4:"0,extend"` + CreationTimeV0 uint32 `mp4:"1,size=32,ver=0"` + ModificationTimeV0 uint32 `mp4:"2,size=32,ver=0"` + CreationTimeV1 uint64 `mp4:"3,size=64,ver=1"` + ModificationTimeV1 uint64 `mp4:"4,size=64,ver=1"` + TrackID uint32 `mp4:"5,size=32"` + Reserved0 uint32 `mp4:"6,size=32,const=0"` + DurationV0 uint32 `mp4:"7,size=32,ver=0"` + DurationV1 uint64 `mp4:"8,size=64,ver=1"` + // + Reserved1 [2]uint32 `mp4:"9,size=32,const=0"` + Layer int16 `mp4:"10,size=16"` // template=0 + AlternateGroup int16 `mp4:"11,size=16"` // template=0 + Volume int16 `mp4:"12,size=16"` // template={if track_is_audio 0x0100 else 0} + Reserved2 uint16 `mp4:"13,size=16,const=0"` + Matrix [9]int32 `mp4:"14,size=32,hex"` // template={ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 }; + Width uint32 `mp4:"15,size=32"` // fixed-point 16.16 + Height uint32 `mp4:"16,size=32"` // fixed-point 16.16 +} + +// GetType returns the BoxType +func (*Tkhd) GetType() BoxType { + return BoxTypeTkhd() +} + +// StringifyField returns field value as string +func (tkhd *Tkhd) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "Width": + return util.FormatUnsignedFixedFloat1616(tkhd.Width), true + case "Height": + return util.FormatUnsignedFixedFloat1616(tkhd.Height), true + default: + return "", false + } +} + +func (tkhd *Tkhd) GetCreationTime() uint64 { + switch tkhd.GetVersion() { + case 0: + return uint64(tkhd.CreationTimeV0) + case 1: + return tkhd.CreationTimeV1 + default: + return 0 + } +} + +func (tkhd *Tkhd) GetModificationTime() uint64 { + switch tkhd.GetVersion() { + case 0: + return uint64(tkhd.ModificationTimeV0) + case 1: + return tkhd.ModificationTimeV1 + default: + return 0 + } +} + +func (tkhd *Tkhd) GetDuration() uint64 { + switch tkhd.GetVersion() { + case 0: + return uint64(tkhd.DurationV0) + case 1: + return tkhd.DurationV1 + default: + return 0 + } +} + +// GetWidth returns value of width as float64 +func (tkhd *Tkhd) GetWidth() float64 { + return float64(tkhd.Width) / (1 << 16) +} + +// GetWidthInt returns value of width as uint16 +func (tkhd *Tkhd) GetWidthInt() uint16 { + return uint16(tkhd.Width >> 16) +} + +// GetHeight returns value of height as float64 +func (tkhd *Tkhd) GetHeight() float64 { + return float64(tkhd.Height) / (1 << 16) +} + +// GetHeightInt returns value of height as uint16 +func (tkhd *Tkhd) GetHeightInt() uint16 { + return uint16(tkhd.Height >> 16) +} + +/*************************** traf ****************************/ + +func BoxTypeTraf() BoxType { return StrToBoxType("traf") } + +func init() { + AddBoxDef(&Traf{}) +} + +// Traf is ISOBMFF traf box type +type Traf struct { + Box +} + +// GetType returns the BoxType +func (*Traf) GetType() BoxType { + return BoxTypeTraf() +} + +/*************************** trak ****************************/ + +func BoxTypeTrak() BoxType { return StrToBoxType("trak") } + +func init() { + AddBoxDef(&Trak{}) +} + +// Trak is ISOBMFF trak box type +type Trak struct { + Box +} + +// GetType returns the BoxType +func (*Trak) GetType() BoxType { + return BoxTypeTrak() +} + +/*************************** trep ****************************/ + +func BoxTypeTrep() BoxType { return StrToBoxType("trep") } + +func init() { + AddBoxDef(&Trep{}, 0) +} + +// Trep is ISOBMFF trep box type +type Trep struct { + FullBox `mp4:"0,extend"` + TrackID uint32 `mp4:"1,size=32"` +} + +// GetType returns the BoxType +func (*Trep) GetType() BoxType { + return BoxTypeTrep() +} + +/*************************** trex ****************************/ + +func BoxTypeTrex() BoxType { return StrToBoxType("trex") } + +func init() { + AddBoxDef(&Trex{}, 0) +} + +// Trex is ISOBMFF trex box type +type Trex struct { + FullBox `mp4:"0,extend"` + TrackID uint32 `mp4:"1,size=32"` + DefaultSampleDescriptionIndex uint32 `mp4:"2,size=32"` + DefaultSampleDuration uint32 `mp4:"3,size=32"` + DefaultSampleSize uint32 `mp4:"4,size=32"` + DefaultSampleFlags uint32 `mp4:"5,size=32,hex"` +} + +// GetType returns the BoxType +func (*Trex) GetType() BoxType { + return BoxTypeTrex() +} + +/*************************** trun ****************************/ + +func BoxTypeTrun() BoxType { return StrToBoxType("trun") } + +func init() { + AddBoxDef(&Trun{}, 0, 1) +} + +// Trun is ISOBMFF trun box type +type Trun struct { + FullBox `mp4:"0,extend"` + SampleCount uint32 `mp4:"1,size=32"` + + // optional fields + DataOffset int32 `mp4:"2,size=32,opt=0x000001"` + FirstSampleFlags uint32 `mp4:"3,size=32,opt=0x000004,hex"` + Entries []TrunEntry `mp4:"4,len=dynamic,size=dynamic"` +} + +type TrunEntry struct { + SampleDuration uint32 `mp4:"0,size=32,opt=0x000100"` + SampleSize uint32 `mp4:"1,size=32,opt=0x000200"` + SampleFlags uint32 `mp4:"2,size=32,opt=0x000400,hex"` + SampleCompositionTimeOffsetV0 uint32 `mp4:"3,size=32,opt=0x000800,ver=0"` + SampleCompositionTimeOffsetV1 int32 `mp4:"4,size=32,opt=0x000800,nver=0"` +} + +// GetType returns the BoxType +func (*Trun) GetType() BoxType { + return BoxTypeTrun() +} + +// GetFieldSize returns size of dynamic field +func (trun *Trun) GetFieldSize(name string, ctx Context) uint { + switch name { + case "Entries": + var size uint + flags := trun.GetFlags() + if flags&0x100 != 0 { + size += 32 // SampleDuration + } + if flags&0x200 != 0 { + size += 32 // SampleSize + } + if flags&0x400 != 0 { + size += 32 // SampleFlags + } + if flags&0x800 != 0 { + size += 32 // SampleCompositionTimeOffsetV0 or V1 + } + return size + } + panic(fmt.Errorf("invalid name of dynamic-size field: boxType=trun fieldName=%s", name)) +} + +// GetFieldLength returns length of dynamic field +func (trun *Trun) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Entries": + return uint(trun.SampleCount) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=trun fieldName=%s", name)) +} + +func (trun *Trun) GetSampleCompositionTimeOffset(index int) int64 { + switch trun.GetVersion() { + case 0: + return int64(trun.Entries[index].SampleCompositionTimeOffsetV0) + case 1: + return int64(trun.Entries[index].SampleCompositionTimeOffsetV1) + default: + return 0 + } +} + +/*************************** udta ****************************/ + +func BoxTypeUdta() BoxType { return StrToBoxType("udta") } + +func init() { + AddBoxDef(&Udta{}) +} + +// Udta is ISOBMFF udta box type +type Udta struct { + Box +} + +// GetType returns the BoxType +func (*Udta) GetType() BoxType { + return BoxTypeUdta() +} + +func isUnderUdta(ctx Context) bool { + return ctx.UnderUdta +} + +/*************************** vmhd ****************************/ + +func BoxTypeVmhd() BoxType { return StrToBoxType("vmhd") } + +func init() { + AddBoxDef(&Vmhd{}, 0) +} + +// Vmhd is ISOBMFF vmhd box type +type Vmhd struct { + FullBox `mp4:"0,extend"` + Graphicsmode uint16 `mp4:"1,size=16"` // template=0 + Opcolor [3]uint16 `mp4:"2,size=16"` // template={0, 0, 0} +} + +// GetType returns the BoxType +func (*Vmhd) GetType() BoxType { + return BoxTypeVmhd() +} + +/*************************** wave ****************************/ + +func BoxTypeWave() BoxType { return StrToBoxType("wave") } + +func init() { + AddBoxDef(&Wave{}) +} + +// Wave is QuickTime wave box +type Wave struct { + Box +} + +// GetType returns the BoxType +func (*Wave) GetType() BoxType { + return BoxTypeWave() +} diff --git a/vendor/github.com/abema/go-mp4/box_types_iso14496_14.go b/vendor/github.com/abema/go-mp4/box_types_iso14496_14.go new file mode 100644 index 000000000..fe9880ca0 --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_iso14496_14.go @@ -0,0 +1,126 @@ +package mp4 + +import "fmt" + +/*************************** esds ****************************/ + +// https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html + +func BoxTypeEsds() BoxType { return StrToBoxType("esds") } + +func init() { + AddBoxDef(&Esds{}, 0) +} + +const ( + ESDescrTag = 0x03 + DecoderConfigDescrTag = 0x04 + DecSpecificInfoTag = 0x05 + SLConfigDescrTag = 0x06 +) + +// Esds is ES descripter box +type Esds struct { + FullBox `mp4:"0,extend"` + Descriptors []Descriptor `mp4:"1,array"` +} + +// GetType returns the BoxType +func (*Esds) GetType() BoxType { + return BoxTypeEsds() +} + +type Descriptor struct { + BaseCustomFieldObject + Tag int8 `mp4:"0,size=8"` // must be 0x03 + Size uint32 `mp4:"1,varint"` + ESDescriptor *ESDescriptor `mp4:"2,extend,opt=dynamic"` + DecoderConfigDescriptor *DecoderConfigDescriptor `mp4:"3,extend,opt=dynamic"` + Data []byte `mp4:"4,size=8,opt=dynamic,len=dynamic"` +} + +// GetFieldLength returns length of dynamic field +func (ds *Descriptor) GetFieldLength(name string, ctx Context) uint { + switch name { + case "Data": + return uint(ds.Size) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=esds fieldName=%s", name)) +} + +func (ds *Descriptor) IsOptFieldEnabled(name string, ctx Context) bool { + switch ds.Tag { + case ESDescrTag: + return name == "ESDescriptor" + case DecoderConfigDescrTag: + return name == "DecoderConfigDescriptor" + default: + return name == "Data" + } +} + +// StringifyField returns field value as string +func (ds *Descriptor) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "Tag": + switch ds.Tag { + case ESDescrTag: + return "ESDescr", true + case DecoderConfigDescrTag: + return "DecoderConfigDescr", true + case DecSpecificInfoTag: + return "DecSpecificInfo", true + case SLConfigDescrTag: + return "SLConfigDescr", true + default: + return "", false + } + default: + return "", false + } +} + +type ESDescriptor struct { + BaseCustomFieldObject + ESID uint16 `mp4:"0,size=16"` + StreamDependenceFlag bool `mp4:"1,size=1"` + UrlFlag bool `mp4:"2,size=1"` + OcrStreamFlag bool `mp4:"3,size=1"` + StreamPriority int8 `mp4:"4,size=5"` + DependsOnESID uint16 `mp4:"5,size=16,opt=dynamic"` + URLLength uint8 `mp4:"6,size=8,opt=dynamic"` + URLString []byte `mp4:"7,size=8,len=dynamic,opt=dynamic,string"` + OCRESID uint16 `mp4:"8,size=16,opt=dynamic"` +} + +func (esds *ESDescriptor) GetFieldLength(name string, ctx Context) uint { + switch name { + case "URLString": + return uint(esds.URLLength) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=ESDescriptor fieldName=%s", name)) +} + +func (esds *ESDescriptor) IsOptFieldEnabled(name string, ctx Context) bool { + switch name { + case "DependsOnESID": + return esds.StreamDependenceFlag + case "URLLength", "URLString": + return esds.UrlFlag + case "OCRESID": + return esds.OcrStreamFlag + default: + return false + } +} + +type DecoderConfigDescriptor struct { + BaseCustomFieldObject + ObjectTypeIndication byte `mp4:"0,size=8"` + StreamType int8 `mp4:"1,size=6"` + UpStream bool `mp4:"2,size=1"` + Reserved bool `mp4:"3,size=1"` + BufferSizeDB uint32 `mp4:"4,size=24"` + MaxBitrate uint32 `mp4:"5,size=32"` + AvgBitrate uint32 `mp4:"6,size=32"` +} diff --git a/vendor/github.com/abema/go-mp4/box_types_iso23001_7.go b/vendor/github.com/abema/go-mp4/box_types_iso23001_7.go new file mode 100644 index 000000000..766c348b0 --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_iso23001_7.go @@ -0,0 +1,108 @@ +package mp4 + +import ( + "bytes" + "fmt" + + "github.com/google/uuid" +) + +/*************************** pssh ****************************/ + +func BoxTypePssh() BoxType { return StrToBoxType("pssh") } + +func init() { + AddBoxDef(&Pssh{}, 0, 1) +} + +// Pssh is ISOBMFF pssh box type +type Pssh struct { + FullBox `mp4:"0,extend"` + SystemID [16]byte `mp4:"1,size=8,uuid"` + KIDCount uint32 `mp4:"2,size=32,nver=0"` + KIDs []PsshKID `mp4:"3,nver=0,len=dynamic,size=128"` + DataSize int32 `mp4:"4,size=32"` + Data []byte `mp4:"5,size=8,len=dynamic"` +} + +type PsshKID struct { + KID [16]byte `mp4:"0,size=8,uuid"` +} + +// GetFieldLength returns length of dynamic field +func (pssh *Pssh) GetFieldLength(name string, ctx Context) uint { + switch name { + case "KIDs": + return uint(pssh.KIDCount) + case "Data": + return uint(pssh.DataSize) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=pssh fieldName=%s", name)) +} + +// StringifyField returns field value as string +func (pssh *Pssh) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "KIDs": + buf := bytes.NewBuffer(nil) + buf.WriteString("[") + for i, e := range pssh.KIDs { + if i != 0 { + buf.WriteString(", ") + } + buf.WriteString(uuid.UUID(e.KID).String()) + } + buf.WriteString("]") + return buf.String(), true + + default: + return "", false + } +} + +// GetType returns the BoxType +func (*Pssh) GetType() BoxType { + return BoxTypePssh() +} + +/*************************** tenc ****************************/ + +func BoxTypeTenc() BoxType { return StrToBoxType("tenc") } + +func init() { + AddBoxDef(&Tenc{}, 0, 1) +} + +// Tenc is ISOBMFF tenc box type +type Tenc struct { + FullBox `mp4:"0,extend"` + Reserved uint8 `mp4:"1,size=8,dec"` + DefaultCryptByteBlock uint8 `mp4:"2,size=4,dec"` // always 0 on version 0 + DefaultSkipByteBlock uint8 `mp4:"3,size=4,dec"` // always 0 on version 0 + DefaultIsProtected uint8 `mp4:"4,size=8,dec"` + DefaultPerSampleIVSize uint8 `mp4:"5,size=8,dec"` + DefaultKID [16]byte `mp4:"6,size=8,uuid"` + DefaultConstantIVSize uint8 `mp4:"7,size=8,opt=dynamic,dec"` + DefaultConstantIV []byte `mp4:"8,size=8,opt=dynamic,len=dynamic"` +} + +func (tenc *Tenc) IsOptFieldEnabled(name string, ctx Context) bool { + switch name { + case "DefaultConstantIVSize", "DefaultConstantIV": + return tenc.DefaultIsProtected == 1 && tenc.DefaultPerSampleIVSize == 0 + } + return false +} + +func (tenc *Tenc) GetFieldLength(name string, ctx Context) uint { + switch name { + case "DefaultConstantIV": + return uint(tenc.DefaultConstantIVSize) + } + panic(fmt.Errorf("invalid name of dynamic-length field: boxType=tenc fieldName=%s", name)) +} + +// GetType returns the BoxType +func (*Tenc) GetType() BoxType { + return BoxTypeTenc() +} diff --git a/vendor/github.com/abema/go-mp4/box_types_metadata.go b/vendor/github.com/abema/go-mp4/box_types_metadata.go new file mode 100644 index 000000000..a56145e99 --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_metadata.go @@ -0,0 +1,172 @@ +package mp4 + +import ( + "fmt" + + "github.com/abema/go-mp4/util" +) + +/*************************** ilst ****************************/ + +func BoxTypeIlst() BoxType { return StrToBoxType("ilst") } +func BoxTypeData() BoxType { return StrToBoxType("data") } + +var ilstMetaBoxTypes = []BoxType{ + StrToBoxType("----"), + StrToBoxType("aART"), + StrToBoxType("akID"), + StrToBoxType("apID"), + StrToBoxType("atID"), + StrToBoxType("cmID"), + StrToBoxType("cnID"), + StrToBoxType("covr"), + StrToBoxType("cpil"), + StrToBoxType("cprt"), + StrToBoxType("desc"), + StrToBoxType("disk"), + StrToBoxType("egid"), + StrToBoxType("geID"), + StrToBoxType("gnre"), + StrToBoxType("pcst"), + StrToBoxType("pgap"), + StrToBoxType("plID"), + StrToBoxType("purd"), + StrToBoxType("purl"), + StrToBoxType("rtng"), + StrToBoxType("sfID"), + StrToBoxType("soaa"), + StrToBoxType("soal"), + StrToBoxType("soar"), + StrToBoxType("soco"), + StrToBoxType("sonm"), + StrToBoxType("sosn"), + StrToBoxType("stik"), + StrToBoxType("tmpo"), + StrToBoxType("trkn"), + StrToBoxType("tven"), + StrToBoxType("tves"), + StrToBoxType("tvnn"), + StrToBoxType("tvsh"), + StrToBoxType("tvsn"), + {0xA9, 'A', 'R', 'T'}, + {0xA9, 'a', 'l', 'b'}, + {0xA9, 'c', 'm', 't'}, + {0xA9, 'c', 'o', 'm'}, + {0xA9, 'd', 'a', 'y'}, + {0xA9, 'g', 'e', 'n'}, + {0xA9, 'g', 'r', 'p'}, + {0xA9, 'n', 'a', 'm'}, + {0xA9, 't', 'o', 'o'}, + {0xA9, 'w', 'r', 't'}, +} + +func IsIlstMetaBoxType(boxType BoxType) bool { + for _, bt := range ilstMetaBoxTypes { + if boxType == bt { + return true + } + } + return false +} + +func init() { + AddBoxDef(&Ilst{}) + AddBoxDefEx(&Data{}, isUnderIlstMeta) + for _, bt := range ilstMetaBoxTypes { + AddAnyTypeBoxDefEx(&IlstMetaContainer{}, bt, isIlstMetaContainer) + } + AddAnyTypeBoxDefEx(&StringData{}, StrToBoxType("mean"), isUnderIlstFreeFormat) + AddAnyTypeBoxDefEx(&StringData{}, StrToBoxType("name"), isUnderIlstFreeFormat) +} + +type Ilst struct { + Box +} + +// GetType returns the BoxType +func (*Ilst) GetType() BoxType { + return BoxTypeIlst() +} + +type IlstMetaContainer struct { + AnyTypeBox +} + +func isIlstMetaContainer(ctx Context) bool { + return ctx.UnderIlst && !ctx.UnderIlstMeta +} + +const ( + DataTypeBinary = 0 + DataTypeStringUTF8 = 1 + DataTypeStringUTF16 = 2 + DataTypeStringMac = 3 + DataTypeStringJPEG = 14 + DataTypeSignedIntBigEndian = 21 + DataTypeFloat32BigEndian = 22 + DataTypeFloat64BigEndian = 23 +) + +type Data struct { + Box + DataType uint32 `mp4:"0,size=32"` + DataLang uint32 `mp4:"1,size=32"` + Data []byte `mp4:"2,size=8"` +} + +// GetType returns the BoxType +func (*Data) GetType() BoxType { + return BoxTypeData() +} + +func isUnderIlstMeta(ctx Context) bool { + return ctx.UnderIlstMeta +} + +// StringifyField returns field value as string +func (data *Data) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + switch name { + case "DataType": + switch data.DataType { + case DataTypeBinary: + return "BINARY", true + case DataTypeStringUTF8: + return "UTF8", true + case DataTypeStringUTF16: + return "UTF16", true + case DataTypeStringMac: + return "MAC_STR", true + case DataTypeStringJPEG: + return "JPEG", true + case DataTypeSignedIntBigEndian: + return "INT", true + case DataTypeFloat32BigEndian: + return "FLOAT32", true + case DataTypeFloat64BigEndian: + return "FLOAT64", true + } + case "Data": + switch data.DataType { + case DataTypeStringUTF8: + return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(data.Data))), true + } + } + return "", false +} + +type StringData struct { + AnyTypeBox + Data []byte `mp4:"0,size=8"` +} + +// StringifyField returns field value as string +func (sd *StringData) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { + if name == "Data" { + return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(sd.Data))), true + } + return "", false +} + +func isUnderIlstFreeFormat(ctx Context) bool { + return ctx.UnderIlstFreeMeta +} diff --git a/vendor/github.com/abema/go-mp4/box_types_opus.go b/vendor/github.com/abema/go-mp4/box_types_opus.go new file mode 100644 index 000000000..5d02d365d --- /dev/null +++ b/vendor/github.com/abema/go-mp4/box_types_opus.go @@ -0,0 +1,54 @@ +package mp4 + +/*************************** Opus ****************************/ + +// https://opus-codec.org/docs/opus_in_isobmff.html + +func BoxTypeOpus() BoxType { return StrToBoxType("Opus") } + +func init() { + AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeOpus()) +} + +/*************************** dOps ****************************/ + +// https://opus-codec.org/docs/opus_in_isobmff.html + +func BoxTypeDOps() BoxType { return StrToBoxType("dOps") } + +func init() { + AddBoxDef(&DOps{}) +} + +type DOps struct { + Box + Version uint8 `mp4:"0,size=8"` + OutputChannelCount uint8 `mp4:"1,size=8"` + PreSkip uint16 `mp4:"2,size=16"` + InputSampleRate uint32 `mp4:"3,size=32"` + OutputGain int16 `mp4:"4,size=16"` + ChannelMappingFamily uint8 `mp4:"5,size=8"` + StreamCount uint8 `mp4:"6,opt=dynamic,size=8"` + CoupledCount uint8 `mp4:"7,opt=dynamic,size=8"` + ChannelMapping []uint8 `mp4:"8,opt=dynamic,size=8,len=dynamic"` +} + +func (DOps) GetType() BoxType { + return BoxTypeDOps() +} + +func (dops DOps) IsOptFieldEnabled(name string, ctx Context) bool { + switch name { + case "StreamCount", "CoupledCount", "ChannelMapping": + return dops.ChannelMappingFamily != 0 + } + return false +} + +func (ops DOps) GetFieldLength(name string, ctx Context) uint { + switch name { + case "ChannelMapping": + return uint(ops.OutputChannelCount) + } + return 0 +} -- cgit v1.2.3