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,可以推客戶端指定編碼格式的媒體流。(前提是服務器目錄下有)
主函數只是小菜,函數調用纔是主食