diff options
author | 2024-07-12 09:39:47 +0000 | |
---|---|---|
committer | 2024-07-12 09:39:47 +0000 | |
commit | cde2fb6244a791b3c5b746112e3a8be3a79f39a4 (patch) | |
tree | 6079d6fb66d90ffbe8c1623525bb86829c162459 /vendor/github.com/abema/go-mp4 | |
parent | [chore] Add interaction policy gtsmodels (#3075) (diff) | |
download | gotosocial-cde2fb6244a791b3c5b746112e3a8be3a79f39a4.tar.xz |
[feature] support processing of (many) more media types (#3090)
* initial work replacing our media decoding / encoding pipeline with ffprobe + ffmpeg
* specify the video codec to use when generating static image from emoji
* update go-storage library (fixes incompatibility after updating go-iotools)
* maintain image aspect ratio when generating a thumbnail for it
* update readme to show go-ffmpreg
* fix a bunch of media tests, move filesize checking to callers of media manager for more flexibility
* remove extra debug from error message
* fix up incorrect function signatures
* update PutFile to just use regular file copy, as changes are file is on separate partition
* fix remaining tests, remove some unneeded tests now we're working with ffmpeg/ffprobe
* update more tests, add more code comments
* add utilities to generate processed emoji / media outputs
* fix remaining tests
* add test for opus media file, add license header to utility cmds
* limit the number of concurrently available ffmpeg / ffprobe instances
* reduce number of instances
* further reduce number of instances
* fix envparsing test with configuration variables
* update docs and configuration with new media-{local,remote}-max-size variables
Diffstat (limited to 'vendor/github.com/abema/go-mp4')
29 files changed, 0 insertions, 6419 deletions
diff --git a/vendor/github.com/abema/go-mp4/.gitignore b/vendor/github.com/abema/go-mp4/.gitignore deleted file mode 100644 index 22d0d82f8..000000000 --- a/vendor/github.com/abema/go-mp4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vendor diff --git a/vendor/github.com/abema/go-mp4/LICENSE b/vendor/github.com/abema/go-mp4/LICENSE deleted file mode 100644 index c06ca63d3..000000000 --- a/vendor/github.com/abema/go-mp4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 AbemaTV - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/abema/go-mp4/README.md b/vendor/github.com/abema/go-mp4/README.md deleted file mode 100644 index 2f3e690be..000000000 --- a/vendor/github.com/abema/go-mp4/README.md +++ /dev/null @@ -1,159 +0,0 @@ -go-mp4 ------- - -[](https://pkg.go.dev/github.com/abema/go-mp4) - -[](https://coveralls.io/github/abema/go-mp4) -[](https://goreportcard.com/report/github.com/abema/go-mp4) - -go-mp4 is Go library which provides low-level I/O interfaces of MP4. -This library supports you to parse or build any MP4 boxes(atoms) directly. - -go-mp4 provides very flexible interfaces for reading boxes. -If you want to read only specific parts of MP4 file, this library extracts those boxes via io.ReadSeeker interface. - -On the other hand, this library is not suitable for complex data conversions. - -## Integration with your Go application - -### Reading - -You can parse MP4 file as follows: - -```go -// expand all boxes -_, err := mp4.ReadBoxStructure(file, func(h *mp4.ReadHandle) (interface{}, error) { - fmt.Println("depth", len(h.Path)) - - // Box Type (e.g. "mdhd", "tfdt", "mdat") - fmt.Println("type", h.BoxInfo.Type.String()) - - // Box Size - fmt.Println("size", h.BoxInfo.Size) - - if h.BoxInfo.IsSupportedType() { - // Payload - box, _, err := h.ReadPayload() - if err != nil { - return nil, err - } - str, err := mp4.Stringify(box, h.BoxInfo.Context) - if err != nil { - return nil, err - } - fmt.Println("payload", str) - - // Expands children - return h.Expand() - } - return nil, nil -}) -``` - -```go -// extract specific boxes -boxes, err := mp4.ExtractBoxWithPayload(file, nil, mp4.BoxPath{mp4.BoxTypeMoov(), mp4.BoxTypeTrak(), mp4.BoxTypeTkhd()}) -if err != nil { - : -} -for _, box := range boxes { - tkhd := box.Payload.(*mp4.Tkhd) - fmt.Println("track ID:", tkhd.TrackID) -} -``` - -```go -// get basic informations -info, err := mp4.Probe(bufseekio.NewReadSeeker(file, 1024, 4)) -if err != nil { - : -} -fmt.Println("track num:", len(info.Tracks)) -``` - -### Writing - -Writer helps you to write box tree. -The following sample code edits emsg box and writes to another file. - -```go -r := bufseekio.NewReadSeeker(inputFile, 128*1024, 4) -w := mp4.NewWriter(outputFile) -_, err = mp4.ReadBoxStructure(r, func(h *mp4.ReadHandle) (interface{}, error) { - switch h.BoxInfo.Type { - case mp4.BoxTypeEmsg(): - // write box size and box type - _, err := w.StartBox(&h.BoxInfo) - if err != nil { - return nil, err - } - // read payload - box, _, err := h.ReadPayload() - if err != nil { - return nil, err - } - // update MessageData - emsg := box.(*mp4.Emsg) - emsg.MessageData = []byte("hello world") - // write box playload - if _, err := mp4.Marshal(w, emsg, h.BoxInfo.Context); err != nil { - return nil, err - } - // rewrite box size - _, err = w.EndBox() - return nil, err - default: - // copy all - return nil, w.CopyBox(r, &h.BoxInfo) - } -}) -``` - -### User-defined Boxes - -You can create additional box definition as follows: - -```go -func BoxTypeXxxx() BoxType { return mp4.StrToBoxType("xxxx") } - -func init() { - mp4.AddBoxDef(&Xxxx{}, 0) -} - -type Xxxx struct { - FullBox `mp4:"0,extend"` - UI32 uint32 `mp4:"1,size=32"` - ByteArray []byte `mp4:"2,size=8,len=dynamic"` -} - -func (*Xxxx) GetType() BoxType { - return BoxTypeXxxx() -} -``` - -### Buffering - -go-mp4 has no buffering feature for I/O. -If you should reduce Read function calls, you can wrap the io.ReadSeeker by [bufseekio](https://github.com/sunfish-shogi/bufseekio). - -## Command Line Tool - -Install mp4tool as follows: - -```sh -go install github.com/abema/go-mp4/cmd/mp4tool@latest - -mp4tool -help -``` - -For example, `mp4tool dump MP4_FILE_NAME` command prints MP4 box tree as follows: - -``` -[moof] Size=504 - [mfhd] Size=16 Version=0 Flags=0x000000 SequenceNumber=1 - [traf] Size=480 - [tfhd] Size=28 Version=0 Flags=0x020038 TrackID=1 DefaultSampleDuration=9000 DefaultSampleSize=33550 DefaultSampleFlags=0x1010000 - [tfdt] Size=20 Version=1 Flags=0x000000 BaseMediaDecodeTimeV1=0 - [trun] Size=424 ... (use -a option to show all) -[mdat] Size=44569 Data=[...] (use -mdat option to expand) -``` diff --git a/vendor/github.com/abema/go-mp4/anytype.go b/vendor/github.com/abema/go-mp4/anytype.go deleted file mode 100644 index d995f59b6..000000000 --- a/vendor/github.com/abema/go-mp4/anytype.go +++ /dev/null @@ -1,19 +0,0 @@ -package mp4 - -type IAnyType interface { - IBox - SetType(BoxType) -} - -type AnyTypeBox struct { - Box - Type BoxType -} - -func (e *AnyTypeBox) GetType() BoxType { - return e.Type -} - -func (e *AnyTypeBox) SetType(boxType BoxType) { - e.Type = boxType -} diff --git a/vendor/github.com/abema/go-mp4/box.go b/vendor/github.com/abema/go-mp4/box.go deleted file mode 100644 index c69e89257..000000000 --- a/vendor/github.com/abema/go-mp4/box.go +++ /dev/null @@ -1,188 +0,0 @@ -package mp4 - -import ( - "errors" - "io" - "math" - - "github.com/abema/go-mp4/internal/bitio" -) - -const LengthUnlimited = math.MaxUint32 - -type ICustomFieldObject interface { - // GetFieldSize returns size of dynamic field - GetFieldSize(name string, ctx Context) uint - - // GetFieldLength returns length of dynamic field - GetFieldLength(name string, ctx Context) uint - - // IsOptFieldEnabled check whether if the optional field is enabled - IsOptFieldEnabled(name string, ctx Context) bool - - // StringifyField returns field value as string - StringifyField(name string, indent string, depth int, ctx Context) (string, bool) - - IsPString(name string, bytes []byte, remainingSize uint64, ctx Context) bool - - BeforeUnmarshal(r io.ReadSeeker, size uint64, ctx Context) (n uint64, override bool, err error) - - OnReadField(name string, r bitio.ReadSeeker, leftBits uint64, ctx Context) (rbits uint64, override bool, err error) - - OnWriteField(name string, w bitio.Writer, ctx Context) (wbits uint64, override bool, err error) -} - -type BaseCustomFieldObject struct { -} - -// GetFieldSize returns size of dynamic field -func (box *BaseCustomFieldObject) GetFieldSize(string, Context) uint { - panic(errors.New("GetFieldSize not implemented")) -} - -// GetFieldLength returns length of dynamic field -func (box *BaseCustomFieldObject) GetFieldLength(string, Context) uint { - panic(errors.New("GetFieldLength not implemented")) -} - -// IsOptFieldEnabled check whether if the optional field is enabled -func (box *BaseCustomFieldObject) IsOptFieldEnabled(string, Context) bool { - return false -} - -// StringifyField returns field value as string -func (box *BaseCustomFieldObject) StringifyField(string, string, int, Context) (string, bool) { - return "", false -} - -func (*BaseCustomFieldObject) IsPString(name string, bytes []byte, remainingSize uint64, ctx Context) bool { - return true -} - -func (*BaseCustomFieldObject) BeforeUnmarshal(io.ReadSeeker, uint64, Context) (uint64, bool, error) { - return 0, false, nil -} - -func (*BaseCustomFieldObject) OnReadField(string, bitio.ReadSeeker, uint64, Context) (uint64, bool, error) { - return 0, false, nil -} - -func (*BaseCustomFieldObject) OnWriteField(string, bitio.Writer, Context) (uint64, bool, error) { - return 0, false, nil -} - -// IImmutableBox is common interface of box -type IImmutableBox interface { - ICustomFieldObject - - // GetVersion returns the box version - GetVersion() uint8 - - // GetFlags returns the flags - GetFlags() uint32 - - // CheckFlag checks the flag status - CheckFlag(uint32) bool - - // GetType returns the BoxType - GetType() BoxType -} - -// IBox is common interface of box -type IBox interface { - IImmutableBox - - // SetVersion sets the box version - SetVersion(uint8) - - // SetFlags sets the flags - SetFlags(uint32) - - // AddFlag adds the flag - AddFlag(uint32) - - // RemoveFlag removes the flag - RemoveFlag(uint32) -} - -type Box struct { - BaseCustomFieldObject -} - -// GetVersion returns the box version -func (box *Box) GetVersion() uint8 { - return 0 -} - -// SetVersion sets the box version -func (box *Box) SetVersion(uint8) { -} - -// GetFlags returns the flags -func (box *Box) GetFlags() uint32 { - return 0x000000 -} - -// CheckFlag checks the flag status -func (box *Box) CheckFlag(flag uint32) bool { - return true -} - -// SetFlags sets the flags -func (box *Box) SetFlags(uint32) { -} - -// AddFlag adds the flag -func (box *Box) AddFlag(flag uint32) { -} - -// RemoveFlag removes the flag -func (box *Box) RemoveFlag(flag uint32) { -} - -// FullBox is ISOBMFF FullBox -type FullBox struct { - BaseCustomFieldObject - Version uint8 `mp4:"0,size=8"` - Flags [3]byte `mp4:"1,size=8"` -} - -// GetVersion returns the box version -func (box *FullBox) GetVersion() uint8 { - return box.Version -} - -// SetVersion sets the box version -func (box *FullBox) SetVersion(version uint8) { - box.Version = version -} - -// GetFlags returns the flags -func (box *FullBox) GetFlags() uint32 { - flag := uint32(box.Flags[0]) << 16 - flag ^= uint32(box.Flags[1]) << 8 - flag ^= uint32(box.Flags[2]) - return flag -} - -// CheckFlag checks the flag status -func (box *FullBox) CheckFlag(flag uint32) bool { - return box.GetFlags()&flag != 0 -} - -// SetFlags sets the flags -func (box *FullBox) SetFlags(flags uint32) { - box.Flags[0] = byte(flags >> 16) - box.Flags[1] = byte(flags >> 8) - box.Flags[2] = byte(flags) -} - -// AddFlag adds the flag -func (box *FullBox) AddFlag(flag uint32) { - box.SetFlags(box.GetFlags() | flag) -} - -// RemoveFlag removes the flag -func (box *FullBox) RemoveFlag(flag uint32) { - box.SetFlags(box.GetFlags() & (^flag)) -} diff --git a/vendor/github.com/abema/go-mp4/box_info.go b/vendor/github.com/abema/go-mp4/box_info.go deleted file mode 100644 index 1cb4b8aa7..000000000 --- a/vendor/github.com/abema/go-mp4/box_info.go +++ /dev/null @@ -1,162 +0,0 @@ -package mp4 - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" - "math" -) - -type Context struct { - // IsQuickTimeCompatible represents whether ftyp.compatible_brands contains "qt ". - IsQuickTimeCompatible bool - - // QuickTimeKeysMetaEntryCount the expected number of items under the ilst box as observed from the keys box - QuickTimeKeysMetaEntryCount int - - // UnderWave represents whether current box is under the wave box. - UnderWave bool - - // UnderIlst represents whether current box is under the ilst box. - UnderIlst bool - - // UnderIlstMeta represents whether current box is under the metadata box under the ilst box. - UnderIlstMeta bool - - // UnderIlstFreeMeta represents whether current box is under "----" box. - UnderIlstFreeMeta bool - - // UnderUdta represents whether current box is under the udta box. - UnderUdta bool -} - -// BoxInfo has common infomations of box -type BoxInfo struct { - // Offset specifies an offset of the box in a file. - Offset uint64 - - // Size specifies size(bytes) of box. - Size uint64 - - // HeaderSize specifies size(bytes) of common fields which are defined as "Box" class member at ISO/IEC 14496-12. - HeaderSize uint64 - - // Type specifies box type which is represented by 4 characters. - Type BoxType - - // ExtendToEOF is set true when Box.size is zero. It means that end of box equals to end of file. - ExtendToEOF bool - - // Context would be set by ReadBoxStructure, not ReadBoxInfo. - Context -} - -func (bi *BoxInfo) IsSupportedType() bool { - return bi.Type.IsSupported(bi.Context) -} - -const ( - SmallHeaderSize = 8 - LargeHeaderSize = 16 -) - -// WriteBoxInfo writes common fields which are defined as "Box" class member at ISO/IEC 14496-12. -// This function ignores bi.Offset and returns BoxInfo which contains real Offset and recalculated Size/HeaderSize. -func WriteBoxInfo(w io.WriteSeeker, bi *BoxInfo) (*BoxInfo, error) { - offset, err := w.Seek(0, io.SeekCurrent) - if err != nil { - return nil, err - } - - var data []byte - if bi.ExtendToEOF { - data = make([]byte, SmallHeaderSize) - } else if bi.Size <= math.MaxUint32 && bi.HeaderSize != LargeHeaderSize { - data = make([]byte, SmallHeaderSize) - binary.BigEndian.PutUint32(data, uint32(bi.Size)) - } else { - data = make([]byte, LargeHeaderSize) - binary.BigEndian.PutUint32(data, 1) - binary.BigEndian.PutUint64(data[SmallHeaderSize:], bi.Size) - } - data[4] = bi.Type[0] - data[5] = bi.Type[1] - data[6] = bi.Type[2] - data[7] = bi.Type[3] - - if _, err := w.Write(data); err != nil { - return nil, err - } - - return &BoxInfo{ - Offset: uint64(offset), - Size: bi.Size - bi.HeaderSize + uint64(len(data)), - HeaderSize: uint64(len(data)), - Type: bi.Type, - ExtendToEOF: bi.ExtendToEOF, - }, nil -} - -// ReadBoxInfo reads common fields which are defined as "Box" class member at ISO/IEC 14496-12. -func ReadBoxInfo(r io.ReadSeeker) (*BoxInfo, error) { - offset, err := r.Seek(0, io.SeekCurrent) - if err != nil { - return nil, err - } - - bi := &BoxInfo{ - Offset: uint64(offset), - } - - // read 8 bytes - buf := bytes.NewBuffer(make([]byte, 0, SmallHeaderSize)) - if _, err := io.CopyN(buf, r, SmallHeaderSize); err != nil { - return nil, err - } - bi.HeaderSize += SmallHeaderSize - - // pick size and type - data := buf.Bytes() - bi.Size = uint64(binary.BigEndian.Uint32(data)) - bi.Type = BoxType{data[4], data[5], data[6], data[7]} - - if bi.Size == 0 { - // box extends to end of file - offsetEOF, err := r.Seek(0, io.SeekEnd) - if err != nil { - return nil, err - } - bi.Size = uint64(offsetEOF) - bi.Offset - bi.ExtendToEOF = true - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - } else if bi.Size == 1 { - // read more 8 bytes - buf.Reset() - if _, err := io.CopyN(buf, r, LargeHeaderSize-SmallHeaderSize); err != nil { - return nil, err - } - bi.HeaderSize += LargeHeaderSize - SmallHeaderSize - bi.Size = binary.BigEndian.Uint64(buf.Bytes()) - } - - if bi.Size == 0 { - return nil, fmt.Errorf("invalid size") - } - - return bi, nil -} - -func (bi *BoxInfo) SeekToStart(s io.Seeker) (int64, error) { - return s.Seek(int64(bi.Offset), io.SeekStart) -} - -func (bi *BoxInfo) SeekToPayload(s io.Seeker) (int64, error) { - return s.Seek(int64(bi.Offset+bi.HeaderSize), io.SeekStart) -} - -func (bi *BoxInfo) SeekToEnd(s io.Seeker) (int64, error) { - return s.Seek(int64(bi.Offset+bi.Size), io.SeekStart) -} diff --git a/vendor/github.com/abema/go-mp4/box_types_3gpp.go b/vendor/github.com/abema/go-mp4/box_types_3gpp.go deleted file mode 100644 index d19640c51..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_3gpp.go +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index 7b929e72b..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_av1.go +++ /dev/null @@ -1,44 +0,0 @@ -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_etsi_ts_102_366.go b/vendor/github.com/abema/go-mp4/box_types_etsi_ts_102_366.go deleted file mode 100644 index 7436e1833..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_etsi_ts_102_366.go +++ /dev/null @@ -1,36 +0,0 @@ -package mp4 - -/*************************** ac-3 ****************************/ - -// https://www.etsi.org/deliver/etsi_ts/102300_102399/102366/01.04.01_60/ts_102366v010401p.pdf - -func BoxTypeAC3() BoxType { return StrToBoxType("ac-3") } - -func init() { - AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeAC3()) -} - -/*************************** dac3 ****************************/ - -// https://www.etsi.org/deliver/etsi_ts/102300_102399/102366/01.04.01_60/ts_102366v010401p.pdf - -func BoxTypeDAC3() BoxType { return StrToBoxType("dac3") } - -func init() { - AddBoxDef(&Dac3{}) -} - -type Dac3 struct { - Box - Fscod uint8 `mp4:"0,size=2"` - Bsid uint8 `mp4:"1,size=5"` - Bsmod uint8 `mp4:"2,size=3"` - Acmod uint8 `mp4:"3,size=3"` - LfeOn uint8 `mp4:"4,size=1"` - BitRateCode uint8 `mp4:"5,size=5"` - Reserved uint8 `mp4:"6,size=5,const=0"` -} - -func (Dac3) GetType() BoxType { - return BoxTypeDAC3() -} 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 deleted file mode 100644 index 017fd918d..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_iso14496_12.go +++ /dev/null @@ -1,2460 +0,0 @@ -package mp4 - -import ( - "errors" - "fmt" - "io" - - "github.com/abema/go-mp4/internal/bitio" - "github.com/abema/go-mp4/internal/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 - } - - if !readerHasSize(r, size) { - return 0, false, fmt.Errorf("not enough bits") - } - - 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 BoxTypeMp4v() BoxType { return StrToBoxType("mp4v") } -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{}, BoxTypeMp4v()) - 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 deleted file mode 100644 index fe9880ca0..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_iso14496_14.go +++ /dev/null @@ -1,126 +0,0 @@ -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_5.go b/vendor/github.com/abema/go-mp4/box_types_iso23001_5.go deleted file mode 100644 index 849411ad1..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_iso23001_5.go +++ /dev/null @@ -1,35 +0,0 @@ -package mp4 - -/*************************** ipcm ****************************/ - -func BoxTypeIpcm() BoxType { return StrToBoxType("ipcm") } - -func init() { - AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeIpcm()) -} - -/*************************** fpcm ****************************/ - -func BoxTypeFpcm() BoxType { return StrToBoxType("fpcm") } - -func init() { - AddAnyTypeBoxDef(&AudioSampleEntry{}, BoxTypeFpcm()) -} - -/*************************** pcmC ****************************/ - -func BoxTypePcmC() BoxType { return StrToBoxType("pcmC") } - -func init() { - AddBoxDef(&PcmC{}, 0, 1) -} - -type PcmC struct { - FullBox `mp4:"0,extend"` - FormatFlags uint8 `mp4:"1,size=8"` - PCMSampleSize uint8 `mp4:"1,size=8"` -} - -func (PcmC) GetType() BoxType { - return BoxTypePcmC() -} 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 deleted file mode 100644 index 766c348b0..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_iso23001_7.go +++ /dev/null @@ -1,108 +0,0 @@ -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 deleted file mode 100644 index 7baba2242..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_metadata.go +++ /dev/null @@ -1,257 +0,0 @@ -package mp4 - -import ( - "fmt" - - "github.com/abema/go-mp4/internal/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 -) - -// Data is a Value BoxType -// https://developer.apple.com/documentation/quicktime-file-format/value_atom -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 -} - -/*************************** numbered items ****************************/ - -// Item is a numbered item under an item list atom -// https://developer.apple.com/documentation/quicktime-file-format/metadata_item_list_atom/item_list -type Item struct { - AnyTypeBox - Version uint8 `mp4:"0,size=8"` - Flags [3]byte `mp4:"1,size=8"` - ItemName []byte `mp4:"2,size=8,len=4"` - Data Data `mp4:"3"` -} - -// StringifyField returns field value as string -func (i *Item) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "ItemName": - return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(i.ItemName))), true - } - return "", false -} - -func isUnderIlstFreeFormat(ctx Context) bool { - return ctx.UnderIlstFreeMeta -} - -func BoxTypeKeys() BoxType { return StrToBoxType("keys") } - -func init() { - AddBoxDef(&Keys{}) -} - -/*************************** keys ****************************/ - -// Keys is the Keys BoxType -// https://developer.apple.com/documentation/quicktime-file-format/metadata_item_keys_atom -type Keys struct { - FullBox `mp4:"0,extend"` - EntryCount int32 `mp4:"1,size=32"` - Entries []Key `mp4:"2,len=dynamic"` -} - -// GetType implements the IBox interface and returns the BoxType -func (*Keys) GetType() BoxType { - return BoxTypeKeys() -} - -// GetFieldLength implements the ICustomFieldObject interface and returns the length of dynamic fields -func (k *Keys) GetFieldLength(name string, ctx Context) uint { - switch name { - case "Entries": - return uint(k.EntryCount) - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=keys fieldName=%s", name)) -} - -/*************************** key ****************************/ - -// Key is a key value field in the Keys BoxType -// https://developer.apple.com/documentation/quicktime-file-format/metadata_item_keys_atom/key_value_key_size-8 -type Key struct { - BaseCustomFieldObject - KeySize int32 `mp4:"0,size=32"` - KeyNamespace []byte `mp4:"1,size=8,len=4"` - KeyValue []byte `mp4:"2,size=8,len=dynamic"` -} - -// GetFieldLength implements the ICustomFieldObject interface and returns the length of dynamic fields -func (k *Key) GetFieldLength(name string, ctx Context) uint { - switch name { - case "KeyValue": - // sizeOf(KeySize)+sizeOf(KeyNamespace) = 8 bytes - return uint(k.KeySize) - 8 - } - panic(fmt.Errorf("invalid name of dynamic-length field: boxType=key fieldName=%s", name)) -} - -// StringifyField returns field value as string -func (k *Key) StringifyField(name string, indent string, depth int, ctx Context) (string, bool) { - switch name { - case "KeyNamespace": - return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(k.KeyNamespace))), true - case "KeyValue": - return fmt.Sprintf("\"%s\"", util.EscapeUnprintables(string(k.KeyValue))), true - } - return "", false -} diff --git a/vendor/github.com/abema/go-mp4/box_types_opus.go b/vendor/github.com/abema/go-mp4/box_types_opus.go deleted file mode 100644 index 5d02d365d..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_opus.go +++ /dev/null @@ -1,54 +0,0 @@ -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 -} diff --git a/vendor/github.com/abema/go-mp4/box_types_vp.go b/vendor/github.com/abema/go-mp4/box_types_vp.go deleted file mode 100644 index 6927b2190..000000000 --- a/vendor/github.com/abema/go-mp4/box_types_vp.go +++ /dev/null @@ -1,53 +0,0 @@ -package mp4 - -// https://www.webmproject.org/vp9/mp4/ - -/*************************** vp08 ****************************/ - -func BoxTypeVp08() BoxType { return StrToBoxType("vp08") } - -func init() { - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeVp08()) -} - -/*************************** vp09 ****************************/ - -func BoxTypeVp09() BoxType { return StrToBoxType("vp09") } - -func init() { - AddAnyTypeBoxDef(&VisualSampleEntry{}, BoxTypeVp09()) -} - -/*************************** VpcC ****************************/ - -func BoxTypeVpcC() BoxType { return StrToBoxType("vpcC") } - -func init() { - AddBoxDef(&VpcC{}) -} - -type VpcC struct { - FullBox `mp4:"0,extend"` - Profile uint8 `mp4:"1,size=8"` - Level uint8 `mp4:"2,size=8"` - BitDepth uint8 `mp4:"3,size=4"` - ChromaSubsampling uint8 `mp4:"4,size=3"` - VideoFullRangeFlag uint8 `mp4:"5,size=1"` - ColourPrimaries uint8 `mp4:"6,size=8"` - TransferCharacteristics uint8 `mp4:"7,size=8"` - MatrixCoefficients uint8 `mp4:"8,size=8"` - CodecInitializationDataSize uint16 `mp4:"9,size=16"` - CodecInitializationData []uint8 `mp4:"10,size=8,len=dynamic"` -} - -func (VpcC) GetType() BoxType { - return BoxTypeVpcC() -} - -func (vpcc VpcC) GetFieldLength(name string, ctx Context) uint { - switch name { - case "CodecInitializationData": - return uint(vpcc.CodecInitializationDataSize) - } - return 0 -} diff --git a/vendor/github.com/abema/go-mp4/extract.go b/vendor/github.com/abema/go-mp4/extract.go deleted file mode 100644 index 7de36b06a..000000000 --- a/vendor/github.com/abema/go-mp4/extract.go +++ /dev/null @@ -1,98 +0,0 @@ -package mp4 - -import ( - "errors" - "io" -) - -type BoxInfoWithPayload struct { - Info BoxInfo - Payload IBox -} - -func ExtractBoxWithPayload(r io.ReadSeeker, parent *BoxInfo, path BoxPath) ([]*BoxInfoWithPayload, error) { - return ExtractBoxesWithPayload(r, parent, []BoxPath{path}) -} - -func ExtractBoxesWithPayload(r io.ReadSeeker, parent *BoxInfo, paths []BoxPath) ([]*BoxInfoWithPayload, error) { - bis, err := ExtractBoxes(r, parent, paths) - if err != nil { - return nil, err - } - - bs := make([]*BoxInfoWithPayload, 0, len(bis)) - for _, bi := range bis { - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - - var ctx Context - if parent != nil { - ctx = parent.Context - } - box, _, err := UnmarshalAny(r, bi.Type, bi.Size-bi.HeaderSize, ctx) - if err != nil { - return nil, err - } - bs = append(bs, &BoxInfoWithPayload{ - Info: *bi, - Payload: box, - }) - } - return bs, nil -} - -func ExtractBox(r io.ReadSeeker, parent *BoxInfo, path BoxPath) ([]*BoxInfo, error) { - return ExtractBoxes(r, parent, []BoxPath{path}) -} - -func ExtractBoxes(r io.ReadSeeker, parent *BoxInfo, paths []BoxPath) ([]*BoxInfo, error) { - if len(paths) == 0 { - return nil, nil - } - - for i := range paths { - if len(paths[i]) == 0 { - return nil, errors.New("box path must not be empty") - } - } - - boxes := make([]*BoxInfo, 0, 8) - - handler := func(handle *ReadHandle) (interface{}, error) { - path := handle.Path - if parent != nil { - path = path[1:] - } - if handle.BoxInfo.Type == BoxTypeAny() { - return nil, nil - } - fm, m := matchPath(paths, path) - if m { - boxes = append(boxes, &handle.BoxInfo) - } - - if fm { - if _, err := handle.Expand(); err != nil { - return nil, err - } - } - return nil, nil - } - - if parent != nil { - _, err := ReadBoxStructureFromInternal(r, parent, handler) - return boxes, err - } - _, err := ReadBoxStructure(r, handler) - return boxes, err -} - -func matchPath(paths []BoxPath, path BoxPath) (forwardMatch bool, match bool) { - for i := range paths { - fm, m := path.compareWith(paths[i]) - forwardMatch = forwardMatch || fm - match = match || m - } - return -} diff --git a/vendor/github.com/abema/go-mp4/field.go b/vendor/github.com/abema/go-mp4/field.go deleted file mode 100644 index 585833e0d..000000000 --- a/vendor/github.com/abema/go-mp4/field.go +++ /dev/null @@ -1,290 +0,0 @@ -package mp4 - -import ( - "fmt" - "os" - "reflect" - "sort" - "strconv" - "strings" -) - -type ( - stringType uint8 - fieldFlag uint16 -) - -const ( - stringType_C stringType = iota - stringType_C_P - - fieldString fieldFlag = 1 << iota // 0 - fieldExtend // 1 - fieldDec // 2 - fieldHex // 3 - fieldISO639_2 // 4 - fieldUUID // 5 - fieldHidden // 6 - fieldOptDynamic // 7 - fieldVarint // 8 - fieldSizeDynamic // 9 - fieldLengthDynamic // 10 -) - -type field struct { - children []*field - name string - cnst string - order int - optFlag uint32 - nOptFlag uint32 - size uint - length uint - flags fieldFlag - strType stringType - version uint8 - nVersion uint8 -} - -func (f *field) set(flag fieldFlag) { - f.flags |= flag -} - -func (f *field) is(flag fieldFlag) bool { - return f.flags&flag != 0 -} - -func buildFields(box IImmutableBox) []*field { - t := reflect.TypeOf(box).Elem() - return buildFieldsStruct(t) -} - -func buildFieldsStruct(t reflect.Type) []*field { - fs := make([]*field, 0, 8) - for i := 0; i < t.NumField(); i++ { - ft := t.Field(i).Type - tag, ok := t.Field(i).Tag.Lookup("mp4") - if !ok { - continue - } - f := buildField(t.Field(i).Name, tag) - f.children = buildFieldsAny(ft) - fs = append(fs, f) - } - sort.SliceStable(fs, func(i, j int) bool { - return fs[i].order < fs[j].order - }) - return fs -} - -func buildFieldsAny(t reflect.Type) []*field { - switch t.Kind() { - case reflect.Struct: - return buildFieldsStruct(t) - case reflect.Ptr, reflect.Array, reflect.Slice: - return buildFieldsAny(t.Elem()) - default: - return nil - } -} - -func buildField(fieldName string, tag string) *field { - f := &field{ - name: fieldName, - } - tagMap := parseFieldTag(tag) - for key, val := range tagMap { - if val != "" { - continue - } - if order, err := strconv.Atoi(key); err == nil { - f.order = order - break - } - } - - if val, contained := tagMap["string"]; contained { - f.set(fieldString) - if val == "c_p" { - f.strType = stringType_C_P - fmt.Fprint(os.Stderr, "go-mp4: string=c_p tag is deprecated!! See https://github.com/abema/go-mp4/issues/76\n") - } - } - - if _, contained := tagMap["varint"]; contained { - f.set(fieldVarint) - } - - if val, contained := tagMap["opt"]; contained { - if val == "dynamic" { - f.set(fieldOptDynamic) - } else { - base := 10 - if strings.HasPrefix(val, "0x") { - val = val[2:] - base = 16 - } - opt, err := strconv.ParseUint(val, base, 32) - if err != nil { - panic(err) - } - f.optFlag = uint32(opt) - } - } - - if val, contained := tagMap["nopt"]; contained { - base := 10 - if strings.HasPrefix(val, "0x") { - val = val[2:] - base = 16 - } - nopt, err := strconv.ParseUint(val, base, 32) - if err != nil { - panic(err) - } - f.nOptFlag = uint32(nopt) - } - - if _, contained := tagMap["extend"]; contained { - f.set(fieldExtend) - } - - if _, contained := tagMap["dec"]; contained { - f.set(fieldDec) - } - - if _, contained := tagMap["hex"]; contained { - f.set(fieldHex) - } - - if _, contained := tagMap["iso639-2"]; contained { - f.set(fieldISO639_2) - } - - if _, contained := tagMap["uuid"]; contained { - f.set(fieldUUID) - } - - if _, contained := tagMap["hidden"]; contained { - f.set(fieldHidden) - } - - if val, contained := tagMap["const"]; contained { - f.cnst = val - } - - f.version = anyVersion - if val, contained := tagMap["ver"]; contained { - ver, err := strconv.Atoi(val) - if err != nil { - panic(err) - } - f.version = uint8(ver) - } - - f.nVersion = anyVersion - if val, contained := tagMap["nver"]; contained { - ver, err := strconv.Atoi(val) - if err != nil { - panic(err) - } - f.nVersion = uint8(ver) - } - - if val, contained := tagMap["size"]; contained { - if val == "dynamic" { - f.set(fieldSizeDynamic) - } else { - size, err := strconv.ParseUint(val, 10, 32) - if err != nil { - panic(err) - } - f.size = uint(size) - } - } - - f.length = LengthUnlimited - if val, contained := tagMap["len"]; contained { - if val == "dynamic" { - f.set(fieldLengthDynamic) - } else { - l, err := strconv.ParseUint(val, 10, 32) - if err != nil { - panic(err) - } - f.length = uint(l) - } - } - - return f -} - -func parseFieldTag(str string) map[string]string { - tag := make(map[string]string, 8) - - list := strings.Split(str, ",") - for _, e := range list { - kv := strings.SplitN(e, "=", 2) - if len(kv) == 2 { - tag[strings.Trim(kv[0], " ")] = strings.Trim(kv[1], " ") - } else { - tag[strings.Trim(kv[0], " ")] = "" - } - } - - return tag -} - -type fieldInstance struct { - field - cfo ICustomFieldObject -} - -func resolveFieldInstance(f *field, box IImmutableBox, parent reflect.Value, ctx Context) *fieldInstance { - fi := fieldInstance{ - field: *f, - } - - cfo, ok := parent.Addr().Interface().(ICustomFieldObject) - if ok { - fi.cfo = cfo - } else { - fi.cfo = box - } - - if fi.is(fieldSizeDynamic) { - fi.size = fi.cfo.GetFieldSize(f.name, ctx) - } - - if fi.is(fieldLengthDynamic) { - fi.length = fi.cfo.GetFieldLength(f.name, ctx) - } - - return &fi -} - -func isTargetField(box IImmutableBox, fi *fieldInstance, ctx Context) bool { - if box.GetVersion() != anyVersion { - if fi.version != anyVersion && box.GetVersion() != fi.version { - return false - } - - if fi.nVersion != anyVersion && box.GetVersion() == fi.nVersion { - return false - } - } - - if fi.optFlag != 0 && box.GetFlags()&fi.optFlag == 0 { - return false - } - - if fi.nOptFlag != 0 && box.GetFlags()&fi.nOptFlag != 0 { - return false - } - - if fi.is(fieldOptDynamic) && !fi.cfo.IsOptFieldEnabled(fi.name, ctx) { - return false - } - - return true -} diff --git a/vendor/github.com/abema/go-mp4/internal/bitio/bitio.go b/vendor/github.com/abema/go-mp4/internal/bitio/bitio.go deleted file mode 100644 index 404fd1b82..000000000 --- a/vendor/github.com/abema/go-mp4/internal/bitio/bitio.go +++ /dev/null @@ -1,8 +0,0 @@ -package bitio - -import "errors" - -var ( - ErrInvalidAlignment = errors.New("invalid alignment") - ErrDiscouragedReader = errors.New("discouraged reader implementation") -) diff --git a/vendor/github.com/abema/go-mp4/internal/bitio/read.go b/vendor/github.com/abema/go-mp4/internal/bitio/read.go deleted file mode 100644 index 4da76eae6..000000000 --- a/vendor/github.com/abema/go-mp4/internal/bitio/read.go +++ /dev/null @@ -1,97 +0,0 @@ -package bitio - -import "io" - -type Reader interface { - io.Reader - - // alignment: - // |-1-byte-block-|--------------|--------------|--------------| - // |<-offset->|<-------------------width---------------------->| - ReadBits(width uint) (data []byte, err error) - - ReadBit() (bit bool, err error) -} - -type ReadSeeker interface { - Reader - io.Seeker -} - -type reader struct { - reader io.Reader - octet byte - width uint -} - -func NewReader(r io.Reader) Reader { - return &reader{reader: r} -} - -func (r *reader) Read(p []byte) (n int, err error) { - if r.width != 0 { - return 0, ErrInvalidAlignment - } - return r.reader.Read(p) -} - -func (r *reader) ReadBits(size uint) ([]byte, error) { - bytes := (size + 7) / 8 - data := make([]byte, bytes) - offset := (bytes * 8) - (size) - - for i := uint(0); i < size; i++ { - bit, err := r.ReadBit() - if err != nil { - return nil, err - } - - byteIdx := (offset + i) / 8 - bitIdx := 7 - (offset+i)%8 - if bit { - data[byteIdx] |= 0x1 << bitIdx - } - } - - return data, nil -} - -func (r *reader) ReadBit() (bool, error) { - if r.width == 0 { - buf := make([]byte, 1) - if n, err := r.reader.Read(buf); err != nil { - return false, err - } else if n != 1 { - return false, ErrDiscouragedReader - } - r.octet = buf[0] - r.width = 8 - } - - r.width-- - return (r.octet>>r.width)&0x01 != 0, nil -} - -type readSeeker struct { - reader - seeker io.Seeker -} - -func NewReadSeeker(r io.ReadSeeker) ReadSeeker { - return &readSeeker{ - reader: reader{reader: r}, - seeker: r, - } -} - -func (r *readSeeker) Seek(offset int64, whence int) (int64, error) { - if whence == io.SeekCurrent && r.reader.width != 0 { - return 0, ErrInvalidAlignment - } - n, err := r.seeker.Seek(offset, whence) - if err != nil { - return n, err - } - r.reader.width = 0 - return n, nil -} diff --git a/vendor/github.com/abema/go-mp4/internal/bitio/write.go b/vendor/github.com/abema/go-mp4/internal/bitio/write.go deleted file mode 100644 index 5f63dd2d2..000000000 --- a/vendor/github.com/abema/go-mp4/internal/bitio/write.go +++ /dev/null @@ -1,61 +0,0 @@ -package bitio - -import ( - "io" -) - -type Writer interface { - io.Writer - - // alignment: - // |-1-byte-block-|--------------|--------------|--------------| - // |<-offset->|<-------------------width---------------------->| - WriteBits(data []byte, width uint) error - - WriteBit(bit bool) error -} - -type writer struct { - writer io.Writer - octet byte - width uint -} - -func NewWriter(w io.Writer) Writer { - return &writer{writer: w} -} - -func (w *writer) Write(p []byte) (n int, err error) { - if w.width != 0 { - return 0, ErrInvalidAlignment - } - return w.writer.Write(p) -} - -func (w *writer) WriteBits(data []byte, width uint) error { - length := uint(len(data)) * 8 - offset := length - width - for i := offset; i < length; i++ { - oi := i / 8 - if err := w.WriteBit((data[oi]>>(7-i%8))&0x01 != 0); err != nil { - return err - } - } - return nil -} - -func (w *writer) WriteBit(bit bool) error { - if bit { - w.octet |= 0x1 << (7 - w.width) - } - w.width++ - - if w.width == 8 { - if _, err := w.writer.Write([]byte{w.octet}); err != nil { - return err - } - w.octet = 0x00 - w.width = 0 - } - return nil -} diff --git a/vendor/github.com/abema/go-mp4/internal/util/io.go b/vendor/github.com/abema/go-mp4/internal/util/io.go deleted file mode 100644 index 1e4681186..000000000 --- a/vendor/github.com/abema/go-mp4/internal/util/io.go +++ /dev/null @@ -1,30 +0,0 @@ -package util - -import ( - "bytes" - "io" -) - -func ReadString(r io.Reader) (string, error) { - b := make([]byte, 1) - buf := bytes.NewBuffer(nil) - for { - if _, err := r.Read(b); err != nil { - return "", err - } - if b[0] == 0 { - return buf.String(), nil - } - buf.Write(b) - } -} - -func WriteString(w io.Writer, s string) error { - if _, err := w.Write([]byte(s)); err != nil { - return err - } - if _, err := w.Write([]byte{0}); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/abema/go-mp4/internal/util/string.go b/vendor/github.com/abema/go-mp4/internal/util/string.go deleted file mode 100644 index b38251bb3..000000000 --- a/vendor/github.com/abema/go-mp4/internal/util/string.go +++ /dev/null @@ -1,42 +0,0 @@ -package util - -import ( - "strconv" - "strings" - "unicode" -) - -func FormatSignedFixedFloat1616(val int32) string { - if val&0xffff == 0 { - return strconv.Itoa(int(val >> 16)) - } else { - return strconv.FormatFloat(float64(val)/(1<<16), 'f', 5, 64) - } -} - -func FormatUnsignedFixedFloat1616(val uint32) string { - if val&0xffff == 0 { - return strconv.Itoa(int(val >> 16)) - } else { - return strconv.FormatFloat(float64(val)/(1<<16), 'f', 5, 64) - } -} - -func FormatSignedFixedFloat88(val int16) string { - if val&0xff == 0 { - return strconv.Itoa(int(val >> 8)) - } else { - return strconv.FormatFloat(float64(val)/(1<<8), 'f', 3, 32) - } -} - -func EscapeUnprintable(r rune) rune { - if unicode.IsGraphic(r) { - return r - } - return rune('.') -} - -func EscapeUnprintables(src string) string { - return strings.Map(EscapeUnprintable, src) -} diff --git a/vendor/github.com/abema/go-mp4/marshaller.go b/vendor/github.com/abema/go-mp4/marshaller.go deleted file mode 100644 index ff6c64c32..000000000 --- a/vendor/github.com/abema/go-mp4/marshaller.go +++ /dev/null @@ -1,663 +0,0 @@ -package mp4 - -import ( - "bytes" - "errors" - "fmt" - "io" - "math" - "reflect" - - "github.com/abema/go-mp4/internal/bitio" -) - -const ( - anyVersion = math.MaxUint8 -) - -var ErrUnsupportedBoxVersion = errors.New("unsupported box version") - -func readerHasSize(reader bitio.ReadSeeker, size uint64) bool { - pre, err := reader.Seek(0, io.SeekCurrent) - if err != nil { - return false - } - - end, err := reader.Seek(0, io.SeekEnd) - if err != nil { - return false - } - - if uint64(end-pre) < size { - return false - } - - _, err = reader.Seek(pre, io.SeekStart) - if err != nil { - return false - } - - return true -} - -type marshaller struct { - writer bitio.Writer - wbits uint64 - src IImmutableBox - ctx Context -} - -func Marshal(w io.Writer, src IImmutableBox, ctx Context) (n uint64, err error) { - boxDef := src.GetType().getBoxDef(ctx) - if boxDef == nil { - return 0, ErrBoxInfoNotFound - } - - v := reflect.ValueOf(src).Elem() - - m := &marshaller{ - writer: bitio.NewWriter(w), - src: src, - ctx: ctx, - } - - if err := m.marshalStruct(v, boxDef.fields); err != nil { - return 0, err - } - - if m.wbits%8 != 0 { - return 0, fmt.Errorf("box size is not multiple of 8 bits: type=%s, bits=%d", src.GetType().String(), m.wbits) - } - - return m.wbits / 8, nil -} - -func (m *marshaller) marshal(v reflect.Value, fi *fieldInstance) error { - switch v.Type().Kind() { - case reflect.Ptr: - return m.marshalPtr(v, fi) - case reflect.Struct: - return m.marshalStruct(v, fi.children) - case reflect.Array: - return m.marshalArray(v, fi) - case reflect.Slice: - return m.marshalSlice(v, fi) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return m.marshalInt(v, fi) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return m.marshalUint(v, fi) - case reflect.Bool: - return m.marshalBool(v, fi) - case reflect.String: - return m.marshalString(v) - default: - return fmt.Errorf("unsupported type: %s", v.Type().Kind()) - } -} - -func (m *marshaller) marshalPtr(v reflect.Value, fi *fieldInstance) error { - return m.marshal(v.Elem(), fi) -} - -func (m *marshaller) marshalStruct(v reflect.Value, fs []*field) error { - for _, f := range fs { - fi := resolveFieldInstance(f, m.src, v, m.ctx) - - if !isTargetField(m.src, fi, m.ctx) { - continue - } - - wbits, override, err := fi.cfo.OnWriteField(f.name, m.writer, m.ctx) - if err != nil { - return err - } - m.wbits += wbits - if override { - continue - } - - err = m.marshal(v.FieldByName(f.name), fi) - if err != nil { - return err - } - } - - return nil -} - -func (m *marshaller) marshalArray(v reflect.Value, fi *fieldInstance) error { - size := v.Type().Size() - for i := 0; i < int(size)/int(v.Type().Elem().Size()); i++ { - var err error - err = m.marshal(v.Index(i), fi) - if err != nil { - return err - } - } - return nil -} - -func (m *marshaller) marshalSlice(v reflect.Value, fi *fieldInstance) error { - length := uint64(v.Len()) - if fi.length != LengthUnlimited { - if length < uint64(fi.length) { - return fmt.Errorf("the slice has too few elements: required=%d actual=%d", fi.length, length) - } - length = uint64(fi.length) - } - - elemType := v.Type().Elem() - if elemType.Kind() == reflect.Uint8 && fi.size == 8 && m.wbits%8 == 0 { - if _, err := io.CopyN(m.writer, bytes.NewBuffer(v.Bytes()), int64(length)); err != nil { - return err - } - m.wbits += length * 8 - return nil - } - - for i := 0; i < int(length); i++ { - m.marshal(v.Index(i), fi) - } - return nil -} - -func (m *marshaller) marshalInt(v reflect.Value, fi *fieldInstance) error { - signed := v.Int() - - if fi.is(fieldVarint) { - return errors.New("signed varint is unsupported") - } - - signBit := signed < 0 - val := uint64(signed) - for i := uint(0); i < fi.size; i += 8 { - v := val - size := uint(8) - if fi.size > i+8 { - v = v >> (fi.size - (i + 8)) - } else if fi.size < i+8 { - size = fi.size - i - } - - // set sign bit - if i == 0 { - if signBit { - v |= 0x1 << (size - 1) - } else { - v &= 0x1<<(size-1) - 1 - } - } - - if err := m.writer.WriteBits([]byte{byte(v)}, size); err != nil { - return err - } - m.wbits += uint64(size) - } - - return nil -} - -func (m *marshaller) marshalUint(v reflect.Value, fi *fieldInstance) error { - val := v.Uint() - - if fi.is(fieldVarint) { - m.writeUvarint(val) - return nil - } - - for i := uint(0); i < fi.size; i += 8 { - v := val - size := uint(8) - if fi.size > i+8 { - v = v >> (fi.size - (i + 8)) - } else if fi.size < i+8 { - size = fi.size - i - } - if err := m.writer.WriteBits([]byte{byte(v)}, size); err != nil { - return err - } - m.wbits += uint64(size) - } - - return nil -} - -func (m *marshaller) marshalBool(v reflect.Value, fi *fieldInstance) error { - var val byte - if v.Bool() { - val = 0xff - } else { - val = 0x00 - } - if err := m.writer.WriteBits([]byte{val}, fi.size); err != nil { - return err - } - m.wbits += uint64(fi.size) - return nil -} - -func (m *marshaller) marshalString(v reflect.Value) error { - data := []byte(v.String()) - for _, b := range data { - if err := m.writer.WriteBits([]byte{b}, 8); err != nil { - return err - } - m.wbits += 8 - } - // null character - if err := m.writer.WriteBits([]byte{0x00}, 8); err != nil { - return err - } - m.wbits += 8 - return nil -} - -func (m *marshaller) writeUvarint(u uint64) error { - for i := 21; i > 0; i -= 7 { - if err := m.writer.WriteBits([]byte{(byte(u >> uint(i))) | 0x80}, 8); err != nil { - return err - } - m.wbits += 8 - } - - if err := m.writer.WriteBits([]byte{byte(u) & 0x7f}, 8); err != nil { - return err - } - m.wbits += 8 - - return nil -} - -type unmarshaller struct { - reader bitio.ReadSeeker - dst IBox - size uint64 - rbits uint64 - ctx Context -} - -func UnmarshalAny(r io.ReadSeeker, boxType BoxType, payloadSize uint64, ctx Context) (box IBox, n uint64, err error) { - dst, err := boxType.New(ctx) - if err != nil { - return nil, 0, err - } - n, err = Unmarshal(r, payloadSize, dst, ctx) - return dst, n, err -} - -func Unmarshal(r io.ReadSeeker, payloadSize uint64, dst IBox, ctx Context) (n uint64, err error) { - boxDef := dst.GetType().getBoxDef(ctx) - if boxDef == nil { - return 0, ErrBoxInfoNotFound - } - - v := reflect.ValueOf(dst).Elem() - - dst.SetVersion(anyVersion) - - u := &unmarshaller{ - reader: bitio.NewReadSeeker(r), - dst: dst, - size: payloadSize, - ctx: ctx, - } - - if n, override, err := dst.BeforeUnmarshal(r, payloadSize, u.ctx); err != nil { - return 0, err - } else if override { - return n, nil - } else { - u.rbits = n * 8 - } - - sn, err := r.Seek(0, io.SeekCurrent) - if err != nil { - return 0, err - } - - if err := u.unmarshalStruct(v, boxDef.fields); err != nil { - if err == ErrUnsupportedBoxVersion { - r.Seek(sn, io.SeekStart) - } - return 0, err - } - - if u.rbits%8 != 0 { - return 0, fmt.Errorf("box size is not multiple of 8 bits: type=%s, size=%d, bits=%d", dst.GetType().String(), u.size, u.rbits) - } - - if u.rbits > u.size*8 { - return 0, fmt.Errorf("overrun error: type=%s, size=%d, bits=%d", dst.GetType().String(), u.size, u.rbits) - } - - return u.rbits / 8, nil -} - -func (u *unmarshaller) unmarshal(v reflect.Value, fi *fieldInstance) error { - var err error - switch v.Type().Kind() { - case reflect.Ptr: - err = u.unmarshalPtr(v, fi) - case reflect.Struct: - err = u.unmarshalStructInternal(v, fi) - case reflect.Array: - err = u.unmarshalArray(v, fi) - case reflect.Slice: - err = u.unmarshalSlice(v, fi) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - err = u.unmarshalInt(v, fi) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - err = u.unmarshalUint(v, fi) - case reflect.Bool: - err = u.unmarshalBool(v, fi) - case reflect.String: - err = u.unmarshalString(v, fi) - default: - return fmt.Errorf("unsupported type: %s", v.Type().Kind()) - } - return err -} - -func (u *unmarshaller) unmarshalPtr(v reflect.Value, fi *fieldInstance) error { - v.Set(reflect.New(v.Type().Elem())) - return u.unmarshal(v.Elem(), fi) -} - -func (u *unmarshaller) unmarshalStructInternal(v reflect.Value, fi *fieldInstance) error { - if fi.size != 0 && fi.size%8 == 0 { - u2 := *u - u2.size = uint64(fi.size / 8) - u2.rbits = 0 - if err := u2.unmarshalStruct(v, fi.children); err != nil { - return err - } - u.rbits += u2.rbits - if u2.rbits != uint64(fi.size) { - return errors.New("invalid alignment") - } - return nil - } - - return u.unmarshalStruct(v, fi.children) -} - -func (u *unmarshaller) unmarshalStruct(v reflect.Value, fs []*field) error { - for _, f := range fs { - fi := resolveFieldInstance(f, u.dst, v, u.ctx) - - if !isTargetField(u.dst, fi, u.ctx) { - continue - } - - rbits, override, err := fi.cfo.OnReadField(f.name, u.reader, u.size*8-u.rbits, u.ctx) - if err != nil { - return err - } - u.rbits += rbits - if override { - continue - } - - err = u.unmarshal(v.FieldByName(f.name), fi) - if err != nil { - return err - } - - if v.FieldByName(f.name).Type() == reflect.TypeOf(FullBox{}) && !u.dst.GetType().IsSupportedVersion(u.dst.GetVersion(), u.ctx) { - return ErrUnsupportedBoxVersion - } - } - - return nil -} - -func (u *unmarshaller) unmarshalArray(v reflect.Value, fi *fieldInstance) error { - size := v.Type().Size() - for i := 0; i < int(size)/int(v.Type().Elem().Size()); i++ { - var err error - err = u.unmarshal(v.Index(i), fi) - if err != nil { - return err - } - } - return nil -} - -func (u *unmarshaller) unmarshalSlice(v reflect.Value, fi *fieldInstance) error { - var slice reflect.Value - elemType := v.Type().Elem() - - length := uint64(fi.length) - if fi.length == LengthUnlimited { - if fi.size != 0 { - left := (u.size)*8 - u.rbits - if left%uint64(fi.size) != 0 { - return errors.New("invalid alignment") - } - length = left / uint64(fi.size) - } else { - length = 0 - } - } - - if u.rbits%8 == 0 && elemType.Kind() == reflect.Uint8 && fi.size == 8 { - totalSize := length * uint64(fi.size) / 8 - - if !readerHasSize(u.reader, totalSize) { - return fmt.Errorf("not enough bits") - } - - buf := bytes.NewBuffer(make([]byte, 0, totalSize)) - if _, err := io.CopyN(buf, u.reader, int64(totalSize)); err != nil { - return err - } - slice = reflect.ValueOf(buf.Bytes()) - u.rbits += uint64(totalSize) * 8 - - } else { - slice = reflect.MakeSlice(v.Type(), 0, 0) - for i := 0; ; i++ { - if fi.length != LengthUnlimited && uint(i) >= fi.length { - break - } - if fi.length == LengthUnlimited && u.rbits >= u.size*8 { - break - } - slice = reflect.Append(slice, reflect.Zero(elemType)) - if err := u.unmarshal(slice.Index(i), fi); err != nil { - return err - } - if u.rbits > u.size*8 { - return fmt.Errorf("failed to read array completely: fieldName=\"%s\"", fi.name) - } - } - } - - v.Set(slice) - return nil -} - -func (u *unmarshaller) unmarshalInt(v reflect.Value, fi *fieldInstance) error { - if fi.is(fieldVarint) { - return errors.New("signed varint is unsupported") - } - - if fi.size == 0 { - return fmt.Errorf("size must not be zero: %s", fi.name) - } - - data, err := u.reader.ReadBits(fi.size) - if err != nil { - return err - } - u.rbits += uint64(fi.size) - - signBit := false - if len(data) > 0 { - signMask := byte(0x01) << ((fi.size - 1) % 8) - signBit = data[0]&signMask != 0 - if signBit { - data[0] |= ^(signMask - 1) - } - } - - var val uint64 - if signBit { - val = ^uint64(0) - } - for i := range data { - val <<= 8 - val |= uint64(data[i]) - } - v.SetInt(int64(val)) - return nil -} - -func (u *unmarshaller) unmarshalUint(v reflect.Value, fi *fieldInstance) error { - if fi.is(fieldVarint) { - val, err := u.readUvarint() - if err != nil { - return err - } - v.SetUint(val) - return nil - } - - if fi.size == 0 { - return fmt.Errorf("size must not be zero: %s", fi.name) - } - - data, err := u.reader.ReadBits(fi.size) - if err != nil { - return err - } - u.rbits += uint64(fi.size) - - val := uint64(0) - for i := range data { - val <<= 8 - val |= uint64(data[i]) - } - v.SetUint(val) - - return nil -} - -func (u *unmarshaller) unmarshalBool(v reflect.Value, fi *fieldInstance) error { - if fi.size == 0 { - return fmt.Errorf("size must not be zero: %s", fi.name) - } - - data, err := u.reader.ReadBits(fi.size) - if err != nil { - return err - } - u.rbits += uint64(fi.size) - - val := false - for _, b := range data { - val = val || (b != byte(0)) - } - v.SetBool(val) - - return nil -} - -func (u *unmarshaller) unmarshalString(v reflect.Value, fi *fieldInstance) error { - switch fi.strType { - case stringType_C: - return u.unmarshalStringC(v) - case stringType_C_P: - return u.unmarshalStringCP(v, fi) - default: - return fmt.Errorf("unknown string type: %d", fi.strType) - } -} - -func (u *unmarshaller) unmarshalStringC(v reflect.Value) error { - data := make([]byte, 0, 16) - for { - if u.rbits >= u.size*8 { - break - } - - c, err := u.reader.ReadBits(8) - if err != nil { - return err - } - u.rbits += 8 - - if c[0] == 0 { - break // null character - } - - data = append(data, c[0]) - } - v.SetString(string(data)) - - return nil -} - -func (u *unmarshaller) unmarshalStringCP(v reflect.Value, fi *fieldInstance) error { - if ok, err := u.tryReadPString(v, fi); err != nil { - return err - } else if ok { - return nil - } - return u.unmarshalStringC(v) -} - -func (u *unmarshaller) tryReadPString(v reflect.Value, fi *fieldInstance) (ok bool, err error) { - remainingSize := (u.size*8 - u.rbits) / 8 - if remainingSize < 2 { - return false, nil - } - - offset, err := u.reader.Seek(0, io.SeekCurrent) - if err != nil { - return false, err - } - defer func() { - if err == nil && !ok { - _, err = u.reader.Seek(offset, io.SeekStart) - } - }() - - buf0 := make([]byte, 1) - if _, err := io.ReadFull(u.reader, buf0); err != nil { - return false, err - } - remainingSize-- - plen := buf0[0] - if uint64(plen) > remainingSize { - return false, nil - } - buf := make([]byte, int(plen)) - if _, err := io.ReadFull(u.reader, buf); err != nil { - return false, err - } - remainingSize -= uint64(plen) - if fi.cfo.IsPString(fi.name, buf, remainingSize, u.ctx) { - u.rbits += uint64(len(buf)+1) * 8 - v.SetString(string(buf)) - return true, nil - } - return false, nil -} - -func (u *unmarshaller) readUvarint() (uint64, error) { - var val uint64 - for { - octet, err := u.reader.ReadBits(8) - if err != nil { - return 0, err - } - u.rbits += 8 - - val = (val << 7) + uint64(octet[0]&0x7f) - - if octet[0]&0x80 == 0 { - return val, nil - } - } -} diff --git a/vendor/github.com/abema/go-mp4/mp4.go b/vendor/github.com/abema/go-mp4/mp4.go deleted file mode 100644 index 2fab24da7..000000000 --- a/vendor/github.com/abema/go-mp4/mp4.go +++ /dev/null @@ -1,171 +0,0 @@ -package mp4 - -import ( - "encoding/binary" - "errors" - "fmt" - "reflect" - "strings" -) - -var ErrBoxInfoNotFound = errors.New("box info not found") - -// BoxType is mpeg box type -type BoxType [4]byte - -func StrToBoxType(code string) BoxType { - if len(code) != 4 { - panic(fmt.Errorf("invalid box type id length: [%s]", code)) - } - return BoxType{code[0], code[1], code[2], code[3]} -} - -// Uint32ToBoxType returns a new BoxType from the provied uint32 -func Uint32ToBoxType(i uint32) BoxType { - b := make([]byte, 4) - binary.BigEndian.PutUint32(b, i) - return BoxType{b[0], b[1], b[2], b[3]} -} - -func (boxType BoxType) String() string { - if isPrintable(boxType[0]) && isPrintable(boxType[1]) && isPrintable(boxType[2]) && isPrintable(boxType[3]) { - s := string([]byte{boxType[0], boxType[1], boxType[2], boxType[3]}) - s = strings.ReplaceAll(s, string([]byte{0xa9}), "(c)") - return s - } - return fmt.Sprintf("0x%02x%02x%02x%02x", boxType[0], boxType[1], boxType[2], boxType[3]) -} - -func isASCII(c byte) bool { - return c >= 0x20 && c <= 0x7e -} - -func isPrintable(c byte) bool { - return isASCII(c) || c == 0xa9 -} - -func (lhs BoxType) MatchWith(rhs BoxType) bool { - if lhs == boxTypeAny || rhs == boxTypeAny { - return true - } - return lhs == rhs -} - -var boxTypeAny = BoxType{0x00, 0x00, 0x00, 0x00} - -func BoxTypeAny() BoxType { - return boxTypeAny -} - -type boxDef struct { - dataType reflect.Type - versions []uint8 - isTarget func(Context) bool - fields []*field -} - -var boxMap = make(map[BoxType][]boxDef, 64) - -func AddBoxDef(payload IBox, versions ...uint8) { - boxMap[payload.GetType()] = append(boxMap[payload.GetType()], boxDef{ - dataType: reflect.TypeOf(payload).Elem(), - versions: versions, - fields: buildFields(payload), - }) -} - -func AddBoxDefEx(payload IBox, isTarget func(Context) bool, versions ...uint8) { - boxMap[payload.GetType()] = append(boxMap[payload.GetType()], boxDef{ - dataType: reflect.TypeOf(payload).Elem(), - versions: versions, - isTarget: isTarget, - fields: buildFields(payload), - }) -} - -func AddAnyTypeBoxDef(payload IAnyType, boxType BoxType, versions ...uint8) { - boxMap[boxType] = append(boxMap[boxType], boxDef{ - dataType: reflect.TypeOf(payload).Elem(), - versions: versions, - fields: buildFields(payload), - }) -} - -func AddAnyTypeBoxDefEx(payload IAnyType, boxType BoxType, isTarget func(Context) bool, versions ...uint8) { - boxMap[boxType] = append(boxMap[boxType], boxDef{ - dataType: reflect.TypeOf(payload).Elem(), - versions: versions, - isTarget: isTarget, - fields: buildFields(payload), - }) -} - -var itemBoxFields = buildFields(&Item{}) - -func (boxType BoxType) getBoxDef(ctx Context) *boxDef { - boxDefs := boxMap[boxType] - for i := len(boxDefs) - 1; i >= 0; i-- { - boxDef := &boxDefs[i] - if boxDef.isTarget == nil || boxDef.isTarget(ctx) { - return boxDef - } - } - if ctx.UnderIlst { - typeID := int(binary.BigEndian.Uint32(boxType[:])) - if typeID >= 1 && typeID <= ctx.QuickTimeKeysMetaEntryCount { - return &boxDef{ - dataType: reflect.TypeOf(Item{}), - isTarget: isIlstMetaContainer, - fields: itemBoxFields, - } - } - } - return nil -} - -func (boxType BoxType) IsSupported(ctx Context) bool { - return boxType.getBoxDef(ctx) != nil -} - -func (boxType BoxType) New(ctx Context) (IBox, error) { - boxDef := boxType.getBoxDef(ctx) - if boxDef == nil { - return nil, ErrBoxInfoNotFound - } - - box, ok := reflect.New(boxDef.dataType).Interface().(IBox) - if !ok { - return nil, fmt.Errorf("box type not implements IBox interface: %s", boxType.String()) - } - - anyTypeBox, ok := box.(IAnyType) - if ok { - anyTypeBox.SetType(boxType) - } - - return box, nil -} - -func (boxType BoxType) GetSupportedVersions(ctx Context) ([]uint8, error) { - boxDef := boxType.getBoxDef(ctx) - if boxDef == nil { - return nil, ErrBoxInfoNotFound - } - return boxDef.versions, nil -} - -func (boxType BoxType) IsSupportedVersion(ver uint8, ctx Context) bool { - boxDef := boxType.getBoxDef(ctx) - if boxDef == nil { - return false - } - if len(boxDef.versions) == 0 { - return true - } - for _, sver := range boxDef.versions { - if ver == sver { - return true - } - } - return false -} diff --git a/vendor/github.com/abema/go-mp4/probe.go b/vendor/github.com/abema/go-mp4/probe.go deleted file mode 100644 index 2ffaf7aca..000000000 --- a/vendor/github.com/abema/go-mp4/probe.go +++ /dev/null @@ -1,684 +0,0 @@ -package mp4 - -import ( - "bytes" - "errors" - "io" - - "github.com/abema/go-mp4/internal/bitio" -) - -type ProbeInfo struct { - MajorBrand [4]byte - MinorVersion uint32 - CompatibleBrands [][4]byte - FastStart bool - Timescale uint32 - Duration uint64 - Tracks Tracks - Segments Segments -} - -// Deprecated: replace with ProbeInfo -type FraProbeInfo = ProbeInfo - -type Tracks []*Track - -// Deprecated: replace with Track -type TrackInfo = Track - -type Track struct { - TrackID uint32 - Timescale uint32 - Duration uint64 - Codec Codec - Encrypted bool - EditList EditList - Samples Samples - Chunks Chunks - AVC *AVCDecConfigInfo - MP4A *MP4AInfo -} - -type Codec int - -const ( - CodecUnknown Codec = iota - CodecAVC1 - CodecMP4A -) - -type EditList []*EditListEntry - -type EditListEntry struct { - MediaTime int64 - SegmentDuration uint64 -} - -type Samples []*Sample - -type Sample struct { - Size uint32 - TimeDelta uint32 - CompositionTimeOffset int64 -} - -type Chunks []*Chunk - -type Chunk struct { - DataOffset uint64 - SamplesPerChunk uint32 -} - -type AVCDecConfigInfo struct { - ConfigurationVersion uint8 - Profile uint8 - ProfileCompatibility uint8 - Level uint8 - LengthSize uint16 - Width uint16 - Height uint16 -} - -type MP4AInfo struct { - OTI uint8 - AudOTI uint8 - ChannelCount uint16 -} - -type Segments []*Segment - -// Deprecated: replace with Segment -type SegmentInfo = Segment - -type Segment struct { - TrackID uint32 - MoofOffset uint64 - BaseMediaDecodeTime uint64 - DefaultSampleDuration uint32 - SampleCount uint32 - Duration uint32 - CompositionTimeOffset int32 - Size uint32 -} - -// Probe probes MP4 file -func Probe(r io.ReadSeeker) (*ProbeInfo, error) { - probeInfo := &ProbeInfo{ - Tracks: make([]*Track, 0, 8), - Segments: make([]*Segment, 0, 8), - } - bis, err := ExtractBoxes(r, nil, []BoxPath{ - {BoxTypeFtyp()}, - {BoxTypeMoov()}, - {BoxTypeMoov(), BoxTypeMvhd()}, - {BoxTypeMoov(), BoxTypeTrak()}, - {BoxTypeMoof()}, - {BoxTypeMdat()}, - }) - if err != nil { - return nil, err - } - var mdatAppeared bool - for _, bi := range bis { - switch bi.Type { - case BoxTypeFtyp(): - var ftyp Ftyp - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - if _, err := Unmarshal(r, bi.Size-bi.HeaderSize, &ftyp, bi.Context); err != nil { - return nil, err - } - probeInfo.MajorBrand = ftyp.MajorBrand - probeInfo.MinorVersion = ftyp.MinorVersion - probeInfo.CompatibleBrands = make([][4]byte, 0, len(ftyp.CompatibleBrands)) - for _, entry := range ftyp.CompatibleBrands { - probeInfo.CompatibleBrands = append(probeInfo.CompatibleBrands, entry.CompatibleBrand) - } - case BoxTypeMoov(): - probeInfo.FastStart = !mdatAppeared - case BoxTypeMvhd(): - var mvhd Mvhd - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - if _, err := Unmarshal(r, bi.Size-bi.HeaderSize, &mvhd, bi.Context); err != nil { - return nil, err - } - probeInfo.Timescale = mvhd.Timescale - if mvhd.GetVersion() == 0 { - probeInfo.Duration = uint64(mvhd.DurationV0) - } else { - probeInfo.Duration = mvhd.DurationV1 - } - case BoxTypeTrak(): - track, err := probeTrak(r, bi) - if err != nil { - return nil, err - } - probeInfo.Tracks = append(probeInfo.Tracks, track) - case BoxTypeMoof(): - segment, err := probeMoof(r, bi) - if err != nil { - return nil, err - } - probeInfo.Segments = append(probeInfo.Segments, segment) - case BoxTypeMdat(): - mdatAppeared = true - } - } - return probeInfo, nil -} - -// ProbeFra probes fragmented MP4 file -// Deprecated: replace with Probe -func ProbeFra(r io.ReadSeeker) (*FraProbeInfo, error) { - probeInfo, err := Probe(r) - return (*FraProbeInfo)(probeInfo), err -} - -func probeTrak(r io.ReadSeeker, bi *BoxInfo) (*Track, error) { - track := new(Track) - - bips, err := ExtractBoxesWithPayload(r, bi, []BoxPath{ - {BoxTypeTkhd()}, - {BoxTypeEdts(), BoxTypeElst()}, - {BoxTypeMdia(), BoxTypeMdhd()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeAvc1()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeAvc1(), BoxTypeAvcC()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeEncv()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeEncv(), BoxTypeAvcC()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeMp4a()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeMp4a(), BoxTypeEsds()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeMp4a(), BoxTypeWave(), BoxTypeEsds()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeEnca()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsd(), BoxTypeEnca(), BoxTypeEsds()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStco()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeCo64()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStts()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeCtts()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsc()}, - {BoxTypeMdia(), BoxTypeMinf(), BoxTypeStbl(), BoxTypeStsz()}, - }) - if err != nil { - return nil, err - } - var tkhd *Tkhd - var elst *Elst - var mdhd *Mdhd - var avc1 *VisualSampleEntry - var avcC *AVCDecoderConfiguration - var audioSampleEntry *AudioSampleEntry - var esds *Esds - var stco *Stco - var stts *Stts - var stsc *Stsc - var ctts *Ctts - var stsz *Stsz - var co64 *Co64 - for _, bip := range bips { - switch bip.Info.Type { - case BoxTypeTkhd(): - tkhd = bip.Payload.(*Tkhd) - case BoxTypeElst(): - elst = bip.Payload.(*Elst) - case BoxTypeMdhd(): - mdhd = bip.Payload.(*Mdhd) - case BoxTypeAvc1(): - track.Codec = CodecAVC1 - avc1 = bip.Payload.(*VisualSampleEntry) - case BoxTypeAvcC(): - avcC = bip.Payload.(*AVCDecoderConfiguration) - case BoxTypeEncv(): - track.Codec = CodecAVC1 - track.Encrypted = true - case BoxTypeMp4a(): - track.Codec = CodecMP4A - audioSampleEntry = bip.Payload.(*AudioSampleEntry) - case BoxTypeEnca(): - track.Codec = CodecMP4A - track.Encrypted = true - audioSampleEntry = bip.Payload.(*AudioSampleEntry) - case BoxTypeEsds(): - esds = bip.Payload.(*Esds) - case BoxTypeStco(): - stco = bip.Payload.(*Stco) - case BoxTypeStts(): - stts = bip.Payload.(*Stts) - case BoxTypeStsc(): - stsc = bip.Payload.(*Stsc) - case BoxTypeCtts(): - ctts = bip.Payload.(*Ctts) - case BoxTypeStsz(): - stsz = bip.Payload.(*Stsz) - case BoxTypeCo64(): - co64 = bip.Payload.(*Co64) - } - } - - if tkhd == nil { - return nil, errors.New("tkhd box not found") - } - track.TrackID = tkhd.TrackID - - if elst != nil { - editList := make([]*EditListEntry, 0, len(elst.Entries)) - for i := range elst.Entries { - editList = append(editList, &EditListEntry{ - MediaTime: elst.GetMediaTime(i), - SegmentDuration: elst.GetSegmentDuration(i), - }) - } - track.EditList = editList - } - - if mdhd == nil { - return nil, errors.New("mdhd box not found") - } - track.Timescale = mdhd.Timescale - track.Duration = mdhd.GetDuration() - - if avc1 != nil && avcC != nil { - track.AVC = &AVCDecConfigInfo{ - ConfigurationVersion: avcC.ConfigurationVersion, - Profile: avcC.Profile, - ProfileCompatibility: avcC.ProfileCompatibility, - Level: avcC.Level, - LengthSize: uint16(avcC.LengthSizeMinusOne) + 1, - Width: avc1.Width, - Height: avc1.Height, - } - } - - if audioSampleEntry != nil && esds != nil { - oti, audOTI, err := detectAACProfile(esds) - if err != nil { - return nil, err - } - track.MP4A = &MP4AInfo{ - OTI: oti, - AudOTI: audOTI, - ChannelCount: audioSampleEntry.ChannelCount, - } - } - - track.Chunks = make([]*Chunk, 0) - if stco != nil { - for _, offset := range stco.ChunkOffset { - track.Chunks = append(track.Chunks, &Chunk{ - DataOffset: uint64(offset), - }) - } - } else if co64 != nil { - for _, offset := range co64.ChunkOffset { - track.Chunks = append(track.Chunks, &Chunk{ - DataOffset: offset, - }) - } - } else { - return nil, errors.New("stco/co64 box not found") - } - - if stts == nil { - return nil, errors.New("stts box not found") - } - track.Samples = make([]*Sample, 0) - for _, entry := range stts.Entries { - for i := uint32(0); i < entry.SampleCount; i++ { - track.Samples = append(track.Samples, &Sample{ - TimeDelta: entry.SampleDelta, - }) - } - } - - if stsc == nil { - return nil, errors.New("stsc box not found") - } - for si, entry := range stsc.Entries { - end := uint32(len(track.Chunks)) - if si != len(stsc.Entries)-1 && stsc.Entries[si+1].FirstChunk-1 < end { - end = stsc.Entries[si+1].FirstChunk - 1 - } - for ci := entry.FirstChunk - 1; ci < end; ci++ { - track.Chunks[ci].SamplesPerChunk = entry.SamplesPerChunk - } - } - - if ctts != nil { - var si uint32 - for ci, entry := range ctts.Entries { - for i := uint32(0); i < entry.SampleCount; i++ { - if si >= uint32(len(track.Samples)) { - break - } - track.Samples[si].CompositionTimeOffset = ctts.GetSampleOffset(ci) - si++ - } - } - } - - if stsz != nil { - for i := 0; i < len(stsz.EntrySize) && i < len(track.Samples); i++ { - track.Samples[i].Size = stsz.EntrySize[i] - } - } - - return track, nil -} - -func detectAACProfile(esds *Esds) (oti, audOTI uint8, err error) { - configDscr := findDescriptorByTag(esds.Descriptors, DecoderConfigDescrTag) - if configDscr == nil || configDscr.DecoderConfigDescriptor == nil { - return 0, 0, nil - } - if configDscr.DecoderConfigDescriptor.ObjectTypeIndication != 0x40 { - return configDscr.DecoderConfigDescriptor.ObjectTypeIndication, 0, nil - } - - specificDscr := findDescriptorByTag(esds.Descriptors, DecSpecificInfoTag) - if specificDscr == nil { - return 0, 0, errors.New("DecoderSpecificationInfoDescriptor not found") - } - - r := bitio.NewReader(bytes.NewReader(specificDscr.Data)) - remaining := len(specificDscr.Data) * 8 - - // audio object type - audioObjectType, read, err := getAudioObjectType(r) - if err != nil { - return 0, 0, err - } - remaining -= read - - // sampling frequency index - samplingFrequencyIndex, err := r.ReadBits(4) - if err != nil { - return 0, 0, err - } - remaining -= 4 - if samplingFrequencyIndex[0] == 0x0f { - if _, err = r.ReadBits(24); err != nil { - return 0, 0, err - } - remaining -= 24 - } - - if audioObjectType == 2 && remaining >= 20 { - if _, err = r.ReadBits(4); err != nil { - return 0, 0, err - } - remaining -= 4 - syncExtensionType, err := r.ReadBits(11) - if err != nil { - return 0, 0, err - } - remaining -= 11 - if syncExtensionType[0] == 0x2 && syncExtensionType[1] == 0xb7 { - extAudioObjectType, _, err := getAudioObjectType(r) - if err != nil { - return 0, 0, err - } - if extAudioObjectType == 5 || extAudioObjectType == 22 { - sbr, err := r.ReadBits(1) - if err != nil { - return 0, 0, err - } - remaining-- - if sbr[0] != 0 { - if extAudioObjectType == 5 { - sfi, err := r.ReadBits(4) - if err != nil { - return 0, 0, err - } - remaining -= 4 - if sfi[0] == 0xf { - if _, err := r.ReadBits(24); err != nil { - return 0, 0, err - } - remaining -= 24 - } - if remaining >= 12 { - syncExtensionType, err := r.ReadBits(11) - if err != nil { - return 0, 0, err - } - if syncExtensionType[0] == 0x5 && syncExtensionType[1] == 0x48 { - ps, err := r.ReadBits(1) - if err != nil { - return 0, 0, err - } - if ps[0] != 0 { - return 0x40, 29, nil - } - } - } - } - return 0x40, 5, nil - } - } - } - } - return 0x40, audioObjectType, nil -} - -func findDescriptorByTag(dscrs []Descriptor, tag int8) *Descriptor { - for _, dscr := range dscrs { - if dscr.Tag == tag { - return &dscr - } - } - return nil -} - -func getAudioObjectType(r bitio.Reader) (byte, int, error) { - audioObjectType, err := r.ReadBits(5) - if err != nil { - return 0, 0, err - } - if audioObjectType[0] != 0x1f { - return audioObjectType[0], 5, nil - } - audioObjectType, err = r.ReadBits(6) - if err != nil { - return 0, 0, err - } - return audioObjectType[0] + 32, 11, nil -} - -func probeMoof(r io.ReadSeeker, bi *BoxInfo) (*Segment, error) { - bips, err := ExtractBoxesWithPayload(r, bi, []BoxPath{ - {BoxTypeTraf(), BoxTypeTfhd()}, - {BoxTypeTraf(), BoxTypeTfdt()}, - {BoxTypeTraf(), BoxTypeTrun()}, - }) - if err != nil { - return nil, err - } - - var tfhd *Tfhd - var tfdt *Tfdt - var trun *Trun - - segment := &Segment{ - MoofOffset: bi.Offset, - } - for _, bip := range bips { - switch bip.Info.Type { - case BoxTypeTfhd(): - tfhd = bip.Payload.(*Tfhd) - case BoxTypeTfdt(): - tfdt = bip.Payload.(*Tfdt) - case BoxTypeTrun(): - trun = bip.Payload.(*Trun) - } - } - - if tfhd == nil { - return nil, errors.New("tfhd not found") - } - segment.TrackID = tfhd.TrackID - segment.DefaultSampleDuration = tfhd.DefaultSampleDuration - - if tfdt != nil { - if tfdt.Version == 0 { - segment.BaseMediaDecodeTime = uint64(tfdt.BaseMediaDecodeTimeV0) - } else { - segment.BaseMediaDecodeTime = tfdt.BaseMediaDecodeTimeV1 - } - } - - if trun != nil { - segment.SampleCount = trun.SampleCount - - if trun.CheckFlag(0x000100) { - segment.Duration = 0 - for ei := range trun.Entries { - segment.Duration += trun.Entries[ei].SampleDuration - } - } else { - segment.Duration = tfhd.DefaultSampleDuration * segment.SampleCount - } - - if trun.CheckFlag(0x000200) { - segment.Size = 0 - for ei := range trun.Entries { - segment.Size += trun.Entries[ei].SampleSize - } - } else { - segment.Size = tfhd.DefaultSampleSize * segment.SampleCount - } - - var duration uint32 - for ei := range trun.Entries { - offset := int32(duration) + int32(trun.GetSampleCompositionTimeOffset(ei)) - if ei == 0 || offset < segment.CompositionTimeOffset { - segment.CompositionTimeOffset = offset - } - if trun.CheckFlag(0x000100) { - duration += trun.Entries[ei].SampleDuration - } else { - duration += tfhd.DefaultSampleDuration - } - } - } - - return segment, nil -} - -func FindIDRFrames(r io.ReadSeeker, trackInfo *TrackInfo) ([]int, error) { - if trackInfo.AVC == nil { - return nil, nil - } - lengthSize := uint32(trackInfo.AVC.LengthSize) - - var si int - idxs := make([]int, 0, 8) - for _, chunk := range trackInfo.Chunks { - end := si + int(chunk.SamplesPerChunk) - dataOffset := chunk.DataOffset - for ; si < end && si < len(trackInfo.Samples); si++ { - sample := trackInfo.Samples[si] - if sample.Size == 0 { - continue - } - for nalOffset := uint32(0); nalOffset+lengthSize+1 <= sample.Size; { - if _, err := r.Seek(int64(dataOffset+uint64(nalOffset)), io.SeekStart); err != nil { - return nil, err - } - data := make([]byte, lengthSize+1) - if _, err := io.ReadFull(r, data); err != nil { - return nil, err - } - var length uint32 - for i := 0; i < int(lengthSize); i++ { - length = (length << 8) + uint32(data[i]) - } - nalHeader := data[lengthSize] - nalType := nalHeader & 0x1f - if nalType == 5 { - idxs = append(idxs, si) - break - } - nalOffset += lengthSize + length - } - dataOffset += uint64(sample.Size) - } - } - return idxs, nil -} - -func (samples Samples) GetBitrate(timescale uint32) uint64 { - var totalSize uint64 - var totalDuration uint64 - for _, sample := range samples { - totalSize += uint64(sample.Size) - totalDuration += uint64(sample.TimeDelta) - } - if totalDuration == 0 { - return 0 - } - return 8 * totalSize * uint64(timescale) / totalDuration -} - -func (samples Samples) GetMaxBitrate(timescale uint32, timeDelta uint64) uint64 { - if timeDelta == 0 { - return 0 - } - var maxBitrate uint64 - var size uint64 - var duration uint64 - var begin int - var end int - for end < len(samples) { - for { - size += uint64(samples[end].Size) - duration += uint64(samples[end].TimeDelta) - end++ - if duration >= timeDelta || end == len(samples) { - break - } - } - bitrate := 8 * size * uint64(timescale) / duration - if bitrate > maxBitrate { - maxBitrate = bitrate - } - for { - size -= uint64(samples[begin].Size) - duration -= uint64(samples[begin].TimeDelta) - begin++ - if duration < timeDelta { - break - } - } - } - return maxBitrate -} - -func (segments Segments) GetBitrate(trackID uint32, timescale uint32) uint64 { - var totalSize uint64 - var totalDuration uint64 - for _, segment := range segments { - if segment.TrackID == trackID { - totalSize += uint64(segment.Size) - totalDuration += uint64(segment.Duration) - } - } - if totalDuration == 0 { - return 0 - } - return 8 * totalSize * uint64(timescale) / totalDuration -} - -func (segments Segments) GetMaxBitrate(trackID uint32, timescale uint32) uint64 { - var maxBitrate uint64 - for _, segment := range segments { - if segment.TrackID == trackID && segment.Duration != 0 { - bitrate := 8 * uint64(segment.Size) * uint64(timescale) / uint64(segment.Duration) - if bitrate > maxBitrate { - maxBitrate = bitrate - } - } - } - return maxBitrate -} diff --git a/vendor/github.com/abema/go-mp4/read.go b/vendor/github.com/abema/go-mp4/read.go deleted file mode 100644 index 7118d802a..000000000 --- a/vendor/github.com/abema/go-mp4/read.go +++ /dev/null @@ -1,199 +0,0 @@ -package mp4 - -import ( - "errors" - "fmt" - "io" -) - -type BoxPath []BoxType - -func (lhs BoxPath) compareWith(rhs BoxPath) (forwardMatch bool, match bool) { - if len(lhs) > len(rhs) { - return false, false - } - for i := 0; i < len(lhs); i++ { - if !lhs[i].MatchWith(rhs[i]) { - return false, false - } - } - if len(lhs) < len(rhs) { - return true, false - } - return false, true -} - -type ReadHandle struct { - Params []interface{} - BoxInfo BoxInfo - Path BoxPath - ReadPayload func() (box IBox, n uint64, err error) - ReadData func(io.Writer) (n uint64, err error) - Expand func(params ...interface{}) (vals []interface{}, err error) -} - -type ReadHandler func(handle *ReadHandle) (val interface{}, err error) - -func ReadBoxStructure(r io.ReadSeeker, handler ReadHandler, params ...interface{}) ([]interface{}, error) { - if _, err := r.Seek(0, io.SeekStart); err != nil { - return nil, err - } - return readBoxStructure(r, 0, true, nil, Context{}, handler, params) -} - -func ReadBoxStructureFromInternal(r io.ReadSeeker, bi *BoxInfo, handler ReadHandler, params ...interface{}) (interface{}, error) { - return readBoxStructureFromInternal(r, bi, nil, handler, params) -} - -func readBoxStructureFromInternal(r io.ReadSeeker, bi *BoxInfo, path BoxPath, handler ReadHandler, params []interface{}) (interface{}, error) { - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - - // check comatible-brands - if len(path) == 0 && bi.Type == BoxTypeFtyp() { - var ftyp Ftyp - if _, err := Unmarshal(r, bi.Size-bi.HeaderSize, &ftyp, bi.Context); err != nil { - return nil, err - } - if ftyp.HasCompatibleBrand(BrandQT()) { - bi.IsQuickTimeCompatible = true - } - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - } - - // parse numbered ilst items after keys box by saving EntryCount field to context - if bi.Type == BoxTypeKeys() { - var keys Keys - if _, err := Unmarshal(r, bi.Size-bi.HeaderSize, &keys, bi.Context); err != nil { - return nil, err - } - bi.QuickTimeKeysMetaEntryCount = int(keys.EntryCount) - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - } - - ctx := bi.Context - if bi.Type == BoxTypeWave() { - ctx.UnderWave = true - } else if bi.Type == BoxTypeIlst() { - ctx.UnderIlst = true - } else if bi.UnderIlst && !bi.UnderIlstMeta && IsIlstMetaBoxType(bi.Type) { - ctx.UnderIlstMeta = true - if bi.Type == StrToBoxType("----") { - ctx.UnderIlstFreeMeta = true - } - } else if bi.Type == BoxTypeUdta() { - ctx.UnderUdta = true - } - - newPath := make(BoxPath, len(path)+1) - copy(newPath, path) - newPath[len(path)] = bi.Type - - h := &ReadHandle{ - Params: params, - BoxInfo: *bi, - Path: newPath, - } - - var childrenOffset uint64 - - h.ReadPayload = func() (IBox, uint64, error) { - if _, err := bi.SeekToPayload(r); err != nil { - return nil, 0, err - } - - box, n, err := UnmarshalAny(r, bi.Type, bi.Size-bi.HeaderSize, bi.Context) - if err != nil { - return nil, 0, err - } - childrenOffset = bi.Offset + bi.HeaderSize + n - return box, n, nil - } - - h.ReadData = func(w io.Writer) (uint64, error) { - if _, err := bi.SeekToPayload(r); err != nil { - return 0, err - } - - size := bi.Size - bi.HeaderSize - if _, err := io.CopyN(w, r, int64(size)); err != nil { - return 0, err - } - return size, nil - } - - h.Expand = func(params ...interface{}) ([]interface{}, error) { - if childrenOffset == 0 { - if _, err := bi.SeekToPayload(r); err != nil { - return nil, err - } - - _, n, err := UnmarshalAny(r, bi.Type, bi.Size-bi.HeaderSize, bi.Context) - if err != nil { - return nil, err - } - childrenOffset = bi.Offset + bi.HeaderSize + n - } else { - if _, err := r.Seek(int64(childrenOffset), io.SeekStart); err != nil { - return nil, err - } - } - - childrenSize := bi.Offset + bi.Size - childrenOffset - return readBoxStructure(r, childrenSize, false, newPath, ctx, handler, params) - } - - if val, err := handler(h); err != nil { - return nil, err - } else if _, err := bi.SeekToEnd(r); err != nil { - return nil, err - } else { - return val, nil - } -} - -func readBoxStructure(r io.ReadSeeker, totalSize uint64, isRoot bool, path BoxPath, ctx Context, handler ReadHandler, params []interface{}) ([]interface{}, error) { - vals := make([]interface{}, 0, 8) - - for isRoot || totalSize >= SmallHeaderSize { - bi, err := ReadBoxInfo(r) - if isRoot && err == io.EOF { - return vals, nil - } else if err != nil { - return nil, err - } - - if !isRoot && bi.Size > totalSize { - return nil, fmt.Errorf("too large box size: type=%s, size=%d, actualBufSize=%d", bi.Type.String(), bi.Size, totalSize) - } - totalSize -= bi.Size - - bi.Context = ctx - - val, err := readBoxStructureFromInternal(r, bi, path, handler, params) - if err != nil { - return nil, err - } - vals = append(vals, val) - - if bi.IsQuickTimeCompatible { - ctx.IsQuickTimeCompatible = true - } - - // preserve keys entry count on context for subsequent ilst number item box - if bi.Type == BoxTypeKeys() { - ctx.QuickTimeKeysMetaEntryCount = bi.QuickTimeKeysMetaEntryCount - } - } - - if totalSize != 0 && !ctx.IsQuickTimeCompatible { - return nil, errors.New("Unexpected EOF") - } - - return vals, nil -} diff --git a/vendor/github.com/abema/go-mp4/string.go b/vendor/github.com/abema/go-mp4/string.go deleted file mode 100644 index 4bc368e42..000000000 --- a/vendor/github.com/abema/go-mp4/string.go +++ /dev/null @@ -1,261 +0,0 @@ -package mp4 - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strconv" - - "github.com/abema/go-mp4/internal/util" -) - -type stringifier struct { - buf *bytes.Buffer - src IImmutableBox - indent string - ctx Context -} - -func Stringify(src IImmutableBox, ctx Context) (string, error) { - return StringifyWithIndent(src, "", ctx) -} - -func StringifyWithIndent(src IImmutableBox, indent string, ctx Context) (string, error) { - boxDef := src.GetType().getBoxDef(ctx) - if boxDef == nil { - return "", ErrBoxInfoNotFound - } - - v := reflect.ValueOf(src).Elem() - - m := &stringifier{ - buf: bytes.NewBuffer(nil), - src: src, - indent: indent, - ctx: ctx, - } - - err := m.stringifyStruct(v, boxDef.fields, 0, true) - if err != nil { - return "", err - } - - return m.buf.String(), nil -} - -func (m *stringifier) stringify(v reflect.Value, fi *fieldInstance, depth int) error { - switch v.Type().Kind() { - case reflect.Ptr: - return m.stringifyPtr(v, fi, depth) - case reflect.Struct: - return m.stringifyStruct(v, fi.children, depth, fi.is(fieldExtend)) - case reflect.Array: - return m.stringifyArray(v, fi, depth) - case reflect.Slice: - return m.stringifySlice(v, fi, depth) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return m.stringifyInt(v, fi, depth) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return m.stringifyUint(v, fi, depth) - case reflect.Bool: - return m.stringifyBool(v, depth) - case reflect.String: - return m.stringifyString(v, depth) - default: - return fmt.Errorf("unsupported type: %s", v.Type().Kind()) - } -} - -func (m *stringifier) stringifyPtr(v reflect.Value, fi *fieldInstance, depth int) error { - return m.stringify(v.Elem(), fi, depth) -} - -func (m *stringifier) stringifyStruct(v reflect.Value, fs []*field, depth int, extended bool) error { - if !extended { - m.buf.WriteString("{") - if m.indent != "" { - m.buf.WriteString("\n") - } - depth++ - } - - for _, f := range fs { - fi := resolveFieldInstance(f, m.src, v, m.ctx) - - if !isTargetField(m.src, fi, m.ctx) { - continue - } - - if f.cnst != "" || f.is(fieldHidden) { - continue - } - - if !f.is(fieldExtend) { - if m.indent != "" { - writeIndent(m.buf, m.indent, depth+1) - } else if m.buf.Len() != 0 && m.buf.Bytes()[m.buf.Len()-1] != '{' { - m.buf.WriteString(" ") - } - m.buf.WriteString(f.name) - m.buf.WriteString("=") - } - - str, ok := fi.cfo.StringifyField(f.name, m.indent, depth+1, m.ctx) - if ok { - m.buf.WriteString(str) - if !f.is(fieldExtend) && m.indent != "" { - m.buf.WriteString("\n") - } - continue - } - - if f.name == "Version" { - m.buf.WriteString(strconv.Itoa(int(m.src.GetVersion()))) - } else if f.name == "Flags" { - fmt.Fprintf(m.buf, "0x%06x", m.src.GetFlags()) - } else { - err := m.stringify(v.FieldByName(f.name), fi, depth) - if err != nil { - return err - } - } - - if !f.is(fieldExtend) && m.indent != "" { - m.buf.WriteString("\n") - } - } - - if !extended { - if m.indent != "" { - writeIndent(m.buf, m.indent, depth) - } - m.buf.WriteString("}") - } - - return nil -} - -func (m *stringifier) stringifyArray(v reflect.Value, fi *fieldInstance, depth int) error { - begin, sep, end := "[", ", ", "]" - if fi.is(fieldString) || fi.is(fieldISO639_2) { - begin, sep, end = "\"", "", "\"" - } else if fi.is(fieldUUID) { - begin, sep, end = "", "", "" - } - - m.buf.WriteString(begin) - - m2 := *m - if fi.is(fieldString) { - m2.buf = bytes.NewBuffer(nil) - } - size := v.Type().Size() - for i := 0; i < int(size)/int(v.Type().Elem().Size()); i++ { - if i != 0 { - m2.buf.WriteString(sep) - } - - if err := m2.stringify(v.Index(i), fi, depth+1); err != nil { - return err - } - - if fi.is(fieldUUID) && (i == 3 || i == 5 || i == 7 || i == 9) { - m.buf.WriteString("-") - } - } - if fi.is(fieldString) { - m.buf.WriteString(util.EscapeUnprintables(m2.buf.String())) - } - - m.buf.WriteString(end) - - return nil -} - -func (m *stringifier) stringifySlice(v reflect.Value, fi *fieldInstance, depth int) error { - begin, sep, end := "[", ", ", "]" - if fi.is(fieldString) || fi.is(fieldISO639_2) { - begin, sep, end = "\"", "", "\"" - } - - m.buf.WriteString(begin) - - m2 := *m - if fi.is(fieldString) { - m2.buf = bytes.NewBuffer(nil) - } - for i := 0; i < v.Len(); i++ { - if fi.length != LengthUnlimited && uint(i) >= fi.length { - break - } - - if i != 0 { - m2.buf.WriteString(sep) - } - - if err := m2.stringify(v.Index(i), fi, depth+1); err != nil { - return err - } - } - if fi.is(fieldString) { - m.buf.WriteString(util.EscapeUnprintables(m2.buf.String())) - } - - m.buf.WriteString(end) - - return nil -} - -func (m *stringifier) stringifyInt(v reflect.Value, fi *fieldInstance, depth int) error { - if fi.is(fieldHex) { - val := v.Int() - if val >= 0 { - m.buf.WriteString("0x") - m.buf.WriteString(strconv.FormatInt(val, 16)) - } else { - m.buf.WriteString("-0x") - m.buf.WriteString(strconv.FormatInt(-val, 16)) - } - } else { - m.buf.WriteString(strconv.FormatInt(v.Int(), 10)) - } - return nil -} - -func (m *stringifier) stringifyUint(v reflect.Value, fi *fieldInstance, depth int) error { - if fi.is(fieldISO639_2) { - m.buf.WriteString(string([]byte{byte(v.Uint() + 0x60)})) - } else if fi.is(fieldUUID) { - fmt.Fprintf(m.buf, "%02x", v.Uint()) - } else if fi.is(fieldString) { - m.buf.WriteString(string([]byte{byte(v.Uint())})) - } else if fi.is(fieldHex) || (!fi.is(fieldDec) && v.Type().Kind() == reflect.Uint8) || v.Type().Kind() == reflect.Uintptr { - m.buf.WriteString("0x") - m.buf.WriteString(strconv.FormatUint(v.Uint(), 16)) - } else { - m.buf.WriteString(strconv.FormatUint(v.Uint(), 10)) - } - - return nil -} - -func (m *stringifier) stringifyBool(v reflect.Value, depth int) error { - m.buf.WriteString(strconv.FormatBool(v.Bool())) - - return nil -} - -func (m *stringifier) stringifyString(v reflect.Value, depth int) error { - m.buf.WriteString("\"") - m.buf.WriteString(util.EscapeUnprintables(v.String())) - m.buf.WriteString("\"") - - return nil -} - -func writeIndent(w io.Writer, indent string, depth int) { - for i := 0; i < depth; i++ { - io.WriteString(w, indent) - } -} diff --git a/vendor/github.com/abema/go-mp4/write.go b/vendor/github.com/abema/go-mp4/write.go deleted file mode 100644 index 72d464444..000000000 --- a/vendor/github.com/abema/go-mp4/write.go +++ /dev/null @@ -1,68 +0,0 @@ -package mp4 - -import ( - "errors" - "io" -) - -type Writer struct { - writer io.WriteSeeker - biStack []*BoxInfo -} - -func NewWriter(w io.WriteSeeker) *Writer { - return &Writer{ - writer: w, - } -} - -func (w *Writer) Write(p []byte) (int, error) { - return w.writer.Write(p) -} - -func (w *Writer) Seek(offset int64, whence int) (int64, error) { - return w.writer.Seek(offset, whence) -} - -func (w *Writer) StartBox(bi *BoxInfo) (*BoxInfo, error) { - bi, err := WriteBoxInfo(w.writer, bi) - if err != nil { - return nil, err - } - w.biStack = append(w.biStack, bi) - return bi, nil -} - -func (w *Writer) EndBox() (*BoxInfo, error) { - bi := w.biStack[len(w.biStack)-1] - w.biStack = w.biStack[:len(w.biStack)-1] - end, err := w.writer.Seek(0, io.SeekCurrent) - if err != nil { - return nil, err - } - bi.Size = uint64(end) - bi.Offset - if _, err = bi.SeekToStart(w.writer); err != nil { - return nil, err - } - if bi2, err := WriteBoxInfo(w.writer, bi); err != nil { - return nil, err - } else if bi.HeaderSize != bi2.HeaderSize { - return nil, errors.New("header size changed") - } - if _, err := w.writer.Seek(end, io.SeekStart); err != nil { - return nil, err - } - return bi, nil -} - -func (w *Writer) CopyBox(r io.ReadSeeker, bi *BoxInfo) error { - if _, err := bi.SeekToStart(r); err != nil { - return err - } - if n, err := io.CopyN(w, r, int64(bi.Size)); err != nil { - return err - } else if n != int64(bi.Size) { - return errors.New("failed to copy box") - } - return nil -} |