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));
}