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 点播服务器的过程大概就是这个样子。

  • 相关阅读:
    Maidsafe-去中心化互联网白皮书
    The Top 20 Cybersecurity Startups To Watch In 2021 Based On Crunchbase
    Top 10 Blockchain Security and Smart Contract Audit Companies
    The 20 Best Cybersecurity Startups To Watch In 2020
    Blockchain In Cybersecurity: 11 Startups To Watch In 2019
    004-STM32+BC26丨260Y基本控制篇(阿里云物联网平台)-在阿里云物联网平台上一型一密动态注册设备(Android)
    涂鸦开发-单片机+涂鸦模组开发+OTA
    000-ESP32学习开发-ESP32烧录板使用说明
    03-STM32+Air724UG远程升级篇OTA(阿里云物联网平台)-STM32+Air724UG使用阿里云物联网平台OTA远程更新STM32程序
    03-STM32+Air724UG远程升级篇OTA(自建物联网平台)-STM32+Air724UG实现利用http/https远程更新STM32程序(TCP指令,单片机程序检查更新)
  • 原文地址:https://www.cnblogs.com/guoliushui/p/8631674.html
Copyright © 2011-2022 走看看