欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SRS 代码分析【保存AAC音频文件】

程序员文章站 2022-07-13 13:34:48
...

SRS 对AAC音频文件的保存主要是调用SrsAacTransmuxer::write_audio(),函数定义如下:

int SrsAacTransmuxer::write_audio(int64_t timestamp, char* data, int size)
{
    int ret = ERROR_SUCCESS;
    
    srs_assert(data);
    
    timestamp &= 0x7fffffff;
    
    SrsBuffer* stream = tag_stream;
    if ((ret = stream->initialize(data, size)) != ERROR_SUCCESS) {
        return ret;
    }
    
    // audio decode
    if (!stream->require(1)) {
        ret = ERROR_AAC_DECODE_ERROR;
        srs_error("aac decode audio sound_format failed. ret=%d", ret);
        return ret;
    }
    
    //从音频Tag中读取AAC Sequence header
    //SoundFormat 4bits | SoundRate 2bits | SoundSize 1bit | SoundType 1bits| AACPacketType 8bits|  
    
    // @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
    int8_t sound_format = stream->read_1bytes();//读取SoundFormat
    
    //int8_t sound_type = sound_format & 0x01;
    //int8_t sound_size = (sound_format >> 1) & 0x01;
    //int8_t sound_rate = (sound_format >> 2) & 0x03;
    sound_format = (sound_format >> 4) & 0x0f;
    
    if ((SrsAudioCodecId)sound_format != SrsAudioCodecIdAAC) {//根据SoundFormat判断是否为AAC
        ret = ERROR_AAC_DECODE_ERROR;
        srs_error("aac required, format=%d. ret=%d", sound_format, ret);
        return ret;
    }
    
    if (!stream->require(1)) {
        ret = ERROR_AAC_DECODE_ERROR;
        srs_error("aac decode aac_packet_type failed. ret=%d", ret);
        return ret;
    }
    
    SrsAudioAacFrameTrait aac_packet_type = (SrsAudioAacFrameTrait)stream->read_1bytes();//读取包类型
    if (aac_packet_type == SrsAudioAacFrameTraitSequenceHeader) {                        //根据包类型判断后面的数据是否为AudioSpecificConfig
    	//接着从音频TAG中提取2字节的AUDIO SPECIFIC CONFIG,后面会将其转换成7字节的ADTS HEADER
    	//AudioSpecificConfig(2byte)结构定义:
    	//|audioObjectType:5bit|samplingFrequencyIndex:4bit|channelConfiguration:4bit|frameLengthFlag:1bit |dependsOnCoreCoder:1bit|extensionFlag:1bit|  

 
        // AudioSpecificConfig
        // 1.6.2.1 AudioSpecificConfig, in ISO_IEC_14496-3-AAC-2001.pdf, page 33.
        //
        // only need to decode the first 2bytes:
        // audioObjectType, 5bits.
        // samplingFrequencyIndex, aac_sample_rate, 4bits.
        // channelConfiguration, aac_channels, 4bits
        if (!stream->require(2)) {
            ret = ERROR_AAC_DECODE_ERROR;
            srs_error("aac decode sequence header failed. ret=%d", ret);
            return ret;
        }
        
        int8_t audioObjectType = stream->read_1bytes();
        aac_sample_rate = stream->read_1bytes();
        
        aac_channels = (aac_sample_rate >> 3) & 0x0f;
        aac_sample_rate = ((audioObjectType << 1) & 0x0e) | ((aac_sample_rate >> 7) & 0x01);
        
        audioObjectType = (audioObjectType >> 3) & 0x1f;
        aac_object = (SrsAacObjectType)audioObjectType;
        
        got_sequence_header = true;
        
        return ret;
    }
    
    if (!got_sequence_header) {
        ret = ERROR_AAC_DECODE_ERROR;
        srs_error("aac no sequence header. ret=%d", ret);
        return ret;
    }
    
    // the left is the aac raw frame data.
    int16_t aac_raw_length = stream->size() - stream->pos();
    
    // write the ADTS header.
    // @see ISO_IEC_14496-3-AAC-2001.pdf, page 75,
    //      1.A.2.2 Audio_Data_Transport_Stream frame, ADTS
    // @see https://github.com/ossrs/srs/issues/212#issuecomment-64145885
    // byte_alignment()
    
    // adts_fixed_header:
    //      12bits syncword,
    //      16bits left.
    // adts_variable_header:
    //      28bits
    //      12+16+28=56bits
    // adts_error_check:
    //      16bits if protection_absent
    //      56+16=72bits
    // if protection_absent:
    //      require(7bytes)=56bits
    // else
    //      require(9bytes)=72bits
    char aac_fixed_header[7];
    if(true) {

        //将从音频TAG中提取2字节的AUDIO SPECIFIC CONFIG转换为7字节的ADTS Header
        char* pp = aac_fixed_header;
        int16_t aac_frame_length = aac_raw_length + 7;
        
        // Syncword 12 bslbf
        *pp++ = 0xff;
        // 4bits left.
        // adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
        // ID 1 bslbf
        // Layer 2 uimsbf
        // protection_absent 1 bslbf
        *pp++ = 0xf1;
        
        // profile 2 uimsbf
        // sampling_frequency_index 4 uimsbf
        // private_bit 1 bslbf
        // channel_configuration 3 uimsbf
        // original/copy 1 bslbf
        // home 1 bslbf
        SrsAacProfile aac_profile = srs_aac_rtmp2ts(aac_object);
        *pp++ = ((aac_profile << 6) & 0xc0) | ((aac_sample_rate << 2) & 0x3c) | ((aac_channels >> 2) & 0x01);
        // 4bits left.
        // adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
        // copyright_identification_bit 1 bslbf
        // copyright_identification_start 1 bslbf
        *pp++ = ((aac_channels << 6) & 0xc0) | ((aac_frame_length >> 11) & 0x03);
        
        // aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
        // use the left 2bits as the 13 and 12 bit,
        // the aac_frame_length is 13bits, so we move 13-2=11.
        *pp++ = aac_frame_length >> 3;
        // adts_buffer_fullness 11 bslbf
        *pp++ = (aac_frame_length << 5) & 0xe0;
        
        // no_raw_data_blocks_in_frame 2 uimsbf
        *pp++ = 0xfc;
    }
    
    // write 7bytes fixed header.
    if ((ret = _fs->write(aac_fixed_header, 7, NULL)) != ERROR_SUCCESS) {
        return ret;
    }
    
    // write aac frame body.
    if ((ret = _fs->write(data + stream->pos(), aac_raw_length, NULL)) != ERROR_SUCCESS) {
        return ret;
    }
    
    return ret;
}

1.音频Tag中AAC Sequence header详细说明
A).SoundFormat, 4bit, 音频格式. The following values are defined:  
//0 = Linear PCM, platform endian  
//1 = ADPCM  
//2 = MP3  
//3 = Linear PCM, little endian  
//4 = Nellymoser 16 kHz mono  
//5 = Nellymoser 8 kHz mono  
//6 = Nellymoser  
//7 = G.711 A-law logarithmic PCM  
//8 = G.711 mu-law logarithmic PCM  
//9 = reserved  
//10 = AAC  
//11 = Speex  
//14 = MP3 8 kHz  
//15 = Device-specific sound  
//Formats 7, 8, 14, and 15 are reserved.  
//AAC is supported in Flash Player 9,0,115,0 and higher.  
//Speex is supported in Flash Player 10 and higher.  
  
B).SoundRate, 2bit, 采样率. The following values are defined:  
//0 = 5.5 kHz  
//1 = 11 kHz  
//2 = 22 kHz  
//3 = 44 kHz  
  
C).SoundSize, 1bit, 采样精度. Size of each audio sample. This parameter only pertains to uncompressed formats. Compressed formats always decode to 16 bits internally.  
//0 = 8-bit samples  
//1 = 16-bit samples  
  
D).SoundType, 1bit, 声道数. Mono or stereo sound  
//0 = Mono sound  
//1 = Stereo sound  
  
E).AACPacketType, 8 bit, AACAUDIODATA的类型. IF SoundFormat == 10  
//只有音频格式为AAC(0x0A),AudioTagHeader中才会多出1个字节的数据AACPacketType  
//0 = AAC sequence header  

//1 = AAC raw  

2.音频Tag中AUDIO SPECIFIC CONFIG详细说明
A).audioObjectType:5bit,表示编码结构类型,AAC main编码为1,LOW低复杂度编码为2,SSR为3。
B).samplingFrequencyIndex:4bit,表示采样率。  
    0x00   96000  
    0x01   88200  
    0x02   64000  
    0x03   48000  
    0x04   44100  
    0x05   32000  
    0x06   24000  
    0x07   22050  
    0x08   16000  
    0x09   12000  
    0x0A   11025  
    0x0B     8000  
    0x0C   reserved  
    0x0D   reserved  
    0x0E   reserved  
    0x0F   escape value  
    按理说,应该是:0 ~ 96000, 1~88200, 2~64000, 3~48000, 4~44100, 5~32000, 6~24000, 7~ 22050, 8~16000...),  
    通常aac固定选中44100,即应该对应为4,但是试验结果表明,当音频采样率小于等于44100时,应该选择3,而当音频采样率为48000时,应该选择2;
 
C).channelConfiguration:4bit,表示声道数。
D).frameLengthFlag:1bit  
E).dependsOnCoreCoder:1bit  
F).extensionFlag:1bit  
最后3bit,固定为0。   

3.ADTS格式说明

ADTS全称是(Audio Data Transport Stream),是AAC的一种十分常见的传输格式。

记得第一次做demux的时候,把AAC音频的ES流从FLV封装格式中抽出来送给硬件解码器时,不能播;保存到本地用pc的播放器播时,我靠也不能播。当时崩溃了,后来通过查找资料才知道。一般的AAC解码器都需要把AAC的ES流打包成ADTS的格式,一般是在AAC ES流前添加7个字节的ADTS header。也就是说你可以吧ADTS这个头看作是AAC的frameheader。

ADTS AAC
ADTS_header AAC ES ADTS_header AAC ES
...
ADTS_header AAC ES

ADTS内容及结构

ADTS 头中相对有用的信息 采样率、声道数、帧长度。想想也是,我要是解码器的话,你给我一堆得AAC音频ES流我也解不出来。每一个带ADTS头信息的AAC流会清晰的告送解码器他需要的这些信息。

一般情况下ADTS的头信息都是7个字节,分为2部分:

adts_fixed_header();

adts_variable_header();

SRS 代码分析【保存AAC音频文件】


syncword :同步头 总是0xFFF, all bits must be 1,代表着一个ADTS帧的开始

ID:MPEG Version: 0 for MPEG-4, 1 for MPEG-2

Layer:always: '00'

profile:表示使用哪个级别的AAC,有些芯片只支持AAC LC 。在MPEG-2 AAC中定义了3种:

SRS 代码分析【保存AAC音频文件】

sampling_frequency_index:表示使用的采样率下标,通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值。

There are 13 supported frequencies:

  • 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
channel_configuration: 表示声道数 

  • 0: Defined in AOT Specifc Config
  • 1: 1 channel: front-center
  • 2: 2 channels: front-left, front-right
  • 3: 3 channels: front-center, front-left, front-right
  • 4: 4 channels: front-center, front-left, front-right, back-center
  • 5: 5 channels: front-center, front-left, front-right, back-left, back-right
  • 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
  • 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
  • 8-15: Reserved
SRS 代码分析【保存AAC音频文件】

frame_length : 一个ADTS帧的长度包括ADTS头和AAC原始流.

adts_buffer_fullness:0x7FF 说明是码率可变的码流