// 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 ( "encoding/hex" "io" log "github.com/q191201771/naza/pkg/nazalog" ) var adts ADTS type ADTS struct { audioObjectType uint8 samplingFrequencyIndex uint8 channelConfig uint8 frameLengthFlag uint8 dependOnCoreCoder uint8 extensionFlag uint8 adtsHeader []byte } // 传入 AAC Sequence Header,一会生成 ADTS 头时需要使用 // @param rtmp message payload,包含前面2个字节 func (obj *ADTS) PutAACSequenceHeader(payload []byte) { log.Debugf(hex.Dump(payload[:4])) soundFormat := payload[0] >> 4 // 10=AAC soundRate := (payload[0] >> 2) & 0x03 // 3=44kHz. For AAC: always 3 soundSize := (payload[0] >> 1) & 0x01 // 0=snd8Bit 1=snd16Bit soundType := payload[0] & 0x01 // For AAC: always 1 aacPacketType := payload[1] // 0:sequence header 1:AAC raw log.Debugf("%d %d %d %d %d", soundFormat, soundRate, soundSize, soundType, aacPacketType) obj.audioObjectType = (payload[2] & 0xf8) >> 3 // 5bit 编码结构类型 obj.samplingFrequencyIndex = ((payload[2] & 0x07) << 1) | (payload[3] >> 7) // 4bit 音频采样率索引值 obj.channelConfig = (payload[3] & 0x78) >> 3 // 4bit 音频输出声道 obj.frameLengthFlag = (payload[3] & 0x04) >> 2 // 1bit obj.dependOnCoreCoder = (payload[3] & 0x02) >> 1 // 1bit obj.extensionFlag = payload[3] & 0x01 // 1bit log.Debugf("%+v", obj) } // 获取 ADTS 头,注意,每个包的长度不同,所以生成的每个包的 ADTS 头也不同 // @param rtmp message payload长度,包含前面2个字节 func (obj *ADTS) GetADTS(length uint16) []byte { // adts fixed header: // syncword 12bit (0: **** ****, 1: **** 0000) 0xfff // ID 1bit (1: 0000 *000) 0 0:MPEG-4 1:MPEG-2 // layer 2bit (1: 0000 0**0) 0 // protection_absent 1bit (1: 0000 000*) 1 // profile 2bit (2: **00 0000) // sampling_frequency_index 4bit (2: 00** **00) // private_bit 1bit (2: 0000 00*0) 0 // channel_configuration 3bit (2: 0000 000*, 3: **00 0000) // origin_copy 1bit (3: 00*0 0000) 0 // home 1bit (3: 000* 0000) 0 // // adts variable_header: // copyright_identification_bit 1bit (3: 0000 *000) 0 // copyright_identification_start 1bit (3: 0000 0*00) 0 // aac_frame_length 13bit (3: 0000 00**, 5: ***0 0000) // adts_buffer_fullness 11bit (5: 000* ****, 6: **** **00) 0x7ff // number_of_raw_data_blocks_in_frame 2bit (6: 0000 00**) 0 // sampling_frequency_index // 0: 96000 Hz // 1: 88200 Hz // 2: 64000 Hz // 3: 48000 Hz // 4: 44100 Hz // 5: 32000 Hz // 6: 24000 Hz // 7: 22050 Hz // 8: 16000 Hz // 9: 12000 Hz // 10: 11025 Hz // 11: 8000 Hz // 12: 7350 Hz // 13: Reserved // 14: Reserved // 15: frequency is written explictly if obj.adtsHeader == nil { obj.adtsHeader = make([]byte, 7) } obj.adtsHeader[0] = 0xff obj.adtsHeader[1] = 0xf1 obj.adtsHeader[2] = ((obj.audioObjectType - 1) << 6) & 0xc0 obj.adtsHeader[2] |= (obj.samplingFrequencyIndex << 2) & 0x3c obj.adtsHeader[2] |= (obj.channelConfig >> 2) & 0x01 obj.adtsHeader[3] = (obj.channelConfig << 6) & 0xc0 // 减去前面2个字节,加上adts的7个字节 length = length - 2 + 7 obj.adtsHeader[3] += uint8(length >> 11) // TODO chef: 为什么这样做,应该只是使用2个字节,取5个再相加是否会超出? obj.adtsHeader[4] = uint8((length & 0x7ff) >> 3) obj.adtsHeader[5] = uint8((length & 0x07) << 5) obj.adtsHeader[5] |= 0x1f obj.adtsHeader[6] = 0xfc return obj.adtsHeader } // 将 rtmp AAC 传入,输出带 ADTS 头的 AAC ES流 // @param rtmp message payload部分 func CaptureAAC(w io.Writer, payload []byte) { if payload[1] == 0 { adts.PutAACSequenceHeader(payload) return } _, _ = w.Write(adts.GetADTS(uint16(len(payload)))) _, _ = w.Write(payload[2:]) }