南京电商网站设计,济宁市住房和城乡建设局网站,网站建设 管理规范,山西建站优化若该文为原创文章#xff0c;转载请注明原文出处 本文章博客地址#xff1a;https://hpzwl.blog.csdn.net/article/details/147879917
长沙红胖子Qt#xff08;长沙创微智科#xff09;博文大全#xff1a;开发技术集合#xff08;包含Qt实用技术、树莓派、三维、OpenCV…若该文为原创文章转载请注明原文出处 本文章博客地址https://hpzwl.blog.csdn.net/article/details/147879917
长沙红胖子Qt长沙创微智科博文大全开发技术集合包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等持续更新中…
FFmpeg、SDL和流媒体开发专栏
上一篇《live555开发笔记二live555创建RTSP服务器源码剖析创建rtsp服务器的基本流程总结》 下一篇敬请期待… 前言 对于live555的rtsp服务器有了而基本的了解之后进一步对示例源码进行剖析熟悉整个h264文件流媒体的开发步骤。 Demo 播放本地文件多路播放的时候总是以第一个文件进度为准所以当前这个Demo是同步播放的。 这对于摄像头采集视频实时播放来说这个是满足这个功能的。 基本概念
Source、Sink、Filter
Source作为数据流的起点负责生成或获取原始数据。例如ByteStreamFileSource从文件读取原始字节流6H264VideoStreamFramer解析H.264视频流并生成帧数据Filter在数据流从Souce流到Sink的过程中能够设置Filter用于过滤或做进一步加工。例如H264or5Fragmenter将视频帧分片以适应RTP包大小解码器Filter将编码数据解码为原始帧。Sink作为数据流的终点负责消费或转发数据。 整个LiveMedia中数据都是从Souce经过一个或多个Filter。终于流向Sink。在server中数据流是从文件或设备流向网络而在client数据流是从网络流向文件或屏幕。 MediaSouce是全部Souce的基类MediaSink是全部Sink的基类。 从类数量和代码规模能够看到。LiveMedia类是整个LIVE555的核心其内部包括数十个操作详细编码和封装格式的类。LiveMedia定义的各种Souce均是从文件读取假设想实现从设备获得实时流的传输能够定义自己的Souce。
ClientSession、ClientConnection
ClientSession对于每一个连接到server的client。server会为其创建一个ClientSession对象保存该client的socket、ip地址等。同一时候在该client中定义了各种响应函数用以处理和回应client的各种请求。ClientConnection用于处理一些与正常播放无关的命令。如命令未找到、命令不支持或媒体文件未找到等。在ClientConnection处理DESCRIBE命令时会创建ClientSession对象。其它命令在ClientSession中处理。
MediaSession、MediaSubsession、Track LIVE555使用MediaSession管理一个包括音视频的媒体文件。每一个MediaSession使用文件名称唯一标识。使用SubSession管理MediaSession中的一个音频流或视频流音频或视频均为一个媒体文件里的媒体流因此一个MediaSession能够有多个MediaSubsession可单独管理音频流、视频流并为每一个媒体流分配一个TrackID如视频流分配为Track1音频流分配为Track2此后client必须在URL指定要为那个Track发送SETUP命令因此我们能够觉得MediaSubsession代表Server端媒体文件的一个Track也即相应一个媒体流。MediaSession代表Server端一个媒体文件。 对于既包括音频又包括视频的媒体文件MediaSession内包括两个MediaSubsession。但MediaSession和MediaSubsession仅代表静态信息。若多个client请求同一个文件server仅会创建一个MediaSession。各个client公用。为了区分各个MediaSession的状态又定义了StreamState类用来管理每一个媒体流的状态。在MediaSubsession中完毕了Souce和Sink连接。Souce对指针象会被设置进sink。在Sink须要数据时能够通过调用Souce的GetNextFrame来获得。 LIVE555中大量使用简单工厂模式每一个子类均有一个CreateNew静态成员。该子类的构造函数被设置为Protected因此在外部不能直接通过new来构造。同一时候。每一个类的构造函数的參数中均有一个指向UsageEnvironment的指针从而能够输出错误信息和将自己增加调度。
HashTable IVE555内部实现了一个简单哈希表类BasicHashTable。在LIVE555中。有非常多地方须要用到该哈希表类。如媒体文件名称与MediaSession的映射SessionID与ClientSession的映射UserName和Password的映射等。
SDP SDP是Session Description Protocol的缩写。是一个用来描写叙述多媒体会话的应用层协议。它是基于文本的用于会话建立过程中的媒体类型和编码方案的协商等。 rtp与rtcp与rtsp服务器
RTP实时传输协议 负责传输实时音视频数据流基于UDP/IP协议实现低延迟传输。支持时间戳、序列号等机制确保数据包的时序性和同步性。不保证传输可靠性需结合RTCP进行质量监控。
RTCP实时传输控制协议 作为RTP的辅助协议用于监控传输质量、反馈统计信息如丢包率、延迟、抖动。功能实现通过发送SR发送者报告和RR接收者报告反馈网络状态。支持带宽动态调整如TMMBR/TMMBN和流同步。
RTSP实时流协议服务器 作为流媒体会话的控制中心负责客户端与服务器的交互如播放、暂停、停止等指令。
会话管理通过SETUP、PLAY、TEARDOWN等命令控制媒体流传输的生命周期。协议协调与RTP/RTCP协同工作RTSP定义控制逻辑RTP传输数据RTCP监控质量。多流支持可同时管理音视频等多路流并通过SDP协议协商编解码参数。 关键类介绍
H264VideoRTPSinkH264视频数据核心组件 H264VideoRTPSink是H.264视频流通过RTP/RTSP协议实现实时传输的关键模块负责协议封装、数据分片和网络适配确保视频流在实时场景下的高效性和兼容性。 H264VideoRTPSink是Live555 流媒体框架中用于封装和传输H.264视频数据的核心组件其作用主要包含以下方面
RTP数据封装H264VideoRTPSink 将 H.264 视频数据按 RTP 协议规范封装成网络传输包。具体包括添加 RTP 包头信息如时间戳、序列号、负载类型等根据 H.264 的 NALU网络抽象层单元结构对视频数据进行分片或重组确保数据适应网络传输的最大传输单元MTU限制。分片处理Fragmentation当单个 H.264 帧超过 MTU 限制时H264VideoRTPSink 会将其拆分为多个 RTP 包例如使用 FU-A 分片模式并在包头中标记分片的起始、中间和结束位置。与 RTSP 协议协同工作在RTSP会话中H264VideoRTPSink作为数据传输的终点Sink与MediaSource数据源配合完成从数据读取到RTP封装的完整流程。在客户端发送PLAY请求后服务器通过H264VideoRTPSink将封装后的RTP流推送至网络。缓冲区管理处理大数据量H.264视频时H264VideoRTPSink需依赖动态调整的缓冲区如OutPacketBuffer::maxSize防止因数据包过大导致的传输失败。
RTCPInstanceRTCP通讯类 在Live555框架中RTCPInstance与RTPSink、RTPInterface等类协作共同实现完整的RTP/RTCP流媒体传输功能。其设计独立于其他高层协议模块仅依赖基础网络组件具备较好的封装性。 RTCPInstance是Live555框架中封装RTCP协议通信的核心类
RTCP协议通信的封装与实现负责RTCP数据包的收发处理支持通过RTPInterface实现基于UDP或TCP的传输。接收到的RTCP报文如SR、RR、BYE等在incomingReportHandler等回调函数中处理实现网络状态反馈和会话控制。网络状态监测与统计统计RTP包的收发情况收集丢包率、延迟、抖动等指标为流量控制提供数据支持。依赖RTPSink类获取发送端统计信息实现与RTP流的关联。反馈与动态调整机制通过发送SR发送者报告和RR接收者报告实时反馈网络质量触发发送速率调整或丢包重传。支持带宽控制机制如TMMBR/TMMBN根据网络状况动态调整媒体流传输参数。会话管理与流同步处理BYE报文实现参与者退出通知维护会话成员状态。通过SDES报文传递参与者描述信息辅助多流同步如音视频同步。
ByteStreamFileSource基础数据源组件 ByteStreamFileSource是Live555中处理文件型H.264流的核心入口组件承担数据读取与基础分块功能并为上层解析、封装模块提供标准化输入接口。 ByteStreamFileSource在Live555 流媒体框架中作为基础数据源组件核心作用如下
原始字节流读取负责从本地文件如 H.264 裸流文件中读取未封装的原始字节数据并以分块Framed形式输出供后续解析模块处理。数据链的起点在典型的 H.264 传输链路如 H264VideoFileServerMediaSubsession中中其作为初始节点启动数据流后续连接解析器如H264VideoStreamParser和分帧器H264VideoStreamFramer形成完整处理链路ByteStreamFileSource → H264VideoStreamParser → H264VideoStreamFramer → … → RTP 封装。可扩展性支持虽然默认实现为文件读取但其继承自FramedSource基类用户可通过自定义派生类如实时采集或编码的数据源替代该组件实现灵活的数据输入适配。关键参数配置支持通过fileSize属性获取文件大小信息便于预估传输带宽需求。在动态服务器场景中需注意其与缓冲区大小如OutPacketBuffer::maxSize的协同配置避免大帧溢出问题。
FrameSource帧源抽象类 FrameSource是Live555中实现按帧输入媒体数据的基础组件为RTSP/RTP 传输提供标准化的数据源接口支持多格式媒体流的灵活扩展。 FrameSource 在 Live555 流媒体框架中作为数据源的核心抽象类其作用可归纳如下
基础数据源抽象FrameSource 是负责按帧Framed提供流媒体数据的基类定义了统一的帧数据读取接口。其子类需实现 doGetNextFrame 方法用于逐帧获取原始媒体数据如视频帧或音频块。RTP数据流起点在RTSP/RTP传输链路中FrameSource 作为数据生产者将媒体数据以帧为单位传递给下游处理模块如解析器、封装器。例如H264VideoStreamFramer 继承自 FrameSource负责将裸 H.264 码流分帧后输出。接口标准化FrameSource 通过纯虚函数强制子类实现关键操作包括帧数据异步获取机制通过 afterGetting 回调触发数据传输帧数据的分块与缓冲区管理。与下游组件协同FrameSource与MediaSink类如H264VideoRTPSink形成数据链路MediaSink通过fSource成员绑定FrameSource驱动数据拉取与封装流程在RTSP会话中FrameSource的数据最终被封装为RTP包并发送至客户端。
H264VideoStreamFramerH264视频流帧器 H264VideoStreamFramer在RTSP流媒体服务中通常由H264VideoFileServerMediaSubsession创建是H.264实时流传输的关键解析层承担了从原始字节流到结构化视频数据的转换任务。 H264VideoStreamFramer在Live555框架中作为视频流解析的核心组件主要承担H.264基本流ES的解析与重构其核心功能如下
H.264原始流解析从ByteStreamFileSource等数据源读取原始字节流通过内置的H264VideoStreamParser解析器识别NALU网络抽象层单元边界将连续字节流分割为独立NALU单元25处理H.264 Annex B格式的起始码如0x00000001实现NALU的精准定位56参数集处理提取并缓存SPS序列参数集和PPS图像参数集用于后续解码器初始化在流启动时优先发送SPS/PPS确保解码端正确初始化。分帧逻辑控制区分VCL视频编码层和非VCL NALU根据帧类型如IDR帧、非IDR帧组织数据输出56处理分片单元Slice的关联性确保帧完整性时间戳生成机制基于视频帧率或外部输入时钟计算RTP时间戳实现与音视频同步处理B帧/P帧的显示时间戳PTS与解码时间戳DTS关系。与上下游组件协作作为FramedSource的子类向上连接ByteStreamFileSource获取原始数据向下对接H264FUAFragmenter完成RTP分片通过事件驱动模型触发数据读取形成Source → Parser → Framer → Fragmenter → RTPSink的完整处理链路。 H264VideoStreamFramer把自己的缓冲其实是sink的传给H264VideoStreamParser每当H264VideoStreamFramer要获取一个NALU时就跟H264VideoStreamParser要而H264VideoStreamParser就从ByteStreamFileSource读一坨数据然后进行分析如果取得了一个NALU就传给H264VideoStreamFramer。 Live555流媒体服务实现基本流程
步骤一创建任务调度管理器 步骤二创建rtp和rtcp 在不同平台使用的socketaddr_storage类型有区别有些事socketaddr_in主要是groupsock的头文件构造函数类型的区别判断是live555各种版本有区别。
步骤三创建H264VideoRTPSink 步骤四创建RTCPInstance 步骤五RTSP服务器 步骤六创建ServerMediaSession实例 步骤七创建subsession实例 步骤八开始播放 步骤九服务器运行 Demo区别 没有启动服务器http端口监听而是直接play。 整理后的中文注释代码
/*为了使此应用程序正常工作H.264 Elementary Stream视频文件*必须*包含SPS和PPS NAL单元最好在文件开头或附近。这些SPS和PPS NAL单元用于指定在输出流的SDP描述中设置的“配置”信息由此应用程序内置的RTSP服务器设置。另请注意与其他一些“*Streamer”演示应用程序不同生成的流只能使用RTSP客户端如“openRTSP”接收
*/#include liveMedia.hh
#include BasicUsageEnvironment.hh
#include GroupsockHelper.hhUsageEnvironment* env;
//char const* inputFileName test.264;
char const* inputFileName T:/test/front/20250311_123244_0.h264;
H264VideoStreamFramer* videoSource;
RTPSink* videoSink;void announceURL(RTSPServer* rtspServer, ServerMediaSession* sms)
{if(rtspServer NULL || sms NULL){return;}UsageEnvironment env rtspServer-envir();env Play this stream using the URL ;if(weHaveAnIPv4Address(env)){char* url rtspServer-ipv4rtspURL(sms);env \ url \;delete[] url;if (weHaveAnIPv6Address(env)){env or ;}}if(weHaveAnIPv6Address(env)){char* url rtspServer-ipv6rtspURL(sms);env \ url \;delete[] url;}env \n;
}void play(); // forwardint main(int argc, char** argv)
{// 步骤一创建任务调度器和运行信息环境TaskScheduler* scheduler BasicTaskScheduler::createNew();env BasicUsageEnvironment::createNew(*scheduler);// 步骤二创建groupsocks用于RTP和RTCPstruct sockaddr_storage destinationAddress;destinationAddress.ss_family AF_INET;((struct sockaddr_in)destinationAddress).sin_addr.s_addr chooseRandomIPv4SSMAddress(*env);// 这是一个多播地址。如果希望使用单播进行流式传输那么应该使用“testOnDemand RTSPServer”测试程序而不是此测试程序作为模型。const unsigned short rtpPortNum 18888;const unsigned short rtcpPortNum rtpPortNum1;const unsigned char ttl 255;const Port rtpPort(rtpPortNum);const Port rtcpPort(rtcpPortNum);Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);rtpGroupsock.multicastSendOnly();Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);rtcpGroupsock.multicastSendOnly(); //// 步骤三从RTP“groupsock”创建“H264视频RTP”接收器OutPacketBuffer::maxSize 100000;videoSink H264VideoRTPSink::createNew(*env, rtpGroupsock, 96);// 步骤四为此RTP接收器创建并启动一个“RTCP实例” kbps为单位RTCP b/w份额const unsigned estimatedSessionBandwidth 500;const unsigned maxCNAMElen 100;unsigned char CNAME[maxCNAMElen1];gethostname((char*)CNAME, maxCNAMElen);CNAME[maxCNAMElen] \0; // just in caseRTCPInstance* rtcp RTCPInstance::createNew(*env,rtcpGroupsock,estimatedSessionBandwidth,CNAME,videoSink,NULL, // 代表服务器True); // 代表SSM源// 步骤五这将自动启动RTCP运行RTSPServer* rtspServer RTSPServer::createNew(*env, 8554);if (rtspServer NULL){*env Failed to create RTSP server: env-getResultMsg() \n;exit(1);}// 步骤六创建ServerMediaSessionServerMediaSession* sms ServerMediaSession::createNew(*env,testStream,inputFileName,Session streamed by \testH264VideoStreamer\,True);// 步骤七创建subsessionsms-addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));rtspServer-addServerMediaSession(sms);announceURL(rtspServer, sms);// 开始流播放:*env Beginning streaming...\n;// 这个开始播放函数调用不调用区别// 1.不调用时有客户端输入无法播放必须调用play进入则会开始调用播放从头开始播放// 2.后进入的客户端播放进度会主动同步首个连接的客户端播放进度play();// 服务器阻塞进入服务循环env-taskScheduler().doEventLoop(); // does not returnreturn 0;
}void afterPlaying(void* clientData)
{*env ...done reading from file\n;// 停止播放videoSink-stopPlaying();// 请注意这也会关闭此源读取的输入文件。这是静态方法可以直接关闭Medium::close(videoSource);// 再次开始播放play();
}void play()
{// 将输入文件作为“字节流文件源”打开ByteStreamFileSource* fileSource ByteStreamFileSource::createNew(*env, inputFileName);if(fileSource NULL){*env Unable to open file \ inputFileName \ as a byte-stream file source\n;exit(1);}FramedSource* videoES fileSource;// 为视频基本流创建帧器videoSource H264VideoStreamFramer::createNew(*env, videoES);// 最后开始播放*env Beginning to read from file...\n;videoSink-startPlaying(*videoSource, afterPlaying, videoSink);
}工程模板v1.2.0 上一篇《live555开发笔记二live555创建RTSP服务器源码剖析创建rtsp服务器的基本流程总结》 下一篇敬请期待… 本文章博客地址https://hpzwl.blog.csdn.net/article/details/147879917