用live555做本地視訊採集轉發,附原始碼

NO IMAGE

        在分別做了基於live555與Darwin兩種開源伺服器的轉發伺服器後,不得不說Darwin確實在架構以及效能方面較live555略勝一籌,不過沒關係,以live555的更新速度,作者的負責,相信在客戶端開發以及ipC等方面會給大家帶來不少幫助,不羅嗦,今天要給大家帶來的是基於live555的本地視訊實時採集與轉發的介紹(有程式碼噢~).。

        在對live555做二次開發時,最好的方式就是儘量多地去繼承自live555,而不要去改動開原始碼本身,尤其是一開始接觸live555,這樣在live555官方升級後,我們再對原生代碼進行升級時,就可以比較少地去考慮自己對live555的修改了,省時省力,效果還不錯。

       不論是做遠端採集轉發還是本地採集轉發,我們首先要做的就是繼承live555中的OnDemandServerMediaSubsession類來實現自己需求的OnDemand類,按照類名Subsession,表示的只是一種型別媒體的會話,如果有多種型別媒體需要轉發(比如音訊、視訊),那麼就需要實現多種OnDemandServerMediaSubsession的繼承,來個性化對不同媒體的轉發,那麼今天我們只對H264視訊進行本地採集和轉發,我們實現的類命名為:H264LiveVideoServerMediaSubsession,主要重寫的方法有

private: // redefined virtual functions
virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
unsigned& estBitrate);
virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
unsigned char rtpPayloadTypeIfDynamic,
FramedSource* inputSource);
protected:
virtual char const* sdpLines();

其中 CreateNewRTPSink類似於H264VideoFileServerMediaSubsession直接返回H264VideoRTPSink物件就行了

RTPSink* H264LiveVideoServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,
unsigned char rtpPayloadTypeIfDynamic,
FramedSource* /*inputSource*/) {
return H264VideoRTPSink::createNew(envir(), rtpGroupsock, 96, 0, "H264");
}

關鍵部分就是createNewStreamSource函式,建立自定義的Source來採集視訊,提供H264VideoRTPSink基類MultiFramedRTPSink通過packFrame()呼叫fSource->getNextFrame(…),一次獲取一個完整幀進行轉發。那麼我們先實現的就是這個Source:

同樣,我們實現的自定義source類繼承自H264VideoStreamFramer,重寫virtual void doGetNextFrame();方法實現本地採集資料的獲取:

void MyH264VideoStreamFramer::doGetNextFrame()
{
TNAL* pNal = NULL;//TNAL自定義的儲存單幀資料的結構體
unsigned char* pOrgImg;
//獲取NAL,如果m_pNalArray還有未取完的,先傳送完,如果傳送完了,從pH264Enc中獲取最新資料幀,存入m_pNalArray連結串列
if((m_pNalArray != NULL) && (m_iCurNal < m_iCurNalNum))
{
pNal = &m_pNalArray[m_iCurNal];//m_pNalArray儲存TNAL的連結串列,儲存本地採集的資料連結串列
}
else
{
m_pH264Enc->CleanNAL(m_pNalArray, m_iCurNalNum);//清空m_pNalArray連結串列
m_iCurNal = 0;
pOrgImg = m_pCamera->QueryFrame();
gettimeofday(&fPresentationTime, NULL);//同一幀的NAL具有相同的時間戳
m_pH264Enc->Encode(pOrgImg, m_pNalArray, m_iCurNalNum);
pNal = &m_pNalArray[m_iCurNal];
}
m_iCurNal  ;
unsigned char* realData = pNal->data;//轉發的資料指標
unsigned int realLen = pNal->size;//轉發的資料長度
if(realLen < fMaxSize)        
{            
memcpy(fTo, realData, realLen);//複製到fTo中,fTo為轉發的中轉地址      
}        
else        
{           
memcpy(fTo, realData, fMaxSize);            
fNumTruncatedBytes = realLen - fMaxSize;        
} 
fDurationInMicroseconds = 40000;//控制播放速度
//gettimeofday(&fPresentationTime, NULL);
fFrameSize = realLen;        
afterGetting(this); //通知RTPSink,資料獲取完成 
}

那麼再回到H264LiveVideoServerMediaSubsession類中,CreateNewSource返回的為MyH264VideoStreamFramer物件

  return MyH264VideoStreamFramer::createNew(envir(), NULL);

於是整個live555從source到sink的連線流程就通了,那麼為什麼要重寫sdpLines函式呢?這裡只是一種簡單形式的轉發實現,其sdp資訊並未真實構造,所以就寫成了固定的格式,大家也可以按照自己的方式去重寫

char const* H264LiveVideoServerMediaSubsession::sdpLines()
{
return fSDPLines = 
"m=video 0 RTP/AVP 96\r\n"
"c=IN IP4 0.0.0.0\r\n"
"b=AS:96\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=fmtp:96 packetization-mode=1;profile-level-id=000000;sprop-parameter-sets=H264\r\n"
"a=control:track1\r\n";
}

至於本地Camera視訊的採集以及H264 Encode,因人而異,對不同的裝置也有不同的樣式,附上的程式碼中實現的是windows本地的camera YUV視訊採集以及264編碼,感謝分享!

原始碼下載地址:http://pan.baidu.com/s/1hqIHMj6

————————————————————
本文轉自www.easydarwin.org,更多開源流媒體解決方案,請關注我們的微信:EasyDarwin