live555 testOnDemandRTSPServer 源码分析

live555 源码框架结构,源码版本最后修改日期:2018-12-13 21

官方相关图解连接:http://www.live555.com/liveMedia/doxygen/html/inherits.html

相关的文章比较多,不过光看别人的介绍很难理解,自己拿源码看,边看边作图理清楚结构关系,再和他人的文章对比下图解是否有误,这样学起来效果不错。

:从 testOnDemandRTSPServer.cpp中分析,main函数中:

先创建了 RTSPServer *rtspServer,创建ServerMediaSession 并添加Subsession. 将ServerMediaSession add到RTSPServer

 RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);

 ServerMediaSession* sms
      = ServerMediaSession::createNew(*env, streamName, streamName,
				      descriptionString);
      sms->addSubsession(H264VideoFileServerMediaSubsession
		       ::createNew(*env, inputFileName, reuseFirstSource));

 rtspServer->addServerMediaSession(sms);



env->taskScheduler().doEventLoop();

GenericMediaServer内部,也可以说是RTSPServer内部,有 RTSPClientConnection和RTSPClientSession两个内部类(友元类),分别表示一个 RTSP 连接(和客户端连接的rtsp),和进行传输的rtsp会话。 GenericMediaServer类中有三个hash表,HashTable* fServerMediaSessions; //记录添加进来的服务端会话 (也可理解为服务端提供的rtsp服务会话层)
HashTable* fClientConnections;  //记录连接的rtsp连接(客户端rtsp使用的tcp连接,也可理解为rtsp连接会话层)
HashTable* fClientSessions; //记录客户端setup 的会话连接(也可以理解为rtp会话层)

在客户端有连接时,创建 RTSPClientConnection,在客户端要求setup时创建RTSPClinetSession具体的创建函数,都是纯虚函数,即GenericMediaServer只提供规范,具体的实现,在子类RTSPServer中。

(1)【创建服务端socket】创建 rtspserver的过程中,先用setUpOurSocket(env, ourPort)创建listen socket,[对应代码在RTSPServer::createNew()]  (2)[监听] 然后调用RTSPServer的父类的构造函数,设置一个回调:当这个socket有数据时就调用这个回调,就使用accept得到一个连接的rtsp socket, [对应代码在GenericMediaServer.cpp::incomingConnectionHandlerOnSocket] (3)【有客户链接,创建对应RTSP使用的tcp连接层】同时创建一个ClientConnection,(顾名思义,这就是一个服务连接,在GenericMediaServer有基本定义,在RTSPServer具体的rtsp server中还有一层和RTSP服务挂钩的ClientConnection的实现) 创建ClientConection是在GenericMediaServer中调用自己的存虚函数 createNewClientConnection(),也就是会调用子类RTSPServer中实现的createNewClientConnection. 【这里注意这个接口return 了对象指针,但其实调用者GenericMediaServer的incomingConnectionHandlerOnSocket()函数 调用的时候直接忽略了其返回值的,而是在RTSPServer::createNewClientConnection(){ return new RTSPClientConnection(*this, clientSocket, clientAddr);}通过第一个参数把Server的引用传递了进去,那么有没有内存泄漏呢?怎么把这个对象保存下来?是在,ClientConnection 类的构造函数中,会把自己通过这个传入的GenericMediaServer ,把自己添加到GenericMediaServer中的成员 fClientConnections 哈希表中。这样就保存下来了,当连接关闭的时候服务端就从自己的这个hash表中找出来这个连接,关闭,delete掉】(4)【用于rtsp协议的tcp连接,处理rtsp请求】创建ClientConnection 后,也要为这个ClientConnection 设置一个回调,当这个连接有数据写入的时候就读取分析数据,然后调用进行会话层面的处理,这里就是 rtsp的 option setup play pause stop 等等的控制了。 具体代码,在GenericMediaServer.cpp GenericMediaServer::ClientConnection::incomingRequestHandler() { int bytesRead = readSocket(envir(), fOurSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);
  handleRequestBytes(bytesRead);// 同样,这个handleRequestBytes也是个纯虚函数,由具体的服务端 RTSPServer类实现,里面真正处理 option setup play pase stop等等
}

:回调的设置,创建RTSPServer类的构造函数,会调用其父类GenericMediaServer的构造函数,在GenericMediaServer的构造函数中执行env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);这个incomingConnectionHandler,就是socket有数据时执行的调用。(5)【处理请求,建立rtp】现在进入 ClientConnection 会话中的 RTSPServer::RTSPClientConnection::handleRequestBytes() //处理请求。在处理请求时,更根据需要调用 GenericMediaServer中的createNewClientSessionWithId()来创建一个 ClinetSession。(如上所述,可以理解为rtp会话层)然后才调用RTSPClientSession::handleCmd_SETUP, (6)[play,启动对应rtp--ServerMediaSubsession]这现在进入RTSPClientSession,(如上所述,可理解为rtp连接层,所以之前往ServerMediaSession添加的ServerMediaSubsession,就相当于往rtsp会话中加入rtp会话)该函数里面会从GenericMediaServer中的fServerMediaSessions哈希表中查找是否有对应的server。 即在最开始,在main函数里面使用rtspServer->addServerMediaSession(sms) 添加的server。 这里会从之前添加的server中取出来,执行:  ServerMediaSubsession* subsession->getStreamParameters()。 也就是调用 H264VideoFileServerMediaSubsession::getStreamParameters(); 它的函数具体实现,在 OnDemandServerMediaSubsession中 OnDemandServerMediaSubsession 类 (6.1)[创建rtp]ServerMediaSubsession 【ServerMediaSubsession就相当于一个rtp】定义的纯虚函数getStreamParameters()要求获取对rtp流的参数,所以子类,必须在调用这个函数返回搭建好的rtp流的信息,首先就是要创建好rtp流,在OnDemandServerMediaSubsession 中实现了这个纯虚函数,创建rtp流,调用 createNewStreamSource()来创建StreamSource,调用createNewRTPSink()来创建rtpSink,如果是用的rtp-over-udp,还需要先创建好供rtp和rtcp使用udp socket. 另,还给OnDemandServerMediaSubsession(如上所述,即可理解为rtp) 创建了两个相关的数据结构(类)StreamStateDestinations
StreamState中,有RTPSink和FrameSource,也是在上述函数getStreamParameters中创建,ServerMediaSubsession的子类必须实现这个纯虚函数,并且在里面实例化数据源FrameSource和数据输出RTPSink,即在H264VideoFileServerMediaSubsession中的createNewStreamSource和createNewRTPSink
当GenericMediaServer中给ClientConnection设置的回调中,处理play命令请求时,即RTSPServer::RTSPClientSession(如上所述,可以理解对应为rtp) handleCmd_PLAY() 函数,调用到fStreamStates[i].subsession->startStream(),  ->
OnDemandServerMedai::sartStream ()->
StreamState::startPlaying()->
MediaSink::startPlaying()->
continuePlaying()-> 调用到 H264or5VideoRTPSink::continuePlaying()
-> MultiFramedRTPSink::continuePlaying()
补充一张大图,结构,调用关系等待。

https://blog.csdn.net/u012459903/article/details/102936752

 

 

 

 

 

 

 

 

 

图一:

从上往下为子类到父类。

图二:红色箭头可以看出 读h264文件 数据的调用过程

图三: 事件驱动,主循环

图三, h264文件读数据详细 调用流程:

图四:从h264读文件数据简要结构流程

发布了96 篇原创文章 · 获赞 27 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/86597475
今日推荐