-
Notifications
You must be signed in to change notification settings - Fork 1
/
stsd.go
157 lines (146 loc) · 3.66 KB
/
stsd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package mp4
import (
"encoding/binary"
"fmt"
"io"
)
// StsdBox - Sample Description Box (stsd - manatory)
// See ISO/IEC 14496-12 Section 8.5.2.2
// Full Box + SampleCount
// All Children are sampleEntries
type StsdBox struct {
Version byte
Flags uint32
SampleCount uint32
AvcX *VisualSampleEntryBox
HvcX *VisualSampleEntryBox
Mp4a *AudioSampleEntryBox
Wvtt *WvttBox
Children []Box
}
// NewStsdBox - Generate a new empty stsd box
func NewStsdBox() *StsdBox {
return &StsdBox{}
}
// AddChild - Add a child box and update SampleCount
func (s *StsdBox) AddChild(box Box) {
switch box.Type() {
case "avc1", "avc3":
s.AvcX = box.(*VisualSampleEntryBox)
case "hvc1", "hev1":
s.HvcX = box.(*VisualSampleEntryBox)
case "mp4a":
s.Mp4a = box.(*AudioSampleEntryBox)
case "wvtt":
s.Wvtt = box.(*WvttBox)
}
s.Children = append(s.Children, box)
s.SampleCount++
}
// AddChild - Replace a child box with one of the same type
func (s *StsdBox) ReplaceChild(box Box) {
switch box.(type) {
case *VisualSampleEntryBox:
for i, b := range s.Children {
switch b.(type) {
case *VisualSampleEntryBox:
s.Children[i] = box.(*VisualSampleEntryBox)
s.AvcX = box.(*VisualSampleEntryBox)
}
}
case *AudioSampleEntryBox:
for i, b := range s.Children {
switch b.(type) {
case *AudioSampleEntryBox:
s.Children[i] = box.(*AudioSampleEntryBox)
s.Mp4a = box.(*AudioSampleEntryBox)
}
}
default:
panic("Cannot handle box type")
}
}
// GetSampleDescription - get one of multiple descriptions
func (s *StsdBox) GetSampleDescription(index int) (Box, error) {
if index >= len(s.Children) {
return nil, fmt.Errorf("Beyond limit of sample descriptors")
}
return s.Children[index], nil
}
// DecodeStsd - box-specific decode
func DecodeStsd(hdr *boxHeader, startPos uint64, r io.Reader) (Box, error) {
var versionAndFlags, sampleCount uint32
err := binary.Read(r, binary.BigEndian, &versionAndFlags)
if err != nil {
return nil, err
}
err = binary.Read(r, binary.BigEndian, &sampleCount)
if err != nil {
return nil, err
}
//Note higher startPos below since not simple container
children, err := DecodeContainerChildren(hdr, startPos+16, startPos+hdr.size, r)
if err != nil {
return nil, err
}
if len(children) != int(sampleCount) {
return nil, fmt.Errorf("Stsd sample count mismatch")
}
stsd := &StsdBox{
Version: byte(versionAndFlags >> 24),
Flags: versionAndFlags & flagsMask,
SampleCount: 0,
}
for _, box := range children {
stsd.AddChild(box)
}
if stsd.SampleCount != sampleCount {
return nil, fmt.Errorf("Stsd sample count mismatch")
}
return stsd, nil
}
// Type - box-specific type
func (s *StsdBox) Type() string {
return "stsd"
}
// Size - box-specific type
func (s *StsdBox) Size() uint64 {
return containerSize(s.Children) + 8
}
// Encode - box-specific encode of stsd - not a usual container
func (s *StsdBox) Encode(w io.Writer) error {
err := EncodeHeader(s, w)
if err != nil {
return err
}
versionAndFlags := (uint32(s.Version) << 24) + s.Flags
err = binary.Write(w, binary.BigEndian, versionAndFlags)
if err != nil {
return err
}
err = binary.Write(w, binary.BigEndian, s.SampleCount)
if err != nil {
return err
}
for _, b := range s.Children {
err = b.Encode(w)
if err != nil {
return err
}
}
return nil
}
func (s *StsdBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
bd := newInfoDumper(w, indent, s, int(s.Version), s.Flags)
if bd.err != nil {
return bd.err
}
var err error
for _, c := range s.Children {
err = c.Info(w, specificBoxLevels, indent+indentStep, indentStep)
if err != nil {
return err
}
}
return err
}