live555源代码学习(主函数研究)

4天

1、

当我写下这篇博客时,是学习live555 4天后的下午。

2、main函数

RTSP服务器,测试程序等等都有对应主函数,主函数比较容易理解,我们就从主函数开始

3、MediaServer的main

在程序 live555MediaServer.cpp中
这个程序的功能是这样的:
相当于建立一个服务器端给客户端连接(内部采取select模型进行IO复用),只需要打开实现RTSP协议的客户端(VLC)就可以播放服务器端的文件了(测试可以),程序运行的小黑框给出了很详细的客户端连接时的地址提示
在这里插入图片描述在这里插入图片描述
可能是因为推的事视频流,所以没有显示视频的总时间

int main(int argc, char** argv) {
  // Begin by setting up our usage environment:
  // 创建工具类
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);

  UserAuthenticationDatabase* authDB = NULL;
#ifdef ACCESS_CONTROL
  // To implement client access control to the RTSP server, do the following:
  authDB = new UserAuthenticationDatabase;
  authDB->addUserRecord("username1", "password1"); // replace these with real strings
  // Repeat the above with each <username>, <password> that you wish to allow
  // access to the server.
#endif

  // Create the RTSP server.  Try first with the default port number (554),
  // and then with the alternative port number (8554):
  // 创建RTSPServer,指定端口为8554,尝试两个端口
  RTSPServer* rtspServer;
  portNumBits rtspServerPortNum = 554;
  rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  if (rtspServer == NULL) {
    rtspServerPortNum = 8554;
    rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  }
  if (rtspServer == NULL) {
    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
    exit(1);
  }
//以下打印屏幕而已,重载了	”<<“
  *env << "LIVE555 Media Server\n";
  *env << "\tversion " << MEDIA_SERVER_VERSION_STRING
       << " (LIVE555 Streaming Media library version "
       << LIVEMEDIA_LIBRARY_VERSION_STRING << ").\n";
  char* urlPrefix = rtspServer->rtspURLPrefix();
  *env << "Play streams from this server using the URL\n\t"
       << urlPrefix << "<filename>\nwhere <filename> is a file present in the current directory.\n";
  *env << "Each file's type is inferred from its name suffix:\n";
  *env << "\t\".264\" => a H.264 Video Elementary Stream file\n";
  *env << "\t\".265\" => a H.265 Video Elementary Stream file\n";
  *env << "\t\".aac\" => an AAC Audio (ADTS format) file\n";
  *env << "\t\".ac3\" => an AC-3 Audio file\n";
  *env << "\t\".amr\" => an AMR Audio file\n";
  *env << "\t\".dv\" => a DV Video file\n";
  *env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";
  *env << "\t\".mkv\" => a Matroska audio+video+(optional)subtitles file\n";
  *env << "\t\".mp3\" => a MPEG-1 or 2 Audio file\n";
  *env << "\t\".mpg\" => a MPEG-1 or 2 Program Stream (audio+video) file\n";
  *env << "\t\".ogg\" or \".ogv\" or \".opus\" => an Ogg audio and/or video file\n";
  *env << "\t\".ts\" => a MPEG Transport Stream file\n";
  *env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";
  *env << "\t\".vob\" => a VOB (MPEG-2 video with AC-3 audio) file\n";
  *env << "\t\".wav\" => a WAV Audio file\n";
  *env << "\t\".webm\" => a WebM audio(Vorbis)+video(VP8) file\n";
  *env << "See http://www.live555.com/mediaServer/ for additional documentation.\n";

  // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
  // Try first with the default HTTP port (80), and then with the alternative HTTP
  // port numbers (8000 and 8080).

  //暂不去研究
  if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
    *env << "(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling, or for HTTP live streaming (for indexed Transport Stream files only).)\n";
  } else {
    *env << "(RTSP-over-HTTP tunneling is not available.)\n";
  }
  //暂不去研究end

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

  return 0; // only to prevent compiler warning
}
第一步:

现在看到这一步是所有测试都有的,创建任务调度器和一个关于程序运行时环境的类对象

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

TaskScheduler是一个任务调度类

第二步

创建类对象

RTSPServer* rtspServer;
portNumBits rtspServerPortNum = 554;
rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);

创建时指出端口,第三个参数暂不去研究,给NULL

第三步

进入任务调度的无限循环中去

env->taskScheduler().doEventLoop();  //这个函数不返回

简单的main函数挡不住后面超级复杂的函数调用,大神的代码分析很有用,快去看

4、proxyServer的main

这是一个测试程序,这个程序厉害了,实现的是流媒体的转发,把前端摄像头的视频流转发给客户端使用,是一个转发流视频的服务器

int main(int argc, char** argv) {
  // Increase the maximum size of video frames that we can 'proxy' without truncation.
  // (Such frames are unreasonably large; the back-end servers should really not be sending frames this large!)
  OutPacketBuffer::maxSize = 100000; // bytes

  // Begin by setting up our usage environment:
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  env = BasicUsageEnvironment::createNew(*scheduler);

..........这里有大段的输入参数检查
//*********************************************************************************************************************************************
  
  // Create the RTSP server. Try first with the configured port number,
  // and then with the default port number (554) if different,
  // and then with the alternative port number (8554):
  //创建RTSPServer类并指定端口(554不行就8554)
  RTSPServer* rtspServer;
  rtspServer = createRTSPServer(rtspServerPortNum);
  if (rtspServer == NULL) {
    if (rtspServerPortNum != 554) {
      *env << "Unable to create a RTSP server with port number " << rtspServerPortNum << ": " << env->getResultMsg() << "\n";
      *env << "Trying instead with the standard port numbers (554 and 8554)...\n";

      rtspServerPortNum = 554;
      rtspServer = createRTSPServer(rtspServerPortNum);
    }
  }
  if (rtspServer == NULL) {
    rtspServerPortNum = 8554;
    rtspServer = createRTSPServer(rtspServerPortNum);
  }
  if (rtspServer == NULL) {
    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
    exit(1);
  }

  // Create a proxy for each "rtsp://" URL specified on the command line:
  for (i = 1; i < argc; ++i) {
    char const* proxiedStreamURL = argv[i];
    char streamName[30];
    if (argc == 2) {
      sprintf(streamName, "%s", "proxyStream"); // there's just one stream; give it this name
    } else {
      sprintf(streamName, "proxyStream-%d", i); // there's more than one stream; distinguish them by name
    }
    ServerMediaSession* sms
      = ProxyServerMediaSession::createNew(*env, rtspServer,
					   proxiedStreamURL, streamName,
					   username, password, tunnelOverHTTPPortNum, verbosityLevel);
    rtspServer->addServerMediaSession(sms);
    
//ServerMediaSession和ServerMediaSubsession都是很重要的两个类,具体看大神代码

    char* proxyStreamURL = rtspServer->rtspURL(sms);
    *env << "RTSP stream, proxying the stream \"" << proxiedStreamURL << "\"\n";
    *env << "\tPlay this stream using the URL: " << proxyStreamURL << "\n";
    delete[] proxyStreamURL;	//NO内存泄漏
  }

  //这个操作暂时不看
  if (proxyREGISTERRequests) {
    *env << "(We handle incoming \"REGISTER\" requests on port " << rtspServerPortNum << ")\n";
  }
  //这个操作暂时不看end

  // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
  // Try first with the default HTTP port (80), and then with the alternative HTTP
  // port numbers (8000 and 8080).

  //这里应该是客户端向网络服务器推流
  if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(37778) || rtspServer->setUpTunnelingOverHTTP(8080)) {
    *env << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
  } else {
    *env << "\n(RTSP-over-HTTP tunneling is not available.)\n";
  }

  // Now, enter the event loop:
  env->taskScheduler().doEventLoop(); // does not return

  return 0; // only to prevent compiler warning
}

转发一台大华摄像机
上图是转发一台大华摄像机,在VLC客户端把视频流播放出来,视频下半部分黑色,原因可能是和缓存区的大小有关

  OutPacketBuffer::maxSize = 100000; // bytes

不过摄像头不在了,也没法去看看是不是这个原因

第一步

都是一样的,创建TaskScheduler和UsageEnvironment类对象

第二步

创建RTSPServer类对象,给端口
这里的创建有一点小不同,这个RTSPServer的类有两种可选

static RTSPServer* createRTSPServer(Port port) {
  if (proxyREGISTERRequests) {
    return RTSPServerWithREGISTERProxying::createNew(*env, port, authDB, authDBForREGISTER, 65, streamRTPOverTCP, verbosityLevel, username, password);
  } else {
    return RTSPServer::createNew(*env, port, authDB);
  }
}

决定条件proxyREGISTERRequests是个bool量,可以通过启动时传参数改变
RTSPServerWithREGISTERProxying不知道是啥,反正默认也不是创建这个类,暂不研究

第三步

创建类ProxyServerMediaSession对象(这里提一下一个类ServerMediaSession,继承了很多子类,这个类所代表的的就是一个媒体文件-> 小电影名.XXX 。对应的还有一个类ServerMediaSubsession,这个是 表示媒体文件中的视频或者音频,他们说两者是包含关系,一个ServerMediaSession可以有多个ServerMediaSubsession。这样的话,对一个媒体文件进行操作本来就是想操作他的视频或者音频啊,因此,在ServerMediaSubsession下又继承了很多对不同编码格式的视频音频操作的类)

第四步

进入调度死循环

5、其他

测试用的代码还有很多,还有一个点播的程序 testOnDemandRTSPServer.cpp,可以推客户端指定编码格式的媒体流。(前提是服务器目录下有)

主函数只是小菜,函数调用才是主食

发布了46 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42718004/article/details/90045089
今日推荐