shithub: openh264

Download patch

ref: 936747e9a48094f376b9cfbca8dfa1ad9144107b
parent: 5c301defbab9756df9a98143ab2d59fa7011424c
parent: 53c057a8a8c57df06864cd428e81b37fd7cca86b
author: HaiboZhu <haibozhu@cisco.com>
date: Tue Sep 22 10:51:29 EDT 2015

Merge pull request #2122 from sijchen/fixsimul

[Encoder] fix for simulcast case when frame rate of lower resolution is higher

--- a/codec/encoder/core/inc/encoder.h
+++ b/codec/encoder/core/inc/encoder.h
@@ -83,6 +83,7 @@
  * \brief   initialize frame coding
  */
 void InitFrameCoding (sWelsEncCtx* pEncCtx, const EVideoFrameType keFrameType);
+void LoadBackFrameNum(sWelsEncCtx* pEncCtx);
 
 EVideoFrameType DecideFrameType (sWelsEncCtx* pEncCtx, const int8_t kiSpatialNum);
 
--- a/codec/encoder/core/inc/encoder_context.h
+++ b/codec/encoder/core/inc/encoder_context.h
@@ -156,7 +156,7 @@
   EWelsSliceType    eSliceType;             // currently coding slice type
   EWelsNalUnitType  eNalType;               // NAL type
   EWelsNalRefIdc    eNalPriority;           // NAL_Reference_Idc currently
-  EWelsNalRefIdc    eLastNalPriority;       // NAL_Reference_Idc in last frame
+  EWelsNalRefIdc    eLastNalPriority[MAX_DEPENDENCY_LAYER];       // NAL_Reference_Idc in last frame
   uint8_t           iNumRef0;
 
   uint8_t           uiDependencyId;         // Idc of dependecy layer to be coded
--- a/codec/encoder/core/src/encoder.cpp
+++ b/codec/encoder/core/src/encoder.cpp
@@ -226,6 +226,41 @@
   return iReturn;
 }
 
+void UpdateFrameNum(sWelsEncCtx* pEncCtx) {
+  bool bNeedFrameNumIncreasing = false;
+  for (int32_t i=0; i<MAX_DEPENDENCY_LAYER; i++) {
+    if (NRI_PRI_LOWEST != pEncCtx->eLastNalPriority[i]) {
+      bNeedFrameNumIncreasing = true;
+    }
+  }
+  if (bNeedFrameNumIncreasing) {
+    if (pEncCtx->iFrameNum < (1 << pEncCtx->pSps->uiLog2MaxFrameNum) - 1)
+      ++ pEncCtx->iFrameNum;
+    else
+      pEncCtx->iFrameNum = 0;    // if iFrameNum overflow
+  }
+  for (int32_t i=0; i<MAX_DEPENDENCY_LAYER; i++) {
+    pEncCtx->eLastNalPriority[i] = NRI_PRI_LOWEST;
+  }
+}
+
+
+void LoadBackFrameNum(sWelsEncCtx* pEncCtx) {
+    bool bNeedFrameNumIncreasing = false;
+    for (int32_t i=0; i<MAX_DEPENDENCY_LAYER; i++) {
+      if (NRI_PRI_LOWEST != pEncCtx->eLastNalPriority[i]) {
+        bNeedFrameNumIncreasing = true;
+      }
+    }
+    if (bNeedFrameNumIncreasing) {
+      if (pEncCtx->iFrameNum != 0) {
+        pEncCtx->iFrameNum --;
+      } else {
+        pEncCtx->iFrameNum = (1 << pEncCtx->pSps->uiLog2MaxFrameNum) - 1;
+      }
+    }
+}
+
 /*!
  * \brief   initialize frame coding
  */
@@ -245,12 +280,8 @@
     else
       pEncCtx->iPOC = 0;
 
-    if (pEncCtx->eLastNalPriority != 0) {
-      if (pEncCtx->iFrameNum < (1 << pEncCtx->pSps->uiLog2MaxFrameNum) - 1)
-        ++ pEncCtx->iFrameNum;
-      else
-        pEncCtx->iFrameNum = 0;    // if iFrameNum overflow
-    }
+    UpdateFrameNum(pEncCtx);
+
     pEncCtx->eNalType           = NAL_UNIT_CODED_SLICE;
     pEncCtx->eSliceType         = P_SLICE;
     pEncCtx->eNalPriority       = NRI_PRI_HIGH;
@@ -275,12 +306,7 @@
     else
       pEncCtx->iPOC = 0;
 
-    if (pEncCtx->eLastNalPriority != 0) {
-      if (pEncCtx->iFrameNum < (1 << pEncCtx->pSps->uiLog2MaxFrameNum) - 1)
-        ++ pEncCtx->iFrameNum;
-      else
-        pEncCtx->iFrameNum = 0;    // if iFrameNum overflow
-    }
+    UpdateFrameNum(pEncCtx);
 
     pEncCtx->eNalType     = NAL_UNIT_CODED_SLICE;
     pEncCtx->eSliceType   = I_SLICE;
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -3481,7 +3481,7 @@
   pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
   pLayerBsInfo->iNalCount     = iCountNal;
 
-  pCtx->eLastNalPriority      = NRI_PRI_HIGHEST;
+  //pCtx->eLastNalPriority      = NRI_PRI_HIGHEST;
   pFbi->iLayerNum             = 1;
   pFbi->eFrameType            = videoFrameTypeInvalid;
 
@@ -3712,17 +3712,10 @@
       pEncCtx->iPOC = (1 << pEncCtx->pSps->iLog2MaxPocLsb) - 2;
     }
 
-    if (pEncCtx->eLastNalPriority != 0) {
-      if (pEncCtx->iFrameNum != 0) {
-        pEncCtx->iFrameNum --;
-      } else {
-        pEncCtx->iFrameNum = (1 << pEncCtx->pSps->uiLog2MaxFrameNum) - 1;
-      }
-    }
-
+    LoadBackFrameNum(pEncCtx);
     pEncCtx->eNalType     = NAL_UNIT_CODED_SLICE;
     pEncCtx->eSliceType   = P_SLICE;
-    pEncCtx->eNalPriority = pEncCtx->eLastNalPriority;
+    //pEncCtx->eNalPriority = pEncCtx->eLastNalPriority; //not need this since eNalPriority will be updated at the beginning of coding a frame
   } else if (keFrameType == videoFrameTypeIDR) {
     pEncCtx->uiIdrPicId --;
 
@@ -3865,7 +3858,7 @@
   while (iSpatialIdx < iSpatialNum) {
     const int32_t iDidIdx       = (pSpatialIndexMap + iSpatialIdx)->iDid;       // get iDid
     SSpatialLayerConfig* pParam = &pSvcParam->sSpatialLayers[iDidIdx];
-    int32_t  iDecompositionStages = pSvcParam->sDependencyLayers[iSpatialIdx].iDecompositionStages;
+    int32_t  iDecompositionStages = pSvcParam->sDependencyLayers[iDidIdx].iDecompositionStages;
     pCtx->uiDependencyId        = iCurDid = (int8_t)iDidIdx;
     pCtx->pVpp->AnalyzeSpatialPic (pCtx, iDidIdx);
 
@@ -4387,6 +4380,7 @@
 #endif//#if defined(MT_DEBUG)
     }
 
+    pCtx->eLastNalPriority[iDidIdx] = eNalRefIdc;
     ++ iSpatialIdx;
 
     if (iCurDid + 1 < pSvcParam->iSpatialLayerNum) {
@@ -4447,7 +4441,6 @@
   }
 
   ++ pCtx->iCodingIndex;
-  pCtx->eLastNalPriority = eNalRefIdc;
   pFbi->iLayerNum = iLayerNum;
   pFbi->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
 
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -3363,6 +3363,12 @@
       WelsDestroyDecoder (decoder[iIdx]);
     }
   }
+#ifdef DEBUG_FILE_SAVE_SimulcastAVCDiffFps
+  for (int i = 0; i <)MAX_SPATIAL_LAYER_NUM;
+  i++) {
+    fclose (fEnc[i]);
+  }
+#endif
 }
 
 TEST_F (EncodeDecodeTestAPI, SimulcastAVC_SPS_PPS_LISTING) {
@@ -3586,4 +3592,136 @@
     fclose (pFile);
   }
 }
+
+
+
+TEST_F (EncodeDecodeTestAPI, SimulcastAVCDiffFps) {
+//#define DEBUG_FILE_SAVE3
+  int iSpatialLayerNum = WelsClip3 ((rand() % MAX_SPATIAL_LAYER_NUM), 2, MAX_SPATIAL_LAYER_NUM);
+  int iWidth       = WelsClip3 ((((rand() % MAX_WIDTH) >> 1)  + 1) << 1, 1 << iSpatialLayerNum, MAX_WIDTH);
+  int iHeight      = WelsClip3 ((((rand() % MAX_HEIGHT) >> 1)  + 1) << 1, 1 << iSpatialLayerNum, MAX_HEIGHT);
+  float fFrameRate = 30;
+  int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
+  int iSliceNum        = 1;
+  encoder_->GetDefaultParams (&param_);
+  prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, &param_);
+
+  //set flag of bSimulcastAVC
+  param_.bSimulcastAVC = true;
+  param_.iTemporalLayerNum = 3;
+
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == cmResultSuccess);
+
+  unsigned char*  pBsBuf[MAX_SPATIAL_LAYER_NUM];
+  int aLen[MAX_SPATIAL_LAYER_NUM] = {0};
+  ISVCDecoder* decoder[MAX_SPATIAL_LAYER_NUM];
+
+#ifdef DEBUG_FILE_SAVE_SimulcastAVCDiffFps
+  FILE* fEnc[MAX_SPATIAL_LAYER_NUM];
+  fEnc[0] = fopen ("enc0.264", "wb");
+  fEnc[1] = fopen ("enc1.264", "wb");
+  fEnc[2] = fopen ("enc2.264", "wb");
+  fEnc[3] = fopen ("enc3.264", "wb");
+#endif
+
+  int iIdx = 0;
+
+  //create decoder
+  for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
+    pBsBuf[iIdx] = static_cast<unsigned char*> (malloc (iWidth * iHeight * 3 * sizeof (unsigned char) / 2));
+    EXPECT_TRUE (pBsBuf[iIdx] != NULL);
+    aLen[iIdx] = 0;
+
+    long rv = WelsCreateDecoder (&decoder[iIdx]);
+    ASSERT_EQ (0, rv);
+    EXPECT_TRUE (decoder[iIdx] != NULL);
+
+    SDecodingParam decParam;
+    memset (&decParam, 0, sizeof (SDecodingParam));
+    decParam.eOutputColorFormat  = videoFormatI420;
+    decParam.uiTargetDqLayer = UCHAR_MAX;
+    decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
+    decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+    rv = decoder[iIdx]->Initialize (&decParam);
+    ASSERT_EQ (0, rv);
+  }
+
+#define PATTERN_NUM (16)
+  const int32_t iTemporalPattern[PATTERN_NUM][MAX_SPATIAL_LAYER_NUM] = { {2, 1, 1, 1}, {2, 2, 2, 1}, {4, 1, 1, 1}, {4, 2, 1, 1},
+    {1, 2, 1, 1}, {1, 1, 2, 1}, {1, 4, 1, 1}, {2, 4, 2, 1}, {1, 4, 2, 1},
+    {1, 2, 2, 1}, {1, 2, 4, 1},
+    {1, 1, 1, 2}, {1, 2, 2, 2}, {1, 2, 2, 4}, {1, 2, 4, 2}, {1, 4, 4, 4},
+  };
+  for (int iPatternIdx = 0; iPatternIdx < PATTERN_NUM; iPatternIdx++) {
+    for (int i = 0; i < iSpatialLayerNum; i++) {
+      param_.sSpatialLayers[i].fFrameRate = (fFrameRate / iTemporalPattern[iPatternIdx][i]);
+    }
+
+    iEncFrameNum = 10;
+    for (int iFrame = 0; iFrame < iEncFrameNum; iFrame++) {
+      int iResult;
+      int iLayerLen = 0;
+      unsigned char* pData[3] = { NULL };
+
+      InitialEncDec (param_.iPicWidth, param_.iPicHeight);
+      EncodeOneFrame (0);
+
+      // init
+      for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
+        aLen[iIdx] = 0;
+      }
+      for (int iLayer = 0; iLayer < info.iLayerNum; ++iLayer) {
+        iLayerLen = 0;
+        const SLayerBSInfo& layerInfo = info.sLayerInfo[iLayer];
+        const int kiFirstNalType = ((* (layerInfo.pBsBuf + 4)) & 0x1f);
+        ASSERT_TRUE ((kiFirstNalType == NAL_SPS) || (kiFirstNalType == NAL_PPS) || (kiFirstNalType == NAL_SLICE)
+                     || (kiFirstNalType == NAL_SLICE_IDR) || (kiFirstNalType == NAL_SEI));
+        for (int iNal = 0; iNal < layerInfo.iNalCount; ++iNal) {
+          iLayerLen += layerInfo.pNalLengthInByte[iNal];
+        }
+
+        iIdx = layerInfo.uiSpatialId;
+        EXPECT_TRUE (iIdx < iSpatialLayerNum);
+        memcpy ((pBsBuf[iIdx] + aLen[iIdx]), layerInfo.pBsBuf, iLayerLen * sizeof (unsigned char));
+        aLen[iIdx] += iLayerLen;
+      }
+
+      for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
+        pData[0] = pData[1] = pData[2] = 0;
+        memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+
+        if (aLen[iIdx] > 0) {
+#ifdef DEBUG_FILE_SAVE_SimulcastAVCDiffFps
+          fwrite (pBsBuf[iIdx], aLen[iIdx], 1, fEnc[iIdx]);
+#endif
+          iResult = decoder[iIdx]->DecodeFrame2 (pBsBuf[iIdx], aLen[iIdx], pData, &dstBufInfo_);
+          EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx;
+
+          iResult = decoder[iIdx]->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_);
+          EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx;
+          EXPECT_EQ (dstBufInfo_.iBufferStatus, 1) << "LayerIdx=" << iIdx;
+        }
+      }
+    }
+  }
+
+  for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
+    free (pBsBuf[iIdx]);
+
+    if (decoder[iIdx] != NULL) {
+      decoder[iIdx]->Uninitialize();
+      WelsDestroyDecoder (decoder[iIdx]);
+    }
+  }
+#ifdef DEBUG_FILE_SAVE_SimulcastAVCDiffFps
+  for (int i = 0; i <)MAX_SPATIAL_LAYER_NUM;
+  i++) {
+    fclose (fEnc[i]);
+  }
+#endif
+}
+
+