live555点播服务器流程简单分析

 

testOnDemandRTSPServer.cpp 是一个简单的点播服务器,可以点播各种媒体文件类型,本文主要分析.264类型文件。

把其他类型的源码使用#if 0 ....#endif 进行屏蔽,这样不相关的代码就可以不看了,也显得简洁了很多。

 

 1 int main(int argc, char** argv) {
 2   // Begin by setting up our usage environment:
 3   TaskScheduler* scheduler = BasicTaskScheduler::createNew();
 4   env = BasicUsageEnvironment::createNew(*scheduler);
 5 
 6   UserAuthenticationDatabase* authDB = NULL;
 7 #ifdef ACCESS_CONTROL
 8   // To implement client access control to the RTSP server, do the following:
 9   authDB = new UserAuthenticationDatabase;
10   authDB->addUserRecord("username1", "password1"); // replace these with real strings
11   // Repeat the above with each <username>, <password> that you wish to allow
12   // access to the server.
13 #endif
14 
15   // Create the RTSP server:
16   RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);
17   if (rtspServer == NULL) {
18     *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
19     exit(1);
20   }
21 
22   char const* descriptionString
23     = "Session streamed by \"testOnDemandRTSPServer\"";
24 
25   // Set up each of the possible streams that can be served by the
26   // RTSP server.  Each such stream is implemented using a
27   // "ServerMediaSession" object, plus one or more
28   // "ServerMediaSubsession" objects for each audio/video substream.
29   // A H.264 video elementary stream:
30   {
31     char const* streamName = "h264ESVideoTest";        //gxq 流名字,媒体名
32     char const* inputFileName = "test.264";            //gxq 文件名,当客户端请求h264ESVideoTest时,实际上打开的是test.264文件
33     
34     //创建一个会话
35     ServerMediaSession* sms
36       = ServerMediaSession::createNew(*env, streamName, streamName,
37                       descriptionString);
38 
39     //在会话中添加一个视频流子会话
40     sms->addSubsession(H264VideoFileServerMediaSubsession
41                ::createNew(*env, inputFileName, reuseFirstSource));
42 
43     //gxq 将此会话加入到哈希表fServerMediaSessions中
44     rtspServer->addServerMediaSession(sms);
45 
46     announceStream(rtspServer, sms, streamName, inputFileName);
47   }
48 
49   if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
50     *env << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
51   } else {
52     *env << "\n(RTSP-over-HTTP tunneling is not available.)\n";
53   }
54 
55   //gxq 执行循环方法,对sock的读取任务和对媒体文件的延时发送操作都在这个循环中
56   env->taskScheduler().doEventLoop(); // does not return
57 
58   return 0; // only to prevent compiler warning
59 }

TaskScheduler* scheduler = BasicTaskScheduler::createNew();
env = BasicUsageEnvironment::createNew(*scheduler);

建立一个任务调度器,并使用该调度器创建一个全局的环境对象,BasicTaskScheduler父类BasicTaskScheduler0中包含一个sock任务双向链表成员变量HandlerSet后面对sock的处理主要是处理此链表

1   // To implement background reads:
2   HandlerSet* fHandlers;            //gxq  一个双向链表,用于保存sock相关任务,SingleStep循环中主要对此链表进行操作
3   int fLastHandledSocketNum;

下面开始正式创建一个服务对象代码如下

  // Create the RTSP server:
  RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);
  if (rtspServer == NULL) {
    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
    exit(1);
  }

创建服务器对象的同时,创建了监听套接字,并将socket与相关处理连接函数放入sock任务链表fHandlers中。

我们来分析一下RTSPServer::createNew()函数,

 1 RTSPServer*
 2 RTSPServer::createNew(UsageEnvironment& env, Port ourPort,
 3               UserAuthenticationDatabase* authDatabase,
 4               unsigned reclamationSeconds) {
 5   int ourSocket = setUpOurSocket(env, ourPort);    //gxq 使用groupsockHelper创建监听sock
 6   if (ourSocket == -1) return NULL;
 7   
 8   //gxq 在父类GenericMediaServer的构造函数中完成sock与处理监听函数的映射,加入到sock任务队列
 9   return new RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationSeconds);
10 }

我们发现在createNew()函数中,创建了监听套接字ourSocket,

继续往下看RTSPServer的构造函数

 1 RTSPServer::RTSPServer(UsageEnvironment& env,
 2                int ourSocket, Port ourPort,
 3                UserAuthenticationDatabase* authDatabase,
 4                unsigned reclamationSeconds)
 5   : GenericMediaServer(env, ourSocket, ourPort, reclamationSeconds),
 6     fHTTPServerSocket(-1), fHTTPServerPort(0),
 7     fClientConnectionsForHTTPTunneling(NULL), // will get created if needed
 8     fTCPStreamingDatabase(HashTable::create(ONE_WORD_HASH_KEYS)),
 9     fPendingRegisterOrDeregisterRequests(HashTable::create(ONE_WORD_HASH_KEYS)),
10     fRegisterOrDeregisterRequestCounter(0), fAuthDB(authDatabase), fAllowStreamingRTPOverTCP(True) {
11 }

 

发现其构造函数调用了父类GenericMediaServer的构造函数,咱们继续往下看看GenericMediaServer的构造函数

 1 GenericMediaServer
 2 ::GenericMediaServer(UsageEnvironment& env, int ourSocket, Port ourPort,
 3              unsigned reclamationSeconds)
 4   : Medium(env),
 5     fServerSocket(ourSocket), fServerPort(ourPort), fReclamationSeconds(reclamationSeconds),
 6     fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)),
 7     fClientConnections(HashTable::create(ONE_WORD_HASH_KEYS)),
 8     fClientSessions(HashTable::create(STRING_HASH_KEYS)) {
 9   ignoreSigPipeOnSocket(fServerSocket); // so that clients on the same host that are killed don't also kill us
10   
11   // Arrange to handle connections from others:            /gxq  将sock任务加入任务队列,当监听到有连接请求时调用incomingConnectionHandler
12   env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);
13 }

发现在GenericMediaServer构造函数中调用任务调度器将监听套接字fServerSocket与处理函数incomingConnectionHandler()放入了sock任务队列。当服务监听到有客户端连接时会调用 incomingConnectionHandler进行处理。

这下分析下来你会发现,这个live RTSP服务器跟咱们平常建立一个普通的服务器的流程没什么区别:

都是创建socket,绑定bi nd,监听listen,监听后使用accept进行处理

(实际incomingConnectionHandler内部就是调用 的accept);

到这里服务器的部署基本已经完成了,但此时还没媒体文件的信息,不要着急咱们接着往下分析。

咱们回到testOnDemandRTSPServer.cpp中的main函数,分析264媒体文件信息

 1 // A H.264 video elementary stream:
 2   {
 3     char const* streamName = "h264ESVideoTest";        //gxq 流名字,媒体名
 4     char const* inputFileName = "test.264";            //gxq 文件名,当客户端请求h264ESVideoTest时,实际上打开的是test.264文件
 5     
 6     //创建一个会话
 7     ServerMediaSession* sms
 8       = ServerMediaSession::createNew(*env, streamName, streamName,
 9                       descriptionString);
10 
11     //在会话中添加一个视频流子会话
12     sms->addSubsession(H264VideoFileServerMediaSubsession
13                ::createNew(*env, inputFileName, reuseFirstSource));
14 
15     //gxq 将此会话加入到哈希表fServerMediaSessions中
16     rtspServer->addServerMediaSession(sms);
17 
18     announceStream(rtspServer, sms, streamName, inputFileName);
19   }

 

代码的注释已经很详细,不再重复。

接下来执行到

1 env->taskScheduler().doEventLoop(); // does not return

此时服务器就已经进入等客户端连接状态了。

 

使用vlc进行测试

 

OK,使用live 点播服务器的过程大概就是这个样子。

 

posted @ 2018-03-23 17:34  郭流水  阅读(570)  评论(0编辑  收藏  举报