From 311f7006fdf0905e957aeb2ff1c90f62f6e041fd Mon Sep 17 00:00:00 2001 From: dongzha Date: Wed, 3 Sep 2014 14:06:01 +0800 Subject: [PATCH] 1. add encoder-engine-decoder API UT for: IDR request, LTR request 2. add decoder api UT for EC: Disable/Enable EC 3. Fix a decoder bug when EC is disabled itoltalMbDec should be set to zero when encouter a new sequence/picture, even when EC is disabled. --- codec/decoder/core/inc/decoder_core.h | 3 +- codec/decoder/core/src/decoder.cpp | 8 +- codec/decoder/core/src/decoder_core.cpp | 19 +- test/api/encode_decode_api_test.cpp | 523 +++++++++++++++++++++++- 4 files changed, 527 insertions(+), 26 deletions(-) diff --git a/codec/decoder/core/inc/decoder_core.h b/codec/decoder/core/inc/decoder_core.h index 3a9e869d..323f737b 100644 --- a/codec/decoder/core/inc/decoder_core.h +++ b/codec/decoder/core/inc/decoder_core.h @@ -144,8 +144,7 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf /* * Check if frame is completed and EC is required */ -bool CheckAndDoEC (PWelsDecoderContext pCtx, uint8_t** pDst, SBufferInfo* pDstInfo); - +bool CheckAndFinishLastPic (PWelsDecoderContext pCtx, uint8_t** pDst, SBufferInfo* pDstInfo); /* * Prepare current dq layer context initialization. */ diff --git a/codec/decoder/core/src/decoder.cpp b/codec/decoder/core/src/decoder.cpp index 009eb082..28679aca 100644 --- a/codec/decoder/core/src/decoder.cpp +++ b/codec/decoder/core/src/decoder.cpp @@ -462,8 +462,8 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in iConsumedBytes = 0; pNalPayload = ParseNalHeader (pCtx, &pCtx->sCurNalHead, pDstNal, iDstIdx, pSrcNal - 3, iSrcIdx + 3, &iConsumedBytes); - if ((pCtx->eErrorConMethod != ERROR_CON_DISABLE) && (IS_VCL_NAL (pCtx->sCurNalHead.eNalUnitType, 1))) { - CheckAndDoEC (pCtx, ppDst, pDstBufInfo); + if (IS_VCL_NAL (pCtx->sCurNalHead.eNalUnitType, 1)) { + CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo); } if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) { iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes); @@ -522,8 +522,8 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in iConsumedBytes = 0; pNalPayload = ParseNalHeader (pCtx, &pCtx->sCurNalHead, pDstNal, iDstIdx, pSrcNal - 3, iSrcIdx + 3, &iConsumedBytes); - if ((pCtx->eErrorConMethod != ERROR_CON_DISABLE) && (IS_VCL_NAL (pCtx->sCurNalHead.eNalUnitType, 1))) { - CheckAndDoEC (pCtx, ppDst, pDstBufInfo); + if (IS_VCL_NAL (pCtx->sCurNalHead.eNalUnitType, 1)) { + CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo); } if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) { iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes); diff --git a/codec/decoder/core/src/decoder_core.cpp b/codec/decoder/core/src/decoder_core.cpp index 26276540..925afce1 100644 --- a/codec/decoder/core/src/decoder_core.cpp +++ b/codec/decoder/core/src/decoder_core.cpp @@ -2001,7 +2001,7 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf return ERR_NONE; } -bool CheckAndDoEC (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { +bool CheckAndFinishLastPic (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { PAccessUnit pAu = pCtx->pAccessUnitList; PNalUnit pCurNal = pAu->pNalUnitsList[pAu->uiEndPos]; if ((pCtx->iTotalNumMbRec != 0) @@ -2009,12 +2009,16 @@ bool CheckAndDoEC (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstI &pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader))) { //Do Error Concealment here if (NeedErrorCon (pCtx)) { //should always be true! - ImplementErrorCon (pCtx); - pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; - DecodeFrameConstruction (pCtx, ppDst, pDstInfo); - if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) { - pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future use - MarkECFrameAsRef (pCtx); + if (pCtx->eErrorConMethod != ERROR_CON_DISABLE) { + ImplementErrorCon (pCtx); + pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; + DecodeFrameConstruction (pCtx, ppDst, pDstInfo); + if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) { + pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future use + MarkECFrameAsRef (pCtx); + } + } else { + DecodeFrameConstruction (pCtx, ppDst, pDstInfo); } pCtx->iPrevFrameNum = pCtx->sLastSliceHeader.iFrameNum; //save frame_num if (pCtx->bLastHasMmco5) @@ -2023,5 +2027,4 @@ bool CheckAndDoEC (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstI } return ERR_NONE; } - } // namespace WelsDec diff --git a/test/api/encode_decode_api_test.cpp b/test/api/encode_decode_api_test.cpp index ad6fbd96..8eb1aa89 100644 --- a/test/api/encode_decode_api_test.cpp +++ b/test/api/encode_decode_api_test.cpp @@ -4,16 +4,28 @@ #include "utils/FileInputStream.h" #include "BaseDecoderTest.h" #include "BaseEncoderTest.h" +#include "wels_common_defs.h" #include +#include +using namespace WelsCommon; + +typedef struct SLost_Sim { + WelsCommon::EWelsNalUnitType eNalType; + bool isLost; +} SLostSim; + struct EncodeDecodeFileParamBase { int numframes; int width; int height; float frameRate; + int slicenum; + bool bLostPara; + const char* pLossSequence; }; -class EncodeDecodeTestBase : public ::testing::Test, +class EncodeDecodeTestBase : public ::testing::TestWithParam, public BaseEncoderTest, public BaseDecoderTest { public: virtual void SetUp() { @@ -54,6 +66,7 @@ class EncodeDecodeTestBase : public ::testing::Test, SEncParamExt param_; BufferedData buf_; SBufferInfo dstBufInfo_; + std::vector m_SLostSim; }; class EncodeDecodeTestAPI : public EncodeDecodeTestBase { @@ -71,12 +84,15 @@ class EncodeDecodeTestAPI : public EncodeDecodeTestBase { } }; -static const EncodeDecodeFileParamBase kFileParamArray = -{300, 160, 96, 6.0f}; +static const EncodeDecodeFileParamBase kFileParamArray[] = { + {300, 160, 96, 6.0f, 2, 1, "000000000000001010101010101010101010101001101010100000010101000011"}, + {300, 140, 96, 6.0f, 4, 1, "000000000000001010101010101010101010101001101010100000010101000011"}, +}; -TEST_F (EncodeDecodeTestAPI, DecoderVclNal) { - EncodeDecodeFileParamBase p = kFileParamArray; +TEST_P (EncodeDecodeTestAPI, DecoderVclNal) { + EncodeDecodeFileParamBase p = GetParam(); prepareParam (p.width, p.height, p.frameRate); + encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); @@ -86,7 +102,9 @@ TEST_F (EncodeDecodeTestAPI, DecoderVclNal) { buf_.SetLength (frameSize); ASSERT_TRUE (buf_.Length() == (size_t)frameSize); - + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); SFrameBSInfo info; memset (&info, 0, sizeof (SFrameBSInfo)); @@ -123,16 +141,19 @@ TEST_F (EncodeDecodeTestAPI, DecoderVclNal) { //ignore last frame } -TEST_F (EncodeDecodeTestAPI, GetOptionFramenum) { - EncodeDecodeFileParamBase p = kFileParamArray; +TEST_P (EncodeDecodeTestAPI, GetOptionFramenum) { + EncodeDecodeFileParamBase p = GetParam(); prepareParam (p.width, p.height, p.frameRate); + encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); //init for encoder // I420: 1(Y) + 1/4(U) + 1/4(V) int frameSize = p.width * p.height * 3 / 2; - + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); buf_.SetLength (frameSize); ASSERT_TRUE (buf_.Length() == (size_t)frameSize); @@ -175,16 +196,19 @@ TEST_F (EncodeDecodeTestAPI, GetOptionFramenum) { //ignore last frame } -TEST_F (EncodeDecodeTestAPI, GetOptionIDR) { - EncodeDecodeFileParamBase p = kFileParamArray; +TEST_P (EncodeDecodeTestAPI, GetOptionIDR) { + EncodeDecodeFileParamBase p = GetParam(); prepareParam (p.width, p.height, p.frameRate); + encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); //init for encoder // I420: 1(Y) + 1/4(U) + 1/4(V) int frameSize = p.width * p.height * 3 / 2; - + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); buf_.SetLength (frameSize); ASSERT_TRUE (buf_.Length() == (size_t)frameSize); @@ -236,3 +260,478 @@ TEST_F (EncodeDecodeTestAPI, GetOptionIDR) { } +long IsKeyFrameLost (ISVCDecoder* pDecoder, SLTRRecoverRequest* p_LTR_Recover_Request, long hr) { + long bLost = NO_RECOVERY_REQUSET; + int tempInt = -1; + int temple_id = -1; + bool m_P2PmodeFlag = true; + pDecoder->GetOption (DECODER_OPTION_TEMPORAL_ID, &temple_id); + if (hr == dsErrorFree) { + if (m_P2PmodeFlag && temple_id == 0) { + pDecoder->GetOption (DECODER_OPTION_IDR_PIC_ID, &tempInt); + // idr_pic_id change ,reset last correct position + if (p_LTR_Recover_Request->uiIDRPicId != tempInt) { + p_LTR_Recover_Request->uiIDRPicId = tempInt; + p_LTR_Recover_Request->iLastCorrectFrameNum = -1; + } + pDecoder->GetOption (DECODER_OPTION_FRAME_NUM, &tempInt); + if (tempInt >= 0) { + p_LTR_Recover_Request->iLastCorrectFrameNum = tempInt; + } + } + bLost = NO_RECOVERY_REQUSET; + } else if (hr & dsNoParamSets) { + bLost = IDR_RECOVERY_REQUEST; + } else if (((hr & dsRefLost) && (1 == temple_id)) || ((dsErrorFree != hr) && (0 == temple_id))) { + bLost = LTR_RECOVERY_REQUEST; + } else { + bLost = NO_RECOVERY_REQUSET; + } + return bLost; +} + +bool IsLTRMarking (ISVCDecoder* pDecoder) { + int bLTR_marking_flag = 0; + pDecoder->GetOption (DECODER_OPTION_LTR_MARKING_FLAG, &bLTR_marking_flag); + return (bLTR_marking_flag) ? (true) : (false); +} + +void LTRRecoveryRequest (ISVCDecoder* pDecoder, ISVCEncoder* pEncoder, SLTRRecoverRequest* p_LTR_Recover_Request, + long hr) { + + long bKLost = IsKeyFrameLost (pDecoder, p_LTR_Recover_Request, hr); + bool m_P2PmodeFlag = true; + if (m_P2PmodeFlag) { + if (bKLost == IDR_RECOVERY_REQUEST) { + pEncoder->ForceIntraFrame (true); + } else if (bKLost == LTR_RECOVERY_REQUEST) { + p_LTR_Recover_Request->uiFeedbackType = LTR_RECOVERY_REQUEST; + pDecoder->GetOption (DECODER_OPTION_FRAME_NUM, &p_LTR_Recover_Request->iCurrentFrameNum); + pDecoder->GetOption (DECODER_OPTION_IDR_PIC_ID, &p_LTR_Recover_Request->uiIDRPicId); + pEncoder->SetOption (ENCODER_LTR_RECOVERY_REQUEST, p_LTR_Recover_Request); + } + } else { + if (bKLost == IDR_RECOVERY_REQUEST || bKLost == LTR_RECOVERY_REQUEST) { + p_LTR_Recover_Request->uiFeedbackType = IDR_RECOVERY_REQUEST; + pDecoder->GetOption (DECODER_OPTION_FRAME_NUM, &p_LTR_Recover_Request->iCurrentFrameNum); + pDecoder->GetOption (DECODER_OPTION_IDR_PIC_ID, &p_LTR_Recover_Request->uiIDRPicId); + pEncoder->SetOption (ENCODER_LTR_RECOVERY_REQUEST, p_LTR_Recover_Request); + } + } +} + +void LTRMarkFeedback (ISVCDecoder* pDecoder, ISVCEncoder* pEncoder, SLTRMarkingFeedback* p_LTR_Marking_Feedback, + long hr) { + if (IsLTRMarking (pDecoder) == true) { + p_LTR_Marking_Feedback->uiFeedbackType = (hr == dsErrorFree) ? (LTR_MARKING_SUCCESS) : (LTR_MARKING_FAILED); + pDecoder->GetOption (DECODER_OPTION_IDR_PIC_ID, &p_LTR_Marking_Feedback->uiIDRPicId); + pDecoder->GetOption (DECODER_OPTION_LTR_MARKED_FRAME_NUM, &p_LTR_Marking_Feedback->iLTRFrameNum); + pEncoder->SetOption (ENCODER_LTR_MARKING_FEEDBACK, p_LTR_Marking_Feedback); + } +} + + +int SimulateNALLoss (const unsigned char* pSrc, int& iSrcLen, std::vector* p_SLostSim, + const char* pLossChars, bool bLossPara, int& iLossIdx, bool& bVCLLoss) { + unsigned char* pDst = new unsigned char[iSrcLen]; + int iLossCharLen = strlen (pLossChars); + int iSkipedBytes = 0; + int iDstLen = 0; + int iBufPos = 0; + int ilastprefixlen = 0; + int i = 0; + bool bLost; + bVCLLoss = false; + SLostSim tmpSLostSim; + p_SLostSim->clear(); + for (i = 0; i < iSrcLen;) { + if (pSrc[i] == 0 && pSrc[i + 1] == 0 && pSrc[i + 2] == 0 && pSrc[i + 3] == 1) { + if (i - iBufPos) { + tmpSLostSim.eNalType = (EWelsNalUnitType) ((* (pSrc + iBufPos + ilastprefixlen)) & 0x1f); // eNalUnitType + bLost = iLossIdx < iLossCharLen ? (pLossChars[iLossIdx] == '1') : (rand() % 2 == 1); + bLost = (!bLossPara) && (IS_PARAM_SETS_NALS (tmpSLostSim.eNalType)) ? false : bLost; + iLossIdx++; + tmpSLostSim.isLost = bLost; + p_SLostSim->push_back (tmpSLostSim); + if (!bLost) { + memcpy (pDst + iDstLen, pSrc + iBufPos, i - iBufPos); + iDstLen += (i - iBufPos); + } else { + bVCLLoss = (IS_VCL_NAL (tmpSLostSim.eNalType, 1)) ? true : bVCLLoss; + iSkipedBytes += (i - iBufPos); + } + } + ilastprefixlen = 4; + iBufPos = i; + i = i + 4; + } else if (pSrc[i] == 0 && pSrc[i + 1] == 0 && pSrc[i + 2] == 1) { + if (i - iBufPos) { + tmpSLostSim.eNalType = (EWelsNalUnitType) ((* (pSrc + iBufPos + ilastprefixlen)) & 0x1f); // eNalUnitType + bLost = iLossIdx < iLossCharLen ? (pLossChars[iLossIdx] == '1') : (rand() % 2 == 1); + bLost = (!bLossPara) && (IS_PARAM_SETS_NALS (tmpSLostSim.eNalType)) ? false : bLost; + iLossIdx++; + tmpSLostSim.isLost = bLost; + p_SLostSim->push_back (tmpSLostSim); + if (!bLost) { + memcpy (pDst + iDstLen, pSrc + iBufPos, i - iBufPos); + iDstLen += (i - iBufPos); + } else { + bVCLLoss = (IS_VCL_NAL (tmpSLostSim.eNalType, 1)) ? true : bVCLLoss; + iSkipedBytes += (i - iBufPos); + } + } + ilastprefixlen = 3; + iBufPos = i; + i = i + 3; + } else { + i++; + } + } + if (i - iBufPos) { + tmpSLostSim.eNalType = (EWelsNalUnitType) ((* (pSrc + iBufPos + ilastprefixlen)) & 0x1f); // eNalUnitType + bLost = iLossIdx < iLossCharLen ? (pLossChars[iLossIdx] == '1') : (rand() % 2 == 1); + bLost = (!bLossPara) && (IS_PARAM_SETS_NALS (tmpSLostSim.eNalType)) ? false : bLost; + iLossIdx++; + tmpSLostSim.isLost = bLost; + p_SLostSim->push_back (tmpSLostSim); + if (!bLost) { + memcpy (pDst + iDstLen, pSrc + iBufPos, i - iBufPos); + iDstLen += (i - iBufPos); + } else { + bVCLLoss = (IS_VCL_NAL (tmpSLostSim.eNalType, 1)) ? true : bVCLLoss; + iSkipedBytes += (i - iBufPos); + } + } + memset ((void*)pSrc, 0, iSrcLen); + memcpy ((void*)pSrc, pDst, iDstLen); + iSrcLen = iDstLen; + delete pDst; + return iSkipedBytes; +} + +TEST_P (EncodeDecodeTestAPI, GetOptionLTR_ALLIDR) { + EncodeDecodeFileParamBase p = GetParam(); + prepareParam (p.width, p.height, p.frameRate); + encoder_->Uninitialize(); + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + int frameSize = p.width * p.height * 3 / 2; + buf_.SetLength (frameSize); + ASSERT_TRUE (buf_.Length() == (size_t)frameSize); + + SFrameBSInfo info; + memset (&info, 0, sizeof (SFrameBSInfo)); + SSourcePicture pic; + memset (&pic, 0, sizeof (SSourcePicture)); + pic.iPicWidth = p.width; + pic.iPicHeight = p.height; + pic.iColorFormat = videoFormatI420; + pic.iStride[0] = pic.iPicWidth; + pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; + pic.pData[0] = buf_.data(); + pic.pData[1] = pic.pData[0] + p.width * p.height; + pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2); + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); + int32_t iSpsPpsIdAddition = 1; + encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition); + int32_t iIDRPeriod = 60; + encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); + SLTRConfig sLtrConfigVal; + sLtrConfigVal.bEnableLongTermReference = 1; + sLtrConfigVal.iLTRRefNum = 1; + encoder_->SetOption (ENCODER_OPTION_LTR, &sLtrConfigVal); + int32_t iLtrPeriod = 2; + encoder_->SetOption (ENCODER_LTR_MARKING_PERIOD, &iLtrPeriod); + int iIdx = 0; + while (iIdx <= p.numframes) { + memset (buf_.data(), rand() % 256, frameSize); + rv = encoder_->EncodeFrame (&pic, &info); + ASSERT_EQ (rv, cmResultSuccess); + ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); + encoder_->ForceIntraFrame (true); + iIdx++; + } +} + +TEST_P (EncodeDecodeTestAPI, GetOptionLTR_ALLLTR) { + SLTRMarkingFeedback m_LTR_Marking_Feedback; + SLTRRecoverRequest m_LTR_Recover_Request; + EncodeDecodeFileParamBase p = GetParam(); + prepareParam (p.width, p.height, p.frameRate); + encoder_->Uninitialize(); + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + int frameSize = p.width * p.height * 3 / 2; + buf_.SetLength (frameSize); + ASSERT_TRUE (buf_.Length() == (size_t)frameSize); + SFrameBSInfo info; + memset (&info, 0, sizeof (SFrameBSInfo)); + + SSourcePicture pic; + memset (&pic, 0, sizeof (SSourcePicture)); + pic.iPicWidth = p.width; + pic.iPicHeight = p.height; + pic.iColorFormat = videoFormatI420; + pic.iStride[0] = pic.iPicWidth; + pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; + pic.pData[0] = buf_.data(); + pic.pData[1] = pic.pData[0] + p.width * p.height; + pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2); + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); + int32_t iSpsPpsIdAddition = 1; + encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition); + int32_t iIDRPeriod = 60; + encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); + SLTRConfig sLtrConfigVal; + sLtrConfigVal.bEnableLongTermReference = 1; + sLtrConfigVal.iLTRRefNum = 1; + encoder_->SetOption (ENCODER_OPTION_LTR, &sLtrConfigVal); + int32_t iLtrPeriod = 2; + encoder_->SetOption (ENCODER_LTR_MARKING_PERIOD, &iLtrPeriod); + int iIdx = 0; + while (iIdx <= p.numframes) { + memset (buf_.data(), rand() % 256, frameSize); + rv = encoder_->EncodeFrame (&pic, &info); + if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { + ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); + } + ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason); + m_LTR_Recover_Request.uiFeedbackType = LTR_RECOVERY_REQUEST; + m_LTR_Recover_Request.iCurrentFrameNum = rand() % 2 == 1 ? -rand() % 10000 : rand() % 10000; + m_LTR_Recover_Request.uiIDRPicId = rand() % 2 == 1 ? -rand() % 10000 : rand() % 10000; + encoder_->SetOption (ENCODER_LTR_RECOVERY_REQUEST, &m_LTR_Recover_Request); + m_LTR_Marking_Feedback.uiFeedbackType = rand() % 2 == 1 ? LTR_MARKING_SUCCESS : LTR_MARKING_FAILED; + m_LTR_Marking_Feedback.uiIDRPicId = rand() % 2 == 1 ? -rand() % 10000 : rand() % 10000; + m_LTR_Marking_Feedback.iLTRFrameNum = rand() % 2 == 1 ? -rand() % 10000 : rand() % 10000; + encoder_->SetOption (ENCODER_LTR_MARKING_FEEDBACK, &m_LTR_Marking_Feedback); + iIdx++; + } +} + +TEST_P (EncodeDecodeTestAPI, GetOptionLTR_Engine) { + SLTRMarkingFeedback m_LTR_Marking_Feedback; + SLTRRecoverRequest m_LTR_Recover_Request; + EncodeDecodeFileParamBase p = GetParam(); + prepareParam (p.width, p.height, p.frameRate); + param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE; + param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = p.slicenum; + encoder_->Uninitialize(); + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + int frameSize = p.width * p.height * 3 / 2; + buf_.SetLength (frameSize); + ASSERT_TRUE (buf_.Length() == (size_t)frameSize); + SFrameBSInfo info; + memset (&info, 0, sizeof (SFrameBSInfo)); + + SSourcePicture pic; + memset (&pic, 0, sizeof (SSourcePicture)); + pic.iPicWidth = p.width; + pic.iPicHeight = p.height; + pic.iColorFormat = videoFormatI420; + pic.iStride[0] = pic.iPicWidth; + pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; + pic.pData[0] = buf_.data(); + pic.pData[1] = pic.pData[0] + p.width * p.height; + pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2); + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); + int32_t iSpsPpsIdAddition = 1; + encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition); + int32_t iIDRPeriod = 60; + encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); + SLTRConfig sLtrConfigVal; + sLtrConfigVal.bEnableLongTermReference = 1; + sLtrConfigVal.iLTRRefNum = 1; + encoder_->SetOption (ENCODER_OPTION_LTR, &sLtrConfigVal); + int32_t iLtrPeriod = 2; + encoder_->SetOption (ENCODER_LTR_MARKING_PERIOD, &iLtrPeriod); + int iIdx = 0; + int iLossIdx = 0; + bool bVCLLoss = false; + while (iIdx <= p.numframes) { + memset (buf_.data(), rand() % 256, frameSize); + rv = encoder_->EncodeFrame (&pic, &info); + if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { + ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); + } + ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason); + //decoding after each encoding frame + int len = 0; + encToDecData (info, len); + unsigned char* pData[3] = { NULL }; + memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); + SimulateNALLoss (info.sLayerInfo[0].pBsBuf, len, &m_SLostSim, p.pLossSequence, p.bLostPara, iLossIdx, bVCLLoss); + rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); + iIdx++; + } +} + +TEST_P (EncodeDecodeTestAPI, SetOptionECFlag_ERROR_CON_DISABLE) { + SLTRMarkingFeedback m_LTR_Marking_Feedback; + SLTRRecoverRequest m_LTR_Recover_Request; + EncodeDecodeFileParamBase p = GetParam(); + prepareParam (p.width, p.height, p.frameRate); + param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE; + param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = p.slicenum; + param_.bEnableLongTermReference = true; + param_.iLTRRefNum = 1; + encoder_->Uninitialize(); + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + if (decoder_ != NULL) { + decoder_->Uninitialize(); + } + SDecodingParam decParam; + memset (&decParam, 0, sizeof (SDecodingParam)); + decParam.eOutputColorFormat = videoFormatI420; + decParam.uiTargetDqLayer = UCHAR_MAX; + decParam.eEcActiveIdc = ERROR_CON_DISABLE; + decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + rv = decoder_->Initialize (&decParam); + ASSERT_EQ (0, rv); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + int frameSize = p.width * p.height * 3 / 2; + buf_.SetLength (frameSize); + ASSERT_TRUE (buf_.Length() == (size_t)frameSize); + SFrameBSInfo info; + memset (&info, 0, sizeof (SFrameBSInfo)); + + SSourcePicture pic; + memset (&pic, 0, sizeof (SSourcePicture)); + pic.iPicWidth = p.width; + pic.iPicHeight = p.height; + pic.iColorFormat = videoFormatI420; + pic.iStride[0] = pic.iPicWidth; + pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; + pic.pData[0] = buf_.data(); + pic.pData[1] = pic.pData[0] + p.width * p.height; + pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2); + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); + int32_t iSpsPpsIdAddition = 1; + encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition); + int32_t iIDRPeriod = 60; + encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); + SLTRConfig sLtrConfigVal; + sLtrConfigVal.bEnableLongTermReference = 1; + sLtrConfigVal.iLTRRefNum = 1; + encoder_->SetOption (ENCODER_OPTION_LTR, &sLtrConfigVal); + int32_t iLtrPeriod = 2; + encoder_->SetOption (ENCODER_LTR_MARKING_PERIOD, &iLtrPeriod); + int iIdx = 0; + int iLossIdx = 0; + int iSkipedBytes; + bool bVCLLoss = false; + while (iIdx <= p.numframes) { + memset (buf_.data(), rand() % 256, frameSize); + rv = encoder_->EncodeFrame (&pic, &info); + if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { + ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); + } + ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason); + //decoding after each encoding frame + int len = 0; + encToDecData (info, len); + unsigned char* pData[3] = { NULL }; + memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); + iSkipedBytes = SimulateNALLoss (info.sLayerInfo[0].pBsBuf, len, &m_SLostSim, p.pLossSequence, p.bLostPara, iLossIdx, + bVCLLoss); + rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); + if (iSkipedBytes && bVCLLoss) { + ASSERT_TRUE (dstBufInfo_.iBufferStatus == 0); + } + iIdx++; + } +} + +TEST_P (EncodeDecodeTestAPI, SetOptionECFlag_ERROR_CON_SLICE_COPY) { + SLTRMarkingFeedback m_LTR_Marking_Feedback; + SLTRRecoverRequest m_LTR_Recover_Request; + EncodeDecodeFileParamBase p = GetParam(); + prepareParam (p.width, p.height, p.frameRate); + param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE; + param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = p.slicenum; + encoder_->Uninitialize(); + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + int frameSize = p.width * p.height * 3 / 2; + buf_.SetLength (frameSize); + ASSERT_TRUE (buf_.Length() == (size_t)frameSize); + SFrameBSInfo info; + memset (&info, 0, sizeof (SFrameBSInfo)); + + SSourcePicture pic; + memset (&pic, 0, sizeof (SSourcePicture)); + pic.iPicWidth = p.width; + pic.iPicHeight = p.height; + pic.iColorFormat = videoFormatI420; + pic.iStride[0] = pic.iPicWidth; + pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1; + pic.pData[0] = buf_.data(); + pic.pData[1] = pic.pData[0] + p.width * p.height; + pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2); + int32_t iTraceLevel = WELS_LOG_QUIET; + encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); + decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); + int32_t iSpsPpsIdAddition = 1; + encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition); + int32_t iIDRPeriod = 60; + encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); + SLTRConfig sLtrConfigVal; + sLtrConfigVal.bEnableLongTermReference = 1; + sLtrConfigVal.iLTRRefNum = 1; + encoder_->SetOption (ENCODER_OPTION_LTR, &sLtrConfigVal); + int32_t iLtrPeriod = 2; + encoder_->SetOption (ENCODER_LTR_MARKING_PERIOD, &iLtrPeriod); + int iIdx = 0; + int iLossIdx = 0; + int iSkipedBytes; + bool bVCLLoss = false; + while (iIdx <= p.numframes) { + memset (buf_.data(), rand() % 256, frameSize); + rv = encoder_->EncodeFrame (&pic, &info); + if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { + ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); + } + ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason); + //decoding after each encoding frame + int len = 0; + encToDecData (info, len); + unsigned char* pData[3] = { NULL }; + memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); + iSkipedBytes = SimulateNALLoss (info.sLayerInfo[0].pBsBuf, len, &m_SLostSim, p.pLossSequence, p.bLostPara, iLossIdx, + bVCLLoss); + uint32_t uiEcIdc = rand() % 2 == 1 ? ERROR_CON_DISABLE : ERROR_CON_SLICE_COPY; + decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc); + rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); + m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction + LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv); + LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); + iIdx++; + } +} + +INSTANTIATE_TEST_CASE_P (EncodeDecodeTestBase, EncodeDecodeTestAPI, + ::testing::ValuesIn (kFileParamArray));