shithub: openh264

Download patch

ref: 7a9f15cb8a1371556242aa2de79d09ae42c57675
parent: 696fb49afe200e5e86368fb1efdeda7876c5a351
parent: 61e668545ba0b3dae1fdf1e1d927a2e452125b40
author: huili2 <huili2@cisco.com>
date: Thu Oct 27 14:21:02 EDT 2016

Merge pull request #2584 from ruil2/forceidr

Set IDR frame independently for simulcast AVC

--- a/codec/api/svc/codec_api.h
+++ b/codec/api/svc/codec_api.h
@@ -319,7 +319,7 @@
   * @param  bIDR true: force encoder to encode frame as IDR frame;false, return 1 and nothing to do
   * @return 0 - success; otherwise - failed;
   */
-  virtual int EXTAPI ForceIntraFrame (bool bIDR) = 0;
+  virtual int EXTAPI ForceIntraFrame (bool bIDR,int iLayerId = -1) = 0;
 
   /**
   * @brief   Set option for encoder, detail option type, please refer to enumurate ENCODER_OPTION.
--- a/codec/encoder/core/inc/extern.h
+++ b/codec/encoder/core/inc/extern.h
@@ -100,7 +100,7 @@
 /*
  * Force coding IDR as follows
  */
-int32_t ForceCodingIDR (sWelsEncCtx* pCtx);
+int32_t ForceCodingIDR (sWelsEncCtx* pCtx,int32_t iLayerId);
 
 /*!
  * \brief   Wels SVC encoder parameters adjustment
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -3140,22 +3140,38 @@
 /*
  * Force coding IDR as follows
  */
-int32_t ForceCodingIDR (sWelsEncCtx* pCtx) {
+int32_t ForceCodingIDR (sWelsEncCtx* pCtx, int32_t iLayerId) {
   if (NULL == pCtx)
     return 1;
-  for (int32_t iDid = 0; iDid < pCtx->pSvcParam->iSpatialLayerNum; iDid++) {
-    SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iDid];
+  if ((iLayerId < 0) || (iLayerId >= MAX_SPATIAL_LAYER_NUM) || (!pCtx->pSvcParam->bSimulcastAVC)) {
+    for (int32_t iDid = 0; iDid < pCtx->pSvcParam->iSpatialLayerNum; iDid++) {
+      SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iDid];
+      pParamInternal->iCodingIndex = 0;
+      pParamInternal->iFrameIndex = 0;
+      pParamInternal->iFrameNum = 0;
+      pParamInternal->iPOC = 0;
+      pParamInternal->bEncCurFrmAsIdrFlag = true;
+      pCtx->sEncoderStatistics[0].uiIDRReqNum++;
+    }
+    WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR(iDid 0-%d)at InputFrameCount=%d\n",
+             pCtx->pSvcParam->iSpatialLayerNum - 1, pCtx->sEncoderStatistics[0].uiInputFrameCount);
+
+
+
+  } else {
+    SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iLayerId];
     pParamInternal->iCodingIndex = 0;
     pParamInternal->iFrameIndex = 0;
     pParamInternal->iFrameNum = 0;
     pParamInternal->iPOC = 0;
     pParamInternal->bEncCurFrmAsIdrFlag = true;
+    pCtx->sEncoderStatistics[iLayerId].uiIDRReqNum++;
+    WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR(iDid %d)at InputFrameCount=%d\n", iLayerId,
+             pCtx->sEncoderStatistics[iLayerId].uiInputFrameCount);
   }
-
   pCtx->bCheckWindowStatusRefreshFlag = false;
 
-  WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR at InputFrameCount=%d\n",
-           pCtx->sEncoderStatistics[0].uiInputFrameCount);
+
   return 0;
 }
 
@@ -3430,7 +3446,7 @@
     pEncCtx->uiIdrPicId --;
 
     //set the next frame to be IDR
-    ForceCodingIDR (pEncCtx);
+    ForceCodingIDR (pEncCtx, pEncCtx->uiDependencyId);
   } else { // B pictures are not supported now, any else?
     assert (0);
   }
@@ -4096,7 +4112,7 @@
     }
 
     if (pCtx->pVpp->UpdateSpatialPictures (pCtx, pSvcParam, iCurTid, iCurDid) != 0) {
-      ForceCodingIDR (pCtx);
+      ForceCodingIDR (pCtx, iCurDid);
       WelsLog (pLogCtx, WELS_LOG_WARNING,
                "WelsEncoderEncodeExt(), Logic Error Found in Preprocess updating. ForceCodingIDR!");
       //the above is to set the next frame IDR
@@ -4122,7 +4138,7 @@
 
   if (ENC_RETURN_CORRECTED == pCtx->iEncoderError) {
     pCtx->pVpp->UpdateSpatialPictures (pCtx, pSvcParam, iCurTid, (pSpatialIndexMap + iSpatialIdx)->iDid);
-    ForceCodingIDR (pCtx);
+    ForceCodingIDR (pCtx, (pSpatialIndexMap + iSpatialIdx)->iDid);
     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), Logic Error Found in temporal level. ForceCodingIDR!");
     //the above is to set the next frame IDR
     pFbi->eFrameType = eFrameType;
--- a/codec/encoder/plus/inc/welsEncoderExt.h
+++ b/codec/encoder/plus/inc/welsEncoderExt.h
@@ -85,7 +85,7 @@
   /*
    * return: 0 - success; otherwise - failed;
    */
-  virtual int EXTAPI ForceIntraFrame (bool bIDR);
+  virtual int EXTAPI ForceIntraFrame (bool bIDR,int32_t iLayerId = -1);
 
   /************************************************************************
    * InDataFormat, IDRInterval, SVC Encode Param, Frame Rate, Bitrate,..
--- a/codec/encoder/plus/src/welsEncoderExt.cpp
+++ b/codec/encoder/plus/src/welsEncoderExt.cpp
@@ -472,7 +472,7 @@
 /*
  *  Force key frame
  */
-int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR) {
+int CWelsH264SVCEncoder::ForceIntraFrame (bool bIDR, int iLayerId) {
   if (! (m_pEncContext && m_bInitialFlag)) {
     return 1;
   }
@@ -479,9 +479,7 @@
   //WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
   //         "CWelsH264SVCEncoder::ForceIntraFrame(), bIDR= %d", bIDR);
 
-  ForceCodingIDR (m_pEncContext);
-
-  m_pEncContext->sEncoderStatistics[0].uiIDRReqNum++;
+  ForceCodingIDR (m_pEncContext, iLayerId);
 
   return 0;
 }
--- a/test/api/cpp_interface_test.cpp
+++ b/test/api/cpp_interface_test.cpp
@@ -47,7 +47,7 @@
     EXPECT_TRUE (gThis == this);
     return 6;
   }
-  virtual int EXTAPI ForceIntraFrame (bool bIDR) {
+  virtual int EXTAPI ForceIntraFrame (bool bIDR,int iLayerId = -1) {
     EXPECT_TRUE (gThis == this);
     return 7;
   }
--- a/test/encoder/EncUT_EncoderExt.cpp
+++ b/test/encoder/EncUT_EncoderExt.cpp
@@ -636,6 +636,65 @@
   EXPECT_GE (sEncParamBase.fMaxFrameRate, 1.0);
 }
 
+TEST_F (EncoderInterfaceTest, ForceIntraFrameSimulCastAVC) {
+  SEncParamExt sEncParamExt;
+  pPtrEnc->GetDefaultParams (&sEncParamExt);
+  sEncParamExt.iUsageType = CAMERA_VIDEO_REAL_TIME;
+  int iSpatialLayerNum = rand() % MAX_SPATIAL_LAYER_NUM;
+  sEncParamExt.iSpatialLayerNum = WELS_CLIP3 (iSpatialLayerNum, 1, MAX_SPATIAL_LAYER_NUM);
+
+
+  sEncParamExt.iPicWidth = 1280;
+  sEncParamExt.iPicHeight = 720;
+  sEncParamExt.iTargetBitrate = 0; //!=0
+  sEncParamExt.iRCMode = RC_BITRATE_MODE; //-1, 0, 1, 2
+  sEncParamExt.bEnableFrameSkip = false;
+  sEncParamExt.fMaxFrameRate = 30; //!=0
+  sEncParamExt.bSimulcastAVC = 1;
+
+  for (int iNum = sEncParamExt.iSpatialLayerNum - 1; iNum >= 0 ; iNum--) {
+    int iScale = 1 << ((sEncParamExt.iSpatialLayerNum - 1) - iNum);
+    sEncParamExt.sSpatialLayers[iNum].iVideoWidth = sEncParamExt.iPicWidth / iScale;
+    sEncParamExt.sSpatialLayers[iNum].iVideoHeight = sEncParamExt.iPicHeight / iScale;
+    sEncParamExt.sSpatialLayers[iNum].iSpatialBitrate = (sEncParamExt.sSpatialLayers[iNum].iVideoWidth *
+        sEncParamExt.sSpatialLayers[iNum].iVideoHeight) / 3;
+    sEncParamExt.iTargetBitrate += sEncParamExt.sSpatialLayers[iNum].iSpatialBitrate;
+  }
+//    int uiTraceLevel = WELS_LOG_INFO;
+//    pPtrEnc->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
+  int iResult = pPtrEnc->InitializeExt (&sEncParamExt);
+  EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess)) << "iUsageType = " << sEncParamExt.iUsageType <<
+      ", iPicWidth = " << sEncParamExt.iPicWidth << ", iPicHeight = " << sEncParamExt.iPicHeight << ", iTargetBitrate = " <<
+      sEncParamExt.iTargetBitrate << ", fMaxFrameRate = " << sEncParamExt.fMaxFrameRate;
+
+  int kiFrameNumber = rand() % 100;
+  if (kiFrameNumber < 20)
+    kiFrameNumber = 20;
+  for (int i = 0; i < kiFrameNumber; i ++) {
+    PrepareOneSrcFrame();
+    bool bForceIdr = (i  == (kiFrameNumber / 2));
+    int iLayerNum = rand() % MAX_SPATIAL_LAYER_NUM;
+    iLayerNum = WELS_CLIP3 (iSpatialLayerNum, 0, sEncParamExt.iSpatialLayerNum - 1);
+    if (bForceIdr) {
+      pPtrEnc->ForceIntraFrame (true, iLayerNum);
+    }
+
+    iResult = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
+    EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
+    if (bForceIdr) {
+      for (int i = 0; i < sFbi.iLayerNum; ++i) {
+        if (sFbi.sLayerInfo[i].uiSpatialId == iLayerNum) {
+          EXPECT_EQ (sFbi.sLayerInfo[i].eFrameType, static_cast<int> (videoFrameTypeIDR));
+        }
+      }
+    }
+  }
+
+  pPtrEnc->Uninitialize();
+  EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
+}
+
+
 TEST_F (EncoderInterfaceTest, ForceIntraFrame) {
   SEncParamBase sEncParamBase;
   GetValidEncParamBase (&sEncParamBase);
@@ -1057,96 +1116,96 @@
 }
 
 TEST_F (EncoderInterfaceTest, NalSizeChecking) {
-   // int uiTraceLevel = WELS_LOG_DETAIL;
-   // pPtrEnc->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
+  // int uiTraceLevel = WELS_LOG_DETAIL;
+  // pPtrEnc->SetOption (ENCODER_OPTION_TRACE_LEVEL, &uiTraceLevel);
 
-    pParamExt->iPicWidth = 1280;
-    pParamExt->iPicHeight = 720;
-    pParamExt->iPicWidth += (rand() << 1) % IMAGE_VARY_SIZE;
-    pParamExt->iPicHeight += (rand() << 1) % IMAGE_VARY_SIZE;
-    pParamExt->fMaxFrameRate = 30;
-    pParamExt->iTemporalLayerNum = rand()%3;
-    pParamExt->iSpatialLayerNum = rand()%4;
-    pParamExt->iNumRefFrame = AUTO_REF_PIC_COUNT;
-    pParamExt->iSpatialLayerNum = WELS_CLIP3(pParamExt->iSpatialLayerNum,1,4);
+  pParamExt->iPicWidth = 1280;
+  pParamExt->iPicHeight = 720;
+  pParamExt->iPicWidth += (rand() << 1) % IMAGE_VARY_SIZE;
+  pParamExt->iPicHeight += (rand() << 1) % IMAGE_VARY_SIZE;
+  pParamExt->fMaxFrameRate = 30;
+  pParamExt->iTemporalLayerNum = rand() % 3;
+  pParamExt->iSpatialLayerNum = rand() % 4;
+  pParamExt->iNumRefFrame = AUTO_REF_PIC_COUNT;
+  pParamExt->iSpatialLayerNum = WELS_CLIP3 (pParamExt->iSpatialLayerNum, 1, 4);
 
-    pParamExt->iMultipleThreadIdc = 1;//multi-thread can't control size. will be fixed.
-    pParamExt->iEntropyCodingModeFlag = rand()%2;
-    int iMaxNalSize =rand()%5000;
-    iMaxNalSize =  WELS_CLIP3(iMaxNalSize,1000,5000);
-    pParamExt->uiMaxNalSize = iMaxNalSize;
-    for(int i = 0;i<pParamExt->iSpatialLayerNum;i++){
-      pParamExt->sSpatialLayers[i].sSliceArgument.uiSliceMode = SM_SIZELIMITED_SLICE;
-      pParamExt->sSpatialLayers[i].sSliceArgument.uiSliceSizeConstraint = iMaxNalSize;
-      pParamExt->sSpatialLayers[i].iVideoHeight = pParamExt->iPicHeight;
-      pParamExt->sSpatialLayers[i].iVideoWidth = pParamExt->iPicWidth;
-      int bitrate = rand()%3000000;
-      pParamExt->sSpatialLayers[i].iSpatialBitrate = WELS_CLIP3(bitrate,500000,3000000) ;
-      pParamExt->iTargetBitrate+= pParamExt->sSpatialLayers[i].iSpatialBitrate;
-      pParamExt->sSpatialLayers[i].fFrameRate = 30;
+  pParamExt->iMultipleThreadIdc = 1;//multi-thread can't control size. will be fixed.
+  pParamExt->iEntropyCodingModeFlag = rand() % 2;
+  int iMaxNalSize = rand() % 5000;
+  iMaxNalSize =  WELS_CLIP3 (iMaxNalSize, 1000, 5000);
+  pParamExt->uiMaxNalSize = iMaxNalSize;
+  for (int i = 0; i < pParamExt->iSpatialLayerNum; i++) {
+    pParamExt->sSpatialLayers[i].sSliceArgument.uiSliceMode = SM_SIZELIMITED_SLICE;
+    pParamExt->sSpatialLayers[i].sSliceArgument.uiSliceSizeConstraint = iMaxNalSize;
+    pParamExt->sSpatialLayers[i].iVideoHeight = pParamExt->iPicHeight;
+    pParamExt->sSpatialLayers[i].iVideoWidth = pParamExt->iPicWidth;
+    int bitrate = rand() % 3000000;
+    pParamExt->sSpatialLayers[i].iSpatialBitrate = WELS_CLIP3 (bitrate, 500000, 3000000) ;
+    pParamExt->iTargetBitrate += pParamExt->sSpatialLayers[i].iSpatialBitrate;
+    pParamExt->sSpatialLayers[i].fFrameRate = 30;
+  }
+  int iResult = pPtrEnc->InitializeExt (pParamExt);
+  const int kiFrameNumber = TEST_FRAMES;
+
+  m_iWidth = pParamExt->iPicWidth;
+  m_iHeight = pParamExt->iPicHeight;
+  m_iPicResSize =  m_iWidth * m_iHeight * 3 >> 1;
+  if (pYUV)
+    delete []pYUV;
+  pYUV = new unsigned char [m_iPicResSize];
+  ASSERT_TRUE (pYUV != NULL);
+  FileInputStream fileStream;
+  ASSERT_TRUE (fileStream.Open ("res/Cisco_Absolute_Power_1280x720_30fps.yuv"));
+  PrepareOneSrcFrame();
+  for (int i = 0; i < kiFrameNumber; i ++) {
+    if (fileStream.read (pYUV, m_iPicResSize) != m_iPicResSize) {
+      break;
     }
-    int iResult = pPtrEnc->InitializeExt (pParamExt);
-    const int kiFrameNumber = TEST_FRAMES;
+    iResult = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
+    EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
+    pSrcPic->uiTimeStamp += 30;
 
-    m_iWidth = pParamExt->iPicWidth;
-    m_iHeight = pParamExt->iPicHeight;
-    m_iPicResSize =  m_iWidth * m_iHeight * 3 >> 1;
-    if(pYUV)
-       delete []pYUV;
-    pYUV = new unsigned char [m_iPicResSize];
-    ASSERT_TRUE (pYUV != NULL);
-    FileInputStream fileStream;
-    ASSERT_TRUE (fileStream.Open ("res/Cisco_Absolute_Power_1280x720_30fps.yuv"));
-    PrepareOneSrcFrame();
-    for (int i = 0; i < kiFrameNumber; i ++) {
-        if(fileStream.read (pYUV, m_iPicResSize) != m_iPicResSize){
-            break;
-        }
-        iResult = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
-        EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
-        pSrcPic->uiTimeStamp += 30;
+    for (int i = 0; i < sFbi.iLayerNum; ++i) {
+      for (int j = 0; j < sFbi.sLayerInfo[i].iNalCount; ++j) {
+        int length = sFbi.sLayerInfo[i].pNalLengthInByte[j];
+        EXPECT_LE (length, iMaxNalSize);
+      }
+    }
 
-        for (int i = 0; i < sFbi.iLayerNum; ++i) {
-            for (int j = 0; j < sFbi.sLayerInfo[i].iNalCount; ++j) {
-                int length = sFbi.sLayerInfo[i].pNalLengthInByte[j];
-                EXPECT_LE (length, iMaxNalSize);
-            }
-        }
+  }
+  pParamExt->iPicWidth = 1280;
+  pParamExt->iPicHeight = 720;
+  pParamExt->iPicWidth += (rand() << 1) % IMAGE_VARY_SIZE;
+  pParamExt->iPicHeight += (rand() << 1) % IMAGE_VARY_SIZE;
+  m_iWidth = pParamExt->iPicWidth;
+  m_iHeight = pParamExt->iPicHeight;
+  m_iPicResSize =  m_iWidth * m_iHeight * 3 >> 1;
+  delete []pYUV;
+  pYUV = new unsigned char [m_iPicResSize];
+  ASSERT_TRUE (pYUV != NULL);
+  iResult = pPtrEnc->InitializeExt (pParamExt);
+  PrepareOneSrcFrame();
 
-    }
-    pParamExt->iPicWidth = 1280;
-    pParamExt->iPicHeight = 720;
-    pParamExt->iPicWidth += (rand() << 1) % IMAGE_VARY_SIZE;
-    pParamExt->iPicHeight += (rand() << 1) % IMAGE_VARY_SIZE;
-    m_iWidth = pParamExt->iPicWidth;
-    m_iHeight = pParamExt->iPicHeight;
-    m_iPicResSize =  m_iWidth * m_iHeight * 3 >> 1;
-    delete []pYUV;
-    pYUV = new unsigned char [m_iPicResSize];
-    ASSERT_TRUE (pYUV != NULL);
-    iResult = pPtrEnc->InitializeExt (pParamExt);
-    PrepareOneSrcFrame();
+  ENCODER_OPTION eOptionId = ENCODER_OPTION_SVC_ENCODE_PARAM_EXT;
+  memcpy (pOption, pParamExt, sizeof (SEncParamExt));
+  pOption ->iPicWidth = m_iWidth;
+  pOption ->iPicHeight = m_iHeight;
+  iResult = pPtrEnc->SetOption (eOptionId, pOption);
+  EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
 
-    ENCODER_OPTION eOptionId = ENCODER_OPTION_SVC_ENCODE_PARAM_EXT;
-    memcpy (pOption, pParamExt, sizeof (SEncParamExt));
-    pOption ->iPicWidth = m_iWidth;
-    pOption ->iPicHeight = m_iHeight;
-    iResult = pPtrEnc->SetOption (eOptionId, pOption);
+  for (int i = 0; i < kiFrameNumber; i ++) {
+    PrepareOneSrcFrame();
+    iResult = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
     EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
+    pSrcPic->uiTimeStamp += 30;
 
-    for (int i = 0; i < kiFrameNumber; i ++) {
-        PrepareOneSrcFrame();
-        iResult = pPtrEnc->EncodeFrame (pSrcPic, &sFbi);
-        EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
-        pSrcPic->uiTimeStamp += 30;
-
-        for (int i = 0; i < sFbi.iLayerNum; ++i) {
-            for (int j = 0; j < sFbi.sLayerInfo[i].iNalCount; ++j) {
-                int length = sFbi.sLayerInfo[i].pNalLengthInByte[j];
-                EXPECT_LE (length, iMaxNalSize);
-            }
-        }
+    for (int i = 0; i < sFbi.iLayerNum; ++i) {
+      for (int j = 0; j < sFbi.sLayerInfo[i].iNalCount; ++j) {
+        int length = sFbi.sLayerInfo[i].pNalLengthInByte[j];
+        EXPECT_LE (length, iMaxNalSize);
+      }
     }
-    iResult = pPtrEnc->Uninitialize();
-    EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
+  }
+  iResult = pPtrEnc->Uninitialize();
+  EXPECT_EQ (iResult, static_cast<int> (cmResultSuccess));
 }