加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

live555源码分析----H264的数据处理-2

(2013-04-13 12:27:00)
标签:

live555

流媒体

it

分类: 流媒体
H264FUAFragmenter::doGetNextFrame函数第一次执行时,执行条件1,需要调用 MPEGVideoStreamFramer::doGetNextFrame读取一个新的frame,获取frame的具体过程稍后再分析。现在先看获取frame之后的工作,afterGettingFrame函数
  1. void H264FUAFragmenter::afterGettingFrame(voidclientData, unsigned frameSize,  
  2.                       unsigned numTruncatedBytes,  
  3.                       struct timeval presentationTime,  
  4.                       unsigned durationInMicroseconds)  
  5.   H264FUAFragmenter* fragmenter (H264FUAFragmenter*)clientData;  
  6.   fragmenter->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime,  
  7.                  durationInMicroseconds);  
  8.  


没什么好说的,再看afterGettingFrame1函数


  1. void H264FUAFragmenter::afterGettingFrame1(unsigned frameSize,  
  2.                        unsigned numTruncatedBytes,  
  3.                        struct timeval presentationTime,  
  4.                        unsigned durationInMicroseconds)  
  5.   fNumValidDataBytes += frameSize;      //保存读到的frame长度  
  6.   fSaveNumTruncatedBytes numTruncatedBytes;  
  7.   fPresentationTime presentationTime;  
  8.   fDurationInMicroseconds durationInMicroseconds;  
  9.   
  10.   
  11.   // Deliver data to the client:  
  12.   doGetNextFrame();  
  13.  


    上面的代码首先记录几个数据到成员变量中,fNumValidDataBytes很重要,表示读取到的frame长度+1。然后又一次调用了H264FUAFragmenter::doGetNextFrame(),这里将进入H264FUAFragmenter::doGetNextFrame函数中第二个条件分支,这种循环调用很容易把人弄迷糊了。

    H264FUAFragmenter::doGetNextFrame函数中第二个条件分支中,处理H264的RTP分片问题,这里是按照RFC3984进行RTP封装的。你应该注意到,在上篇文章"RTP的打包与发送"中,也出现了分片的代码(MultiFramedRTPSink::packFrame函数中),那里直接将frame按MTU的长度来拆分。那为什么H264还要自定义一套RTP打包的标准呢?暂时我也不清楚。


    在H264FUAFragmenter::doGetNextFrame()最后调用了 FramedSource::afterGetting


  1. void FramedSource::afterGetting(FramedSource* source)  
  2.   source->fIsCurrentlyAwaitingData False;     //表示已经获取到数据了,处于非等待状态  
  3.       // indicates that we can be read again  
  4.       // Note that this needs to be done here, in case the "fAfterFunc"  
  5.       // called below tries to read another frame (which it usually will)  
  6.   
  7.   
  8.   //通过回调用进行后续处理  
  9.   if (source->fAfterGettingFunc != NULL)  
  10.     (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,  
  11.                    source->fFrameSize, source->fNumTruncatedBytes,  
  12.                    source->fPresentationTime,  
  13.                    source->fDurationInMicroseconds);  
  14.    
  15.  



    上面的代码主要是调用了FramedSource::getNextFrame函数中传递下来的回调函数,这个回调函数就是MultiFramedRTPSink::afterGettingFrame,处理过程在上一篇文章"RTP的打包与发送"中已经分析过了。
  
    现在来看MPEGVideoStreamFramer::doGetNextFrame获取Frame的过程。继承关系:H264VideoStreamFramer->MPEGVideoStreamFramer->FramedFilter->FramedSource。在继承路径中存在FrameFilter,这说明H264VideoStreamFramer包装了其它source(包装的是读取文件的字节流source)。doGetNextFrame函数首先在MPEGVideoStreamFramer中实现。


  1. void MPEGVideoStreamFramer::doGetNextFrame()  
  2.   fParser->registerReadInterest(fTo, fMaxSize); //将目的buffer信息注册到语法分析类中  
  3.   continueReadProcessing();     //继续进行读数据  
  4.  



    这里的MPEGVideoStreamFramer::fParser,是一个MPEGVideoStreamParser类型指针,作为语法分析器。再来看continueReadProcessing函数


  1. void MPEGVideoStreamFramer::continueReadProcessing()  
  2.   unsigned acquiredFrameSize fParser->parse();    //文件的语法分析(即demux)  
  3.   if (acquiredFrameSize 0)  
  4.     // We were able to acquire frame from the input.  
  5.     // It has already been copied to the reader's space.  
  6.     fFrameSize acquiredFrameSize;  
  7.     fNumTruncatedBytes fParser->numTruncatedBytes();  
  8.   
  9.   
  10.     // "fPresentationTime" should have already been computed.  
  11.   
  12.   
  13.     // Compute "fDurationInMicroseconds" now:  
  14.     fDurationInMicroseconds  
  15.       (fFrameRate == 0.0 || ((int)fPictureCount) 0)  
  16.       (unsigned)((fPictureCount*1000000)/fFrameRate);  
  17. #ifdef DEBUG  
  18.     fprintf(stderr, "%d bytes @%u.d, fDurationInMicroseconds: %d ((%d*1000000)/%f)\n"acquiredFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds, fPictureCount, fFrameRate);  
  19. #endif  
  20.     fPictureCount 0;  
  21.       
  22.     //  
  23.     //调用自身的afterGetting函数,因为这不一个"leaf" source, 所以可能直接调用,  
  24.     //而不用担心出现无限递归  
  25.     //  
  26.     // Call our own 'after getting' function.  Because we're not 'leaf'  
  27.     // source, we can call this directly, without risking infinite recursion.  
  28.     afterGetting(this);  
  29.   else  
  30.     // We were unable to parse complete frame from the input, because:  
  31.     // we had to read more data from the source stream, or  
  32.     // the source stream has ended.  
  33.    
  34.  


    函数中首先调用了MPEGVideoStreamParser::parse函数,将一个完整的Frame分析出来,并copy到了fTo(fTo就是OutPacketBuffer中的缓冲区)中,这其中肯定也实现了从文件中读取数据的过程。这里的fNumTruncatedBytes变量需要注意,fNumTruncatedBytes>0的话,表明Frame的实际长度大于fTo的最大长度,这将导致数据丢失,这时就要考虑增加缓冲区的长度了。成功获取一个Frame后,将调用afterGetting函数处理后续工作。
    先来看parse函数,parse是定义在MPEGVideoStreamParser中的纯虚函数,在子类H264VideoStreamParser中实现。parse主要是从文件的字节流中,分离出一个个的Frame,对于H264而言其实就是对一个个的NALU。*.264文件的格式非常简单,每个NALU以 0x00000001 作为起始符号(中间的NALU也可以以0x000001作为起始符),顺序存放。


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有