LIVE555 利用FIFO實現直播

1.LIVE555 直播

直播方案採取的是  直播流  -> FIFO -> 輸出  的技術路線。


2.搭建:

a. 在LIVE555 編譯之後,在BIN文件下,有很多可執行程序生成,這些程序有些是LIVE555服務器(live555MediaServer),有些是客戶端(testRTSPClient),還有大量的流推送服務(testMPEG2TransportStreamer)

b.我們選取testOnDemandRTSPServer(客戶響應服務) 和  testMPEG2TransportStreamer(推流) 就可以搭建一個live555直播。


3.服務端代碼修改:

在 testOnDemandRTSPServer.cpp 中我們可以看到以下代碼內容:

// A MPEG-2 Transport Stream, coming from a live UDP (raw-UDP or RTP/UDP) source:
  {
    char const* streamName = "mpeg2TransportStreamFromUDPSourceTest";
    char const* inputAddressStr = "239.255.42.42";
        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
        // (Note: If the input UDP source is unicast rather than multicast, then change this to NULL.)
    portNumBits const inputPortNum = 1234;
        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
    Boolean const inputStreamIsRawUDP = False; 
    ServerMediaSession* sms
      = ServerMediaSession::createNew(*env, streamName, streamName,
          descriptionString);
    sms->addSubsession(MPEG2TransportUDPServerMediaSubsession
         ::createNew(*env, inputAddressStr, inputPortNum, inputStreamIsRawUDP));
    rtspServer->addServerMediaSession(sms);
    char* url = rtspServer->rtspURL(sms);
    *env << "\n\"" << streamName << "\" stream, from a UDP Transport Stream input source \n\t(";
    if (inputAddressStr != NULL) {
      *env << "IP multicast address " << inputAddressStr << ",";
    } else {
      *env << "unicast;";
    }
    *env << " port " << inputPortNum << ")\n";
    *env << "Play this stream using the URL \"" << url << "\"\n";
    delete[] url;
  }

我們需要修改的地方有以下幾處:

a. 把輸入流的地址,從 "239.255.42.42" 改爲迴環地址 “127.0.0.1”(因爲推流程序和服務程序都在本機)

b. 把輸出的流名streamName  從 "mpeg2TransportStreamFromUDPSourceTest" 改爲自己設定的 “live”


4.推流端服務代碼修改:

推流代碼 testMPEG2TransportStreamer.cpp 有以下幾個地方需要修改:

a. 對應服務端,把發送地址改爲 “127.0.0.1"

   char const* destinationAddressStr = "127.0.0.1";

b. 原先的推流代碼不支持FIFO,他是把一個本地文件不停的循環播放,因此我們需要把本地文件改爲FIFO:

  char const* inputFileName = "test.ts"; 改爲 char const* inputFileName = "/var/ibuf_fifo";

c. 因爲FIFO文件有一點特殊(後邊會提及),我們需要修改播放的類 ByteStreamFileSource ,如果不想修改,我們可以直接抄襲 ByteStreamFileSource類自己生成一個新類,然後修改代碼。

   FIFO文件的特殊性: 前端的編碼器修改參數,必然會中斷編碼器流輸出,此時FIFO會被testMPEG2TransportStreamer這個發送端讀空。

                      當編碼器重新送流後,FIFO也會處於一種臨界讀空的狀態,導致播放時十分卡頓。

                      因此需要處理FIFO的上溢和下溢。

   具體的修改: 在類的 fileReadableHandler函數中添加以下內容(此處的修改以FIFO的大小爲2M爲例):

void newByteStreamFileSource::fileReadableHandler(newByteStreamFileSource* source, int /*mask*/) 
{
	// 新增代碼,防止FIFO上溢或者下溢,如果上溢則取出一部分數據,下溢則等待
	int count = 0;
	ioctl(fileno(source->fFid), FIONREAD, &count);
	if((count < 0x40000) || (count >= 0x1FF000))
	{
		if(count >= 0x1FF000)
		{
			int dropNum = 0;
			char buffer[0x200000] = {0};
			dropNum = fread(buffer, 1,  1000  * 188 , source->fFid);
			printf("[%s]%d Drop data  (%d) ...\n", __func__, __LINE__, dropNum);
		}
		source->handleClosure();
	}
	// 新增代碼結束

	if (!source->isCurrentlyAwaitingData())
	{
		source->doStopGettingFrames(); // we're not ready for the data yet
		return;
	}

	source->doReadFromFile();
}


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