// Copyright 2019, Chef. All rights reserved. // https://github.com/q191201771/lal // // Use of this source code is governed by a MIT-style license // that can be found in the License file. // // Author: Chef (191201771@qq.com) package aac import ( "fmt" "github.com/q191201771/naza/pkg/nazalog" "github.com/q191201771/naza/pkg/nazaerrors" "github.com/q191201771/lal/pkg/base" "github.com/q191201771/naza/pkg/nazabits" ) // AudioSpecificConfig(asc) // keywords: Seq Header, // e.g. rtmp, flv // // ADTS(Audio Data Transport Stream) // e.g. es, ts // // StreamMuxConfig // const ( AdtsHeaderLength = 7 AscSamplingFrequencyIndex96000 = 0 AscSamplingFrequencyIndex88200 = 1 AscSamplingFrequencyIndex64000 = 2 AscSamplingFrequencyIndex48000 = 3 AscSamplingFrequencyIndex44100 = 4 AscSamplingFrequencyIndex32000 = 5 AscSamplingFrequencyIndex24000 = 6 AscSamplingFrequencyIndex22050 = 7 AscSamplingFrequencyIndex16000 = 8 AscSamplingFrequencyIndex12000 = 9 AscSamplingFrequencyIndex11025 = 10 AscSamplingFrequencyIndex8000 = 11 AscSamplingFrequencyIndex7350 = 12 ) const ( minAscLength = 2 ) // AscContext // // // <1.6.2.1 AudioSpecificConfig>, // <1.5.1.1 Audio Object type definition>, // <1.6.3.3 samplingFrequencyIndex>, // <1.6.3.4 channelConfiguration> // -------------------------------------------------------- // audio object type [5b] 1=AAC MAIN 2=AAC LC // samplingFrequencyIndex [4b] 0=96000, 1=88200, 2=64000, 3=48000, 4=44100, 5=32000, 6=24000, 7=22050, 8=16000, 9=12000, 10=11025, 11=11025, 12=7350 // channelConfiguration [4b] 1=center front speaker 2=left, right front speakers type AscContext struct { AudioObjectType uint8 // [5b] SamplingFrequencyIndex uint8 // [4b] ChannelConfiguration uint8 // [4b] } func NewAscContext(asc []byte) (*AscContext, error) { var ascCtx AscContext if err := ascCtx.Unpack(asc); err != nil { return nil, err } return &ascCtx, nil } // Unpack // // @param asc: 2字节的AAC Audio Specifc Config。 // // 注意,如果是rtmp/flv的message/tag,应去除Seq Header头部的2个字节。 // 函数调用结束后,内部不持有该内存块。 func (ascCtx *AscContext) Unpack(asc []byte) error { if len(asc) < minAscLength { return nazaerrors.Wrap(base.ErrShortBuffer) } br := nazabits.NewBitReader(asc) ascCtx.AudioObjectType, _ = br.ReadBits8(5) ascCtx.SamplingFrequencyIndex, _ = br.ReadBits8(4) ascCtx.ChannelConfiguration, _ = br.ReadBits8(4) return nil } // Pack // // @return asc: 内存块为独立新申请;函数调用结束后,内部不持有该内存块 func (ascCtx *AscContext) Pack() (asc []byte) { asc = make([]byte, minAscLength) bw := nazabits.NewBitWriter(asc) bw.WriteBits8(5, ascCtx.AudioObjectType) bw.WriteBits8(4, ascCtx.SamplingFrequencyIndex) bw.WriteBits8(4, ascCtx.ChannelConfiguration) return } // PackAdtsHeader // // 获取ADTS头,由于ADTS头中的字段依赖包的长度,而每个包的长度可能不同,所以每个包的ADTS头都需要独立生成。 // // @param frameLength: raw aac frame的大小。 // // 注意,如果是rtmp/flv的message/tag,应去除Seq Header头部的2个字节。 // // @return h: 内存块为独立新申请;函数调用结束后,内部不持有该内存块 func (ascCtx *AscContext) PackAdtsHeader(frameLength int) (out []byte) { out = make([]byte, AdtsHeaderLength) _ = ascCtx.PackToAdtsHeader(out, frameLength) return } // PackToAdtsHeader // // @param out: 函数调用结束后,内部不持有该内存块 func (ascCtx *AscContext) PackToAdtsHeader(out []byte, frameLength int) error { if len(out) < AdtsHeaderLength { return nazaerrors.Wrap(base.ErrShortBuffer) } // // <1.A.2.2.1 Fixed Header of ADTS>, // <1.A.2.2.2 Variable Header of ADTS>, // <1.A.3.2.1 Definitions: Bitstream elements for ADTS> // ---------------------------------------------------- // Syncword [12b] '1111 1111 1111' // ID [1b] 1=MPEG-2 AAC 0=MPEG-4 // Layer [2b] // protection_absent [1b] 1=no crc check // Profile_ObjectType [2b] // sampling_frequency_index [4b] // private_bit [1b] // channel_configuration [3b] // origin/copy [1b] // home [1b] // Emphasis??? // ------------------------------------ // copyright_identification_bit [1b] // copyright_identification_start [1b] // aac_frame_length [13b] // adts_buffer_fullness [11b] // no_raw_data_blocks_in_frame [2b] bw := nazabits.NewBitWriter(out) // Syncword 0(8) 1(4) bw.WriteBits16(12, 0xFFF) // ID, Layer, protection_absent 1(4) bw.WriteBits8(4, 0x1) // 2(2) // // profile_ObjectType: The interpretation of this bitstream element depends on the value of the ID bit. If ID is // equal to ‘1’ this field holds the same information as the profile field in the ADTS stream defined in ISO/IEC // 13818-7. If ID is equal to ‘0’ this element denotes the MPEG-4 Audio Object Type according to the table // defined in subclause 5.1.1. bw.WriteBits8(2, ascCtx.AudioObjectType-1) // 2(4) bw.WriteBits8(4, ascCtx.SamplingFrequencyIndex) // private_bit 2(1) bw.WriteBits8(1, 0) // 2(1) 3(2) bw.WriteBits8(3, ascCtx.ChannelConfiguration) // origin/copy, home, copyright_identification_bit, copyright_identification_start 3(4) bw.WriteBits8(4, 0) // 3(2) 4(8) 5(3) bw.WriteBits16(13, uint16(frameLength+AdtsHeaderLength)) // adts_buffer_fullness 5(5) 6(6) bw.WriteBits16(11, 0x7FF) // no_raw_data_blocks_in_frame 6(2) bw.WriteBits8(2, 0) return nil } func (ascCtx *AscContext) GetSamplingFrequency() (int, error) { // 临时日志,观察不常见的采样率 switch ascCtx.SamplingFrequencyIndex { case AscSamplingFrequencyIndex48000, AscSamplingFrequencyIndex44100, AscSamplingFrequencyIndex22050, AscSamplingFrequencyIndex16000: // noop default: nazalog.Warnf("unusual sampling frequency. ascCtx=%+v", ascCtx) } switch ascCtx.SamplingFrequencyIndex { case AscSamplingFrequencyIndex96000: return 96000, nil case AscSamplingFrequencyIndex88200: return 88200, nil case AscSamplingFrequencyIndex64000: return 64000, nil case AscSamplingFrequencyIndex48000: return 48000, nil case AscSamplingFrequencyIndex44100: return 44100, nil case AscSamplingFrequencyIndex32000: return 32000, nil case AscSamplingFrequencyIndex22050: return 22050, nil case AscSamplingFrequencyIndex16000: return 16000, nil case AscSamplingFrequencyIndex12000: return 12000, nil case AscSamplingFrequencyIndex11025: return 11025, nil case AscSamplingFrequencyIndex8000: return 8000, nil case AscSamplingFrequencyIndex7350: return 7350, nil } return -1, fmt.Errorf("%w. asCtx=%+v", base.ErrSamplingFrequencyIndex, ascCtx) } type AdtsHeaderContext struct { AscCtx AscContext AdtsLength uint16 // 字段中的值,包含了adts header + adts frame } func NewAdtsHeaderContext(adtsHeader []byte) (*AdtsHeaderContext, error) { var ctx AdtsHeaderContext if err := ctx.Unpack(adtsHeader); err != nil { return nil, err } return &ctx, nil } // Unpack // // @param adtsHeader: 函数调用结束后,内部不持有该内存块 func (ctx *AdtsHeaderContext) Unpack(adtsHeader []byte) error { if len(adtsHeader) < AdtsHeaderLength { return nazaerrors.Wrap(base.ErrShortBuffer) } br := nazabits.NewBitReader(adtsHeader) _ = br.SkipBits(16) v, _ := br.ReadBits8(2) // // profile_ObjectType: The interpretation of this bitstream element depends on the value of the ID bit. If ID is // equal to ‘1’ this field holds the same information as the profile field in the ADTS stream defined in ISO/IEC // 13818-7. If ID is equal to ‘0’ this element denotes the MPEG-4 Audio Object Type according to the table // defined in subclause 5.1.1. ctx.AscCtx.AudioObjectType = v + 1 ctx.AscCtx.SamplingFrequencyIndex, _ = br.ReadBits8(4) _ = br.SkipBits(1) ctx.AscCtx.ChannelConfiguration, _ = br.ReadBits8(3) _ = br.SkipBits(4) ctx.AdtsLength, _ = br.ReadBits16(13) return nil } // MakeAscWithAdtsHeader // // @param adtsHeader: 函数调用结束后,内部不持有该内存块 // // @return asc: 内存块为独立新申请;函数调用结束后,内部不持有该内存块 func MakeAscWithAdtsHeader(adtsHeader []byte) (asc []byte, err error) { var ctx *AdtsHeaderContext if ctx, err = NewAdtsHeaderContext(adtsHeader); err != nil { return nil, err } return ctx.AscCtx.Pack(), nil }