ZLMedia--AAC的流程

将conf\config.ini中[rtsp ]directProxy=1。未搞明白直接代理和非直接代理在流程上有什么不同。

一.RtspSession::onRecv--RtspSession.cpp

从网络上得到一个包。对于ACC包buf->data()[1]==0x2。

b  /opt/ZLMediaKit/src/Rtsp/RtspSession.cpp:132(因加日志有所差异;打印时只打印前100个字节。下同。)

1、第1个字节标识符,用于与RTSP区分。为0x24,即字符”$",表示传输的RTP包。

2、第2个字节,channel,用于区分RTP和RTCP。ACC:0x02,H264:0x00,RTCP:0x01或03.

3、第3、4个字节RTP包的大小,如050b,表示字节的长度为1291,表示整个包的长度,包括RTP包header和payload。但不包括RTP over TCP 的这4个字节。

4、第5个字节以后的12个字节:

 

 (1)80:10000000

V: 2bits,表示版本号。

P: 1bit,表示是否支持填充,不支持。

X: 1bit, 表示是否支持Rtp头扩展,不支持。

CC(CSRC count): 4bits,表示头部之后contributing sources identifiers的个数。

(2)e1:11100001

M: 1bit; 该值为1时,表示该数据包是一帧数据的最后一个数据包。

PT: 7bits,表示传输的多媒体类型(标识了RTP载荷的类型)。常用的的96表示h264,97 表示ACC。1100001表示97。

(3)sequence number:16bits(2字节),表示RTP包序号。

(4)timestamp:32bits(4字节),表示时间戳, 必须使用90 kHz 时钟频率。

(5)SSRC:32bits(4字节),用于标识同步信源,参加同一视频会议的两个同步信源不能有相同的SSRC.

(6)CSRC:特约信源标识符,每个CSRC占用4个字节,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。cc为0,所以这个没有。

5.Payload的前两个字节,表示ACC的ACC的帧数。

如用FFMPEG推送,前两个字节为00 50.,表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数

0000 0000 0101 0000

auto au_header_count = ((ptr[0] << 8) | ptr[1]) >> 4;

表示一个RTP包有5个AAC包。

6.如前两个字节为00 50,后面10个字节为AAC包的长度表示。

之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用
uint16_t size = ((au_header_ptr[0] << 8) | au_header_ptr[1]) >> 3;

如07 f8,用二进制表示为:0000 0111 1111 1000。其中高13位表示一帧AAC负载的字节长度,低3位无用。即 1111 1111表示为这个AAC包为255个字节。

7.每个AA包不带头。

二. HttpRequestSplitter::input--HttpRequestSplitter.cpp

b  /opt/ZLMediaKit/src/Http/HttpRequestSplitter.cpp:68

 

 这一步主要是将不同的类型的包分类处理,对于rtp没有改变接收的内容,调用 onRecvHeader。

三.RtspSplitter::onRecvHeader--RtspSplitter.cpp

 在这个函数中将rtp包和rtsp包分别处理,为了调试的方便,只处理ACC时,将相关代码改为:

if(_isRtpPacket){
if(data[1]==0x2)
{
onRtpPacket(data,len);
}

return 0;
}
加了行条件if(data[1]==0x2)

四.RtspSession::onRtpPacket--RtspSession.cpp

这个函数将RTP与RTCP包分开处理。

RTP包调用:handleOneRtp函数。传入参数时将RTSP去掉,前4个字节。

五.RtpMultiReceiver::handleOneRtp--RtpReceiver.h

没有对数据进行改变,将由track处理。

六.RtpTrack::inputRtp--RtpReceiver.cpp

b  /opt/ZLMediaKit/src/Rtsp/RtpReceiver.cpp:35

 在这个函数中又重新加上了RTSP的前4个字节。并调用  rtp->ntp_stamp = _ntp_stamp.getNtpStamp(rtp->getStamp(), sample_rate);改变时间戳。

七.RtspSession::onBeforeRtpSorted--RtspSession.cpp

调用updateRtcpContext对RTCP进行处理。RTCP先不详细解释。

###################################################################

1、2、3、4、5、6、7可以重复执行,存储起来供后续调用。

###################################################################

八.RtspSession::onRtpSorted--RtspSession.cpp

将RTP包存储到推流相关绑定的源中。

九.RtspMediaSourceImp::onWrite--RtspMediaSourceImp.h

将RTP包存储到解复用中。

十.RtspDemuxer::inputRtp--RtspDemuxer.cpp

将RTP包存储到解码器中。

十一.AACRtpDecoder::flushData--AACRtp.cpp

b  /opt/ZLMediaKit/src/Extension/AACRtp.cpp:93

 1.首2字节表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数

auto au_header_count = ((ptr[0] << 8) | ptr[1]) >> 4;

 2.之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用
uint16_t size = ((au_header_ptr[0] << 8) | au_header_ptr[1]) >> 3;

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

 - adts_fixed_header(); —— 固定头信息,头信息中的每一帧都相同.

 - adts_variable_header(); —— 可变头信息,头信息则在帧与帧之间可变.

class AdtsHeader{
public:
unsigned int syncword = 0; //12 bslbf 同步字The bit string ‘1111 1111 1111’,说明一个ADTS帧的开始
unsigned int id; //1 bslbf MPEG 标示符, 设置为1。0 for MPEG-4, 1 for MPEG-2
unsigned int layer; //2 uimsbf Indicates which layer is used. Set to ‘00’
unsigned int protection_absent; //1 bslbf 表示是否误码校验 set to 1 if there is no CRC and 0 if there is CRC
unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC,表示使用哪个级别的AAC,如profile的值等于 Audio Object Type的值减1,即profile = MPEG-4 Audio Object Type - 1
unsigned int sf_index; //4 uimsbf 表示使用的采样率下标(见下图)
unsigned int private_bit; //1 bslbf
unsigned int channel_configuration; //3 uimsbf 表示声道数。比如2表示立体声双声道.

unsigned int original; //1 bslbf
unsigned int home; //1 bslbf
//下面的为改变的参数即每一帧都不同
unsigned int copyright_identification_bit; //1 bslbf
unsigned int copyright_identification_start; //1 bslbf
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流
//no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
//所以说number_of_raw_data_blocks_in_frame == 0
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
};

 

 

  固定: 28 位 可变:28位,共56位,7个字节。

4. ADTS头部赋值的代码。

 

static void parseAacConfig(const string &config, AdtsHeader &adts) {
    uint8_t cfg1 = config[0];
    uint8_t cfg2 = config[1];

    int audioObjectType;
    int sampling_frequency_index;
    int channel_configuration;

    audioObjectType = cfg1 >> 3;
    sampling_frequency_index = ((cfg1 & 0x07) << 1) | (cfg2 >> 7);
    channel_configuration = (cfg2 & 0x7F) >> 3;

    adts.syncword = 0x0FFF;
    adts.id = 0;
    adts.layer = 0;
    adts.protection_absent = 1;
    adts.profile = audioObjectType - 1;
    adts.sf_index = sampling_frequency_index;
    adts.private_bit = 0;
    adts.channel_configuration = channel_configuration;
    adts.original = 0;
    adts.home = 0;
    adts.copyright_identification_bit = 0;
    adts.copyright_identification_start = 0;
    adts.aac_frame_length = 7;
    adts.adts_buffer_fullness = 2047;
    adts.no_raw_data_blocks_in_frame = 0;
}

(1)config在SDP中config中得到。如1408.

(2)cfg1、cfg2分别为16进制的0x14和0x08,二制的0001 0100 ,0000 1000。

(3)audioObjectType 为2.profile的值等于 Audio Object Type的值减1,表示使用哪个级别的AAC。1: AAC Main 2:AAC LC (Low Complexity) 3:AAC SSR (Scalable Sample Rate) 4:AAC LTP (Long Term Prediction)。

(4)sampling_frequency_index 采样率的下标.8表示16000。

(5)channel_configuration 标识声道数。

5.将ADTS的头部赋给7个字节。

static void dumpAdtsHeader(const AdtsHeader &hed, uint8_t *out) {
    out[0] = (hed.syncword >> 4 & 0xFF); //8bit
    out[1] = (hed.syncword << 4 & 0xF0); //4 bit
    out[1] |= (hed.id << 3 & 0x08); //1 bit
    out[1] |= (hed.layer << 1 & 0x06); //2bit
    out[1] |= (hed.protection_absent & 0x01); //1 bit
    out[2] = (hed.profile << 6 & 0xC0); // 2 bit
    out[2] |= (hed.sf_index << 2 & 0x3C); //4bit
    out[2] |= (hed.private_bit << 1 & 0x02); //1 bit
    out[2] |= (hed.channel_configuration >> 2 & 0x03); //1 bit
    out[3] = (hed.channel_configuration << 6 & 0xC0);  // 2 bit
    out[3] |= (hed.original << 5 & 0x20);                //1 bit
    out[3] |= (hed.home << 4 & 0x10);                //1 bit
    out[3] |= (hed.copyright_identification_bit << 3 & 0x08);            //1 bit
    out[3] |= (hed.copyright_identification_start << 2 & 0x04);        //1 bit
    out[3] |= (hed.aac_frame_length >> 11 & 0x03);                //2 bit
    out[4] = (hed.aac_frame_length >> 3 & 0xFF);                //8 bit
    out[5] = (hed.aac_frame_length << 5 & 0xE0);                //3 bit
    out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F);                //5 bit
    out[6] = (hed.adts_buffer_fullness << 2 & 0xFC);                //6 bit
    out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03);                //2 bit
}

 6.加入ADTS头

经auto size = dumpAacConfig(_aac_cfg, _frame->_buffer.size(), (uint8_t *) adts_header, sizeof(adts_header));后

frame中入了7个字节的头

十二.AACTrack::inputFrame--AAC.cpp

将frame送入到track中。根据ADTS字头生成相关信息,更新ADTS字头中关于 track的信息。

1.得到frame的长度,包含了ADTS的头。

调用getAacFrameLength((uint8_t *) ptr, end - ptr),关键代码就一行:

len = ((uint16_t) (data[3] & 0x03) << 11) | ((uint16_t) data[4] << 3) | ((uint16_t) (data[5] >> 5) & 0x07);

2.再次到  frame.h 中bool inputFrame(const Frame::Ptr &frame) override,然后进行十三步。

十三.MediaSink::inputFrame--MediaSink.cpp

判断t各个rack是否准备好。

十二-1.再次执行步骤十二

十四.MediaSink::addTrack--track->addDelegate--MediaSink.cpp

各个track准备好以后,执行代理函数。

十五.MultiMediaSourceMuxer::onTrackFrame--MultiMediaSourceMuxer.cpp

将frame传给RtspMediaSourceMuxer。

十六.RtspMediaSourceMuxer:inputFrame--RtspMediaSourceMuxer.h

将frame传给RtspMuxer。

十七.RtspMuxer::inputFrame---RtspMuxer.cpp

将frame传给RtpCodec。

 十八. AACRtpEncoder::inputFrame--AACRtp.cpp

将frame加上4个字节。0和16固定,另两个字节是frame长度。

 

_section_buf[2] = (len >> 5) & 0xFF;
_section_buf[3] = ((len & 0x1F) << 3) & 0xFF;

高13位表示一帧AAC负载的字节长度,低3位无用。

 

十九.ACRtpEncoder::makeAACRtp--AACRtp.cpp

生成rtp,并传给RtpCodec。

二十.RtpInfo::makeRtp--RtpCodec.cpp

对于每个frame加上rtsp over tcp 头和 rtp头.

十一.RtpRing::inputRtp--RtpCodec.h

将rtp写RingBuffer中。

十二.RingBuffer::write--RingBuffer.h

调用代理进一步处理。 _delegate->onWrite(std::move(in), is_key)。

十三.RtspMediaSource:onWrite--RtspMediaSource.h

对 SdpTrack信息进行更新,并通知和存入PacketCache<RtpPacket>中。

十四.PacketCache:inputPacket--MediaSource.h

追加数据到最后。

十四.RtspMediaSource:onFlush--RtspMediaSource.h

更新RingBuffer。

 

¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

以FFMPEG为例,每个RTP中包含5个FRAME数据,11-24要重复执行5次,再处理下一个包。

¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

===================================下面为拉流的流程====================================================

1._play_reader->setReadCB( RtspSession::handleReq_Play--RtspSession.cpp)

2.RtspSession::sendRtpPacket(RtspSession.cpp)

3.RtspSession::send(RtspSession.cpp))

4.SocketHelper::send(Socket.cpp)

最后发送的是1帧数据。RTSP启始+RTSP头+0x00 0x01 两个字节的帧长+AAC数据。

posted @ 2022-09-17 14:33  泽良_小涛  阅读(395)  评论(0编辑  收藏  举报