Live555做本地采集视频直播

来源:互联网 发布:三国杀网络错误请重试 编辑:程序博客网 时间:2024/05/01 23:44

        在分别做了基于live555与Darwin两种开源服务器转发服务器后,不得不说Darwin确实在架构以及性能方面较live555略胜一筹,不过没关系,以live555的更新速度,作者的负责,相信在客户端开发以及ipC等方面会给大家带来不少帮助,不罗嗦,今天要给大家带来的是基于live555的本地视频实时采集转发的介绍(有代码噢~).。

        在对live555做二次开发时,最好的方式就是尽量多地去继承自live555,而不要去改动开源代码本身,尤其是一开始接触live555,这样在live555官方升级后,我们再对本地代码进行升级时,就可以比较少地去考虑自己对live555的修改了,省时省力,效果还不错。

       不论是做远端采集转发还是本地采集转发(我们这里说明的代码为google code中开源代码),我们首先要做的就是继承live555中的OnDemandServerMediaSubsession类来实现自己需求的OnDemand类,按照类名Subsession,表示的只是一种类型媒体的会话,如果有多种类型媒体需要转发(比如音频、视频),那么就需要实现多种OnDemandServerMediaSubsession的继承,来个性化对不同媒体转发,那么今天我们只对H264视频进行本地采集转发,我们实现的类命名为:H264LiveVideoServerMediaSubsession,主要重写的方法有

查看文本打印?
  1. private// redefined virtual functions  
  2.   virtual FramedSource* createNewStreamSource(unsigned clientSessionId,  
  3.                           unsigned& estBitrate);  
  4.   virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,  
  5.                                     unsigned char rtpPayloadTypeIfDynamic,  
  6.                                     FramedSource* inputSource);  
  7. protected:  
  8.   virtual char const* sdpLines();  


其中 CreateNewRTPSink类似于H264VideoFileServerMediaSubsession直接返回H264VideoRTPSink对象就行了

查看文本打印?
  1. RTPSink* H264LiveVideoServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,  
  2.                                   unsigned char rtpPayloadTypeIfDynamic,  
  3.                                   FramedSource* /*inputSource*/) {  
  4.   return H264VideoRTPSink::createNew(envir(), rtpGroupsock, 96, 0, "H264");  
  5. }  

关键部分就是createNewStreamSource函数,创建自定义的Source来采集视频,提供H264VideoRTPSink基类MultiFramedRTPSink通过packFrame()调用fSource->getNextFrame(...),一次获取一个完整帧进行转发。那么我们先实现的就是这个Source:

同样,我们实现的自定义source类继承自H264VideoStreamFramer,重写virtual void doGetNextFrame();方法实现本地采集数据的获取:

查看文本打印?
  1. void MyH264VideoStreamFramer::doGetNextFrame()  
  2. {  
  3.     TNAL* pNal = NULL;//TNAL自定义的存储单帧数据的结构体  
  4.     unsigned char* pOrgImg;  
  5.       
  6.     //获取NAL,如果m_pNalArray还有未取完的,先发送完,如果发送完了,从pH264Enc中获取最新数据帧,存入m_pNalArray链表  
  7.     if((m_pNalArray != NULL) && (m_iCurNal < m_iCurNalNum))  
  8.     {  
  9.         pNal = &m_pNalArray[m_iCurNal];//m_pNalArray存储TNAL的链表,存储<strong>本地</strong><strong>采集</strong>的数据链表  
  10.     }  
  11.     else  
  12.     {  
  13.         m_pH264Enc->CleanNAL(m_pNalArray, m_iCurNalNum);//清空m_pNalArray链表  
  14.         m_iCurNal = 0;  
  15.           
  16.         pOrgImg = m_pCamera->QueryFrame();  
  17.         gettimeofday(&fPresentationTime, NULL);//同一帧的NAL具有相同的时间戳  
  18.   
  19.          m_pH264Enc->Encode(pOrgImg, m_pNalArray, m_iCurNalNum);  
  20.         pNal = &m_pNalArray[m_iCurNal];  
  21.     }  
  22.     m_iCurNal++;  
  23.   
  24.     unsigned char* realData = pNal->data;//<strong><strong>转发</strong></strong>的数据指针  
  25.     unsigned int realLen = pNal->size;//<strong><strong>转发</strong></strong>的数据长度  
  26.       
  27.     if(realLen < fMaxSize)          
  28.     {              
  29.       memcpy(fTo, realData, realLen);//复制到fTo中,fTo为<strong><strong>转发</strong></strong>的中转地址        
  30.     }          
  31.     else          
  32.     {             
  33.       memcpy(fTo, realData, fMaxSize);              
  34.       fNumTruncatedBytes = realLen - fMaxSize;          
  35.     }   
  36.   
  37.     fDurationInMicroseconds = 40000;//控制播放速度  
  38.     //gettimeofday(&fPresentationTime, NULL);  
  39.   
  40.     fFrameSize = realLen;          
  41.     afterGetting(this); //通知RTPSink,数据获取完成   
  42. }  

那么再回到H264LiveVideoServerMediaSubsession类中,CreateNewSource返回的为MyH264VideoStreamFramer对象

查看文本打印?
  1. return MyH264VideoStreamFramer::createNew(envir(), NULL);  

于是整个live555从source到sink的连接流程就通了,那么为什么要重写sdpLines函数呢?这里只是一种简单形式的转发实现,其sdp信息并未真实构造,所以就写成了固定的格式,大家也可以按照自己的方式去重写

查看文本打印?
  1. char const* H264LiveVideoServerMediaSubsession::sdpLines()  
  2. {  
  3.     return fSDPLines =   
  4.         "m=video 0 RTP/AVP 96\r\n"  
  5.         "c=IN IP4 0.0.0.0\r\n"  
  6.         "b=AS:96\r\n"  
  7.         "a=rtpmap:96 H264/90000\r\n"  
  8.         "a=fmtp:96 packetization-mode=1;profile-level-id=000000;sprop-parameter-sets=H264\r\n"  
  9.         "a=control:track1\r\n";  
  10. }  


至于本地Camera视频采集以及H264 Encode,因人而异,对不同的设备也有不同的样式,附上的代码中实现的是windows本地的camera YUV视频采集以及264编码,再次说明,代码为google code中下载,感谢分享者的分享!

1 0
原创粉丝点击