1. 程式人生 > >live555讀檔案改為記憶體讀取實現

live555讀檔案改為記憶體讀取實現

        最近遇到有人問live555視訊直播的問題,剛好前段時間接觸過,這個功能可以通過讀記憶體資料實現;

        具體實現方式是參考的這篇文章思路,可以先了解一下看看:

        http://blog.chinaunix.net/uid-15063109-id-132142.html

        live555原始碼裡面有一個讀檔案的測試demo,live555mediaserver,本文修改這份原始碼實現讀記憶體直播功能;

        首先先了解一下live555資料流和live555mediaserver demo中的函式呼叫層次,以H264為例:


        由以上兩個圖可知,要想實現直播功能,有兩個方案:

        1)修改BypteStreamFileSource類中的 讀取檔案程式碼,改成從記憶體中讀取,這個方案修改最簡單,但是會破壞Live555框架的原始碼

        2)參考BypteStreamFileSource寫一個ByteStreamLiveSource,修改讀檔案部分; 

由於source是由H264VideoFileServerMediaSubsession建立並呼叫的,所以要同步新建一個H264VideoLiveServerMediaSubsession類

        這裡只討論第二種方案,下面看程式碼:

        1)DynamicRTSPServer.cpp

中 createNewSMS函式:

  } else if (strcmp(extension, ".264") == 0) {
    // Assumed to be a H.264 Video Elementary Stream file:
    NEW_SMS("H.264 Video");
    OutPacketBuffer::maxSize = 100000; // allow for some possibly large H.264 frames
    sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
  } else if (strcmp(extension, ".265") == 0) {

         上面的程式碼就是根據RTSP請求中檔名的字尾呼叫不同的碼流解析類,由於我們新建了一個 H264VideoLiveServerMediaSubsession 類,這裡要改成

sms->addSubsession(H264VideoLiveServerMediaSubsession::createNew(env, fileName, reuseSource));

         2)修改H264VideoLiveServerMediaSubsession類修改createNewStreamSource函式

FramedSource* H264VideoLiveServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate)
{
	/* Remain to do : assign estBitrate */
	estBitrate = 1000; // kbps, estimate

	// Create the video source:
	ByteStreamLiveSource* liveSource = ByteStreamLiveSource::createNew(envir(), fFileName);
	//ByteStreamFileSource* liveSource = ByteStreamFileSource::createNew(envir(), fFileName);
	if (liveSource == NULL)
	{
		return NULL;
	}

	// Create a framer for the Video Elementary Stream:
	return H264VideoStreamFramer::createNew(envir(), liveSource);
}

        3)ByteStreamLiveSource修改

void ByteStreamFileSource::doGetNextFrame() {
  if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
    handleClosure();
    return;
  }

#ifdef READ_FROM_FILES_SYNCHRONOUSLY
  doReadFromFile();
#else
  if (!fHaveStartedReading) {
    // Await readable data from the file:
    envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
	       (TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
    fHaveStartedReading = True;
  }
#endif
}
上面ByteStreamFileSource是讀取檔案程式碼,只要在新建的ByteStreamLiveSource為中新增一個doReadFromBuffer函式,實現從記憶體中讀取功能,然後替換掉doReadFromFile函式就OK了,像這樣:
void ByteStreamLiveSource::doGetNextFrame() {
// 	if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
// 		handleClosure();
// 		return;
// 	}

#ifdef READ_FROM_FILES_SYNCHRONOUSLY
	doReadFromBuffer();
#else
	if (!fHaveStartedReading) {
		// Await readable data from the file:
		envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
			(TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
		fHaveStartedReading = True;
	}
#endif
}
        doReadFromBuffer需要拷貝碼流資料到 fTo 緩衝區,實現也比較簡單,這裡就不寫了。

        H264VideoLiveServerMediaSubsession類和ByteStreamLiveSource類原始檔地址:  

        http://download.csdn.net/detail/lifexx/9654860

        ps: 原始檔無法執行,僅供參考