summaryrefslogtreecommitdiff
path: root/vendor/github.com/abema/go-mp4/read.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/abema/go-mp4/read.go')
-rw-r--r--vendor/github.com/abema/go-mp4/read.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/vendor/github.com/abema/go-mp4/read.go b/vendor/github.com/abema/go-mp4/read.go
new file mode 100644
index 000000000..fa69561aa
--- /dev/null
+++ b/vendor/github.com/abema/go-mp4/read.go
@@ -0,0 +1,182 @@
+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
+ }
+ }
+
+ 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 != 0 {
+ 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
+ }
+ }
+
+ if totalSize != 0 {
+ return nil, errors.New("Unexpected EOF")
+ }
+
+ return vals, nil
+}