shithub: openh264

Download patch

ref: 9b0322330c9ef973d1960892f6a9de391caf716f
parent: 75aa8e564ca011137f2331f2c0bfaf8691688374
parent: bc2c4b0db0488cbe29b4286c8b2dfae519be080f
author: sijchen <sijchen@cisco.com>
date: Fri Apr 18 06:57:40 EDT 2014

Merge pull request #709 from huili2/ec_mb_check

add EC frame/slice copy.

--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -112,6 +112,7 @@
 //enuerate the types of error concealment methods
 typedef enum {
   ERROR_CON_DISABLE = 0,
+  ERROR_CON_FRAME_COPY,
   ERROR_CON_SLICE_COPY,
 } ERROR_CON_IDC;
 
--- a/codec/console/dec/src/h264dec.cpp
+++ b/codec/console/dec/src/h264dec.cpp
@@ -199,6 +199,8 @@
     pDecoder->GetOption (DECODER_OPTION_VCL_NAL, &iFeedbackVclNalInAu);
     int32_t iFeedbackTidInAu;
     pDecoder->GetOption (DECODER_OPTION_TEMPORAL_ID, &iFeedbackTidInAu);
+    int32_t iErrorConMethod = ERROR_CON_SLICE_COPY;
+    pDecoder->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iErrorConMethod);
 //~end for
 
     iStart = WelsTime();
--- a/codec/decoder/core/inc/dec_frame.h
+++ b/codec/decoder/core/inc/dec_frame.h
@@ -74,6 +74,7 @@
   int8_t (*pNzcRs)[24];
   int8_t*  pResidualPredFlag;
   int8_t*  pInterPredictionDoneFlag;
+  bool*    pMbCorrectlyDecodedFlag;
   int16_t (*pScaledTCoeff)[MB_COEFF_LIST_SIZE];
   int8_t (*pIntraPredMode)[8];  //0~3 top4x4 ; 4~6 left 4x4; 7 intra16x16
   int8_t (*pIntra4x4FinalMode)[MB_BLOCK4x4_NUM];
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -211,6 +211,7 @@
     int32_t* pSliceIdc[LAYER_NUM_EXCHANGEABLE];		// using int32_t for slice_idc
     int8_t*  pResidualPredFlag[LAYER_NUM_EXCHANGEABLE];
     int8_t*  pInterPredictionDoneFlag[LAYER_NUM_EXCHANGEABLE];
+    bool*    pMbCorrectlyDecodedFlag[LAYER_NUM_EXCHANGEABLE];
     uint32_t iMbWidth;
     uint32_t iMbHeight;
   } sMb;
@@ -279,6 +280,7 @@
 #endif
   bool       bNewSeqBegin;
   int32_t iErrorConMethod; //
+  PPicture pPreviousDecodedPictureInDpb; //pointer to previously decoded picture in DPB for error concealment
   PGetIntraPredFunc pGetI16x16LumaPredFunc[7];		//h264_predict_copy_16x16;
   PGetIntraPredFunc pGetI4x4LumaPredFunc[14];		// h264_predict_4x4_t
   PGetIntraPredFunc pGetIChromaPredFunc[7];		// h264_predict_8x8_t
@@ -293,7 +295,7 @@
 
   /* For Block */
   SBlockFunc          sBlockFunc;
-  /* For EC */
+
   int32_t iCurSeqIntervalTargetDependId;
   int32_t iCurSeqIntervalMaxPicWidth;
   int32_t iCurSeqIntervalMaxPicHeight;
--- a/codec/decoder/core/inc/error_concealment.h
+++ b/codec/decoder/core/inc/error_concealment.h
@@ -54,7 +54,7 @@
 bool NeedErrorCon (PWelsDecoderContext pCtx);
 // ImplementErrorConceal
 // Do actual error concealment
-int32_t ImplementErrorCon (PWelsDecoderContext pCtx);
+void ImplementErrorCon (PWelsDecoderContext pCtx);
 
 } // namespace WelsDec
 
--- a/codec/decoder/core/src/decode_slice.cpp
+++ b/codec/decoder/core/src/decode_slice.cpp
@@ -394,6 +394,7 @@
     }
 
     ++pSlice->iTotalMbInCurSlice;
+    pCurLayer->pMbCorrectlyDecodedFlag[iNextMbXyIndex] = true;
 
     if (pSliceHeader->pPps->uiNumSliceGroups > 1) {
       iNextMbXyIndex = FmoNextMb (pFmo, iNextMbXyIndex);
--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -164,7 +164,8 @@
   pCtx->pPicBuff[LIST_1]		= NULL;
 
   pCtx->bAvcBasedFlag			= true;
-  pCtx->iErrorConMethod = ERROR_CON_DISABLE;
+  pCtx->iErrorConMethod = ERROR_CON_SLICE_COPY;
+  pCtx->pPreviousDecodedPictureInDpb = NULL;
 
 }
 
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -54,12 +54,21 @@
   const int32_t kiHeight = pCurDq->iMbHeight << 4;
 
   const int32_t kiTotalNumMbInCurLayer = pCurDq->iMbWidth * pCurDq->iMbHeight;
+  bool bFrameCompleteFlag = true;
 
   if (pCtx->iTotalNumMbRec != kiTotalNumMbInCurLayer) {
+    if ((pCtx->iTotalNumMbRec != 0) && (I_SLICE == pCurDq->sLayerInfo.sSliceInLayer.eSliceType)) { //TODO should be IDR instead of I_SLICE!
+      memcpy (& (pCtx->sFrameCrop), & (pCurDq->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.pSps->sFrameCrop), sizeof (SPosOffset));
+#ifdef LONG_TERM_REF
+      pCtx->bParamSetsLostFlag = false;
+#else
+      pCtx->bReferenceLostAtT0Flag = false;
+#endif //LONG_TERM_REF
+    }
     WelsLog (pCtx, WELS_LOG_WARNING,
              "DecodeFrameConstruction():::iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d \n",
              pCtx->iTotalNumMbRec, kiTotalNumMbInCurLayer, pCurDq->iMbWidth, pCurDq->iMbHeight);
-    return -1;
+    bFrameCompleteFlag = false; //return later after output buffer is done
   }
 #ifdef NO_WAITING_AU
   pCtx->iTotalNumMbRec = 0;
@@ -99,6 +108,14 @@
   ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset  * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
   pDstInfo->iBufferStatus = 1;
 
+  if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete
+    pDstInfo->iBufferStatus = (int32_t) bFrameCompleteFlag;
+
+  if (!bFrameCompleteFlag) {
+    pCtx->iErrorCode |= dsBitstreamError;
+    return -1;
+  }
+
   return 0;
 }
 
@@ -955,6 +972,8 @@
     pCtx->sMb.pInterPredictionDoneFlag[i] = (int8_t*) WelsMalloc (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
         int8_t), "pCtx->sMb.pInterPredictionDoneFlag[]");
 
+    pCtx->sMb.pMbCorrectlyDecodedFlag[i] = (bool*) WelsMalloc (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (bool), "pCtx->sMb.pMbCorrectlyDecodedFlag[]");
+
     // check memory block valid due above allocated..
     WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY,
                            ((NULL == pCtx->sMb.pMbType[i]) ||
@@ -972,7 +991,8 @@
                             (NULL == pCtx->sMb.pSubMbType[i]) ||
                             (NULL == pCtx->sMb.pSliceIdc[i]) ||
                             (NULL == pCtx->sMb.pResidualPredFlag[i]) ||
-                            (NULL == pCtx->sMb.pInterPredictionDoneFlag[i])
+                            (NULL == pCtx->sMb.pInterPredictionDoneFlag[i]) ||
+                            (NULL == pCtx->sMb.pMbCorrectlyDecodedFlag[i])
                            )
                           )
 
@@ -1100,6 +1120,12 @@
 
       pCtx->sMb.pInterPredictionDoneFlag[i] = NULL;
     }
+
+    if (pCtx->sMb.pMbCorrectlyDecodedFlag[i]) {
+      WelsFree (pCtx->sMb.pMbCorrectlyDecodedFlag[i], "pCtx->sMb.pMbCorrectlyDecodedFlag[]");
+      pCtx->sMb.pMbCorrectlyDecodedFlag[i] = NULL;
+    }
+
     WelsFree (pDq, "pDq");
 
     pDq = NULL;
@@ -1560,8 +1586,6 @@
   pCtx->bNewSeqBegin = false;
   if (ERR_NONE != iErr) {
     WelsLog (pCtx, WELS_LOG_INFO, "returned error from decoding:[0x%x]\n", iErr);
-
-    pDstInfo->iBufferStatus = 0;
     return iErr;
   }
 
@@ -1651,6 +1675,7 @@
     pCurDq->pSubMbType      = pCtx->sMb.pSubMbType[0];
     pCurDq->pInterPredictionDoneFlag = pCtx->sMb.pInterPredictionDoneFlag[0];
     pCurDq->pResidualPredFlag = pCtx->sMb.pResidualPredFlag[0];
+    pCurDq->pMbCorrectlyDecodedFlag = pCtx->sMb.pMbCorrectlyDecodedFlag[0];
   }
 }
 
@@ -1725,6 +1750,7 @@
     if (pCtx->iTotalNumMbRec == 0) { //Picture start to decode
       for (int32_t i = 0; i < LAYER_NUM_EXCHANGEABLE; ++ i)
         memset (pCtx->sMb.pSliceIdc[i], 0xff, (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int32_t)));
+      memset (pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag, 0, pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight);
     }
     GetI4LumaIChromaAddrTable (pCtx->iDecBlockOffsetArray, pCtx->pDec->iLinesize[0], pCtx->pDec->iLinesize[1]);
 
@@ -1796,15 +1822,16 @@
                      "referencing pictures lost due frame gaps exist, prev_frame_num: %d, curr_frame_num: %d\n", pCtx->iPrevFrameNum,
                      pSh->iFrameNum);
 
+            pCtx->iErrorCode |= dsRefLost;
+            if (pCtx->iErrorConMethod == ERROR_CON_DISABLE) {
 #ifdef LONG_TERM_REF
-            pCtx->bParamSetsLostFlag = true;
+              pCtx->bParamSetsLostFlag = true;
 #else
-            pCtx->bReferenceLostAtT0Flag = true;
+              pCtx->bReferenceLostAtT0Flag = true;
 #endif
-            ResetParameterSetsState (pCtx);
-
-            pCtx->iErrorCode |= dsRefLost;
-            return ERR_INFO_REFERENCE_PIC_LOST;
+              ResetParameterSetsState (pCtx);
+              return ERR_INFO_REFERENCE_PIC_LOST;
+            }
           }
         }
 
@@ -1875,6 +1902,9 @@
 #endif
 
       }
+
+      pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC
+
       if (uiNalRefIdc > 0) {
         iRet = WelsMarkAsRef (pCtx);
         if (iRet != ERR_NONE) {
--- a/codec/decoder/core/src/error_concealment.cpp
+++ b/codec/decoder/core/src/error_concealment.cpp
@@ -66,33 +66,130 @@
 
 //Do error concealment using frame copy method
 void DoErrorConFrameCopy (PWelsDecoderContext pCtx) {
-  //TODO
+  PPicture pDstPic = pCtx->pDec;
+  PPicture pSrcPic = pCtx->pPreviousDecodedPictureInDpb;
+  uint32_t uiHeightInPixelY = (pCtx->pSps->iMbHeight) << 4;
+  int32_t iStrideY = pDstPic->iLinesize[0];
+  int32_t iStrideUV = pDstPic->iLinesize[1];
+  if (pSrcPic == NULL) { //no ref pic, assign specific data to picture
+    memset (pDstPic->pData[0], 0, uiHeightInPixelY * iStrideY);
+    memset (pDstPic->pData[1], 0, (uiHeightInPixelY >> 1) * iStrideUV);
+    memset (pDstPic->pData[2], 0, (uiHeightInPixelY >> 1) * iStrideUV);
+  } else { //has ref pic here
+    memcpy (pDstPic->pData[0], pSrcPic->pData[0], uiHeightInPixelY * iStrideY);
+    memcpy (pDstPic->pData[1], pSrcPic->pData[1], (uiHeightInPixelY >> 1) * iStrideUV);
+    memcpy (pDstPic->pData[2], pSrcPic->pData[2], (uiHeightInPixelY >> 1) * iStrideUV);
+  }
 }
 
 
 //Do error concealment using slice copy method
 void DoErrorConSliceCopy (PWelsDecoderContext pCtx) {
-  //TODO
+  int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
+  int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
+  PPicture pDstPic = pCtx->pDec;
+  PPicture pSrcPic = pCtx->pPreviousDecodedPictureInDpb;
+
+  //uint8_t *pDstData[3], *pSrcData[3];
+  bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
+
+  //Do slice copy late
+  int32_t iMbXyIndex;
+  uint8_t* pSrcData, *pDstData;
+  uint32_t iSrcStride; // = pSrcPic->iLinesize[0];
+  uint32_t iDstStride = pDstPic->iLinesize[0];
+  for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
+    for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
+      iMbXyIndex = iMbY * iMbWidth + iMbX;
+      if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
+        if (pSrcPic != NULL) {
+          iSrcStride = pSrcPic->iLinesize[0];
+          //Y component
+          pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;;
+          pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16;
+          pCtx->sCopyFunc.pCopyLumaFunc (pDstData, iDstStride, pSrcData, iSrcStride);
+          //U component
+          pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
+          pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
+          //V component
+          pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
+          pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
+        } else { //pSrcPic == NULL
+          //Y component
+          pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
+          for (int32_t i = 0; i < 16; ++i) {
+            memset (pDstData, 0, 16);
+            pDstData += iDstStride;
+          }
+          //U component
+          pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 0, 8);
+            pDstData += iDstStride / 2;
+          }
+          //V component
+          pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 0, 8);
+            pDstData += iDstStride / 2;
+          }
+        } //
+      } //!pMbCorrectlyDecodedFlag[iMbXyIndex]
+    } //iMbX
+  } //iMbY
 }
 
+
 //Mark erroneous frame as Ref Pic into DPB
 int32_t MarkECFrameAsRef (PWelsDecoderContext pCtx) {
-  //TODO
+  int32_t iRet = WelsMarkAsRef (pCtx);
+  if (iRet != ERR_NONE) {
+    pCtx->pDec = NULL;
+    return iRet;
+  }
+  ExpandReferencingPicture (pCtx->pDec, pCtx->sExpandPicFunc.pExpandLumaPicture,
+                            pCtx->sExpandPicFunc.pExpandChromaPicture);
+  pCtx->pDec = NULL;
+
   return ERR_NONE;
 }
 
 bool NeedErrorCon (PWelsDecoderContext pCtx) {
   bool bNeedEC = false;
-  //TODO
+  int32_t iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
+  for (int32_t i = 0; i < iMbNum; ++i) {
+    if (!pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag[i]) {
+      bNeedEC = true;
+      break;
+    }
+  }
   return bNeedEC;
 }
 
 // ImplementErrorConceal
 // Do actual error concealment
-int32_t ImplementErrorCon (PWelsDecoderContext pCtx) {
-  int32_t iRet = ERR_NONE;
-  //TODO
-  return iRet;
+void ImplementErrorCon (PWelsDecoderContext pCtx) {
+  if (!NeedErrorCon (pCtx))
+    return;
+
+  if (ERROR_CON_DISABLE == pCtx->iErrorConMethod) {
+    pCtx->iErrorCode |= dsBitstreamError;
+    return;
+  } else if (ERROR_CON_FRAME_COPY == pCtx->iErrorConMethod) {
+    DoErrorConFrameCopy (pCtx);
+  } else if (ERROR_CON_SLICE_COPY == pCtx->iErrorConMethod) {
+    DoErrorConSliceCopy (pCtx);
+  } //TODO add other EC methods here in the future
+
+  //mark the erroneous frame as Ref pic in DPB
+  MarkECFrameAsRef (pCtx);
+  //need update frame_num due current frame is well decoded
+  pCtx->iPrevFrameNum	= pCtx->pSliceHeader->iFrameNum;
+  if (pCtx->bLastHasMmco5)
+    pCtx->iPrevFrameNum = 0;
+
 }
 
 } // namespace WelsDec