现在开讲 testRTSPClient。在官网这这样一段介绍,参看:RTSP client
翻译下来就是:
testRTSPClient 是一个命令行程序,显示如何打开和接收由 RTSP URL 指定的媒体流,即以rtsp://开头的URL
在这个演示应用中,接收到的音频/视频数据什么也没有。 但是,您可以在自己的应用程序中使用和调整此代码(例如)解码和播放接收到的数据。
openRTSP 类似于“testRTSPClient”,但具有更多的功能。 这是一个命令行程序,它与“testRTSPClient”不同,旨在用作一个完整的全功能应用程序(而不是在其他应用程序中使用其代码)。 也正应为如此,openRTSP”源代码并不是最好的例子,因为它包含很多额外的选项,大多数你可能不需要。
所以,如果您正在寻找如何使用“LIVE555 Streaming Media”代码构建自己的RTSP / RTP媒体播放器客户端
应该使用“testRTSPClient”应用程序代码(也在“testProgs”目录中)作为模型。
一、源码解析
参看:庖丁解牛-----Live555源码彻底解密(根据testRTSPClient讲解)
参看:庖丁解牛-----Live555源码彻底解密(testRTSPClient流程图)
参看:live555/testProgs/testRTSPClient.cpp
推荐使用 ctags 来查看源码进行分析
参看:日常生活小技巧 -- vim 中 ctags 的安装和使用
下面所说的跳转查看就是 ctrl+},然后看完后返回跳转前位置 ctrl+t
(1)首先从 testRTSPClient.cpp 的 main函数开始看起
上图可以看到,创建BasicTaskScheduler 和 BisicUsageEnvironment对象。
重点是 openURL 函数,然后 ctrl+] 跳转查看 openURL 的定义
首先通过 ourRTSPClient::createNew 函数最终会调用 ourRTSPClient 的构造函数,基类 RTSPClient 的指针指向派生类 ourRTSPClient 对象,并且最终会调用 RTSPClient 的构造函数;
sendDescribeCommand 函数往服务器端发送 Describe 请求;continueAfterDESCRIBE 为回调函数;在DoEventLoop 中的 SingleStep 中调用;
RTP over tcp 还是udp 由宏 #define REQUEST_STREAMING_OVER_TCP False 进行控制;
(2)然后跳转查看 sendDescribeCommand
将continueAfterDESCRIBE 函数传递到 responseHandler,相当于 continueAfterDESCRIBE 为一个回调函数;注意 RequestRecord 这个类的作用;在 SendRequest 中调用 RequestRecord 的构造函数.
(3)然后跳转查看 RequestRecord
可看到将回调函数保存在 RequestRecord 类的 fHandler 上;
(4)然后跳转查看 fHandler
根据上图可看到 RequestRecord 类定义。所以说 在 SendRequest 中调用 RequestRecord 的构造函数.
(5)然后返回到(2),跳转查看 sendRequest
函数有点长,自行查看吧。
然后其中有一部分:
(6)然后跳转查看 openConnection
parseRTSPURL
setupStreamSocket
connectToServer
setBackgroundHandling
incomingDataHandler
这几个函数下面需要一一看一下,根据名字也可能看出它们是什么作用的。
(7)然后跳转查看 setBackgroundHandling
上图为 setBackgroundHandling 函数定义,其中 HandlerSet* fHandlers 连上服务器后,调用incomingDataHandler 回调函数;
(8)然后跳转查看 assignHandler
(9)然后跳转查看 lookupHandler
回顾(6)~(9)
openConnection 函数用来连接到服务器;在该函数中首先调用
parseRTSPURL 解析客户端的 RtspURL;然后建立socket(),然后
connectToServer 连接到服务器;;
incomingDataHandler 为回调函数;
incomingDataHandler 函数,最终赋值给了 handler->handlerProc = handlerProc;
那么我们接下来就看看这几个函数。
(10)然后返回到(6),跳转查看 parseRTSPURL
函数有点长,自行查看吧。
(11)然后返回到(6),跳转查看 setupStreamSocket
建立 socket 的函数为 setupStreamSocket,该函数建立的是一个 tcp 的 socket;
setupStreamSocket 函数首先创建 socket,然后设置 SO_REUSEADDR socket 属性;并且调用 bind 函数绑定socket;最后将 socket 设置成非阻塞形式;
(12)然后返回到(6),跳转查看 connectToServer
主要起作用的是这句话:
envir().taskScheduler().setBackgroundHandling(socketNum,SOCKET_WRITABLE|SOCKET_EXCEPTION,(TaskScheduler::BackgroundHandlerProc*)&connectionHandler,
然后
setBackgroundHandling 我们在 (7)里看过了。现在看一下 connectionHandler
(12)然后跳转查看 connectionHandler
(13)然后跳转查看 connectionHandler1
(14)然后返回到(1),跳转查看 doEventLoop
这里如果想要该程序退出,在外面将 *watchVariable=1 就可以了
(15)然后跳转查看 SingleStep
函数有点长,自行查看吧
connectionHandler 在 SingleStep 函数中会调用,调用如下:
(*handler->handlerProc)(handler->clientData,resultConditionSet);
到此,将数据接收部分的源码分析完了。