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:

#include <BasicUsageEnvironment.hh>
#include "DynamicRTSPServer.hh"
#include "version.hh" int main(int argc, char** argv) {
// Begin by setting up our usage environment:
// TaskScheduler用于任务计划
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
// UsageEnvironment用于输出
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 //建立 RTSP server. 使用默认端口 (554),
// and then with the alternative port number (8554):
RTSPServer* rtspServer;
portNumBits rtspServerPortNum = 554;
//创建 RTSPServer实例
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\".aac\" => an AAC Audio (ADTS format) file\n";
*env << "\t\".amr\" => an AMR Audio file\n";
*env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";
*env << "\t\".dv\" => a DV Video 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\".ts\" => a MPEG Transport Stream file\n";
*env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";
*env << "\t\".wav\" => a WAV Audio 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.)\n";
} else {
*env << "(RTSP-over-HTTP tunneling is not available.)\n";
}
//进入一个永久的循环
env->taskScheduler().doEventLoop(); // does not return return 0; // only to prevent compiler warning
}

DynamicRTSPServer.cpp:

#include "DynamicRTSPServer.hh"
#include <liveMedia.hh>
#include <string.h> DynamicRTSPServer*
DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
UserAuthenticationDatabase* authDatabase,
unsigned reclamationTestSeconds) {
int ourSocket = -1; do {
//建立TCP socket(socket(),bind(),listen()...)
int ourSocket = setUpOurSocket(env, ourPort);
if (ourSocket == -1) break; return new DynamicRTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
} while (0); if (ourSocket != -1) ::closeSocket(ourSocket);
return NULL;
} DynamicRTSPServer::DynamicRTSPServer(UsageEnvironment& env, int ourSocket,
Port ourPort,
UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
: RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds) {
} DynamicRTSPServer::~DynamicRTSPServer() {
} static ServerMediaSession* createNewSMS(UsageEnvironment& env,
char const* fileName, FILE* fid); // forward //查找ServerMediaSession(对应服务器上一个媒体文件,,或设备),如果没有的话就创建一个
//streamName例:A.avi
ServerMediaSession*
DynamicRTSPServer::lookupServerMediaSession(char const* streamName) {
// First, check whether the specified "streamName" exists as a local file:
FILE* fid = fopen(streamName, "rb");
//如果返回文件指针不为空,则文件存在
Boolean fileExists = fid != NULL; // Next, check whether we already have a "ServerMediaSession" for this file:
//看看是否有这个ServerMediaSession
ServerMediaSession* sms = RTSPServer::lookupServerMediaSession(streamName);
Boolean smsExists = sms != NULL; // Handle the four possibilities for "fileExists" and "smsExists":
//文件没了,ServerMediaSession有,删之
if (!fileExists) {
if (smsExists) {
// "sms" was created for a file that no longer exists. Remove it:
removeServerMediaSession(sms);
}
return NULL;
} else {
//文件有,ServerMediaSession无,加之
if (!smsExists) {
// Create a new "ServerMediaSession" object for streaming from the named file.
sms = createNewSMS(envir(), streamName, fid);
addServerMediaSession(sms);
}
fclose(fid);
return sms;
}
} #define NEW_SMS(description) do {\
char const* descStr = description\
", streamed by the LIVE555 Media Server";\
sms = ServerMediaSession::createNew(env, fileName, fileName, descStr);\
} while(0) //创建一个ServerMediaSession
static ServerMediaSession* createNewSMS(UsageEnvironment& env,
char const* fileName, FILE* /*fid*/) {
// Use the file name extension to determine the type of "ServerMediaSession":
//获取扩展名,以“.”开始。不严密,万一文件名有多个点?
char const* extension = strrchr(fileName, '.');
if (extension == NULL) return NULL; ServerMediaSession* sms = NULL;
Boolean const reuseSource = False;
if (strcmp(extension, ".aac") == 0) {
// Assumed to be an AAC Audio (ADTS format) file:
// 调用ServerMediaSession::createNew()
//还会调用MediaSubsession
NEW_SMS("AAC Audio");
sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
} else if (strcmp(extension, ".amr") == 0) {
// Assumed to be an AMR Audio file:
NEW_SMS("AMR Audio");
sms->addSubsession(AMRAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
} else if (strcmp(extension, ".m4e") == 0) {
// Assumed to be a MPEG-4 Video Elementary Stream file:
NEW_SMS("MPEG-4 Video");
sms->addSubsession(MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
} else if (strcmp(extension, ".mp3") == 0) {
// Assumed to be a MPEG-1 or 2 Audio file:
NEW_SMS("MPEG-1 or 2 Audio");
// To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
//#define STREAM_USING_ADUS 1
// To also reorder ADUs before streaming, uncomment the following:
//#define INTERLEAVE_ADUS 1
// (For more information about ADUs and interleaving,
// see <http://www.live555.com/rtp-mp3/>)
Boolean useADUs = False;
Interleaving* interleaving = NULL;
#ifdef STREAM_USING_ADUS
useADUs = True;
#ifdef INTERLEAVE_ADUS
unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...
unsigned const interleaveCycleSize
= (sizeof interleaveCycle)/(sizeof (unsigned char));
interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);
#endif
#endif
sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving));
} else if (strcmp(extension, ".mpg") == 0) {
// Assumed to be a MPEG-1 or 2 Program Stream (audio+video) file:
NEW_SMS("MPEG-1 or 2 Program Stream");
MPEG1or2FileServerDemux* demux
= MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);
sms->addSubsession(demux->newVideoServerMediaSubsession());
sms->addSubsession(demux->newAudioServerMediaSubsession());
} else if (strcmp(extension, ".ts") == 0) {
// Assumed to be a MPEG Transport Stream file:
// Use an index file name that's the same as the TS file name, except with ".tsx":
unsigned indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0"
char* indexFileName = new char[indexFileNameLen];
sprintf(indexFileName, "%sx", fileName);
NEW_SMS("MPEG Transport Stream");
sms->addSubsession(MPEG2TransportFileServerMediaSubsession::createNew(env, fileName, indexFileName, reuseSource));
delete[] indexFileName;
} else if (strcmp(extension, ".wav") == 0) {
// Assumed to be a WAV Audio file:
NEW_SMS("WAV Audio Stream");
// To convert 16-bit PCM data to 8-bit u-law, prior to streaming,
// change the following to True:
Boolean convertToULaw = False;
sms->addSubsession(WAVAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, convertToULaw));
} else if (strcmp(extension, ".dv") == 0) {
// Assumed to be a DV Video file
// First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000).
OutPacketBuffer::maxSize = 300000; NEW_SMS("DV Video");
sms->addSubsession(DVVideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
} return sms;
}

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. dig命令(转载)

    dig命令使用大全(linux上域名查询) 可以这样说,翻译本篇文档的过程就是我重新学习DNS的过程,dig命令可以帮助我们学习DNS的原理,配置,以及其查询过程.以前使用dig仅仅是查询一下A记录或 ...

  2. iOS获取一个方法的执行时间

    #import <Foundation/Foundation.h> #import <mach/mach_time.h> typedef void (^block)(void) ...

  3. Apache POI组件操作Excel,制作报表(二)

    本文接上一篇继续探究POI组件的使用.     现在来看看Excel的基本设置问题,以2007为例,先从工作簿来说,设置列宽,因为生成表格列应该固定,而行是遍历生成的,所以可以在工作簿级别来设置列宽, ...

  4. PC--CSS常识

    1.不要使用过小的图片做背景平铺.这就是为何很多人都不用 1px 的原因,这才知晓.宽高 1px 的图片平铺出一个宽高 200px 的区域,需要 200*200=40, 000 次,占用资源.2.无 ...

  5. 飘逸的python - 解决一个有限制的组合需求

    假设有一个团队技能的需求. 这类技能是要集齐所有指定的人就能激活. 但是因为同一个人又2种身份存在,比如杨戬/神杨戬,于是便产生了组合. 这种组合跟普通组合不一样,普通组合可以随意组合.而这种组合是每 ...

  6. windows下用vs2008和boost结合编译程序

      原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://co63oc.blog.51cto.com/904636/504469 win ...

  7. 关于bxslider在点击左右按钮之后不能自动切换的问题解决

    bxslider很好,但是也弄了个很脑残的设置,每次点击左右按钮之后,就不能自动切换了,要重新点击下方播放的按钮,相当不好用.问度娘没能解决,但是发现一个论坛说要修改源码,这个也找了好久,没找到,问群 ...

  8. jquery简单切换插件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  9. iOS 面试基础题

    1.UIWindow和UIView和 CALayer 的联系和区别? 答:UIView是视图的基类,UIViewController是视图控制器的基类,UIResponder是表示一个可以在屏幕上响应 ...

  10. java基础知识2

    58.线程的基本概念.线程的基本状态以及状态之间的关系线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身.Java中的线程有四种状态分别是:运行.就绪.挂 ...