You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/aac/aac.go

98 lines
3.9 KiB
Go

package aac
import (
"encoding/hex"
"github.com/q191201771/nezha/pkg/log"
"io"
)
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 <payload> rtmp message payload包含前面2个字节
func (obj *ADTS) PutAACSequenceHeader(payload []byte) {
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
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(hex.Dump(payload[:4]))
log.Debugf("%d %d %d %d", soundFormat, soundRate, soundSize, soundType)
log.Debugf("%+v", obj)
}
// 获取 ADTS 头,注意,每个包的长度不同,所以生成的每个包的 ADTS 头也不同
// @param <length> 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
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 <payload> 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:])
}