-
Notifications
You must be signed in to change notification settings - Fork 84
/
hdlr.go
140 lines (129 loc) · 3.81 KB
/
hdlr.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
package mp4
import (
"fmt"
"io"
"github.com/Eyevinn/mp4ff/bits"
)
// HdlrBox - Handler Reference Box (hdlr - mandatory)
//
// Contained in: Media Box (mdia) or Meta Box (meta)
//
// This box describes the type of data contained in the trak.
// Most common hnadler types are: "vide" (video track), "soun" (audio track), "subt" (subtitle track),
// "text" (text track). "meta" (timed Metadata track), clcp (Closed Captions (QuickTime))
type HdlrBox struct {
Version byte
Flags uint32
PreDefined uint32
HandlerType string
Name string // Null-terminated UTF-8 string according to ISO/IEC 14496-12 Sec. 8.4.3.3
LacksNullTermination bool // This should be false, but we allow true as well
}
// CreateHdlr - create mediaType-specific hdlr box
func CreateHdlr(mediaOrHdlrType string) (*HdlrBox, error) {
hdlr := &HdlrBox{}
switch mediaOrHdlrType {
case "video", "vide":
hdlr.HandlerType = "vide"
hdlr.Name = "mp4ff video handler"
case "audio", "soun":
hdlr.HandlerType = "soun"
hdlr.Name = "mp4ff audio handler"
case "subtitle", "subt":
hdlr.HandlerType = "subt"
hdlr.Name = "mp4ff subtitle handler"
case "text", "wvtt":
hdlr.HandlerType = "text"
hdlr.Name = "mp4ff text handler"
case "meta":
hdlr.HandlerType = "meta"
hdlr.Name = "mp4ff timed metadata handler"
case "clcp":
hdlr.HandlerType = "subt"
hdlr.Name = "mp4ff closed captions handler"
default:
if len(mediaOrHdlrType) != 4 {
return nil, fmt.Errorf("handler type is not four characters: %s", mediaOrHdlrType)
}
hdlr.HandlerType = mediaOrHdlrType
hdlr.Name = fmt.Sprintf("mp4ff %s handler", mediaOrHdlrType)
}
return hdlr, nil
}
// DecodeHdlr - box-specific decode
func DecodeHdlr(hdr BoxHeader, startPos uint64, r io.Reader) (Box, error) {
data, err := readBoxBody(r, hdr)
if err != nil {
return nil, err
}
sr := bits.NewFixedSliceReader(data)
return DecodeHdlrSR(hdr, startPos, sr)
}
// DecodeHdlrSR - box-specific decode
func DecodeHdlrSR(hdr BoxHeader, startPos uint64, sr bits.SliceReader) (Box, error) {
versionAndFlags := sr.ReadUint32()
h := HdlrBox{
Version: byte(versionAndFlags >> 24),
Flags: versionAndFlags & flagsMask,
PreDefined: sr.ReadUint32(),
HandlerType: sr.ReadFixedLengthString(4),
}
sr.SkipBytes(12) // 12 bytes of zero
nrBytesLeft := hdr.payloadLen() - 24
if nrBytesLeft > 0 {
bytesLeft := sr.ReadBytes(nrBytesLeft)
lastChar := bytesLeft[len(bytesLeft)-1]
if lastChar != 0 {
h.LacksNullTermination = true
h.Name = string(bytesLeft)
} else {
h.Name = string(bytesLeft[:len(bytesLeft)-1])
}
} else {
h.LacksNullTermination = true
}
return &h, sr.AccError()
}
// Type - box type
func (b *HdlrBox) Type() string {
return "hdlr"
}
// Size - calculated size of box
func (b *HdlrBox) Size() uint64 {
size := uint64(boxHeaderSize + 24 + len(b.Name) + 1)
if b.LacksNullTermination {
size--
}
return size
}
// Encode - write box to w
func (b *HdlrBox) Encode(w io.Writer) error {
sw := bits.NewFixedSliceWriter(int(b.Size()))
err := b.EncodeSW(sw)
if err != nil {
return err
}
_, err = w.Write(sw.Bytes())
return err
}
// EncodeSW - box-specific encode to slicewriter
func (b *HdlrBox) EncodeSW(sw bits.SliceWriter) error {
err := EncodeHeaderSW(b, sw)
if err != nil {
return err
}
versionAndFlags := (uint32(b.Version) << 24) | b.Flags
sw.WriteUint32(versionAndFlags)
sw.WriteUint32(b.PreDefined)
sw.WriteString(b.HandlerType, false)
sw.WriteZeroBytes(12)
sw.WriteString(b.Name, !b.LacksNullTermination)
return sw.AccError()
}
// Info - write box-specific information
func (b *HdlrBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error {
bd := newInfoDumper(w, indent, b, int(b.Version), b.Flags)
bd.write(" - handlerType: %s", b.HandlerType)
bd.write(" - handlerName: %q", b.Name)
return bd.err
}