96 lines
2.2 KiB
Go
96 lines
2.2 KiB
Go
package esio
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.r-2.top/kunmeng/vdk/av"
|
|
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
|
"git.r-2.top/kunmeng/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)
|
|
}
|