首页 > 编程语言 >zlmediakit源码学习(深入解析RTSP拉流)

zlmediakit源码学习(深入解析RTSP拉流)

时间:2024-10-31 19:33:38浏览次数:1  
标签:RtspPlayer zlmediakit 函数 H264 RTSP 源码 RTP cpp 回调

一、知其然更要知其所以然!花费了几天时间,对ZLM的源码再进行一次研究学习。通过梳理RTSP拉流过程,加深对ZLM架构的了解。

二、业务流程:

 三、完整代码剖析:

1.WebApi.cpp。在installWebApi中注册拉流代理接口:addStreamProxy()。1)检查是否已经存在;2)创建拉流代理;3)设置超时重试、拉流结果回调、播放关闭回调。4)调用player的play

 2.PlayerProxy.cpp,继承自MediaPlayer。在play函数中设置播放回调,调用Player的play接口。并设置播放重连等异常处理的回调机制。

 3.MediaPlayer.cpp,继承自PlayerBase。在play函数中通过PlayerBase创建真正的播放delegate,设置响应的回调处理函数。设置成一个MediaSource。调用真正播放代理的play函数。

4.PlayerBase.cpp。在createPlayer函数中通过传入的url字符串判断创建rtsp或rtmp或http播放代理

5.RtspPlayer.cpp,继承自PlayerBase,TcpClient,RtspSplitter,RtpRecevier。在play函数中通过RtspUrl的parse函数解析url地址,创建连接startConnect。

 6.Parser.cpp。封装了对各种流地址解析函数。RtspUrl::parse实现了对rtsp流地址的解析。

 7.RtspPlayer.cpp。上接第5步,在对摄像机连接成功之后的onConnect回调中开始进行RTSP协议的交互,首先发送Options请求。

 8.RtspPlayer.cpp。在sendOptions函数中调用sendRtspRequest函数发送Options请求,并色设置改状态对应的_on_response回复处理函数(下文介绍),在回复处理函数中处理摄像机返回的OPTIONS报文,处理成功之后发送Describe请求,进入RTSP协议的下一个交互。RSTP协议交互都是按照这个套路。

 9.RtspPlayer.cpp。在sendRtspRequest函数中封装了构造RTSP报文,向摄像仪发送RTSP命令的方法,里面包含了session权限字段计算填充。

 10.RtspSplitter.cpp,继承自HttpRequestSplitter类(各种网络协议的数据分割都是基于该类实现,暂不分析)。经过一系列接收到的摄像机发送报文解析之后进入到onRecvHeader函数。在RTSP协议交互完成之前,进行onWholeRtspPacket函数进行RTSP协议包处理。

 11.RtspPlayer.cpp。上接第8步,在onWholeRtspPacket函数中进行对设置的_on_response回调函数进行RTSP协议处理。如第8步中对Options回复处理之后调用sendDescribe函数,进入下一流程。

 12.RtspPlayer.cpp。在sendDescribe函数中设置对应的回复处理函数handleResDESCRIBE,并且发送DESCRIBE请求

 13.RtspPlayer.cpp。在handleResDESCRIBE函数中Describe的返回结果处理,其中handleResponse第一次会失败,要先经过401鉴权认证。第二次成功后解析摄像机返回的SDP中包含的音视频编码信息,创建对应的track。也初始化rtcp相关内容。开始sendSetup(0)环节,使能第一个摄像机媒体通道。

 14.RtspPlayer.cpp。在sendSetup函数中对对应Index的媒体通道进行处理,首先设置_on_response函数,然后根据拉流类型分别发送TCP或UDP方式的setup请求。TCP模式下复用rtsp数据通道;UDP模式下需要先创建两个udp的socket,并将端口发送到摄像机。creteUdpsockIfNecessary函数不再分析。

 15.RtspPlayer.cpp。在handleResSETUP函数中对摄像机返回的SETUP回复进行处理,值得注意的:UDP模式时新创建的udp连接是只用于接收视频流,因此需要单独再设置下OnRead回调,在回调中进行handeOneRtp的处理。当所有通道都setup完毕后,发送sendPause(type_play,0)环节,Play第一个媒体通管道。

 16.RtspPlayer.cpp。在sendPause函数中封装了play和pause两种处理。设置了_on_response未handleResPAUSE。

 17.RtspPlayer.cpp。在handleResPAUSE中实现对Play命令的回复处理。当摄像机回复200时,认为点播成功。进行onPlayResult_l回调。

 18.RtspPlayer.cpp。在onPlayResult_l中,如果播放成功执行onPlayResult函数回调。同时启动一个检测RTP收流超时的定时器。

 19.RtspPlayer.cpp。在onPlayResult函数中执行父类的onPlayResult函数:

 20.PlayerProxy.cpp。上接第2步,onPlayResult的回调函数是在play的时候设置的。如果播放成功,回调播放成功的处理函数,失败,则进行重试播放。

 21.PlayerProxy.cpp。很关键!在onPlaySuccess函数中创建真正的MediaSource对象,里面有两个重要的操作:_muxer->addTrack(videoTrack)和_videoTrack->addDelegate(_muxer)。很重要,后面再分析。

 22.MultiMediaSourceMuxer.cpp。ZLM的灵魂类!,继承自MediaSink。在类构造函数中创建其它协议的MediaSource对象

 23.MediaSink.cpp。上接第21步,在track中设置onTrackReady回调,同时设置addDelegate事件,用于接收媒体流的视频帧,先缓存,轨道就绪后触发OnTrackFrame回调。

 

24.休息一会儿喘口气~。上面命令交互基本完成,接下去分析视频流。

25.RtspPlayer.cpp。上接第10步,在接收到一个RTP包时,会进入到onRtpPacket函数。ZLM是通道RTP数据包的第二个字节来区分RTP还是RTCP的,也用来获取到轨道号(待研究),如果是RTP包,进入handleOneRtp函数。

 26.RtpReceiver.h。收到RTP包后写入到对应轨道中进行后续处理。inputRtp

 27.RtpReceiver.cpp。在inputRtp函数中对RTP的头部进行解析校验。将负责构造成RtpPacket之后使用sortPacket函数进行重排。

 28.RtpReceiver.h。在sortPacket函数中进行RTP包的乱序重排,重排具体实现不再分析。通过output()函数,回调出最新的RTP包。

 29.RtpReceive.h。在output函数中将帧回调出去。

 30.RtspPlayer.cpp。接上29步,经过一系列设置回调之后,最终将排序之后得到的RTP包回调到onRtpSorted函数中,并通过onRecvRTP函数进一步回调。

 31.RtspPlayer.cpp。在onRecvRTP函数中将得到的RTP帧输入到解复用器中进行解包_demuxer->inputRtp。onWrite函数是自身创建的RtspMediaSorce写原始帧,暂不分析。

 32.RtspDemuxer.cpp。在inputRtp函数中将音视频分别放入到对应的解码器中进行解码(解析出裸帧)。

 33.H264Rtp.cpp。在inputRtp函数中对RTP包通过decodeRtp函数进行解包,RTP解包的过程不再分析,最终得到一个完整的H264视频帧。

 34.H264Rtp.cpp。经过一系列的RTP解包和拼接之后得到一个完整的视频帧,输出到outputFrame函数中,并且通过inputFrame函数发送出去。

 35.Frame.h。在inputFrame函数中将得到的原始视频帧通过设置的代理回调对外进行分发。

 36.RtspPlayer.cpp。上接第13步的handleResDESCRIBE函数,在获取到摄像机上报的SDP信息后,忽略了一个重要的函数onCheckSDP。里面主要有两个操作:setSdp和loadSdp。

 37.RtspMediaSourceImp.cpp。使用sdp_parser可以解析出的音视频轨道信息。将生成的RtspMediaSource通过regist函数注册到全局视频列表中。

 38.MediaSource.cpp。regist函数是将媒体MedisSource注册到全局的s_media_source_map中。

39.MediaSource.cpp。可以看到s_media_source_map是一个static的静态全局变量。是一个多级的map。提供了regist()、unregist()、find()函数。

 

 40.RtspDemuxer.cpp。上接第36步,创建了一个RtspDemuxer解封装器。通过loadSdp函数建立对应的视频解封装器和音频解封装器。makeVideoTrack

 41.RtspDemuxer.cpp。在makeVideoTrack中例如可以创建一个RTP_H264的解封装器。这样就能对得上第32步_video_rtp_decoder->inputRtp()。至此分析完了RTSP作为客户端与摄像机完成RTSP协议交互,视频流RTP协议解封装的过程。

 

42.再休息一会儿喘口气~。上面已经实现了一个解析RTSP视频流中的原始H264帧的过程。接下来分析拿到帧之后的操作。

43.上接第41步,在创建_video_rtp_decoder解封装器之后,通过_video_rtp_decoder->addDelegate(_video_track)的方式设置解码后调。上接第35步,当_video_rtp_decoder对接收到的H264_RTP包进行解封装并组合成完整的H264视频帧之后,对外分发,即回调回_video_track视频规中。

44.H264.cpp。在H264Track::inputFrame函数中,接收到解封装回调的H264原始帧,通过inputFrame_l函数再次对外分发。代码中使用到了spliteH264函数,主要是为了对某些SPS、PPS、I帧连包的情景,进行拆包。spliteH264函数不再分析。

 45.H264.cpp。在H264Track::inputFrame_1函数中实现对帧的分发,需要特别注意的时,加入摄像机上传的原始视频流中不包含SPS和PPS帧,ZLM通过insertConfigFrame方式在I帧之前插入自身根据SDP信息构造的SPS和PPS帧,保证视频流中不缺失SPS和PPS。

 46.H264.cpp。H264Track::insertConfigFrame。根据SDP信息中的_sps和_pps字符串构造SPS和PPS帧。

 47.H264.h。createConfigFrame函数是一个模版函数,用于创建H264、H265的配置帧。

 48.Frame.h。VideoTrack派生自FrameDispatcher类,可以进行视频帧的对外分发。上接第46步,VideoTrack获取到的H264视频帧,通过这个外部注册delegete代理的方式对外分发。

 49.MediaSink.cpp。再回到很关键的第21步,在在onPlaySuccess函数中,把player也创建成了一个MediaSource对象_muxer,并且执行了一次videoTrack->addDelegate(_muxer)的操作。_muxer对象本质上也是一个mediasink,实现了MediaSink::inputFrame方法。因此在player的H264Track对外分发H264视频帧时,其实是回到到了player构造的MediaServer的中。至此,MediaServer就能够得到解封装之后的视频帧了。

 50.MediaSink.cpp。额外说明:在上步MediaSink::inputFrame函数中,it->second.first->inputFram(frame)实际上是调用的h264Track的inputFrame函数。回顾第23步Media::addTrack函数中track->addDelegate()中设置的inputFrame处理函数为当轨道全部就绪时执行onTrackFrame函数,进一步向上回调。

 51.MediaSink.cpp。再分析一下第49步的chekTrackIfReady函数。在上述回顾第23步中,_muxer->addTrack时分别注册了音视频轨道的_tarck_ready_callback函数,会在轨道就绪时触发onYrackReady回调。当轨道全部就绪时,会通过emitAllTrackReady函数触发onAllTrackReady回调。

 52.MediaSink.cpp。emitAllTrackReady函数需要结合上面第23步和第49步一起看,在第23步中mediasserver的track添加了一个delegate代理,即在第49步回调回来的视频帧在轨道未全部就绪时,先缓存到_frame_unread中。当轨道全部就绪时,将之前缓存的视频帧一起通过onTrackFrame函数对外输出。同时触发onAllTrackReady回调。

 53.MultiMediaSourceMuxer.cpp。onTrackReady(),上接第22步,由player创造的MultiMediaSourceMuxer中创建了多个协议对象。此处向各协议对象添加轨道。

 54.MultiMediaSourceMuxer.cpp。onAllTrackReady(),此处向各协议对象通知轨道添加完成。

 55.MultiMediaSourceMuxer.cpp。onTrackFrame()此处向各协议对象写入原始视频帧。

 56.接下来就要分析其它协议接收到addTrack和inputFrame之后如何处理了。

标签:RtspPlayer,zlmediakit,函数,H264,RTSP,源码,RTP,cpp,回调
From: https://www.cnblogs.com/feixiang-energy/p/18502532

相关文章

  • (开题报告)django+vuejavaweb学生宿舍管理系统论文+源码
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于学生宿舍管理系统的研究,现有研究多集中于传统管理模式或单一功能模块的实现。在国内外,传统的学生宿舍管理方式主要依赖人工操作,效......
  • 基于SpringBoot+Vue的民族婚纱预定管理系统设计与实现毕设(文档+源码)
            目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:        大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的民族婚纱预定管理系统,项目源码请点击文章末尾联系我哦~目前有各类......
  • 基于SpringBoot+Vue的社团管理系统设计与实现毕设(文档+源码)
            目录一、项目介绍二、开发环境三、功能介绍四、核心代码五、效果图六、源码获取:        大家好呀,我是一个混迹在java圈的码农。今天要和大家分享的是一款基于SpringBoot+Vue的社团管理系统,项目源码请点击文章末尾联系我哦~目前有各类成品毕......
  • java+vue计算机毕设高校党建管理平台设计与现实-以西藏民族大学为例【开题+程序+论文+
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,高校党建工作面临着新的机遇与挑战。特别是在西藏民族大学这样的特殊地域环境中,如何有效管理和推进党建工作,成为了一个亟待解......
  • linux使用者须知!Ls命令输出的颜色究竟由什么含义?教你轻松区分~(带私活源码)
     在linux中我们经常会用到Ls命令,我们发现Ls的输出中有各种各样的颜色,今天和大家共同了解一下Ls背后的故事。简介Linux ls(英文全拼:listdirectorycontents)命令用于显示指定工作目录下之内容(列出目前工作目录所含的文件及子目录)。我们可以看到ls的输出中有着不同的颜色......
  • UcOs-III 源码阅读: os_mem.c
    //作用:固定大小内存管理器的代码,内存分区代码/***********************************************************************************************************uC/OS-III*TheReal......
  • Python——石头剪刀布(附源码+多模式二改优化版)
    编程初学者通常会从简单的项目开始,以建立基础并增强信心。石头剪刀布游戏是一个很好的起点,因为它涉及到基本的逻辑判断、用户输入处理和随机数生成。本文将详细介绍如何使用Python编写一个石头剪刀布游戏,并提供完整的代码和解释。目录一、游戏介绍二、基本代码解析与实现......
  • Ubuntu24安装Gitlab源码管理系统
    Ubuntu20.04LTS,22.04LTS,24.04LTS安装和配置所需的依赖sudoapt-getupdatesudoapt-getinstall-ycurlopenssh-serverca-certificatestzdataperl(可选)如果要使用Postfix来发送电子邮件通知,执行以下安装命令。sudoapt-getinstall-ypostfix如果您想使用......
  • UcOs-III 源码阅读: os_mutex.c
    //作用:管理互斥量的代码/***********************************************************************************************************uC/OS-III*TheReal-TimeKernel**......
  • 斐波那契时间序列,精准捕捉市场拐点 MT4免费公式源码!
    指标名称:斐波那契时间序列版本:MT4ver.2.01斐波那契时间序列是一种技术分析工具,通过将斐波那契数列(如1,2,3,5,8,13等)应用于时间轴上,用于预测市场价格的时间周期拐点。斐波那契时间序列在股票、外汇和其他市场分析中常用,帮助预测趋势反转或调整发生的时间节点。斐波那......