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,可以推客户端指定编码格式的媒体流。(前提是服务器目录下有)
主函数只是小菜,函数调用才是主食