live555是使用十分广泛的开源流媒体服务器,之前也看过其他人写的live555的学习笔记,在这里自己简单总结下。

live555源代码有以下几个明显的特点:

1.头文件是.hh后缀的,但没觉得和.h后缀的有什么不同

2.采用了面向对象的程序设计思路,里面各种对象

好了,不罗嗦,使用vc2010打开live555的vc工程,看到live555源代码结构如下:

源代码由5个工程构成(4个库和一个主程序):

libUsageEnvironment.lib;libliveMedia.lib;libgroupsock.lib;libBasicUsageEnvironment.lib;以及live555MediaServer

这里我们只分析live555MediaServer这个主程序,其实代码量并不大,主要有两个CPP:DynamicRTSPServer.cpp和live555MediaServer.cpp

程序的main()在live555MediaServer.cpp中,在main()中调用了DynamicRTSPServer中的类

不废话,直接贴上有注释的源码

live555MediaServer.cpp:

  1. #include <BasicUsageEnvironment.hh>
  2. #include "DynamicRTSPServer.hh"
  3. #include "version.hh"
  4.  
  5. int main(int argc, char** argv) {
  6. // Begin by setting up our usage environment:
  7. // TaskScheduler用于任务计划
  8. TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  9. // UsageEnvironment用于输出
  10. UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
  11.  
  12. UserAuthenticationDatabase* authDB = NULL;
  13. #ifdef ACCESS_CONTROL
  14. // To implement client access control to the RTSP server, do the following:
  15. authDB = new UserAuthenticationDatabase;
  16. authDB->addUserRecord("username1", "password1"); // replace these with real strings
  17. // Repeat the above with each <username>, <password> that you wish to allow
  18. // access to the server.
  19. #endif
  20.  
  21. //建立 RTSP server. 使用默认端口 (554),
  22. // and then with the alternative port number (8554):
  23. RTSPServer* rtspServer;
  24. portNumBits rtspServerPortNum = 554;
  25. //创建 RTSPServer实例
  26. rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  27. if (rtspServer == NULL) {
  28. rtspServerPortNum = 8554;
  29. rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  30. }
  31. if (rtspServer == NULL) {
  32. *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
  33. exit(1);
  34. }
  35. //用到了运算符重载
  36. *env << "LIVE555 Media Server\n";
  37. *env << "\tversion " << MEDIA_SERVER_VERSION_STRING
  38. << " (LIVE555 Streaming Media library version "
  39. << LIVEMEDIA_LIBRARY_VERSION_STRING << ").\n";
  40.  
  41. char* urlPrefix = rtspServer->rtspURLPrefix();
  42. *env << "Play streams from this server using the URL\n\t"
  43. << urlPrefix << "<filename>\nwhere <filename> is a file present in the current directory.\n";
  44. *env << "Each file's type is inferred from its name suffix:\n";
  45. *env << "\t\".aac\" => an AAC Audio (ADTS format) file\n";
  46. *env << "\t\".amr\" => an AMR Audio file\n";
  47. *env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";
  48. *env << "\t\".dv\" => a DV Video file\n";
  49. *env << "\t\".mp3\" => a MPEG-1 or 2 Audio file\n";
  50. *env << "\t\".mpg\" => a MPEG-1 or 2 Program Stream (audio+video) file\n";
  51. *env << "\t\".ts\" => a MPEG Transport Stream file\n";
  52. *env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";
  53. *env << "\t\".wav\" => a WAV Audio file\n";
  54. *env << "See http://www.live555.com/mediaServer/ for additional documentation.\n";
  55.  
  56. // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
  57. // Try first with the default HTTP port (80), and then with the alternative HTTP
  58. // port numbers (8000 and 8080).
  59.  
  60. if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
  61. *env << "(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
  62. } else {
  63. *env << "(RTSP-over-HTTP tunneling is not available.)\n";
  64. }
  65. //进入一个永久的循环
  66. env->taskScheduler().doEventLoop(); // does not return
  67.  
  68. return 0; // only to prevent compiler warning
  69. }

DynamicRTSPServer.cpp:

  1. #include "DynamicRTSPServer.hh"
  2. #include <liveMedia.hh>
  3. #include <string.h>
  4.  
  5. DynamicRTSPServer*
  6. DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
  7. UserAuthenticationDatabase* authDatabase,
  8. unsigned reclamationTestSeconds) {
  9. int ourSocket = -1;
  10.  
  11. do {
  12. //建立TCP socket(socket(),bind(),listen()...)
  13. int ourSocket = setUpOurSocket(env, ourPort);
  14. if (ourSocket == -1) break;
  15.  
  16. return new DynamicRTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
  17. } while (0);
  18.  
  19. if (ourSocket != -1) ::closeSocket(ourSocket);
  20. return NULL;
  21. }
  22.  
  23. DynamicRTSPServer::DynamicRTSPServer(UsageEnvironment& env, int ourSocket,
  24. Port ourPort,
  25. UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
  26. : RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds) {
  27. }
  28.  
  29. DynamicRTSPServer::~DynamicRTSPServer() {
  30. }
  31.  
  32. static ServerMediaSession* createNewSMS(UsageEnvironment& env,
  33. char const* fileName, FILE* fid); // forward
  34.  
  35. //查找ServerMediaSession(对应服务器上一个媒体文件,,或设备),如果没有的话就创建一个
  36. //streamName例:A.avi
  37. ServerMediaSession*
  38. DynamicRTSPServer::lookupServerMediaSession(char const* streamName) {
  39. // First, check whether the specified "streamName" exists as a local file:
  40. FILE* fid = fopen(streamName, "rb");
  41. //如果返回文件指针不为空,则文件存在
  42. Boolean fileExists = fid != NULL;
  43.  
  44. // Next, check whether we already have a "ServerMediaSession" for this file:
  45. //看看是否有这个ServerMediaSession
  46. ServerMediaSession* sms = RTSPServer::lookupServerMediaSession(streamName);
  47. Boolean smsExists = sms != NULL;
  48.  
  49. // Handle the four possibilities for "fileExists" and "smsExists":
  50. //文件没了,ServerMediaSession有,删之
  51. if (!fileExists) {
  52. if (smsExists) {
  53. // "sms" was created for a file that no longer exists. Remove it:
  54. removeServerMediaSession(sms);
  55. }
  56. return NULL;
  57. } else {
  58. //文件有,ServerMediaSession无,加之
  59. if (!smsExists) {
  60. // Create a new "ServerMediaSession" object for streaming from the named file.
  61. sms = createNewSMS(envir(), streamName, fid);
  62. addServerMediaSession(sms);
  63. }
  64. fclose(fid);
  65. return sms;
  66. }
  67. }
  68.  
  69. #define NEW_SMS(description) do {\
  70. char const* descStr = description\
  71. ", streamed by the LIVE555 Media Server";\
  72. sms = ServerMediaSession::createNew(env, fileName, fileName, descStr);\
  73. } while(0)
  74.  
  75. //创建一个ServerMediaSession
  76. static ServerMediaSession* createNewSMS(UsageEnvironment& env,
  77. char const* fileName, FILE* /*fid*/) {
  78. // Use the file name extension to determine the type of "ServerMediaSession":
  79. //获取扩展名,以“.”开始。不严密,万一文件名有多个点?
  80. char const* extension = strrchr(fileName, '.');
  81. if (extension == NULL) return NULL;
  82.  
  83. ServerMediaSession* sms = NULL;
  84. Boolean const reuseSource = False;
  85. if (strcmp(extension, ".aac") == 0) {
  86. // Assumed to be an AAC Audio (ADTS format) file:
  87. // 调用ServerMediaSession::createNew()
  88. //还会调用MediaSubsession
  89. NEW_SMS("AAC Audio");
  90. sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  91. } else if (strcmp(extension, ".amr") == 0) {
  92. // Assumed to be an AMR Audio file:
  93. NEW_SMS("AMR Audio");
  94. sms->addSubsession(AMRAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  95. } else if (strcmp(extension, ".m4e") == 0) {
  96. // Assumed to be a MPEG-4 Video Elementary Stream file:
  97. NEW_SMS("MPEG-4 Video");
  98. sms->addSubsession(MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  99. } else if (strcmp(extension, ".mp3") == 0) {
  100. // Assumed to be a MPEG-1 or 2 Audio file:
  101. NEW_SMS("MPEG-1 or 2 Audio");
  102. // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
  103. //#define STREAM_USING_ADUS 1
  104. // To also reorder ADUs before streaming, uncomment the following:
  105. //#define INTERLEAVE_ADUS 1
  106. // (For more information about ADUs and interleaving,
  107. // see <http://www.live555.com/rtp-mp3/>)
  108. Boolean useADUs = False;
  109. Interleaving* interleaving = NULL;
  110. #ifdef STREAM_USING_ADUS
  111. useADUs = True;
  112. #ifdef INTERLEAVE_ADUS
  113. unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...
  114. unsigned const interleaveCycleSize
  115. = (sizeof interleaveCycle)/(sizeof (unsigned char));
  116. interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);
  117. #endif
  118. #endif
  119. sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving));
  120. } else if (strcmp(extension, ".mpg") == 0) {
  121. // Assumed to be a MPEG-1 or 2 Program Stream (audio+video) file:
  122. NEW_SMS("MPEG-1 or 2 Program Stream");
  123. MPEG1or2FileServerDemux* demux
  124. = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);
  125. sms->addSubsession(demux->newVideoServerMediaSubsession());
  126. sms->addSubsession(demux->newAudioServerMediaSubsession());
  127. } else if (strcmp(extension, ".ts") == 0) {
  128. // Assumed to be a MPEG Transport Stream file:
  129. // Use an index file name that's the same as the TS file name, except with ".tsx":
  130. unsigned indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0"
  131. char* indexFileName = new char[indexFileNameLen];
  132. sprintf(indexFileName, "%sx", fileName);
  133. NEW_SMS("MPEG Transport Stream");
  134. sms->addSubsession(MPEG2TransportFileServerMediaSubsession::createNew(env, fileName, indexFileName, reuseSource));
  135. delete[] indexFileName;
  136. } else if (strcmp(extension, ".wav") == 0) {
  137. // Assumed to be a WAV Audio file:
  138. NEW_SMS("WAV Audio Stream");
  139. // To convert 16-bit PCM data to 8-bit u-law, prior to streaming,
  140. // change the following to True:
  141. Boolean convertToULaw = False;
  142. sms->addSubsession(WAVAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, convertToULaw));
  143. } else if (strcmp(extension, ".dv") == 0) {
  144. // Assumed to be a DV Video file
  145. // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000).
  146. OutPacketBuffer::maxSize = 300000;
  147.  
  148. NEW_SMS("DV Video");
  149. sms->addSubsession(DVVideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  150. }
  151.  
  152. return sms;
  153. }

live555 源代码简单分析1:主程序的更多相关文章

  1. Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()

    ffmpeg 源代码简单分析 : av_read_frame() http://blog.csdn.net/leixiaohua1020/article/details/12678577 ffmpeg ...

  2. FFmpeg的HEVC解码器源代码简单分析:环路滤波(Loop Filter)

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  3. FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-TU

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  4. FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-PU

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  5. FFmpeg的HEVC解码器源代码简单分析:解码器主干部分

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  6. FFmpeg的HEVC解码器源代码简单分析:解析器(Parser)部分

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  7. FFmpeg的HEVC解码器源代码简单分析:概述

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  8. FFmpeg与libx264接口源代码简单分析

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  9. x264源代码简单分析:熵编码(Entropy Encoding)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

随机推荐

  1. Android核心基础(十)

    1.音频采集 你可以使用手机进行现场录音,实现步骤如下: 第一步:在功能清单文件AndroidManifest.xml中添加音频刻录权限: <uses-permission android:na ...

  2. Javascript刷新页面的几种方法:

    Javascript刷新页面的几种方法: 1    history.go(0) 2    window.location.reload() window.location.reload(true)  ...

  3. runtime的基本应用

    1.什么是runtime? runtime是一套底层的C语言API,包含很多强大实用的C语言数据类型和C语言函数,平时我们编写的OC代码,底层都是基于runtime实现的. 2.runtime有什么作 ...

  4. C#操作IE

    操作IE主要使用两个Com Dll: 1.Microsoft Internet Controls 2.Microsoft HTML Object Library 使用Microsoft Interne ...

  5. [置顶] 正则表达式应用:匹配IP地址

    都知道iP地址有四个数值,三个点号组成.三个数值的具体范围为0到255,为了使用正则表达式匹配就必须分析IP地址的组成 1先分析数值,2再组合数值和点号 1先分析数值 IP地址的数字范围从0到255, ...

  6. [Javascript] property function && Enumeration

    var vehicle3 = { type: "Submarine", capacity: 8, storedAt: "Underwater Outpost", ...

  7. Oracle 更改用户名

    直接更改系统user$表中的用户名. 查询要更改的用户名 SQL> select user#,name,password from user$ where name ='TICKETS'; US ...

  8. NET基础课--对象的筛选和排序(NET之美)

    1.数据量不大的时候取出数据缓存于服务器,然后排序,筛选等基于缓存进行以提高效率. 排序或筛选的方法是使用集合类型提供的,如List<T>.sort()  List<T>.Fi ...

  9. 利用PHP/MYSQL实现的简易微型博客(转)

    数据库:ly_php_base 表:ly_micro_blog(仅仅有一个表)字段:id,title,date,content,hits 文件: 文件 描述 default.php 默认主页.显示博文 ...

  10. .net 基础之截取字符串

    在实际开发中有时难免会遇到需要获取某个字符串中的某些字符串,这里我们可以用到字符串截取的办法. 截取字符串的方法很容易(暂不包含中文字符串),只要稍微有点.net基础的人看了都能看懂. /// < ...