加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-14 04:03:45 所属栏目:大数据 来源:网络整理
导读:?现在来分析live555中关于H264的处理部分,主要包括从文件中读取数据进行并进行frame(NALU)的分割,然后对frame进行分片,这些工作都是在frame交给RTP sink之前完成的。接着上篇分析文章(RTP的打包与发送)中提到的MultiFramedRTP::packFrame函数进行分析。 [
?现在来分析live555中关于H264的处理部分,主要包括从文件中读取数据进行并进行frame(NALU)的分割,然后对frame进行分片,这些工作都是在frame交给RTP sink之前完成的。接着上篇分析文章(RTP的打包与发送)中提到的MultiFramedRTP::packFrame函数进行分析。
[cpp] view plain copy print ?
  1. void?MultiFramedRTPSink::packFrame()?{??
  2. ??if?(fOutBuf->haveOverflowData())?{??
  3. ...??
  4. ??}?else?{??
  5. ...??
  6. ??
  7. ??
  8. ????// ??
  9. ????//从source中获取下一个frame ??
  10. ????// ??
  11. ????fSource->getNextFrame(fOutBuf->curPtr(),?fOutBuf->totalBytesAvailable(),??
  12. ??????????????afterGettingFrame,?this,?ourHandleClosure,?this);??
  13. ??}??
  14. }??


?? ?getNextFrame是定义在FramedSource中的非虚函数,从source中获取下一个frame,然后调用回调函数afterGettingFrame。afterGettingFrame被定义为静态函数,因为在C++中类成员函数是不能作为回调用函数的。不过这里为什么要用回调函数回?
?? ?注意,对于H264来说,上面的fSource并不是MPEGVideoStreamFramer类,因为在 H264VideoRTPSink::continuePlaying()函数中改变了fSource的值。 ? ?
[cpp] view plain copy print ?
  1. Boolean?H264VideoRTPSink::continuePlaying()?{??
  2. ??//?First,?check?whether?we?have?a?'fragmenter'?class?set?up?yet. ??
  3. ??//?If?not,?create?it?now: ??
  4. ??if?(fOurFragmenter?==?NULL)?{??
  5. ????//创建一个辅助类H264FUAFragmenter,用于H264按照RFC3984进行RTP打包 ??
  6. ??
  7. ????fOurFragmenter?=?new?H264FUAFragmenter(envir(),?fSource,?OutPacketBuffer::maxSize,??
  8. ???????????????????????ourMaxPacketSize()?-?12/*RTP?hdr?size*/);??
  9. ????fSource?=?fOurFragmenter;??
  10. ??}??
  11. ??
  12. ??
  13. ??//?Then?call?the?parent?class's?implementation: ??
  14. ??return?MultiFramedRTPSink::continuePlaying();??
  15. }??


?? ?fSource被指向了H264FUAFragmenter类,这个类主要实现了H264按照RFC3984进行RTP分包,不过这里的实现每个RTP中最多只包含一个NALU,没有实现组合封包的情形。这个类的继承关系如下:H264FUAFragmenter->FramedFilter->FramedSource。很明显,这是一个filter,包装了MPEGVideoStreamFramer类的对像。
?? ?先来看来看getNextFrame的实现

[cpp] view plain copy print ?
  1. void?FramedSource::getNextFrame(unsigned?char*?to,?unsigned?maxSize,??
  2. ????????????????afterGettingFunc*?afterGettingFunc,??
  3. ????????????????void*?afterGettingClientData,??
  4. ????????????????onCloseFunc*?onCloseFunc,??
  5. ????????????????void*?onCloseClientData)?{??
  6. ??//?Make?sure?we're?not?already?being?read: ??
  7. ??if?(fIsCurrentlyAwaitingData)?{??
  8. ????envir()?<<?"FramedSource["?<<?this?<<?"]::getNextFrame():?attempting?to?read?more?than?once?at?the?same?time!n";??
  9. ????envir().internalError();??
  10. ??}??
  11. ??
  12. ??
  13. ??fTo?=?to;?????????????//buffer地址 ??
  14. ??fMaxSize?=?maxSize;???//buffer最大长度 ??
  15. ??fNumTruncatedBytes?=?0;?//?by?default;?could?be?changed?by?doGetNextFrame() ??
  16. ??fDurationInMicroseconds?=?0;?//?by?default;?could?be?changed?by?doGetNextFrame() ??
  17. ??fAfterGettingFunc?=?afterGettingFunc;?????????????//获取完一个frame后将执行这个函数 ??
  18. ??fAfterGettingClientData?=?afterGettingClientData;?//这个参数就是MultiFramedRTPSink类型指针 ??
  19. ??fOnCloseFunc?=?onCloseFunc;??
  20. ??fOnCloseClientData?=?onCloseClientData;??
  21. ??fIsCurrentlyAwaitingData?=?True;??
  22. ??
  23. ??
  24. ??doGetNextFrame();??
  25. }??


?? ?上面的函数主要是进行一些成员变量的初始化,获取到的frame需要保存到fTo地址中,然后调用fAfterGettingFunc函数,若文件读取完毕,还需要调用fOnCloseFunc函数。重要的工作还是在doGetNextFrame函数中完成,不过它是定义在FramedSource类中的纯虚函数,需要在子类中重新实现。
?? ?现在来看H264FUAFragmenter中对doGetNextFrame的实现

[cpp] view plain copy print ?
  1. void?H264FUAFragmenter::doGetNextFrame()?{??
  2. ??if?(fNumValidDataBytes?==?1)?{??
  3. ??????//读取一个新的frame ??
  4. ????//?We?have?no?NAL?unit?data?currently?in?the?buffer.??Read?a?new?one: ??
  5. ????fInputSource->getNextFrame(&fInputBuffer[1],?fInputBufferSize?-?1,??
  6. ???????????????????afterGettingFrame,??
  7. ???????????????????FramedSource::handleClosure,?this);??
  8. ??}?else?{??
  9. ??????// ??
  10. ??????//现在buffer中已经存在NALU数据了,需要考虑三种情况 ??
  11. ??????//1.一个新的NALU,且足够小能投递给RTP?sink。 ??
  12. ??????//2.一个新的NALU,但是比RTP?sink要求的包大了,投递第一个分片作为一个FU-A?packet,?并带上一个额外的头字节。 ??
  13. ??????//3.部分NALU数据,投递下一个分片作为一个FU-A?packet,并带上2个额外的头字节。 ??
  14. ????//?We?have?NAL?unit?data?in?the?buffer.??There?are?three?cases?to?consider: ??
  15. ????//?1.?There?is?a?new?NAL?unit?in?the?buffer,?and?it's?small?enough?to?deliver ??
  16. ????//????to?the?RTP?sink?(as?is). ??
  17. ????//?2.?There?is?a?new?NAL?unit?in?the?buffer,?but?it's?too?large?to?deliver?to ??
  18. ????//????the?RTP?sink?in?its?entirety.??Deliver?the?first?fragment?of?this?data,??
  19. ????//????as?a?FU-A?packet,?with?one?extra?preceding?header?byte. ??
  20. ????//?3.?There?is?a?NAL?unit?in?the?buffer,?and?we've?already?delivered?some ??
  21. ????//????fragment(s)?of?this.??Deliver?the?next?fragment?of?this?data,??
  22. ????//????as?a?FU-A?packet,?with?two?extra?preceding?header?bytes. ??
  23. ??
  24. ??
  25. ????if?(fMaxSize?<?fMaxOutputPacketSize)?{?//?shouldn't?happen ??
  26. ??????envir()?<<?"H264FUAFragmenter::doGetNextFrame():?fMaxSize?("??
  27. ??????????<<?fMaxSize?<<?")?is?smaller?than?expectedn";??
  28. ????}?else?{??
  29. ??????fMaxSize?=?fMaxOutputPacketSize;??
  30. ????}??
  31. ??
  32. ??
  33. ????fLastFragmentCompletedNALUnit?=?True;?//?by?default ??
  34. ????if?(fCurDataOffset?==?1)?{?//?case?1?or?2 ??
  35. ??????if?(fNumValidDataBytes?-?1?<=?fMaxSize)?{?//?case?1 ??
  36. ??????????// ??
  37. ??????????//情况1,?处理整个NALU ??
  38. ??????????// ??
  39. ????memmove(fTo,?&fInputBuffer[1],?fNumValidDataBytes?-?1);??
  40. ????fFrameSize?=?fNumValidDataBytes?-?1;??
  41. ????fCurDataOffset?=?fNumValidDataBytes;??
  42. ??????}?else?{?//?case?2 ??
  43. ??????????// ??
  44. ??????????//情况2,处理NALU的第1个分片。注意,我们添加FU指示符和FU头字节(with?S?bit)到包的最前面( ??
  45. ??????????//重用已经存在的NAL?头字节作为FU的头字节) ??
  46. ??????????// ??
  47. ????//?We?need?to?send?the?NAL?unit?data?as?FU-A?packets.??Deliver?the?first ??
  48. ????//?packet?now.??Note?that?we?add?FU?indicator?and?FU?header?bytes?to?the?front ??
  49. ????//?of?the?packet?(reusing?the?existing?NAL?header?byte?for?the?FU?header). ??
  50. ????fInputBuffer[0]?=?(fInputBuffer[1]?&?0xE0)?|?28;?//?FU?indicator ??
  51. ????fInputBuffer[1]?=?0x80?|?(fInputBuffer[1]?&?0x1F);?//?FU?header?(with?S?bit)???重用NALU头字节 ??
  52. ????memmove(fTo,?fInputBuffer,?fMaxSize);??
  53. ????fFrameSize?=?fMaxSize;??
  54. ????fCurDataOffset?+=?fMaxSize?-?1;??
  55. ????fLastFragmentCompletedNALUnit?=?False;??
  56. ??????}??
  57. ????}?else?{?//?case?3 ??
  58. ????????// ??
  59. ????????//情况3,处理非第1个分片。需要添加FU指示符和FU头(我们重用了第一个分片中的字节,但是需要清除S位, ??
  60. ????????//并在最后一个分片中添加E位) ??
  61. ????????// ??
  62. ????????// ??
  63. ??????//?We?are?sending?this?NAL?unit?data?as?FU-A?packets.??We've?already?sent?the ??
  64. ??????//?first?packet?(fragment).??Now,?send?the?next?fragment.??Note?that?we?add ??
  65. ??????//?FU?indicator?and?FU?header?bytes?to?the?front.??(We?reuse?these?bytes?that ??
  66. ??????//?we?already?sent?for?the?first?fragment,?but?clear?the?S?bit,?and?add?the?E ??
  67. ??????//?bit?if?this?is?the?last?fragment.) ??
  68. ??????fInputBuffer[fCurDataOffset-2]?=?fInputBuffer[0];?//?FU?indicator ??
  69. ??????fInputBuffer[fCurDataOffset-1]?=?fInputBuffer[1]&~0x80;?//?FU?header?(no?S?bit) ??
  70. ??????unsigned?numBytesToSend?=?2?+?fNumValidDataBytes?-?fCurDataOffset;??
  71. ??????if?(numBytesToSend?>?fMaxSize)?{??
  72. ????//?We?can't?send?all?of?the?remaining?data?this?time: ??
  73. ????numBytesToSend?=?fMaxSize;??
  74. ????fLastFragmentCompletedNALUnit?=?False;??
  75. ??????}?else?{??
  76. ????// ??
  77. ????//最后一个分片,需要在FU头中设置E标志位 ??
  78. ????//?This?is?the?last?fragment: ??
  79. ????fInputBuffer[fCurDataOffset-1]?|=?0x40;?//?set?the?E?bit?in?the?FU?header ??
  80. ????fNumTruncatedBytes?=?fSaveNumTruncatedBytes;??
  81. ??????}??
  82. ??????memmove(fTo,?&fInputBuffer[fCurDataOffset-2],?numBytesToSend);??
  83. ??????fFrameSize?=?numBytesToSend;??
  84. ??????fCurDataOffset?+=?numBytesToSend?-?2;??
  85. ????}??
  86. ??
  87. ??
  88. ????if?(fCurDataOffset?>=?fNumValidDataBytes)?{??
  89. ??????//?We're?done?with?this?data.??Reset?the?pointers?for?receiving?new?data: ??
  90. ??????fNumValidDataBytes?=?fCurDataOffset?=?1;??
  91. ????}??
  92. ??
  93. ??
  94. ????//?Complete?delivery?to?the?client: ??
  95. ????FramedSource::afterGetting(this);??
  96. ??}??
  97. }??


?? ?H264FUAFragmenter::doGetNextFrame函数第一次执行时,执行条件1,需要调用 MPEGVideoStreamFramer::doGetNextFrame读取一个新的frame,获取frame的具体过程稍后再分析。现在先看获取frame之后的工作,afterGettingFrame函数
[cpp] view plain copy print ?
  1. void?H264FUAFragmenter::afterGettingFrame(void*?clientData,?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函数


[cpp] view plain copy print ?
  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


[cpp] view plain copy print ?
  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中实现。


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



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


[cpp] view plain copy print ?
  1. void?MPEGVideoStreamFramer::continueReadProcessing()?{??
  2. ??unsigned?acquiredFrameSize?=?fParser->parse();????//文件的语法分析(即demux) ??
  3. ??if?(acquiredFrameSize?>?0)?{??
  4. ????//?We?were?able?to?acquire?a?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)???0??
  16. ??????:?(unsigned)((fPictureCount*1000000)/fFrameRate);??
  17. #ifdef?DEBUG ??
  18. ????fprintf(stderr,?"%d?bytes?@%u.%06d,?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?a?'leaf' ??
  27. ????//?source,?we?can?call?this?directly,?without?risking?infinite?recursion. ??
  28. ????afterGetting(this);??
  29. ??}?else?{??
  30. ????//?We?were?unable?to?parse?a?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作为起始符),顺序存放。


[cpp] view plain copy print ?
  1. unsigned?H264VideoStreamParser::parse()?{??
  2. ??try?{??
  3. ????// ??
  4. ????//首先找到起始符号,?并跳过。文件流的最开始必需以0x00000001开始,但后续的NALU充许以0x000001(3?bytes)作为分隔 ??
  5. ????// ??
  6. ????//?The?stream?must?start?with?a?0x00000001: ??
  7. ????if?(!fHaveSeenFirstStartCode)?{??
  8. ??????//?Skip?over?any?input?bytes?that?precede?the?first?0x00000001: ??
  9. ??????u_int32_t?first4Bytes;??
  10. ??????while?((first4Bytes?=?test4Bytes())?!=?0x00000001)?{??
  11. ????get1Byte();?setParseState();?//?ensures?that?we?progress?over?bad?data ??
  12. ??????}??
  13. ??????skipBytes(4);?//?skip?this?initial?code ??
  14. ????????
  15. ??????setParseState();??
  16. ??????fHaveSeenFirstStartCode?=?True;?//?from?now?on ??
  17. ????}??
  18. ????// ??
  19. ????//将起始标志也保存到目的缓冲区中 ??
  20. ????// ??
  21. ????if?(fOutputStartCodeSize?>?0)?{??
  22. ??????//?Include?a?start?code?in?the?output: ??
  23. ??????save4Bytes(0x00000001);?????
  24. ????}??
  25. ??????
  26. ????// ??
  27. ????//保存所有数据,直至遇到起始标志,或者文件结束符。需要注意NALU中的第一个字节,因为它指示了NALU的类型 ??
  28. ????// ??
  29. ????//?Then?save?everything?up?until?the?next?0x00000001?(4?bytes)?or?0x000001?(3?bytes),?or?we?hit?EOF. ??
  30. ????//?Also?make?note?of?the?first?byte,?because?it?contains?the?"nal_unit_type":? ??
  31. ????u_int8_t?firstByte;??
  32. ????if?(haveSeenEOF())?{??
  33. ???????// ??
  34. ???????//已经设置了文件结束标志,将剩下的数据保存也来即可 ??
  35. ???????// ??
  36. ??????//?We?hit?EOF?the?last?time?that?we?tried?to?parse?this?data,??
  37. ??????//?so?we?know?that?the?remaining?unparsed?data?forms?a?complete?NAL?unit: ??
  38. ??????unsigned?remainingDataSize?=?totNumValidBytes()?-?curOffset();??
  39. ??????if?(remainingDataSize?==?0)?(void)get1Byte();?//?forces?another?read,?which?will?cause?EOF?to?get?handled?for?real?this?time ??
  40. #ifdef?DEBUG ??
  41. ??????fprintf(stderr,?"This?NAL?unit?(%d?bytes)?ends?with?EOFn",?remainingDataSize);??
  42. #endif ??
  43. ??????if?(remainingDataSize?==?0)?return?0;??
  44. ??????firstByte?=?get1Byte();???//将第一个字节保存下来,其指示了NALU的类型 ??
  45. ??????saveByte(firstByte);??
  46. ????????
  47. ??????while?(--remainingDataSize?>?0)?{??
  48. ????saveByte(get1Byte());??
  49. ??????}??
  50. ????}?else?{??
  51. ??????u_int32_t?next4Bytes?=?test4Bytes();??
  52. ??????firstByte?=?next4Bytes>>24;???//将第一个字节保存下来 ??
  53. ??????// ??
  54. ??????//将下一个起始符号之前的数据都保存下来 ??
  55. ??????// ??
  56. ??????while?(next4Bytes?!=?0x00000001?&&?(next4Bytes&0xFFFFFF00)?!=?0x00000100)?{??
  57. ????//?We?save?at?least?some?of?"next4Bytes". ??
  58. ????if?((unsigned)(next4Bytes&0xFF)?>?1)?{??//一次可以保存4个字节,并不需要一个一个字节对比,除非到了结尾 ??
  59. ??????//?Common?case:?0x00000001?or?0x000001?definitely?doesn't?begin?anywhere?in?"next4Bytes",?so?we?save?all?of?it: ??
  60. ??????save4Bytes(next4Bytes);??
  61. ??????skipBytes(4);??
  62. ????}?else?{??
  63. ??????//?Save?the?first?byte,?and?continue?testing?the?rest: ??
  64. ??????saveByte(next4Bytes>>24);??
  65. ??????skipBytes(1);??
  66. ????}??
  67. ????next4Bytes?=?test4Bytes();??
  68. ??????}??
  69. ??????//?Assert:?next4Bytes?starts?with?0x00000001?or?0x000001,?and?we've?saved?all?previous?bytes?(forming?a?complete?NAL?unit). ??
  70. ??????//?Skip?over?these?remaining?bytes,?up?until?the?start?of?the?next?NAL?unit: ??
  71. ??????if?(next4Bytes?==?0x00000001)?{??
  72. ????skipBytes(4);??
  73. ??????}?else?{??
  74. ????skipBytes(3);??
  75. ??????}??
  76. ????}??
  77. ???
  78. ????u_int8_t?nal_ref_idc?=?(firstByte&0x60)>>5;??
  79. ????u_int8_t?nal_unit_type?=?firstByte&0x1F;??
  80. #ifdef?DEBUG ??
  81. ????fprintf(stderr,?"Parsed?%d-byte?NAL-unit?(nal_ref_idc:?%d,?nal_unit_type:?%d?("%s"))n",??
  82. ????????curFrameSize()-fOutputStartCodeSize,?nal_ref_idc,?nal_unit_type,?nal_unit_type_description[nal_unit_type]);??
  83. #endif ??
  84. ??
  85. ??
  86. ????// ??
  87. ????//下面根据NALU的类型来作具体的分析 ??
  88. ????// ??
  89. ????switch?(nal_unit_type)?{??
  90. ??????case?6:?{?//?Supplemental?enhancement?information?(SEI) ??
  91. ????analyze_sei_data();??
  92. ????//?Later,?perhaps?adjust?"fPresentationTime"?if?we?saw?a?"pic_timing"?SEI?payload????##### ??
  93. ????break;??
  94. ??????}??
  95. ??????case?7:?{?//?Sequence?parameter?set?(序列参数集) ??
  96. ??????// ??
  97. ??????//保存一份SPS的副本到H264VideoStreamFramer中,后面的pps也需要保存,sps中可能还包含了帧率信息 ??
  98. ??????// ??
  99. ????//?First,?save?a?copy?of?this?NAL?unit,?in?case?the?downstream?object?wants?to?see?it: ??
  100. ????usingSource()->saveCopyOfSPS(fStartOfFrame?+?fOutputStartCodeSize,?fTo?-?fStartOfFrame?-?fOutputStartCodeSize);??
  101. ??
  102. ??
  103. ????//?Parse?this?NAL?unit?to?check?whether?frame?rate?information?is?present: ??
  104. ????unsigned?num_units_in_tick,?time_scale,?fixed_frame_rate_flag;??
  105. ????analyze_seq_parameter_set_data(num_units_in_tick,?fixed_frame_rate_flag);??
  106. ????if?(time_scale?>?0?&&?num_units_in_tick?>?0)?{??
  107. ??????usingSource()->fFrameRate?=?time_scale/(2.0*num_units_in_tick);???//sps中包含了帧率信息 ??
  108. #ifdef?DEBUG ??
  109. ??????fprintf(stderr,?"Set?frame?rate?to?%f?fpsn",?usingSource()->fFrameRate);??
  110. ??????if?(fixed_frame_rate_flag?==?0)?{??
  111. ????????fprintf(stderr,?"tWARNING:?"fixed_frame_rate_flag"?was?not?setn");??
  112. ??????}??
  113. #endif ??
  114. ????}?else?{????//sps中不包含帧率信息,则使用source中设置的默认帧率 ??
  115. #ifdef?DEBUG ??
  116. ??????fprintf(stderr,?"tThis?"Sequence?Parameter?Set"?NAL?unit?contained?no?frame?rate?information,?so?we?use?a?default?frame?rate?of?%f?fpsn",?usingSource()->fFrameRate);??
  117. #endif ??
  118. ????}??
  119. ????break;??
  120. ??????}??
  121. ??????case?8:?{?//?Picture?parameter?set?(图像参数集PPS) ??
  122. ????//?Save?a?copy?of?this?NAL?unit,?in?case?the?downstream?object?wants?to?see?it: ??
  123. ????usingSource()->saveCopyOfPPS(fStartOfFrame?+?fOutputStartCodeSize,?fTo?-?fStartOfFrame?-?fOutputStartCodeSize);??
  124. ??????}??
  125. ????}??
  126. ??????
  127. ????usingSource()->setPresentationTime();???//设置当前的时间 ??
  128. #ifdef?DEBUG ??
  129. ????unsigned?long?secs?=?(unsigned?long)usingSource()->fPresentationTime.tv_sec;??
  130. ????unsigned?uSecs?=?(unsigned)usingSource()->fPresentationTime.tv_usec;??
  131. ????fprintf(stderr,?"tPresentation?time:?%lu.%06un",?secs,?uSecs);??
  132. #endif ??
  133. ??????
  134. ????// ??
  135. ????//如果这个NALU是一个VCL?NALU(即包含的是视频数据),我们需要扫描下一个NALU的起始符, ??
  136. ????//以判断这个NALU是否是当前的"access?unit"(这个"access?unit"应该可以理解为一帧图像帧吧)。 ??
  137. ????//我们需要根据这个信息去指明何时该增加"fPresentationTime"(RTP?打包时也需要根据这个信息,决定是否设置"M"位)。 ??
  138. ????// ??
  139. ????//?If?this?NAL?unit?is?a?VCL?NAL?unit,?we?also?scan?the?start?of?the?next?NAL?unit,?to?determine?whether?this?NAL?unit ??
  140. ????//?ends?the?current?'access?unit'.??We?need?this?information?to?figure?out?when?to?increment?"fPresentationTime". ??
  141. ????//?(RTP?streamers?also?need?to?know?this?in?order?to?figure?out?whether?or?not?to?set?the?"M"?bit.) ??
  142. ????Boolean?thisNALUnitEndsAccessUnit?=?False;?//?until?we?learn?otherwise? ??
  143. ????if?(haveSeenEOF())?{??
  144. ??????//?There?is?no?next?NAL?unit,?so?we?assume?that?this?one?ends?the?current?'access?unit': ??
  145. ??????thisNALUnitEndsAccessUnit?=?True;??
  146. ????}?else?{??
  147. ??????Boolean?const?isVCL?=?nal_unit_type?<=?5?&&?nal_unit_type?>?0;?//?Would?need?to?include?type?20?for?SVC?and?MVC?##### ??
  148. ??????if?(isVCL)?{??
  149. ????u_int32_t?first4BytesOfNextNALUnit?=?test4Bytes();??
  150. ????u_int8_t?firstByteOfNextNALUnit?=?first4BytesOfNextNALUnit>>24;??
  151. ????u_int8_t?next_nal_ref_idc?=?(firstByteOfNextNALUnit&0x60)>>5;??
  152. ????u_int8_t?next_nal_unit_type?=?firstByteOfNextNALUnit&0x1F;??
  153. ????if?(next_nal_unit_type?>=?6)?{??
  154. ????????//下一个NALU不是VCL的,当前的"access?unit"结束了 ??
  155. ??????//?The?next?NAL?unit?is?not?a?VCL;?therefore,?we?assume?that?this?NAL?unit?ends?the?current?'access?unit': ??
  156. #ifdef?DEBUG ??
  157. ??????fprintf(stderr,?"t(The?next?NAL?unit?is?not?a?VCL)n");??
  158. #endif ??
  159. ??????thisNALUnitEndsAccessUnit?=?True;??
  160. ????}?else?{??
  161. ????????//下一个NALU也是VCL的,还需要检查一下它们是不是属于同一个"access?unit" ??
  162. ??????//?The?next?NAL?unit?is?also?a?VLC.??We?need?to?examine?it?a?little?to?figure?out?if?it's?a?different?'access?unit'. ??
  163. ??????//?(We?use?many?of?the?criteria?described?in?section?7.4.1.2.4?of?the?H.264?specification.) ??
  164. ??????Boolean?IdrPicFlag?=?nal_unit_type?==?5;??
  165. ??????Boolean?next_IdrPicFlag?=?next_nal_unit_type?==?5;??
  166. ??????if?(next_IdrPicFlag?!=?IdrPicFlag)?{??
  167. ????????//?IdrPicFlag?differs?in?value ??
  168. #ifdef?DEBUG ??
  169. ????????fprintf(stderr,?"t(IdrPicFlag?differs?in?value)n");??
  170. #endif ??
  171. ????????thisNALUnitEndsAccessUnit?=?True;??
  172. ??????}?else?if?(next_nal_ref_idc?!=?nal_ref_idc?&&?next_nal_ref_idc*nal_ref_idc?==?0)?{??
  173. ????????//?nal_ref_idc?differs?in?value?with?one?of?the?nal_ref_idc?values?being?equal?to?0 ??
  174. #ifdef?DEBUG ??
  175. ????????fprintf(stderr,?"t(nal_ref_idc?differs?in?value?with?one?of?the?nal_ref_idc?values?being?equal?to?0)n");??
  176. #endif ??
  177. ????????thisNALUnitEndsAccessUnit?=?True;??
  178. ??????}?else?if?((nal_unit_type?==?1?||?nal_unit_type?==?2?||?nal_unit_type?==?5)??
  179. ?????????????&&?(next_nal_unit_type?==?1?||?next_nal_unit_type?==?2?||?next_nal_unit_type?==?5))?{??
  180. ????????//?Both?this?and?the?next?NAL?units?begin?with?a?"slice_header". ??
  181. ????????//?Parse?this?(for?each),?to?get?parameters?that?we?can?compare: ??
  182. ??????????
  183. ????????//?Current?NAL?unit's?"slice_header": ??
  184. ????????unsigned?frame_num,?pic_parameter_set_id,?idr_pic_id;??
  185. ????????Boolean?field_pic_flag,?bottom_field_flag;??
  186. ????????analyze_slice_header(fStartOfFrame?+?fOutputStartCodeSize,?fTo,??
  187. ?????????????????frame_num,?idr_pic_id,?field_pic_flag,?bottom_field_flag);??
  188. ??????????
  189. ????????//?Next?NAL?unit's?"slice_header": ??
  190. #ifdef?DEBUG ??
  191. ????????fprintf(stderr,?"????Next?NAL?unit's?slice_header:n");??
  192. #endif ??
  193. ????????u_int8_t?next_slice_header[NUM_NEXT_SLICE_HEADER_BYTES_TO_ANALYZE];??
  194. ????????testBytes(next_slice_header,?sizeof?next_slice_header);??
  195. ????????unsigned?next_frame_num,?next_pic_parameter_set_id,?next_idr_pic_id;??
  196. ????????Boolean?next_field_pic_flag,?next_bottom_field_flag;??
  197. ????????analyze_slice_header(next_slice_header,?&next_slice_header[sizeof?next_slice_header],?next_nal_unit_type,??
  198. ?????????????????next_frame_num,?next_idr_pic_id,?next_field_pic_flag,?next_bottom_field_flag);??
  199. ??????????
  200. ????????if?(next_frame_num?!=?frame_num)?{??
  201. ??????????//?frame_num?differs?in?value ??
  202. #ifdef?DEBUG ??
  203. ??????????fprintf(stderr,?"t(frame_num?differs?in?value)n");??
  204. #endif ??
  205. ??????????thisNALUnitEndsAccessUnit?=?True;??
  206. ????????}?else?if?(next_pic_parameter_set_id?!=?pic_parameter_set_id)?{??
  207. ??????????//?pic_parameter_set_id?differs?in?value ??
  208. #ifdef?DEBUG ??
  209. ??????????fprintf(stderr,?"t(pic_parameter_set_id?differs?in?value)n");??
  210. #endif ??
  211. ??????????thisNALUnitEndsAccessUnit?=?True;??
  212. ????????}?else?if?(next_field_pic_flag?!=?field_pic_flag)?{??
  213. ??????????//?field_pic_flag?differs?in?value ??
  214. #ifdef?DEBUG ??
  215. ??????????fprintf(stderr,?"t(field_pic_flag?differs?in?value)n");??
  216. #endif ??
  217. ??????????thisNALUnitEndsAccessUnit?=?True;??
  218. ????????}?else?if?(next_bottom_field_flag?!=?bottom_field_flag)?{??
  219. ??????????//?bottom_field_flag?differs?in?value ??
  220. #ifdef?DEBUG ??
  221. ??????????fprintf(stderr,?"t(bottom_field_flag?differs?in?value)n");??
  222. #endif ??
  223. ??????????thisNALUnitEndsAccessUnit?=?True;??
  224. ????????}?else?if?(next_IdrPicFlag?==?1?&&?next_idr_pic_id?!=?idr_pic_id)?{??
  225. ??????????//?IdrPicFlag?is?equal?to?1?for?both?and?idr_pic_id?differs?in?value ??
  226. ??????????//?Note:?We?already?know?that?IdrPicFlag?is?the?same?for?both. ??
  227. #ifdef?DEBUG ??
  228. ??????????fprintf(stderr,?"t(IdrPicFlag?is?equal?to?1?for?both?and?idr_pic_id?differs?in?value)n");??
  229. #endif ??
  230. ??????????thisNALUnitEndsAccessUnit?=?True;??
  231. ????????}??
  232. ??????}??
  233. ????}??
  234. ??????}??
  235. ????}??
  236. ??????
  237. ????if?(thisNALUnitEndsAccessUnit)?{??
  238. #ifdef?DEBUG ??
  239. ??????fprintf(stderr,?"*****This?NAL?unit?ends?the?current?access?unit*****n");??
  240. #endif ??
  241. ??????usingSource()->fPictureEndMarker?=?True;??//这里就是设置RTP打包时用到的M标志了 ??
  242. ??????++usingSource()->fPictureCount;??
  243. ??
  244. ??
  245. ??????// ??
  246. ??????//下一个NALU不再属于当前"access unit""时,才改变时间 ??
  247. ??????// ??
  248. ??????//?Note?that?the?presentation?time?for?the?next?NAL?unit?will?be?different: ??
  249. ??????struct?timeval&?nextPT?=?usingSource()->fNextPresentationTime;?//?alias 这里是引用  ??
  250. ??????nextPT?=?usingSource()->fPresentationTime;??
  251. ??????double?nextFraction?=?nextPT.tv_usec/1000000.0?+?1/usingSource()->fFrameRate;???
  252. ??????unsigned?nextSecsIncrement?=?(long)nextFraction;??
  253. ??????nextPT.tv_sec?+=?(long)nextSecsIncrement;??
  254. ??????nextPT.tv_usec?=?(long)((nextFraction?-?nextSecsIncrement)*1000000);??
  255. ????}??
  256. ????setParseState();??
  257. ??
  258. ??
  259. ????return?curFrameSize();??
  260. ??}?catch?(int?/*e*/)?{??
  261. #ifdef?DEBUG ??
  262. ????fprintf(stderr,?"H264VideoStreamParser::parse()?EXCEPTION?(This?is?normal?behavior?-?*not*?an?error)n");??
  263. #endif ??
  264. ????return?0;??//?the?parsing?got?interrupted ??
  265. ??}??
  266. }??
?? ?H264VideoStreamParser::parse()函数除了取出Frame,还对NALU中的部分参数做了解释工作。对于PPS或者SPS类型的NALU,要保存到H264VideoStreamFramer中。"access unit",在这里可以理解为一副图像,一个"access unit"可以包含多个NALU,很显示这些NALU的时间戳应该是相同的。实际上,很多时候一个"access unit"单元只包含一个NALU,这里简单多了。分析过程是根据section 7.4.1.2.4 of the H.264 specification进行的。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读