forked from deepch/vdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decoderconf.go
95 lines (84 loc) · 2.23 KB
/
decoderconf.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
package esio
import (
"errors"
"fmt"
"github.com/zebemce/vdk/av"
"github.com/zebemce/vdk/codec/aacparser"
"github.com/zebemce/vdk/utils/bits/pio"
)
type DecoderConfigDescriptor struct {
ObjectType ObjectType
StreamType StreamType
BufferSize uint32
MaxBitrate uint32
AvgBitrate uint32
AudioSpecific []byte
}
type ObjectType uint8
// ISO/IEC 14496-1 7.2.6.6.2 Table 5
const ObjectTypeAudio = ObjectType(0x40)
type StreamType uint8
// ISO/IEC 14496-1 7.2.6.6.2 Table 6
const StreamTypeAudioStream = StreamType(0x05)
func parseDecoderConfig(d []byte) (*DecoderConfigDescriptor, error) {
if len(d) < 13 {
return nil, errors.New("DecoderConfigDescriptor short")
}
conf := &DecoderConfigDescriptor{
ObjectType: ObjectType(d[0]),
StreamType: StreamType(d[1] >> 2),
BufferSize: pio.U24BE(d[2:]),
MaxBitrate: pio.U32BE(d[5:]),
AvgBitrate: pio.U32BE(d[9:]),
}
d = d[13:]
for len(d) > 0 {
tag, contents, remainder, err := parseHeader(d)
if err != nil {
return nil, fmt.Errorf("DecoderConfigDescriptor: %w", err)
}
d = remainder
switch tag {
case TagDecoderSpecificInfo:
switch conf.ObjectType {
case ObjectTypeAudio:
conf.AudioSpecific = contents
}
}
}
return conf, nil
}
func (c *DecoderConfigDescriptor) appendTo(b *builder) error {
if c == nil {
return nil
}
cursor := b.Descriptor(TagDecoderConfigDescriptor)
defer cursor.DescriptorDone(-1)
b.WriteByte(byte(c.ObjectType))
b.WriteByte(byte(c.StreamType<<2) | 1)
b.WriteU24(c.BufferSize)
b.WriteU32(c.MaxBitrate)
b.WriteU32(c.AvgBitrate)
switch {
case c.AudioSpecific != nil:
// ISO/IEC 14496-3
// 1.6.2.1 - base AudioSpecificConfig
// 4.4.1 - GASpecificConfig
// but we don't actually need to inspect this right now so just preserve the bytes
c2 := b.Descriptor(TagDecoderSpecificInfo)
b.Write(c.AudioSpecific)
c2.DescriptorDone(-1)
}
return nil
}
func DecoderConfigFromCodecData(stream av.CodecData) (*DecoderConfigDescriptor, error) {
switch cd := stream.(type) {
case aacparser.CodecData:
return &DecoderConfigDescriptor{
ObjectType: ObjectTypeAudio,
StreamType: StreamTypeAudioStream,
AudioSpecific: cd.MPEG4AudioConfigBytes(),
}, nil
}
return nil, fmt.Errorf("can't marshal %T to DecoderConfigDescriptor", stream)
}