zoukankan      html  css  js  c++  java
  • 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() << "
    ";
    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 << "
    (We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)
    ";
    51   } else {
    52     *env << "
    (RTSP-over-HTTP tunneling is not available.)
    ";
    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() << "
    ";
        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 点播服务器的过程大概就是这个样子。

  • 相关阅读:
    Android RecyclerView如何去掉上拉刷新和下拉加载的阴影
    python如何在列表、对象、集合中根据条件筛选数据
    解决Glide在一个imageview上更换图片时会闪的问题
    响应时间三个非常重要的时间点
    android 向系统日历添加日程事件
    android 系统日历 插入重复事件规则 RRULE
    android Calendar Provider
    android edittext设置获取焦点
    android 自定义光标颜色
    android动态改变TextView字体大小遇到的问题
  • 原文地址:https://www.cnblogs.com/guoliushui/p/8631674.html
Copyright © 2011-2022 走看看