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

124 lines
4.3 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 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"
"github.com/q191201771/naza/pkg/nazabits"
log "github.com/q191201771/naza/pkg/nazalog"
)
// TODO chef: 把Seq Header头两字节的解析和ADTS的内容分离开
var adts ADTS
// Audio Data Transport Stream
type ADTS struct {
audioObjectType uint8
samplingFrequencyIndex uint8
channelConfiguration uint8
adtsHeader []byte
}
// 传入AAC Sequence Header调用GetADTS时需要使用
// @param <payload> rtmp message payload包含前面2个字节
func (obj *ADTS) PutAACSequenceHeader(payload []byte) {
// <spec-video_file_format_spec_v10.pdf>, <Audio tags, AUDIODATA>, <page 10/48>
// ----------------------------------------------------------------------------
// soundFormat [4b] 10=AAC
// soundRate [2b] 3=44kHz. AAC always 3
// soundSize [1b] 0=snd8Bit, 1=snd16Bit
// soundType [1b] 0=sndMono, 1=sndStereo. AAC always 1
// aacPackageType [8b] 0=seq header, 1=AAC raw
soundFormat := nazabits.GetBits8(payload[0], 4, 4)
soundRate := nazabits.GetBits8(payload[0], 2, 2)
soundSize := nazabits.GetBit8(payload[0], 1)
soundType := nazabits.GetBit8(payload[0], 0)
aacPacketType := payload[1]
log.Debugf("%s %d %d %d %d %d", hex.Dump(payload[:4]), soundFormat, soundRate, soundSize, soundType, aacPacketType)
// <ISO_IEC_14496-3.pdf>
// <1.6.2.1 AudioSpecificConfig>, <page 33/110>
// <1.5.1.1 Audio Object type definition>, <page 23/110>
// <1.6.3.3 samplingFrequencyIndex>, <page 35/110>
// <1.6.3.4 channelConfiguration>
// --------------------------------------------------------
// audio object type [5b] 2=AAC LC
// samplingFrequencyIndex [4b] 3=48000
// channelConfiguration [4b] 2=left, right front speakers
obj.audioObjectType = uint8(nazabits.GetBits16(payload[2:], 11, 5))
obj.samplingFrequencyIndex = uint8(nazabits.GetBits16(payload[2:], 7, 4))
obj.channelConfiguration = uint8(nazabits.GetBits16(payload[2:], 3, 4))
log.Debugf("%+v", obj)
}
// 获取 ADTS 头注意由于ADTS头依赖包的长度而每个包的长度不同所以生成的每个包的 ADTS 头也不同
// @param <length> rtmp message payload长度包含前面2个字节
func (obj *ADTS) GetADTS(length uint16) []byte {
// <ISO_IEC_14496-3.pdf>
// <1.A.2.2.1 Fixed Header of ADTS>, <page 75/110>
// <1.A.2.2.2 Variable Header of ADTS>, <page 76/110>
// <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]
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.channelConfiguration >> 2) & 0x01
obj.adtsHeader[3] = (obj.channelConfiguration << 6) & 0xc0
// 减去前面2个字节再加上加上adts的7个字节
length += 5
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:])
}