shithub: openh264

Download patch

ref: 36c7b556e330886377f257b1232e06b80e64947c
parent: 3c3d4ef64b0f1cab1d510bc88a8d4718a5bd14d7
parent: db11ba7a34d1e7e984596325a63d74191259e003
author: dongzha <[email protected]>
date: Tue May 27 09:53:35 EDT 2014

Merge pull request #896 from ruil2/enc_rc_4

fix vlc overflow

--- a/codec/encoder/core/inc/rc.h
+++ b/codec/encoder/core/inc/rc.h
@@ -66,8 +66,6 @@
   VGOP_SIZE             = 8,
 
   //qp information
-  FIX_MIN_QP_MODE       = 10, //qp <10 will cause level code overflow in cavlc coding which isn't suppored in baseline profile
-  FIX_MAX_QP_MODE       = 51,
   GOM_MIN_QP_MODE       = 12,
   GOM_MAX_QP_MODE       = 36,
   MAX_LOW_BR_QP			= 42,
--- a/codec/encoder/core/inc/set_mb_syn_cavlc.h
+++ b/codec/encoder/core/inc/set_mb_syn_cavlc.h
@@ -79,8 +79,8 @@
 
 void  InitCavlcTable();
 
-void  WriteBlockResidualCavlc (int16_t* pCoffLevel, int32_t iEndIdx, int32_t iCalRunLevelFlag,
-                               int32_t iResidualProperty, int8_t iNC, SBitStringAux* pBs);
+int32_t  WriteBlockResidualCavlc (int16_t* pCoffLevel, int32_t iEndIdx, int32_t iCalRunLevelFlag,
+                                  int32_t iResidualProperty, int8_t iNC, SBitStringAux* pBs);
 
 #if defined(__cplusplus)
 extern "C" {
--- a/codec/encoder/core/inc/svc_enc_slice_segment.h
+++ b/codec/encoder/core/inc/svc_enc_slice_segment.h
@@ -95,6 +95,7 @@
   int32_t		iBsStackLeftBits;
 
   int32_t		iMbSkipRunStack;
+  uint8_t   uiLastMbQp;
 } SDynamicSlicingStack;
 
 /*!
--- a/codec/encoder/core/inc/svc_set_mb_syn_cavlc.h
+++ b/codec/encoder/core/inc/svc_set_mb_syn_cavlc.h
@@ -50,7 +50,7 @@
 
 namespace WelsSVCEnc {
 
-void WelsWriteMbResidual (SMbCache* sMbCacheInfo, SMB* pCurMb, SBitStringAux* pBs);
+int32_t WelsWriteMbResidual (SMbCache* sMbCacheInfo, SMB* pCurMb, SBitStringAux* pBs);
 
 void WelsSpatialWriteSubMbPred (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb);
 
--- a/codec/encoder/core/inc/wels_const.h
+++ b/codec/encoder/core/inc/wels_const.h
@@ -202,6 +202,7 @@
   ENC_RETURN_CORRECTED = 0x08, //unexpected value but corrected by encoder
   ENC_RETURN_INVALIDINPUT = 0x10, //invalid input
   ENC_RETURN_MEMOVERFLOWFOUND = 0x20,
+  ENC_RETURN_VLCOVERFLOWFOUND = 0x40
 };
 //TODO: need to complete the return checking in encoder and fill in more types if needed
 
--- a/codec/encoder/core/src/ratectl.cpp
+++ b/codec/encoder/core/src/ratectl.cpp
@@ -928,7 +928,7 @@
     pEncCtx->iGlobalQp = WELS_CLIP3 (WELS_ROUND (pEncCtx->iGlobalQp -
                                      pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp), GOM_MIN_QP_MODE, GOM_MAX_QP_MODE);
   } else {
-    pEncCtx->iGlobalQp = WELS_CLIP3 (pEncCtx->iGlobalQp, FIX_MIN_QP_MODE, FIX_MAX_QP_MODE);
+    pEncCtx->iGlobalQp = WELS_CLIP3 (pEncCtx->iGlobalQp, 0, 51);
   }
 
   pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp;
@@ -940,14 +940,16 @@
 void  WelsRcMbInitDisable (void* pCtx, SMB* pCurMb, SSlice* pSlice) {
   sWelsEncCtx* pEncCtx = (sWelsEncCtx*)pCtx;
   int32_t iLumaQp					= pEncCtx->iGlobalQp;
+
   SDqLayer* pCurLayer				= pEncCtx->pCurDqLayer;
   const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
 
+
   if (pEncCtx->pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE)) {
     iLumaQp   = (int8_t)WELS_CLIP3 (iLumaQp +
                                     pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], GOM_MIN_QP_MODE, 51);
   } else {
-    iLumaQp = WELS_CLIP3 (iLumaQp, FIX_MIN_QP_MODE, FIX_MAX_QP_MODE);
+    iLumaQp = WELS_CLIP3 (iLumaQp, 0, 51);
   }
   pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (iLumaQp + kuiChromaQpIndexOffset)];
   pCurMb->uiLumaQp = iLumaQp;
--- a/codec/encoder/core/src/set_mb_syn_cavlc.cpp
+++ b/codec/encoder/core/src/set_mb_syn_cavlc.cpp
@@ -41,6 +41,7 @@
 #include "set_mb_syn_cavlc.h"
 #include "vlc_encoder.h"
 #include "cpu_core.h"
+#include "wels_const.h"
 
 namespace WelsSVCEnc {
 SCoeffFunc    sCoeffFunc;
@@ -77,8 +78,8 @@
   return iTotalZeros;
 }
 
-void  WriteBlockResidualCavlc (int16_t* pCoffLevel, int32_t iEndIdx, int32_t iCalRunLevelFlag,
-                               int32_t iResidualProperty, int8_t iNC, SBitStringAux* pBs) {
+int32_t  WriteBlockResidualCavlc (int16_t* pCoffLevel, int32_t iEndIdx, int32_t iCalRunLevelFlag,
+                                  int32_t iResidualProperty, int8_t iNC, SBitStringAux* pBs) {
   ENFORCE_STACK_ALIGN_1D (int16_t, iLevel, 16, 16)
   ENFORCE_STACK_ALIGN_1D (uint8_t, uiRun, 16, 16)
 
@@ -121,7 +122,7 @@
     CAVLC_BS_WRITE (n, iValue);
 
     CAVLC_BS_UNINIT (pBs);
-    return;
+    return ENC_RETURN_SUCCESS;
   }
 
   /* Step 4: */
@@ -152,7 +153,9 @@
     } else if (iLevelPrefix >= 15) {
       iLevelPrefix = 15;
       iLevelSuffix = iLevelCode - (iLevelPrefix << uiSuffixLength);
-
+      //for baseline profile,overflow when the length of iLevelSuffix is larger than 11.
+      if (iLevelSuffix >> 11)
+        return ENC_RETURN_VLCOVERFLOWFOUND;
       if (uiSuffixLength == 0) {
         iLevelSuffix -= 15;
       }
@@ -197,6 +200,7 @@
   }
 
   CAVLC_BS_UNINIT (pBs);
+  return ENC_RETURN_SUCCESS;
 }
 
 
--- a/codec/encoder/core/src/svc_encode_slice.cpp
+++ b/codec/encoder/core/src/svc_encode_slice.cpp
@@ -460,7 +460,25 @@
     pfIdctFour4x4 (pDecV, kiDecStrideChroma, pDecV, kiDecStrideChroma, pScaledTcoeff + 320);
   }
 }
-
+inline void StashMBStatus (SDynamicSlicingStack* pDss, SBitStringAux* pBs, SSlice* pSlice, int32_t iMbSkipRun = 0) {
+  pDss->pBsStackBufPtr	= pBs->pBufPtr;
+  pDss->uiBsStackCurBits	= pBs->uiCurBits;
+  pDss->iBsStackLeftBits	= pBs->iLeftBits;
+  pDss->uiLastMbQp =  pSlice->uiLastMbQp;
+  pDss->iMbSkipRunStack = iMbSkipRun;
+}
+void StashPopMBStatus (SDynamicSlicingStack* pDss, SBitStringAux* pBs, SSlice* pSlice, int32_t* pMbSkipRun = 0) {
+  pBs->pBufPtr		= pDss->pBsStackBufPtr;
+  pBs->uiCurBits	= pDss->uiBsStackCurBits;
+  pBs->iLeftBits	= pDss->iBsStackLeftBits;
+  pSlice->uiLastMbQp = pDss->uiLastMbQp;
+  if(pMbSkipRun)
+    *pMbSkipRun = pDss->iMbSkipRunStack;
+}
+void UpdateQpForOverflow (SMB* pCurMb, uint8_t kuiChromaQpIndexOffset) {
+  pCurMb->uiLumaQp += DELTA_QP;
+  pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];
+}
 // for intra non-dynamic pSlice
 //encapsulate two kinds of reconstruction:
 //first. store base or highest Dependency Layer with only one quality (without CS RS reconstruction)
@@ -477,22 +495,31 @@
   const int32_t kiTotalNumMb		= pCurLayer->iMbWidth * pCurLayer->iMbHeight;
   int32_t iCurMbIdx				= 0, iNumMbCoded = 0;
   const int32_t kiSliceIdx			= pSlice->uiSliceIdx;
+  const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
 
   SWelsMD sMd;
   int32_t iEncReturn = ENC_RETURN_SUCCESS;
-
+  SBitStringAux* pBs = pSlice->pSliceBsa;
+  SDynamicSlicingStack sDss;
   for (; ;) {
+    StashMBStatus (&sDss, pBs, pSlice);
     iCurMbIdx	= iNextMbIdx;
     pCurMb = &pMbList[ iCurMbIdx ];
+
     pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice);
+    WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
 
+TRY_REENCODING:
     sMd.iLambda = g_kiQpCostTable[pCurMb->uiLumaQp];
-
-    WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
     WelsMdIntraMb (pEncCtx, &sMd, pCurMb, pMbCache);
     UpdateNonZeroCountCache (pCurMb, pMbCache);
 
     iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);
+    if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) {
+      StashPopMBStatus (&sDss, pBs, pSlice);
+      UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);
+      goto TRY_REENCODING;
+    }
     if (ENC_RETURN_SUCCESS != iEncReturn)
       return iEncReturn;
 
@@ -505,7 +532,6 @@
     pEncCtx->pFuncList->pfRc.pfWelsRcMbInfoUpdate (pEncCtx, pCurMb, sMd.iCostLuma, pSlice);
 
     ++iNumMbCoded;
-
     iNextMbIdx = WelsGetNextMbOfSlice (pSliceCtx, iCurMbIdx);
     if (iNextMbIdx == -1 || iNextMbIdx >= kiTotalNumMb || iNumMbCoded >= kiTotalNumMb) {
       break;
@@ -540,6 +566,8 @@
   for (; ;) {
     iCurMbIdx	= iNextMbIdx;
     pCurMb = &pMbList[ iCurMbIdx ];
+
+    StashMBStatus (&sDss, pBs, pSlice);
     pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice);
     // if already reaches the largest number of slices, set QPs to the upper bound
     if (pSlice->bDynamicSlicingSliceSizeCtrlFlag) {
@@ -546,18 +574,19 @@
       pCurMb->uiLumaQp = pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId].iMaxQp;
       pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];
     }
+    WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
 
+TRY_REENCODING:
     sMd.iLambda = g_kiQpCostTable[pCurMb->uiLumaQp];
-
-    WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
     WelsMdIntraMb (pEncCtx, &sMd, pCurMb, pMbCache);
     UpdateNonZeroCountCache (pCurMb, pMbCache);
-    //stack pBs pointer
-    sDss.pBsStackBufPtr	= pBs->pBufPtr;
-    sDss.uiBsStackCurBits	= pBs->uiCurBits;
-    sDss.iBsStackLeftBits	= pBs->iLeftBits;
 
     iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);
+    if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) {
+      StashPopMBStatus (&sDss, pBs, pSlice);
+      UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);
+      goto TRY_REENCODING;
+    }
     if (ENC_RETURN_SUCCESS != iEncReturn)
       return iEncReturn;
 
@@ -926,12 +955,14 @@
   const int32_t kiSliceIdx				= pSlice->uiSliceIdx;
   const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
   int32_t iEncReturn = ENC_RETURN_SUCCESS;
-
+  SDynamicSlicingStack sDss;
   for (;;) {
+    StashMBStatus (&sDss, pBs, pSlice, iMbSkipRun);
     //point to current pMb
     iCurMbIdx	= iNextMbIdx;
     pCurMb = &pMbList[ iCurMbIdx ];
 
+
     //step(1): set QP for the current MB
     pEncCtx->pFuncList->pfRc.pfWelsRcMbInit (pEncCtx, pCurMb, pSlice);
 
@@ -938,6 +969,8 @@
     //step (2). save some vale for future use, initial pWelsMd
     WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
     WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY);
+
+TRY_REENCODING:
     WelsInitInterMDStruc (pCurMb, pMvdCostTableInter, kiMvdInterTableStride, pMd);
     pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache);
     //mb_qp
@@ -961,6 +994,11 @@
       BsWriteUE (pBs, iMbSkipRun);
       iMbSkipRun = 0;
       iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);
+      if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) {
+        StashPopMBStatus (&sDss, pBs, pSlice, &iMbSkipRun);
+        UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);
+        goto TRY_REENCODING;
+      }
       if (ENC_RETURN_SUCCESS != iEncReturn)
         return iEncReturn;
     }
@@ -1018,6 +1056,10 @@
   SDynamicSlicingStack sDss;
   sDss.iStartPos = BsGetBitsPos (pBs);
   for (;;) {
+    //DYNAMIC_SLICING_ONE_THREAD - MultiD
+    //stack pBs pointer
+    StashMBStatus (&sDss, pBs, pSlice, iMbSkipRun);
+
     //point to current pMb
     iCurMbIdx	= iNextMbIdx;
     pCurMb = &pMbList[ iCurMbIdx ];
@@ -1036,6 +1078,8 @@
     //step (2). save some vale for future use, initial pWelsMd
     WelsMdIntraInit (pEncCtx, pCurMb, pMbCache, kiSliceFirstMbXY);
     WelsMdInterInit (pEncCtx, pSlice, pCurMb, kiSliceFirstMbXY);
+
+TRY_REENCODING:
     WelsInitInterMDStruc (pCurMb, pMvdCostTableInter, kiMvdInterTableStride, pMd);
     pEncCtx->pFuncList->pfInterMd (pEncCtx, pMd, pSlice, pCurMb, pMbCache);
     //mb_qp
@@ -1051,15 +1095,6 @@
 
     //step (6): begin to write bit stream; if the pSlice size is controlled, the writing may be skipped
 
-    //DYNAMIC_SLICING_ONE_THREAD - MultiD
-    //stack pBs pointer
-    sDss.pBsStackBufPtr	= pBs->pBufPtr;
-    sDss.uiBsStackCurBits	= pBs->uiCurBits;
-    sDss.iBsStackLeftBits	= pBs->iLeftBits;
-    //stack Pskip status
-    sDss.iMbSkipRunStack = iMbSkipRun;
-    //DYNAMIC_SLICING_ONE_THREAD - MultiD
-
     if (IS_SKIP (pCurMb->uiMbType)) {
       pCurMb->uiLumaQp	= pSlice->uiLastMbQp;
       pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];
@@ -1069,6 +1104,11 @@
       BsWriteUE (pBs, iMbSkipRun);
       iMbSkipRun = 0;
       iEncReturn = WelsSpatialWriteMbSyn (pEncCtx, pSlice, pCurMb);
+      if (iEncReturn == ENC_RETURN_VLCOVERFLOWFOUND) {
+        StashPopMBStatus (&sDss, pBs, pSlice, &iMbSkipRun);
+        UpdateQpForOverflow (pCurMb, kuiChromaQpIndexOffset);
+        goto TRY_REENCODING;
+      }
       if (ENC_RETURN_SUCCESS != iEncReturn)
         return iEncReturn;
     }
--- a/codec/encoder/core/src/svc_set_mb_syn_cavlc.cpp
+++ b/codec/encoder/core/src/svc_set_mb_syn_cavlc.cpp
@@ -244,7 +244,8 @@
     pSlice->uiLastMbQp = pCurMb->uiLumaQp;
 
     BsWriteSE (pBs, kiDeltaQp);
-    WelsWriteMbResidual (pMbCache, pCurMb, pBs);
+    if (WelsWriteMbResidual (pMbCache, pCurMb, pBs))
+      return ENC_RETURN_VLCOVERFLOWFOUND;
   } else {
     pCurMb->uiLumaQp = pSlice->uiLastMbQp;
     pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp +
@@ -255,7 +256,7 @@
   return CheckBitstreamBuffer (pSlice->uiSliceIdx, pEncCtx, pBs);
 }
 
-void WelsWriteMbResidual (SMbCache* sMbCacheInfo, SMB* pCurMb, SBitStringAux* pBs) {
+int32_t WelsWriteMbResidual (SMbCache* sMbCacheInfo, SMB* pCurMb, SBitStringAux* pBs) {
   int32_t i;
   Mb_Type uiMbType					= pCurMb->uiMbType;
   const int32_t kiCbpChroma		= pCurMb->uiCbp >> 4;
@@ -269,7 +270,8 @@
     iA = pNonZeroCoeffCount[8];
     iB = pNonZeroCoeffCount[ 1];
     WELS_NON_ZERO_COUNT_AVERAGE (iC, iA, iB);
-    WriteBlockResidualCavlc (sMbCacheInfo->pDct->iLumaI16x16Dc, 15, 1, LUMA_4x4, iC, pBs);
+    if (WriteBlockResidualCavlc (sMbCacheInfo->pDct->iLumaI16x16Dc, 15, 1, LUMA_4x4, iC, pBs))
+      return ENC_RETURN_VLCOVERFLOWFOUND;
 
     /* AC Luma */
     if (kiCbpLuma) {
@@ -324,10 +326,12 @@
   if (kiCbpChroma) {
     /* Chroma DC residual present */
     pBlock = sMbCacheInfo->pDct->iChromaDc[0]; // Cb
-    WriteBlockResidualCavlc (pBlock, 3, 1, CHROMA_DC, CHROMA_DC_NC_OFFSET, pBs);
+    if (WriteBlockResidualCavlc (pBlock, 3, 1, CHROMA_DC, CHROMA_DC_NC_OFFSET, pBs))
+      return ENC_RETURN_VLCOVERFLOWFOUND;
 
     pBlock += 4; // Cr
-    WriteBlockResidualCavlc (pBlock, 3, 1, CHROMA_DC, CHROMA_DC_NC_OFFSET, pBs);
+    if (WriteBlockResidualCavlc (pBlock, 3, 1, CHROMA_DC, CHROMA_DC_NC_OFFSET, pBs))
+      return ENC_RETURN_VLCOVERFLOWFOUND;
 
     /* Chroma AC residual present */
     if (kiCbpChroma & 0x02) {
@@ -355,6 +359,7 @@
       }
     }
   }
+  return 0;
 }
 
 } // namespace WelsSVCEnc
--- a/codec/processing/src/common/util.h
+++ b/codec/processing/src/common/util.h
@@ -67,8 +67,15 @@
 
 #define WELS_MAX(x, y)	((x) > (y) ? (x) : (y))
 #define WELS_MIN(x, y)	((x) < (y) ? (x) : (y))
+
+#ifndef WELS_SIGN
 #define WELS_SIGN(a)	((int32_t)(a) >> 31)
+#endif
+
+#ifndef WELS_ABS
 #define WELS_ABS(a)		((WELS_SIGN(a) ^ (int32_t)(a)) - WELS_SIGN(a))
+#endif
+
 #define WELS_CLAMP(x, minv, maxv)  WELS_MIN(WELS_MAX(x, minv), maxv)
 
 #define ALIGNBYTES         (16)       /* Worst case is requiring alignment to an 16 byte boundary */