Live555学习之(二)------- testOnDemandRTSPServer
好文章,来自【福优学苑@音视频+流媒体】
首先,看看这个程序的说明:
// A test program that demonstrates how to stream - via unicast RTP
// - various kinds of file on demand, using a built-in RTSP server.
就是说这个程序演示了如何利用RTSPServer这个类来对媒体文件进行单播,OnDemand的意思是收到RTSP客户端请求时才进行流化和单播。
下面,首先看main函数,很简单,主要包含以下几个步骤:
// Begin by setting up our usage environmen // 创建工具类 TaskScheduler* scheduler = BasicTaskScheduler::createNew(); env = BasicUsageEnvironment::createNew(*scheduler); // Create the RTSP server: // 创建RTSPServer,指定端口为8554 RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB); if (rtspServer == NULL) { *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; exit(1); } char const* descriptionString = "Session streamed by \"testOnDemandRTSPServer\""; // Set up each of the possible streams that can be served by the // RTSP server. Each such stream is implemented using a // "ServerMediaSession" object, plus one or more // "ServerMediaSubsession" objects for each audio/video substream. /* 为每一种媒体文件创建会话,简单理解就是:一个ServerMediaSession对象对应一个媒体文件,一个媒体文件中可能同时包含音频和视频,对于每个视频或者音频,对应一个ServerMediaSubsession对象, 一个ServerMediaSession中可以包含多个ServerMediaSubsession对象 */ // 这里我们只看H.264文件 // A H.264 video elementary stream: { char const* streamName = "h264ESVideoTest"; //标识请求播放该媒体文件时使用的名称 char const* inputFileName = "test.264"; //默认媒体文件名为test.264 ServerMediaSession* sms = ServerMediaSession::createNew(*env, streamName, streamName,descriptionString); //为该媒体文件创建一个ServerMediaSession /* .264文件只包含视频,创建一个ServerMediaSubsession对象并添加到ServerMediaSession H264VideoFileServerMediaSubsession是ServerMediaSubsession的子类,针对不同格式有不同的实现类 */ sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(*env, inputFileName, reuseFirstSource)); rtspServer->addServerMediaSession(sms); //将刚才创建的ServerMediaSession添加到RTSPServer中 announceStream(rtspServer, sms, streamName, inputFileName); //打印出播放该媒体文件的rtsp地址 } // 程序从下面开始进入一个主循环,后面的return 0不会被执行。 env->taskScheduler().doEventLoop(); // does not return return 0; // only to prevent compiler warning
Live555是单线程的,基于事件驱动模式,程序从doEventLoop函数出进入无限循环,在这个循环中不断地查看事件队列是否有事件需要去处理,有就去处理,没有则休眠一小会儿,看下doEventLoop函数,该函数在live/BasicUsageEnvironment/BasicTaskScheduler0.cpp文件中定义。
void BasicTaskScheduler0::doEventLoop(char* watchVariable) { // Repeatedly loop, handling readble sockets and timed events: while (1) { if (watchVariable != NULL && *watchVariable != 0) break; SingleStep(); //SingleStep函数中,对可读数据的socket进行读数据,对事件队列中的事件调用对应的处理函数处理 } }
主循环部分的代码比较简单,那我们就需要仔细看看创建RTSPServer,创建ServerMediaSession以及ServerMediaSubsession这部分的代码,看这部分代码之前,我们需要先对RTSP协议的建立连接过程有个大概的了解,在此我就不再详述,网上有很多讲解这个过程的博文,在此推荐一个:http://www.cnblogs.com/qq78292959/archive/2010/08/12/2077039.html
RTSPServer类即表示一个流媒体服务器实例,RTSPServer::createNew是一个简单工厂函数,使用指定的端口(8554)创建一个TCP的socket用于等待客户端的连接,然后new一个RTSPServer实例。
RTSPServer* RTSPServer::createNew(UsageEnvironment& env, Port ourPort, UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds) { int ourSocket = setUpOurSocket(env, ourPort); if (ourSocket == -1) return NULL; return new RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds); } RTSPServer的构造函数: RTSPServer::RTSPServer(UsageEnvironment& env, int ourSocket, Port ourPort, UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds) : Medium(env), fRTSPServerPort(ourPort), fRTSPServerSocket(ourSocket), fHTTPServerSocket(-1), fHTTPServerPort(0), fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)), fClientConnections(HashTable::create(ONE_WORD_HASH_KEYS)), fClientConnectionsForHTTPTunneling(NULL), // will get created if needed fClientSessions(HashTable::create(STRING_HASH_KEYS)), fPendingRegisterRequests(HashTable::create(ONE_WORD_HASH_KEYS)), fRegisterRequestCounter(0), fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds), fAllowStreamingRTPOverTCP(True) { ignoreSigPipeOnSocket(ourSocket); // so that clients on the same host that are killed don't also kill us // Arrange to handle connections from others: env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this); }
这里主要看一下turnOnBackgroundReadHandling函数,这个函数的作用即将某个socket加入SOCKET SET(参见select模型),并指定相应的处理函数。这里的处理函数即收到RTSP客户端连接请求时的回调处理函数incomingConnectionHandlerRTSP,第三个参数作为回调函数的参数。
ServerMediaSession::createNew是一个简单工厂模式函数,在其中new了一个ServerMediaSession对象,看一下ServerMediaSession这个类的定义。
class ServerMediaSession: public Medium { public: static ServerMediaSession* createNew(UsageEnvironment& env, char const* streamName = NULL, char const* info = NULL, char const* description = NULL, Boolean isSSM = False, char const* miscSDPLines = NULL); static Boolean lookupByName(UsageEnvironment& env, char const* mediumName, ServerMediaSession*& resultSession); char* generateSDPDescription(); // based on the entire session //产生媒体描述信息(SDP),在收到DESCRIBE命令后回复给RTSP客户端 // Note: The caller is responsible for freeing the returned string char const* streamName() const { return fStreamName; } // 返回流的名称 Boolean addSubsession(ServerMediaSubsession* subsession); // 添加表示子会话的ServerMediaSubsession对象 unsigned numSubsessions() const { return fSubsessionCounter; } void testScaleFactor(float& scale); // sets "scale" to the actual supported scale float duration() const; // 返回流的持续时间 // a result == 0 means an unbounded session (the default) // a result < 0 means: subsession durations differ; the result is -(the largest). // a result > 0 means: this is the duration of a bounded session unsigned referenceCount() const { return fReferenceCount; } // 返回请求该流的RTSP客户端数目 void incrementReferenceCount() { ++fReferenceCount; } void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; } Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; } // fDeleteWhenUnreferenced表示在没有客户端请求该流时,是否从RTSPServer中删除该流 void deleteAllSubsessions(); // Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state // Note: If you have already added this "ServerMediaSession" to a "RTSPServer" then, before calling this function, // you must first close any client connections that use it, // by calling "RTSPServer::closeAllClientSessionsForServerMediaSession()". protected: ServerMediaSession(UsageEnvironment& env, char const* streamName, char const* info, char const* description, Boolean isSSM, char const* miscSDPLines); // called only by "createNew()" virtual ~ServerMediaSession(); private: // redefined virtual functions virtual Boolean isServerMediaSession() const; private: Boolean fIsSSM; // Linkage fields: friend class ServerMediaSubsessionIterator; // ServerMediaSubsessionIterator是一个用于访问ServerMediaSubsession对象的迭代器 ServerMediaSubsession* fSubsessionsHead; ServerMediaSubsession* fSubsessionsTail; unsigned fSubsessionCounter; char* fStreamName; char* fInfoSDPString; char* fDescriptionSDPString; char* fMiscSDPLines; struct timeval fCreationTime; unsigned fReferenceCount; Boolean fDeleteWhenUnreferenced; };
这里主要看一下turnOnBackgroundReadHandling函数,这个函数的作用即将某个socket加入SOCKET SET(参见select模型),并指定相应的处理函数。这里的处理函数即收到RTSP客户端连接请求时的回调处理函数incomingConnectionHandlerRTSP,第三个参数作为回调函数的参数。
ServerMediaSession::createNew是一个简单工厂模式函数,在其中new了一个ServerMediaSession对象,看一下ServerMediaSession这个类的定义。
好文章,来自【福优学苑@音视频+流媒体】
***【在线视频教程】***