live555中關於mpeg4的處理

轉載地址:http://blog.csdn.net/gavinr/article/details/7162369


live555支持mpeg4的ES(Elemental Stream)流,相關類爲MPEGVideoStreamFramer、MPEG4ESVideoRTPSink。我想擴展其對avi格式的支持,將avi中的MPEG4數據包解析出來後,交給MPEGVideoStreamFramer進行處理。後來發現,這樣根本不行。問題在於,MPEGVideoStreamFramer處理的是嚴格的MPEG4 ES流。

    先簡單的說明一下MPEG4的ES流:

MPEG4 Elemental stream 組成如下:
VOS->VO->VOL->GOV(可選)->VOP
VOS 視覺對像序列     
VO 視覺對像
VOL 視覺對對象層
GOV 視覺對象平面組(VOP組)
VOP 視覺對象平面 

   緊跟着VOP開始的,有一個2bit 的標誌,用來表示這個Frame到底是一個 I Frame,P Frame,B Frame抑或是S Frame(GMS-VOP)
標誌如下:
00: I Frame
01: P Frame
10: B Frame
11: S Frame


起始符及結束符定義如下:

  1. #define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0  
  2. #define VISUAL_OBJECT_SEQUENCE_END_CODE   0x000001B1  
  3. #define GROUP_VOP_START_CODE              0x000001B3  
  4. #define VISUAL_OBJECT_START_CODE          0x000001B5  
  5. #define VOP_START_CODE                    0x000001B6  


    用二進制方式打開avi文件,發現只存在vop開始符,說明只存在VOP層次,而不是嚴格的ES流。可以認爲一個VOP對應着一個幀。


    後來發現,live555中實現了另一個類,MPEG4VideoStreamDiscreteFramer, 繼承自MPEG4VideoStreamFramer。它可以處理VOS,也可以處理一個個的BOV及VOP,正好可以滿足需求。
    看一下MPEG4VideoStreamDiscreteFramer對MPEG4數據的處理
  1. void MPEG4VideoStreamDiscreteFramer  
  2. ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,  
  3.                      struct timeval presentationTime,  
  4.                      unsigned durationInMicroseconds) {  
  5.   // Check that the first 4 bytes are a system code:  
  6.   if (frameSize >= 4 && fTo[0] == 0 && fTo[1] == 0 && fTo[2] == 1) {  
  7.     fPictureEndMarker = True; // Assume that we have a complete 'picture' here  
  8.     unsigned i = 3;  
  9.   
  10.   
  11.     //  
  12.     //視覺對象序列,按照完整的MPEG4 Elemental Stream進行解析  
  13.     //  
  14.     if (fTo[i] == 0xB0) { // VISUAL_OBJECT_SEQUENCE_START_CODE  
  15.       // The next byte is the "profile_and_level_indication":  
  16.       if (frameSize >= 5) fProfileAndLevelIndication = fTo[4];  
  17.   
  18.   
  19.       // The start of this frame - up to the first GROUP_VOP_START_CODE  
  20.       // or VOP_START_CODE - is stream configuration information.  Save this:  
  21.       for (i = 7; i < frameSize; ++i) {  
  22.     if ((fTo[i] == 0xB3 /*GROUP_VOP_START_CODE*/ ||  
  23.          fTo[i] == 0xB6 /*VOP_START_CODE*/)  
  24.         && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) {  
  25.       break// The configuration information ends here  
  26.     }  
  27.       }  
  28.       fNumConfigBytes = i < frameSize ? i-3 : frameSize;  
  29.       delete[] fConfigBytes; fConfigBytes = new unsigned char[fNumConfigBytes];  
  30.       for (unsigned j = 0; j < fNumConfigBytes; ++j) fConfigBytes[j] = fTo[j];  
  31.   
  32.   
  33.       // This information (should) also contain a VOL header, which we need  
  34.       // to analyze, to get "vop_time_increment_resolution" (which we need  
  35.       // - along with "vop_time_increment" - in order to generate accurate  
  36.       // presentation times for "B" frames).  
  37.       analyzeVOLHeader();  
  38.     }  
  39.   
  40.   
  41.     if (i < frameSize) {  
  42.       u_int8_t nextCode = fTo[i];  
  43.   
  44.   
  45.       //  
  46.       //VOP組  
  47.       //  
  48.       if (nextCode == 0xB3 /*GROUP_VOP_START_CODE*/) {  
  49.     // Skip to the following VOP_START_CODE (if any):  
  50.     for (i += 4; i < frameSize; ++i) {  
  51.       if (fTo[i] == 0xB6 /*VOP_START_CODE*/  
  52.           && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) {  
  53.         nextCode = fTo[i];  
  54.         break;  
  55.       }  
  56.     }  
  57.       }  
  58.   
  59.   
  60.       //  
  61.       //視覺對象平面  
  62.       //  
  63.       if (nextCode == 0xB6 /*VOP_START_CODE*/ && i+5 < frameSize) {  
  64.     ++i;  
  65.   
  66.   
  67.     // Get the "vop_coding_type" from the next byte:  
  68.     u_int8_t nextByte = fTo[i++];  
  69.     u_int8_t vop_coding_type = nextByte>>6;   //VOP開始符後的2bit,表示幀類型I/P/B/S  
  70.   
  71.   
  72.     // Next, get the "modulo_time_base" by counting the '1' bits that  
  73.     // follow.  We look at the next 32-bits only.  
  74.     // This should be enough in most cases.  
  75.     u_int32_t next4Bytes  
  76.       = (fTo[i]<<24)|(fTo[i+1]<<16)|(fTo[i+2]<<8)|fTo[i+3];  
  77.     i += 4;  
  78.     u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6);  
  79.     unsigned modulo_time_base = 0;  
  80.     u_int32_t mask = 0x80000000;  
  81.     while ((timeInfo&mask) != 0) {  
  82.       ++modulo_time_base;  
  83.       mask >>= 1;  
  84.     }  
  85.     mask >>= 2;  
  86.   
  87.   
  88.     // Then, get the "vop_time_increment".  
  89.     unsigned vop_time_increment = 0;  
  90.     // First, make sure we have enough bits left for this:  
  91.     if ((mask>>(fNumVTIRBits-1)) != 0) {  
  92.       for (unsigned i = 0; i < fNumVTIRBits; ++i) {  
  93.         vop_time_increment |= timeInfo&mask;  
  94.         mask >>= 1;  
  95.       }  
  96.       while (mask != 0) {  
  97.         vop_time_increment >>= 1;  
  98.         mask >>= 1;  
  99.       }  
  100.     }  
  101.   
  102.   
  103.     //  
  104.     //若是"B"frame, 需要修正時間時間戳  
  105.     //  
  106.     // If this is a "B" frame, then we have to tweak "presentationTime":  
  107.     if (vop_coding_type == 2/*B*/  
  108.         && (fLastNonBFramePresentationTime.tv_usec > 0 ||  
  109.         fLastNonBFramePresentationTime.tv_sec > 0)) {  
  110.       int timeIncrement  
  111.         = fLastNonBFrameVop_time_increment - vop_time_increment;  
  112.       if (timeIncrement<0) timeIncrement += vop_time_increment_resolution;  
  113.       unsigned const MILLION = 1000000;  
  114.       double usIncrement = vop_time_increment_resolution == 0 ? 0.0  
  115.         : ((double)timeIncrement*MILLION)/vop_time_increment_resolution;  
  116.       unsigned secondsToSubtract = (unsigned)(usIncrement/MILLION);  
  117.       unsigned uSecondsToSubtract = ((unsigned)usIncrement)%MILLION;  
  118.   
  119.   
  120.       presentationTime = fLastNonBFramePresentationTime;  
  121.       if ((unsigned)presentationTime.tv_usec < uSecondsToSubtract) {  
  122.         presentationTime.tv_usec += MILLION;  
  123.         if (presentationTime.tv_sec > 0) --presentationTime.tv_sec;  
  124.       }  
  125.       presentationTime.tv_usec -= uSecondsToSubtract;  
  126.       if ((unsigned)presentationTime.tv_sec > secondsToSubtract) {  
  127.         presentationTime.tv_sec -= secondsToSubtract;  
  128.       } else {  
  129.         presentationTime.tv_sec = presentationTime.tv_usec = 0;  
  130.       }  
  131.     } else {  
  132.       fLastNonBFramePresentationTime = presentationTime;  
  133.       fLastNonBFrameVop_time_increment = vop_time_increment;  
  134.     }  
  135.       }  
  136.     }  
  137.   }  
  138.   
  139.   
  140.   // Complete delivery to the client:  
  141.   fFrameSize = frameSize;  
  142.   fNumTruncatedBytes = numTruncatedBytes;  
  143.   fPresentationTime = presentationTime;  
  144.   fDurationInMicroseconds = durationInMicroseconds;  
  145.   afterGetting(this);  
  146. }  


上面的代碼,其實只完成一個功能,就是噹噹前VOP爲B幀時,調整時間戳。


最後關注一下,MPEG4 ES流時間戳的處理。 在處理MPEG4 的ES流時,使用MPEG4VideoStreamFramer,作爲source。使用分析器MPEG4VideoStreamParser,對完整的MPEG4 Elemental Stream進行分析,主要是解析出其中的時間信息。

  1. void MPEGVideoStreamFramer::continueReadProcessing() {  
  2.   unsigned acquiredFrameSize = fParser->parse();  
  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.     //  
  14.     //根據幀計數及幀率計算幀的持續時間  
  15.     //  
  16.     // Compute "fDurationInMicroseconds" now:  
  17.     fDurationInMicroseconds  
  18.       = (fFrameRate == 0.0 || ((int)fPictureCount) < 0) ? 0  
  19.       : (unsigned)((fPictureCount*1000000)/fFrameRate);  
  20.   
  21.   
  22.     fPictureCount = 0;  
  23.   
  24.   
  25.     // Call our own 'after getting' function.  Because we're not a 'leaf'  
  26.     // source, we can call this directly, without risking infinite recursion.  
  27.     afterGetting(this);  
  28.   } else {  
  29.     // We were unable to parse a complete frame from the input, because:  
  30.     // - we had to read more data from the source stream, or  
  31.     // - the source stream has ended.  
  32.   }  
  33. }  


計算fDurationInMicroseconds需要frame rate參數fFrameRate, 它是通過分析VOL頭確定的


  1. void MPEG4VideoStreamParser::analyzeVOLHeader() {  
  2.     //  
  3.     //從VOL中解析出時間信息  
  4.     //  
  5.   // Extract timing information (in particular,  
  6.   // "vop_time_increment_resolution") from the VOL Header:  
  7. ...  
  8.   do {  
  9.   
  10.   
  11.       ...  
  12.   
  13.   
  14.     // Use "vop_time_increment_resolution" as the 'frame rate'  
  15.     // (really, 'tick rate'):  
  16.     usingSource()->fFrameRate = (double)vop_time_increment_resolution;  //幀率  
  17.   
  18.   
  19.     return;  
  20.   } while (0);  
  21.   
  22. ...  
  23. }  



發佈了0 篇原創文章 · 獲贊 9 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章