vdk/format/fmp4/esio/decoderconf.go
kunmeng 0e65c9d1cc
Some checks failed
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
将包名改为 git.r-2.top/kunmeng/vdk
2025-01-24 14:45:45 +08:00

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)
}