ZLMedia--h264的流程
将conf\config.ini中[rtsp ]directProxy=1。和AAC的流程基本相同。
还未搞明白直接代理和非直接代理在流程上有什么不同。
一.RtspSession::onRecv--RtspSession.cpp
从网络上得到一个包。对于H264包buf->data()[1]==0x0。
1.用FFMPEG推送的第一个视频包
(1)第一个字节0x24,表示开始。
(2)第二个字节0x00,是视频。
(3)3、4字节0x 00 2a,用10进制表示42,表示RTP包的长度为42.
(4)RTP Payload的第一个字节0x18(0001 1000),即10进制24。这个字节是NAL Header ,
Type为24,表示:STAP-A(单一时间组合包模式 A,用于一个 RTP 包荷载多个 NALU)
一个 RTP 包荷载多个 NALU,结构如下。 一个 RTP 包荷载多个 NALU,结构如下。
结合抓图:
00 15:两个字节的长度, 表示第一个NALU的长度为21(10进制,含NALU HEADER)。
67:一个字节的NALU HEADER,即0110 0111。0:必须为0, 11 :指示该 NALU 重要性,该值越大说明该 NALU 越重要,需要受到保护。00111:为7,SPS(序列参数集)
向后数21个字节
00 04:两个字节的长度, 表示第二个NALU的长度为4(10进制,含NALU HEADER)。
68:一个字节的NALU HEADER,即01101000。0:必须为0,11表示非常重要;01000:为8,PPS(图像参数集)。
2.用FFMPEG推送的关键帧的开始视频包
(1)Payload第一个字节7c即0111 1100
11100:28表明为分片模式。用于将一个 NALU 分片到多个 RTP 包中。RTP 头部之后的第一个字节为 FU indicator,第二个字节为 FU header。
(2)
(3)FU indicator 结构如下所示,同NAUL HEADER 。
(4)FU header 结构如下所示,字段含义如下
第二个字节85(10000101),type 101为5:IDR 图像的片(关键帧)。
3.IDR中间的一包数据
(1)Payload第一个字节7c即0111 1100。11100:28表明为分片模式。用于将一个 NALU 分片到多个 RTP 包中。RTP 头部之后的第一个字节为 FU indicator,第二个字节为 FU header。
(2)第二个字节为05即0000 0101。表白是一个中间的NALU,类型仍旧为5(IDR关键帧)。
4.IDR帧的最后一帧
(1)Marker变为true.
(2)第二个字节变为45,即0100 0101。表示关键的最后一帧。
二. HttpRequestSplitter::input--HttpRequestSplitter.cpp
b /opt/ZLMediaKit/src/Http/HttpRequestSplitter.cpp:67 if data[1]==0x0
b /opt/ZLMediaKit/src/Http/HttpRequestSplitter.cpp:65 if header_size==46
三.RtspSplitter::onRecvHeader--RtspSplitter.cpp
b /opt/ZLMediaKit/src/Rtsp/RtspSplitter.cpp:63
在这个函数中将rtp包和rtsp包分别处理,在这个函数中,可以方便的观察各个rtp包。
四.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:99
在这个函数中又重新加上了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包存储到解码器中。
==================================以后的步骤是和ACC有区别的==========================================
十一、H264RtpDecoder::inputRtp--H264Rtp.cpp
调用解码器。
十二、H264RtpDecoder::decodeRtp--H264Rtp.cpp
调用不同的函数对不同的包进行解码。
frame[0]这个字节是NAL Header ,第一个字节0x18(0001 1000),即10进制24。
Type为24,表示:STAP-A(单一时间组合包模式 A,用于一个 RTP 包荷载多个 NALU)。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\
十三、H264RtpDecoder::unpackStapA-- H264Rtp.cpp
- SPS,前两个字节0x0, 0x15,即十进制21.
- PPs,前两个字节0x0, 0x4,即十进制4.
十三-1、H264RtpDecoder::mergeFu-- H264Rtp.cpp
Type为28时,将多个rtp包合为一帧。
b H264Rtp.cpp:111
1.第一帧时:
prt[0] 7c 0111 1100 type 11100 28
nal_suffix = *ptr & (~0x1F) 0110 0000
fu—>prt[1] 85 1000 0101 type 00101 5 表I帧
enum {
NAL_IDR = 5,
NAL_SEI = 6,
NAL_SPS = 7,
NAL_PPS = 8,
NAL_AUD = 9,
NAL_B_P = 1,
};
合为一帧时,前面加4个字节,\x00\x00\x00\x01
后面一个字节为NALU 头,nal_suffix | fu->nal_type,即0110 0000| 0000 0101 à0110 0101 à0x65
2.不为第一帧是,将前面的FU Indicator和FU Header去掉,直接加入后面。
然后执行到十五。
十四、H264RtpDecoder:: singleFrame-- H264Rtp.cpp
- 对每帧加上00 00 00 01的帧头。
2.对pts进行赋值。PTS是真正录制和播放的时间戳.
十五、H264RtpDecoder::outputFrame-- H264Rtp.cpp
对dts进行了赋值,将每帧数据交编码器处理。
_dts_generator.getDts(frame->_pts, frame->_dts);
十六、FrameDispatcher : : inputFrame—Frame.h
对形成的帧派发给代理。
十七、H264Track::inputFrame--H264.cpp
主要对sps和pps帧进一步处理。对其它帧交由代理处理。
十八、MediaSink::addTrack-- MediaSink.cpp
track->addDelegate,如果不满足条件对帧进行存储,满足条件则由onTrackFrame继续处理。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
十九、MultiMediaSourceMuxer::onTrackFrame-- MultiMediaSourceMuxer.cpp
这里是一个重要的节点,对发出来的数据双进行封装,将由MultiMediaSourceMuxer::inputFrame进行处理(这里先对RTSP进行说明)。
二十、RtspMuxer::inputFrame-- RtspMuxer.cpp
通过TrackType得到编码器,进一步处理。
二十一、H264RtpEncoder::inputFrame-- H264Rtp.cpp
b /opt/ZLMediaKit/src/Extension/H264Rtp.cpp:290
取出sps、pps帧,及最后一帧。
二十二、 H264RtpEncoder::inputFrame_l-- H264Rtp.cpp
对每帧进一步处理,保证每一个关键帧前都有SPS与PPS。并调用packRtp进行Rtp打包。
二十三、H264RtpEncoder::packRtp-- H264Rtp.cpp
按type的类型分类处理。type为24,即STAP-A模式;type为28,即FU-A模式。
b /opt/ZLMediaKit/src/Extension/H264Rtp.cpp:223
getMaxSize为1388。下面按type为24先行说明。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
二十四、H264RtpEncoder::packRtpStapA-- H264Rtp.cpp
- 调用makeRtp生成RTP包。这个包包括4个字节的rtsp over tcp 头,12个字节的rtp头。
- Payload前加三个字节,第一个字节为类型,第二、三个字节为长度。
payload[0] = (ptr[0] & (~0x1F)) | 24;
NRI变为11,表示非常重要。
b /opt/ZLMediaKit/src/Extension/H264Rtp.cpp:279
二十四-1、H264RtpEncoder::packRtpFu---- H264Rtp.cpp
b H264Rtp.cpp:234
把每一帧分成多个rtp包。每个rtp包的长度为:1386
二十五、RtpRing::inputRtp-- RtpCodec.h
Rtp包写入到RingType中。
二十六、RingBuffer::write-- RingBuffer.h
调用_delegate->onWrite(std::move(in), is_key);
二十七、RtspMediaSource::onWrite-- RtspMediaSource.h
b /opt/ZLMediaKit/src/Rtsp/RtspMediaSource.h:161
对track和缓冲组更新,并通知数据变化。调用将数据插入缓冲区函数。
二十八、PacketCache::inputPacket--MediaSource.h
将RTP包追加到RTP LIST后面。
二十九、PacketCache::onFlush--MediaSource.h
更新RTP LIST。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库