live555 源代码简单分析1:主程序
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:主程序的更多相关文章
- Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()
ffmpeg 源代码简单分析 : av_read_frame() http://blog.csdn.net/leixiaohua1020/article/details/12678577 ffmpeg ...
- FFmpeg的HEVC解码器源代码简单分析:环路滤波(Loop Filter)
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-TU
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-PU
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg的HEVC解码器源代码简单分析:解码器主干部分
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg的HEVC解码器源代码简单分析:解析器(Parser)部分
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg的HEVC解码器源代码简单分析:概述
===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...
- FFmpeg与libx264接口源代码简单分析
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- x264源代码简单分析:熵编码(Entropy Encoding)部分
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
随机推荐
- Socket,非阻塞,fcntl
一.fcntl 用以下方法将socket设置成为非阻塞方式 int flags = fcntl(socket,F_GETFL,0); fcntl(socket,F_SETFL,flags|O_NON ...
- CharacterController 角色控制器实现移动和跳跃
之前我使用SimpleMove来控制角色的移动, 后来又想实现人物的跳跃, 看见圣典里面是使用Move来实现的. =.= 然后我都把他们改成move来实现了 代码实现: using UnityEngi ...
- Hibernate(三)——框架中的关系映射
在设计数据库时我们会考虑,表与表之间的关系,例如我们前边经常提到的一对一,一对多,多对多关系,在数据库中我们通过外键,第三张表等来实现这些关系.而Hibernate时间实体类和数据库中的表进行的映射, ...
- The kth great number(set)
The kth great number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Oth ...
- ASP.NET MVC 之表格分页
简单效果图:(框架:MVC+NHibernate) 要点: (1)首先建立表格分页Model(GridModel.cs) (2)然后建立数据展示页(PageCloth.cshtml) (3)再建分页版 ...
- easyUI的combobox设置隐藏和显示
今天遇到一个需求,需要在combobox选择不同选项时,分别切换另一个控件为text或者combobox. 当时想了各种办法,想将combobx和text切换隐藏,但是都没得到自己想要的效果.最终还是 ...
- nodejs 批处理运行 app.js
1.直接执行run.bat文件 以下的内容为批处理文件run.bat中的内容,批处理命令中NODE_PATH为Node.js的安装路径. 使用express 生成的项目.app.js为 ...
- VS2008找不到MFC90d.dll错误解决方法
问题是在更新嵌入的清单文件时发生的,由于FAT32的原因而未能更新嵌入的清单文件,于是我们有如下两种解决方法: (1)不启用增量链接.在项目的“属性|配置属性|链接器|常规”中的“启用增量链接”选择“ ...
- JS数组追加数组采用push.apply的坑(转)
JS数组追加数组没有现成的函数,这么多年我已经习惯了a.push.apply(a, b);这种自以为很酷的,不需要写for循环的写法,一直也没遇到什么问题,直到今天我要append的b是个很大的数组时 ...
- SQL Server一些常见却不太记得住的命令
一.数据库大小查询 1. exec sp_spaceused '表名' --(SQL统计数据,大量事务操作后可能不准)2. exec sp_spaceused '表名', true ...