shithub: openh264

Download patch

ref: b304687197cf59ed24ee6fc4756f7f91b72f613f
parent: 5b12578960b1a9cbb009a4ed2ffb41459345ec71
parent: 06b8e1abb7b13367ef6ad6f385197b94dfe647f9
author: sijchen <sijchen@cisco.com>
date: Thu Mar 5 04:24:30 EST 2015

Merge pull request #1833 from huili2/parseonly_au_incomplete_input_final

allow slice-level data come in for parse only

--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -366,6 +366,9 @@
 
 //for Parse only
   bool bParseOnly;
+  bool bFramePending;
+  int32_t iNalNum;
+  int32_t iNalLenInByte[MAX_NAL_UNITS_IN_LAYER];
   SSpsBsInfo sSpsBsInfo [MAX_SPS_COUNT];
   SSpsBsInfo sSubsetSpsBsInfo [MAX_PPS_COUNT];
   SPpsBsInfo sPpsBsInfo [MAX_PPS_COUNT];
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -72,6 +72,79 @@
     }
   }
 
+  if (pCtx->bParseOnly) { //should exit for parse only to prevent access NULL pDstInfo
+    PAccessUnit pCurAu = pCtx->pAccessUnitList;
+    static bool bFirstIDR = true;
+    if (dsErrorFree == pCtx->iErrorCode) { //correct decoding, add to data buffer
+      SParserBsInfo* pParser = pCtx->pParserBsInfo;
+      SNalUnit* pCurNal = NULL;
+      int32_t iTotalNalLen = 0;
+      int32_t iNalLen = 0;
+      int32_t iNum = 0;
+      while (iNum < pParser->iNalNum) {
+        iTotalNalLen += pParser->iNalLenInByte[iNum++];
+      }
+      uint8_t* pDstBuf = pParser->pDstBuff + iTotalNalLen;
+      int32_t iIdx = pCurAu->uiStartPos;
+      int32_t iEndIdx = pCurAu->uiEndPos;
+      uint8_t* pNalBs = NULL;
+      pParser->uiOutBsTimeStamp = (pCurAu->pNalUnitsList [iIdx]) ? pCurAu->pNalUnitsList [iIdx]->uiTimeStamp : 0;
+      //pParser->iNalNum = 0;
+      pParser->iSpsWidthInPixel = (pCtx->pSps->iMbWidth << 4);
+      pParser->iSpsHeightInPixel = (pCtx->pSps->iMbHeight << 4);
+
+      if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR
+        if (bFirstIDR) { //add required sps/pps
+          bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType);
+          SSpsBsInfo* pSpsBs = NULL;
+          SPpsBsInfo* pPpsBs = NULL;
+          int32_t iSpsId = pCtx->pSps->iSpsId;
+          int32_t iPpsId = pCtx->pPps->iPpsId;
+          pCtx->bParamSetsLostFlag = false;
+          //find required sps, pps and write into dst buff
+          pSpsBs = bSubSps ? &pCtx->sSubsetSpsBsInfo [iSpsId] : &pCtx->sSpsBsInfo [iSpsId];
+          memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen);
+          pParser->iNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
+          pCtx->iNalLenInByte[pCtx->iNalNum ++] = pSpsBs->uiSpsBsLen;
+          pDstBuf += pSpsBs->uiSpsBsLen;
+          pPpsBs = &pCtx->sPpsBsInfo [iPpsId];
+          memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen);
+          pParser->iNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
+          pDstBuf += pPpsBs->uiPpsBsLen;
+          bFirstIDR = false;
+        }
+      } else { //IDR required SPS, PPS
+        bFirstIDR = true;
+      }
+      //then VCL data re-write
+      while (iIdx <= iEndIdx) {
+        pCurNal = pCurAu->pNalUnitsList [iIdx ++];
+        iNalLen = pCurNal->sNalData.sVclNal.iNalLength;
+        pNalBs = pCurNal->sNalData.sVclNal.pNalPos;
+        pParser->iNalLenInByte [pParser->iNalNum ++] = iNalLen;
+        memcpy (pDstBuf, pNalBs, iNalLen);
+        pDstBuf += iNalLen;
+      }
+      if (pCtx->iTotalNumMbRec == kiTotalNumMbInCurLayer) { //frame complete
+        pCtx->iTotalNumMbRec = 0;
+        pCtx->bFramePending = false;
+      } else if (pCtx->iTotalNumMbRec != 0) { //frame incomplete
+        pCtx->bFramePending = true;
+        pCtx->pDec->bIsComplete = false;
+        pCtx->iErrorCode |= dsFramePending;
+        return -1;
+        //pCtx->pParserBsInfo->iNalNum = 0;
+      }
+    } else { //error
+      pCtx->pParserBsInfo->uiOutBsTimeStamp = 0;
+      pCtx->pParserBsInfo->iNalNum = 0;
+      pCtx->pParserBsInfo->iSpsWidthInPixel = 0;
+      pCtx->pParserBsInfo->iSpsHeightInPixel = 0;
+      return -1;
+    }
+    return 0;
+  }
+
   if (pCtx->iTotalNumMbRec != kiTotalNumMbInCurLayer) {
     WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
              "DecodeFrameConstruction(): iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d ",
@@ -87,15 +160,6 @@
 
   pCtx->iTotalNumMbRec = 0;
 
-  if (pCtx->bParseOnly) { //should exit for parse only to prevent access NULL pDstInfo
-    if (bFrameCompleteFlag)
-      return 0;
-    else { //incomplete frame
-      pCtx->pDec->bIsComplete = false;
-      return -1;
-    }
-  }
-
   //////output:::normal path
   pDstInfo->uiOutYuvTimeStamp = pPic->uiTimeStamp;
   ppDst[0]      = pPic->pData[0];
@@ -401,6 +465,18 @@
   pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead;
   pCtx->sRawData.pEnd = pCtx->sRawData.pHead + pCtx->iMaxBsBufferSizeInByte;
   if (pCtx->bParseOnly) {
+    pCtx->pParserBsInfo = static_cast<SParserBsInfo*> (WelsMallocz (sizeof (SParserBsInfo), "pCtx->pParserBsInfo"));
+    if (pCtx->pParserBsInfo == NULL) {
+      return ERR_INFO_OUT_OF_MEMORY;
+    }
+    memset (pCtx->pParserBsInfo, 0, sizeof (SParserBsInfo));
+    pCtx->pParserBsInfo->pDstBuff = static_cast<uint8_t*> (WelsMallocz (MAX_ACCESS_UNIT_CAPACITY * sizeof (uint8_t),
+                                    "pCtx->pParserBsInfo->pDstBuff"));
+    if (pCtx->pParserBsInfo->pDstBuff == NULL) {
+      return ERR_INFO_OUT_OF_MEMORY;
+    }
+    memset (pCtx->pParserBsInfo->pDstBuff, 0, MAX_ACCESS_UNIT_CAPACITY * sizeof (uint8_t));
+
     if ((pCtx->sSavedData.pHead = static_cast<uint8_t*> (WelsMallocz (pCtx->iMaxBsBufferSizeInByte,
                                   "pCtx->sSavedData.pHead"))) == NULL) {
       return ERR_INFO_OUT_OF_MEMORY;
@@ -506,15 +582,24 @@
   pCtx->sRawData.pEnd                 = NULL;
   pCtx->sRawData.pStartPos	        = NULL;
   pCtx->sRawData.pCurPos             = NULL;
-  if (pCtx->sSavedData.pHead) {
-    WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData->pHead");
+  if (pCtx->bParseOnly) {
+    if (pCtx->sSavedData.pHead) {
+      WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData->pHead");
+    }
+    pCtx->sSavedData.pHead                = NULL;
+    pCtx->sSavedData.pEnd                 = NULL;
+    pCtx->sSavedData.pStartPos	        = NULL;
+    pCtx->sSavedData.pCurPos              = NULL;
+    if (pCtx->pParserBsInfo) {
+      if (pCtx->pParserBsInfo->pDstBuff) {
+        WelsFree (pCtx->pParserBsInfo->pDstBuff, "pCtx->pParserBsInfo->pDstBuff");
+        pCtx->pParserBsInfo->pDstBuff = NULL;
+      }
+      WelsFree (pCtx->pParserBsInfo, "pCtx->pParserBsInfo");
+      pCtx->pParserBsInfo = NULL;
+    }
   }
-  pCtx->sSavedData.pHead                = NULL;
-  pCtx->sSavedData.pEnd                 = NULL;
-  pCtx->sSavedData.pStartPos	        = NULL;
-  pCtx->sSavedData.pCurPos              = NULL;
 }
-
 /*
  *	DecodeNalHeaderExt
  *	Trigger condition: NAL_UNIT_TYPE = NAL_UNIT_PREFIX or NAL_UNIT_CODED_SLICE_EXT
@@ -1864,57 +1949,6 @@
 
   iErr = DecodeCurrentAccessUnit (pCtx, ppDst, pDstInfo);
 
-  if (pCtx->bParseOnly) {
-    if ((dsErrorFree == pCtx->iErrorCode) && (iErr == 0)) { //frame complete, output
-      SParserBsInfo* pParser = pCtx->pParserBsInfo;
-      uint8_t* pDstBuf = pParser->pDstBuff;
-      SNalUnit* pCurNal = NULL;
-      int32_t iNalLen = 0;
-      int32_t iIdx = pCurAu->uiStartPos;
-      int32_t iEndIdx = pCurAu->uiEndPos;
-      uint8_t* pNalBs = NULL;
-      pParser->uiOutBsTimeStamp = (pCurAu->pNalUnitsList [iIdx]) ? pCurAu->pNalUnitsList [iIdx]->uiTimeStamp : 0;
-      pParser->iNalNum = 0;
-      pParser->iSpsWidthInPixel = (pCtx->pSps->iMbWidth << 4);
-      pParser->iSpsHeightInPixel = (pCtx->pSps->iMbHeight << 4);
-
-      if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR
-        bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType);
-        SSpsBsInfo* pSpsBs = NULL;
-        SPpsBsInfo* pPpsBs = NULL;
-        int32_t iSpsId = pCtx->pSps->iSpsId;
-        int32_t iPpsId = pCtx->pPps->iPpsId;
-        pCtx->bParamSetsLostFlag = false;
-        //find required sps, pps and write into dst buff
-        pSpsBs = bSubSps ? &pCtx->sSubsetSpsBsInfo [iSpsId] : &pCtx->sSpsBsInfo [iSpsId];
-        memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen);
-        pParser->iNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
-        pDstBuf += pSpsBs->uiSpsBsLen;
-        pPpsBs = &pCtx->sPpsBsInfo [iPpsId];
-        memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen);
-        pParser->iNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
-        pDstBuf += pPpsBs->uiPpsBsLen;
-      } //IDR required SPS, PPS
-      //then VCL data re-write
-      while (iIdx <= iEndIdx) {
-        pCurNal = pCurAu->pNalUnitsList [iIdx ++];
-        iNalLen = pCurNal->sNalData.sVclNal.iNalLength;
-        pNalBs = pCurNal->sNalData.sVclNal.pNalPos;
-        pParser->iNalLenInByte [pParser->iNalNum ++] = iNalLen;
-        memcpy (pDstBuf, pNalBs, iNalLen);
-        pDstBuf += iNalLen;
-      }
-    } else { //error
-      pCtx->pParserBsInfo->uiOutBsTimeStamp = 0;
-      pCtx->pParserBsInfo->iNalNum = 0;
-      pCtx->pParserBsInfo->iSpsWidthInPixel = 0;
-      pCtx->pParserBsInfo->iSpsHeightInPixel = 0;
-      if (dsErrorFree == pCtx->iErrorCode) { //frame not complete
-        pCtx->iErrorCode |= dsFramePending;
-      }
-    }
-  }
-
   WelsDecodeAccessUnitEnd (pCtx);
 
   if (ERR_NONE != iErr) {
@@ -2056,6 +2090,8 @@
 
     if (pCtx->pDec == NULL) {
       pCtx->pDec = PrefetchPic (pCtx->pPicBuff[0]);
+      if (pCtx->iTotalNumMbRec != 0)
+        pCtx->iTotalNumMbRec = 0;
 
       if (NULL == pCtx->pDec) {
         WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
@@ -2326,6 +2362,8 @@
       if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) {
         MarkECFrameAsRef (pCtx);
       }
+    } else if (pCtx->bParseOnly) { //clear parse only internal data status
+      pCtx->pParserBsInfo->iNalNum = 0;
     } else {
       if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) {
         pCtx->pDec = NULL;
--- a/codec/decoder/core/src/pic_queue.cpp
+++ b/codec/decoder/core/src/pic_queue.cpp
@@ -82,19 +82,25 @@
   iLumaSize	= iPicWidth * iPicHeight;
   iChromaSize	= iPicChromaWidth * iPicChromaHeight;
 
-  pPic->pBuffer[0]	= static_cast<uint8_t*> (WelsMallocz (iLumaSize /* luma */
-                      + (iChromaSize << 1) /* Cb,Cr */, "_pic->buffer[0]"));
-  memset (pPic->pBuffer[0], 128, (iLumaSize + (iChromaSize << 1)));
+  if (pCtx->bParseOnly) {
+    pPic->pBuffer[0] = pPic->pBuffer[1] = pPic->pBuffer[2] = NULL;
+    pPic->pData[0] = pPic->pData[1] = pPic->pData[2] = NULL;
+    pPic->iLinesize[0] = iPicWidth;
+    pPic->iLinesize[1] = pPic->iLinesize[2] = iPicChromaWidth;
+  } else {
+    pPic->pBuffer[0]	= static_cast<uint8_t*> (WelsMallocz (iLumaSize /* luma */
+                        + (iChromaSize << 1) /* Cb,Cr */, "_pic->buffer[0]"));
+    memset (pPic->pBuffer[0], 128, (iLumaSize + (iChromaSize << 1)));
 
-  WELS_VERIFY_RETURN_PROC_IF (NULL, NULL == pPic->pBuffer[0], FreePicture (pPic));
-  pPic->iLinesize[0] = iPicWidth;
-  pPic->iLinesize[1] = pPic->iLinesize[2] = iPicChromaWidth;
-  pPic->pBuffer[1]	= pPic->pBuffer[0] + iLumaSize;
-  pPic->pBuffer[2]	= pPic->pBuffer[1] + iChromaSize;
-  pPic->pData[0]	= pPic->pBuffer[0] + (1 + pPic->iLinesize[0]) * PADDING_LENGTH;
-  pPic->pData[1]	= pPic->pBuffer[1] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[1]) * PADDING_LENGTH) >> 1);
-  pPic->pData[2]	= pPic->pBuffer[2] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[2]) * PADDING_LENGTH) >> 1);
-
+    WELS_VERIFY_RETURN_PROC_IF (NULL, NULL == pPic->pBuffer[0], FreePicture (pPic));
+    pPic->iLinesize[0] = iPicWidth;
+    pPic->iLinesize[1] = pPic->iLinesize[2] = iPicChromaWidth;
+    pPic->pBuffer[1]	= pPic->pBuffer[0] + iLumaSize;
+    pPic->pBuffer[2]	= pPic->pBuffer[1] + iChromaSize;
+    pPic->pData[0]	= pPic->pBuffer[0] + (1 + pPic->iLinesize[0]) * PADDING_LENGTH;
+    pPic->pData[1]	= pPic->pBuffer[1] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[1]) * PADDING_LENGTH) >> 1);
+    pPic->pData[2]	= pPic->pBuffer[2] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[2]) * PADDING_LENGTH) >> 1);
+  }
   pPic->iPlanes		= 3;	// yv12 in default
   pPic->iWidthInPixel	= kiPicWidth;
   pPic->iHeightInPixel = kiPicHeight;
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -574,7 +574,10 @@
 
   m_pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding.
   m_pDecContext->eErrorConMethod = ERROR_CON_DISABLE; //add protection to disable EC here.
-  m_pDecContext->pParserBsInfo = pDstInfo;
+  if (!m_pDecContext->bFramePending) { //frame complete
+    m_pDecContext->pParserBsInfo->iNalNum = 0;
+    memset (m_pDecContext->pParserBsInfo->iNalLenInByte, 0, MAX_NAL_UNITS_IN_LAYER);
+  }
   pDstInfo->iNalNum = 0;
   pDstInfo->iSpsWidthInPixel = pDstInfo->iSpsHeightInPixel = 0;
   if (pDstInfo) {
@@ -584,6 +587,10 @@
     m_pDecContext->uiTimeStamp = 0;
   }
   WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, NULL, NULL, pDstInfo);
+  if (!m_pDecContext->bFramePending && m_pDecContext->pParserBsInfo->iNalNum) {
+    memcpy (pDstInfo, m_pDecContext->pParserBsInfo, sizeof (SParserBsInfo));
+  }
+
   m_pDecContext->bInstantDecFlag = false; //reset no-delay flag
 
   return (DECODING_STATE) m_pDecContext->iErrorCode;
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -2461,7 +2461,6 @@
 const uint32_t kiHeight = 96; //DO NOT CHANGE!
 const uint32_t kiFrameRate = 12; //DO NOT CHANGE!
 const uint32_t kiFrameNum = 100; //DO NOT CHANGE!
-const uint32_t kiMaxBsSize = 10000000; //DO NOT CHANGE!
 const char* pHashStr[] = { //DO NOT CHANGE!
   "d1c255a57aa2c5e1192a90680c00e6ee3e73fe59",
   "f350001c333902029800bd291fbed915a4bdf19a",
@@ -2487,9 +2486,6 @@
     int rv = decoder_->Initialize (&decParam);
     ASSERT_EQ (0, rv);
     memset (&BsInfo_, 0, sizeof (SParserBsInfo));
-    BsInfo_.pDstBuff = NULL;
-    BsInfo_.pDstBuff = new unsigned char [kiMaxBsSize];
-    ASSERT_TRUE (BsInfo_.pDstBuff != NULL);
     fYuv_ = fopen ("./res/CiscoVT2people_160x96_6fps.yuv", "rb");
     ASSERT_TRUE (fYuv_ != NULL);
     iWidth_ = kiWidth;
@@ -2497,10 +2493,6 @@
   }
   void TearDown() {
     EncodeDecodeTestBase::TearDown();
-    if (BsInfo_.pDstBuff) {
-      delete[] BsInfo_.pDstBuff;
-      BsInfo_.pDstBuff = NULL;
-    }
     fclose (fYuv_);
   }
 
@@ -3449,7 +3441,7 @@
     uint8_t* ptr = buf_.data();
     uint8_t uiVal = rand() % 256;
     for (int i = 0; i < frameSize; i++) {
-      ptr[i] = bAllRandom? (rand() % 256) :uiVal;
+      ptr[i] = bAllRandom ? (rand() % 256) : uiVal;
     }
     int rv = encoder_->EncodeFrame (&EncPic, &info);
     if (0 == iCheckTypeIndex)
@@ -3464,9 +3456,9 @@
 
 TEST_P (EncodeTestAPI, SetEncOptionSize) {
   EncodeOptionParam p = GetParam();
-  FILE * pFile = NULL;
-  if (p.sFileSave != NULL && strlen(p.sFileSave) > 0) {
-    pFile = fopen(p.sFileSave, "wb");
+  FILE* pFile = NULL;
+  if (p.sFileSave != NULL && strlen (p.sFileSave) > 0) {
+    pFile = fopen (p.sFileSave, "wb");
   }
   memset (&param_, 0, sizeof (SEncParamExt));
   encoder_->GetDefaultParams (&param_);
@@ -3502,16 +3494,16 @@
   unsigned char* pData[3] = { NULL };
   while (iIdx <= p.iNumframes) {
     EncodeOneFrameRandom (0, p.bAllRandom);
-    encToDecData(info, iLen);
-    if( pFile ) {
+    encToDecData (info, iLen);
+    if (pFile) {
       fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, pFile);
       fflush (pFile);
     }
-    memset(&dstBufInfo_, 0, sizeof(SBufferInfo));
-    if(iLen && p.bTestDecoder) {
-      rv = decoder_->DecodeFrameNoDelay(info.sLayerInfo[0].pBsBuf, iLen, pData, &dstBufInfo_);
-      ASSERT_EQ(rv, 0);
-      ASSERT_EQ(dstBufInfo_.iBufferStatus, 1);
+    memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+    if (iLen && p.bTestDecoder) {
+      rv = decoder_->DecodeFrameNoDelay (info.sLayerInfo[0].pBsBuf, iLen, pData, &dstBufInfo_);
+      ASSERT_EQ (rv, 0);
+      ASSERT_EQ (dstBufInfo_.iBufferStatus, 1);
     }
     int iLayer = 0;
     while (iLayer < info.iLayerNum) {
@@ -3529,7 +3521,7 @@
     }
     iIdx++;
   }
-  if( pFile ) {
+  if (pFile) {
     fclose (pFile);
   }
 }