本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为对应的视频和音频数据为止。
进入testProgs目录,执行./openRTSP rtsp://xxxx/test.mp4
对于RTSP协议的处理部分,可设置断点在setupStreams函数中,并跟踪即可进行分析。
这里主要分析进入如下的while(1)循环中的代码
- void BasicTaskScheduler0::doEventLoop(char* watchVariable)
- {
- // Repeatedly loop, handling readble sockets and timed events:
- while (1)
- {
- if (watchVariable != NULL && *watchVariable != 0) break;
- SingleStep();
- }
- }
从这里可知,live555在客户端处理数据实际上是单线程的程序,不断执行SingleStep()函数中的代码。通过查看该函数代码里,下面一句代码为重点
- (*handler->handlerProc)(handler->clientData, resultConditionSet);
其中该条代码出现了两次,通过调试跟踪它的执行轨迹,第一次出现调用的函数是为了处理和RTSP服务器的通信协议的商定,而第二次出现调用的函数才是处理真正的视频和音频数据。对于RTSP通信协议的分析我们暂且不讨论,而直接进入第二次调用该函数的部分。
在我们的调试过程中在执行到上面的函数时就直接调用到livemedia目录下的如下函数
- void MultiFramedRTPSource::networkReadHandler(MultiFramedRTPSource* source, int /*mask*/)
- {
- source->networkReadHandler1();
- }
//下面这个函数实现的主要功能就是从socket端读取数据并存储数据
- void MultiFramedRTPSource::networkReadHandler1()
- {
- BufferedPacket* bPacket = fPacketReadInProgress;
- if (bPacket == NULL)
- {
- // Normal case: Get a free BufferedPacket descriptor to hold the new network packet:
- //分配一块新的存储空间来存储从socket端读取的数据
- bPacket = fReorderingBuffer->getFreePacket(this);
- }
- // Read the network packet, and perform sanity checks on the RTP header:
- Boolean readSuccess = False;
- do
- {
- Boolean packetReadWasIncomplete = fPacketReadInProgress != NULL;
- //fillInData()函数封装了从socket端获取数据的过程,到此函数执行完已经将数据保存到了bPacket对象中
- if (!bPacket->fillInData(fRTPInterface, packetReadWasIncomplete))
- {
- if (bPacket->bytesAvailable() == 0)
- {
- envir() << "MultiFramedRTPSource error: Hit limit when reading incoming packet over TCP. Increase \"MAX_PACKET_SIZE\"\n";
- }
- break;
- }
- if (packetReadWasIncomplete)
- {
- // We need additional read(s) before we can process the incoming packet:
- fPacketReadInProgress = bPacket;
- return;
- } else
- {
- fPacketReadInProgress = NULL;
- }
- //省略关于RTP包的处理
- ...
- ...
- ...
- //fReorderingBuffer为MultiFramedRTPSource类中的对象,该对象建立了一个存储Packet数据包对象的链表
- //下面的storePacket()函数即将上面获取的数据包存储在链表中
- if (!fReorderingBuffer->storePacket(bPacket)) break;
- readSuccess = True;
- } while (0);
- if (!readSuccess) fReorderingBuffer->freePacket(bPacket);
- doGetNex