forked from Eyevinn/mp4ff
-
Notifications
You must be signed in to change notification settings - Fork 1
/
traf.go
161 lines (147 loc) · 3.55 KB
/
traf.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
158
159
160
161
package mp4
import (
"errors"
"io"
)
// TrafBox - Track Fragment Box (traf)
//
// Contained in : Movie Fragment Box (moof)
//
type TrafBox struct {
Tfhd *TfhdBox
Tfdt *TfdtBox
Trun *TrunBox // The first TrunBox
Truns []*TrunBox
Children []Box
}
// DecodeTraf - box-specific decode
func DecodeTraf(hdr *boxHeader, startPos uint64, r io.Reader) (Box, error) {
children, err := DecodeContainerChildren(hdr, startPos, startPos+hdr.size, r)
if err != nil {
return nil, err
}
t := &TrafBox{}
for _, b := range children {
err := t.AddChild(b)
if err != nil {
return nil, err
}
}
return t, nil
}
// AddChild - add child box
func (t *TrafBox) AddChild(b Box) error {
switch b.Type() {
case "tfhd":
t.Tfhd = b.(*TfhdBox)
case "tfdt":
t.Tfdt = b.(*TfdtBox)
case "trun":
if t.Trun == nil {
t.Trun = b.(*TrunBox)
}
t.Truns = append(t.Truns, b.(*TrunBox))
default:
}
t.Children = append(t.Children, b)
return nil
}
// Type - return box type
func (t *TrafBox) Type() string {
return "traf"
}
// Size - return calculated size
func (t *TrafBox) Size() uint64 {
return containerSize(t.Children)
}
// GetChildren - list of child boxes
func (t *TrafBox) GetChildren() []Box {
return t.Children
}
// Encode - write box to w
func (t *TrafBox) Encode(w io.Writer) error {
return EncodeContainer(t, w)
}
func (t *TrafBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
return ContainerInfo(t, w, specificBoxLevels, indent, indentStep)
}
// OptimizeTfhdTrun - optimize trun by default values in tfhd box
// Only look at first trun, even if there is more than one
// Don't optimize again, if already done so that no data is present
func (t *TrafBox) OptimizeTfhdTrun() error {
tfhd := t.Tfhd
trun := t.Trun
if len(trun.Samples) == 0 {
return errors.New("No samples in trun")
}
if len(trun.Samples) == 1 {
return nil // No need to optimize
}
if trun.HasSampleDuration() {
hasCommonDur := true
commonDur := trun.Samples[0].Dur
for _, s := range trun.Samples {
if s.Dur != commonDur {
hasCommonDur = false
break
}
}
if hasCommonDur {
// Set defaultSampleDuration in tfhd and remove from trun
tfhd.Flags = tfhd.Flags | defaultSampleDurationPresent
tfhd.DefaultSampleDuration = commonDur
trun.flags = trun.flags & ^sampleDurationPresentFlag
}
}
if trun.HasSampleSize() {
hasCommonSize := true
commonSize := trun.Samples[0].Size
for _, s := range trun.Samples {
if s.Size != commonSize {
hasCommonSize = false
break
}
}
if hasCommonSize {
// Set defaultSampleSize in tfhd and remove from trun
tfhd.Flags = tfhd.Flags | defaultSampleSizePresent
tfhd.DefaultSampleSize = commonSize
trun.flags = trun.flags & ^sampleSizePresentFlag
}
}
if trun.HasSampleFlags() {
firstSampleFlags := trun.Samples[0].Flags
hasCommonFlags := true
commonSampleFlags := trun.Samples[1].Flags
for i, s := range trun.Samples {
if i >= 1 {
if s.Flags != commonSampleFlags {
hasCommonFlags = false
break
}
}
}
if hasCommonFlags {
if firstSampleFlags != commonSampleFlags {
trun.firstSampleFlags = firstSampleFlags
trun.flags |= firstSampleFlagsPresentFlag
}
tfhd.Flags = tfhd.Flags | defaultSampleFlagsPresent
tfhd.DefaultSampleFlags = commonSampleFlags
trun.flags = trun.flags & ^sampleFlagsPresentFlag
}
}
if trun.HasSampleCTO() {
allZeroCTO := true
for _, s := range trun.Samples {
if s.Cto != 0 {
allZeroCTO = false
break
}
}
if allZeroCTO {
trun.flags = trun.flags & ^sampleCTOPresentFlag
}
}
return nil
}