live555源代碼學習(主函數研究)

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,可以推客戶端指定編碼格式的媒體流。(前提是服務器目錄下有)

主函數只是小菜,函數調用纔是主食

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章