123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- package aac
- import (
- "encoding/hex"
- "fmt"
- "github.com/AlexxIT/go2rtc/pkg/bits"
- "github.com/AlexxIT/go2rtc/pkg/core"
- )
- const (
- TypeAACMain = 1
- TypeAACLC = 2 // Low Complexity
- TypeAACLD = 23 // Low Delay (48000, 44100, 32000, 24000, 22050)
- TypeESCAPE = 31
- TypeAACELD = 39 // Enhanced Low Delay
- AUTime = 1024
- // FMTP streamtype=5 - audio stream
- FMTP = "streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config="
- )
- var sampleRates = [16]uint32{
- 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350,
- 0, 0, 0, // protection from request sampleRates[15]
- }
- func ConfigToCodec(conf []byte) *core.Codec {
- // https://en.wikipedia.org/wiki/MPEG-4_Part_3#MPEG-4_Audio_Object_Types
- rd := bits.NewReader(conf)
- codec := &core.Codec{
- FmtpLine: FMTP + hex.EncodeToString(conf),
- PayloadType: core.PayloadTypeRAW,
- }
- objType := rd.ReadBits(5)
- if objType == TypeESCAPE {
- objType = 32 + rd.ReadBits(6)
- }
- switch objType {
- case TypeAACLC, TypeAACLD, TypeAACELD:
- codec.Name = core.CodecAAC
- default:
- codec.Name = fmt.Sprintf("AAC-%X", objType)
- }
- if sampleRateIdx := rd.ReadBits8(4); sampleRateIdx < 0x0F {
- codec.ClockRate = sampleRates[sampleRateIdx]
- } else {
- codec.ClockRate = rd.ReadBits(24)
- }
- codec.Channels = rd.ReadBits16(4)
- return codec
- }
- func DecodeConfig(b []byte) (objType, sampleFreqIdx, channels byte, sampleRate uint32) {
- rd := bits.NewReader(b)
- objType = rd.ReadBits8(5)
- if objType == 0b11111 {
- objType = 32 + rd.ReadBits8(6)
- }
- sampleFreqIdx = rd.ReadBits8(4)
- if sampleFreqIdx == 0b1111 {
- sampleRate = rd.ReadBits(24)
- } else {
- sampleRate = sampleRates[sampleFreqIdx]
- }
- channels = rd.ReadBits8(4)
- return
- }
- func EncodeConfig(objType byte, sampleRate uint32, channels byte, shortFrame bool) []byte {
- wr := bits.NewWriter(nil)
- if objType < TypeESCAPE {
- wr.WriteBits8(objType, 5)
- } else {
- wr.WriteBits8(TypeESCAPE, 5)
- wr.WriteBits8(objType-32, 6)
- }
- i := indexUint32(sampleRates[:], sampleRate)
- if i >= 0 {
- wr.WriteBits8(byte(i), 4)
- } else {
- wr.WriteBits8(0xF, 4)
- wr.WriteBits(sampleRate, 24)
- }
- wr.WriteBits8(channels, 4)
- switch objType {
- case TypeAACLD:
- // https://github.com/FFmpeg/FFmpeg/blob/67d392b97941bb51fb7af3a3c9387f5ab895fa46/libavcodec/aacdec_template.c#L841
- wr.WriteBool(shortFrame)
- wr.WriteBit(0) // dependsOnCoreCoder
- wr.WriteBit(0) // extension_flag
- wr.WriteBits8(0, 2) // ep_config
- case TypeAACELD:
- // https://github.com/FFmpeg/FFmpeg/blob/67d392b97941bb51fb7af3a3c9387f5ab895fa46/libavcodec/aacdec_template.c#L922
- wr.WriteBool(shortFrame)
- wr.WriteBits8(0, 3) // res_flags
- wr.WriteBit(0) // ldSbrPresentFlag
- wr.WriteBits8(0, 4) // ELDEXT_TERM
- wr.WriteBits8(0, 2) // ep_config
- }
- return wr.Bytes()
- }
- func indexUint32(s []uint32, v uint32) int {
- for i := range s {
- if v == s[i] {
- return i
- }
- }
- return -1
- }
|