ref: e89f8a51b25fbe2ef5bba781b26236a53d09bc37
dir: /test/api/decode_api_test.cpp/
#include <gtest/gtest.h> #include "codec_def.h" #include "utils/BufferedData.h" #include "utils/FileInputStream.h" #include "BaseDecoderTest.h" #include "BaseEncoderTest.h" #include "wels_common_defs.h" #include "utils/HashFunctions.h" #include <string> #include <vector> #include "encode_decode_api_test.h" using namespace WelsCommon; static void TestOutPutTrace (void* ctx, int level, const char* string) { STraceUnit* pTraceUnit = (STraceUnit*) ctx; EXPECT_LE (level, pTraceUnit->iTarLevel); } TEST_P (EncodeDecodeTestAPI, DecoderVclNal) { EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); ASSERT_TRUE (InitialEncDec (p.width, p.height)); int iIdx = 0; while (iIdx <= p.numframes) { EncodeOneFrame (0); //decoding after each encoding frame int vclNal, len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); ASSERT_TRUE (rv == cmResultSuccess); rv = decoder_->GetOption (DECODER_OPTION_VCL_NAL, &vclNal); EXPECT_EQ (vclNal, FEEDBACK_UNKNOWN_NAL); //no reconstruction, unknown return rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction ASSERT_TRUE (rv == cmResultSuccess); rv = decoder_->GetOption (DECODER_OPTION_VCL_NAL, &vclNal); EXPECT_EQ (vclNal, FEEDBACK_VCL_NAL); iIdx++; } //while //ignore last frame } TEST_P (EncodeDecodeTestAPI, GetOptionFramenum) { EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); ASSERT_TRUE (InitialEncDec (p.width, p.height)); int32_t iEncFrameNum = -1; int32_t iDecFrameNum; int iIdx = 0; while (iIdx <= p.numframes) { EncodeOneFrame (0); //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_FRAME_NUM, &iDecFrameNum); EXPECT_EQ (iDecFrameNum, -1); iEncFrameNum++; rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_FRAME_NUM, &iDecFrameNum); EXPECT_EQ (iEncFrameNum, iDecFrameNum); iIdx++; } //while //ignore last frame } TEST_P (EncodeDecodeTestAPI, GetOptionIDR) { EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); //init for encoder // I420: 1(Y) + 1/4(U) + 1/4(V) int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); ASSERT_TRUE (InitialEncDec (p.width, p.height)); int32_t iEncCurIdrPicId = 0; int32_t iDecCurIdrPicId; int32_t iIDRPeriod = 1; int32_t iSpsPpsIdAddition = 0; int iIdx = 0; while (iIdx <= p.numframes) { iSpsPpsIdAddition = rand() % 2; //the current strategy supports more than 2 modes, but the switch between the modes>2 is not allowed iIDRPeriod = (rand() % 150) + 1; encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod); encoder_->SetOption (ENCODER_OPTION_SPS_PPS_ID_STRATEGY, &iSpsPpsIdAddition); EncodeOneFrame (0); if (info.eFrameType == videoFrameTypeIDR) { iEncCurIdrPicId = iEncCurIdrPicId + 1; } //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_IDR_PIC_ID, &iDecCurIdrPicId); EXPECT_EQ (iDecCurIdrPicId, iEncCurIdrPicId); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_IDR_PIC_ID, &iDecCurIdrPicId); EXPECT_EQ (iDecCurIdrPicId, iEncCurIdrPicId); iIdx++; } //while //ignore last frame } TEST_P (EncodeDecodeTestAPI, InOutTimeStamp) { EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); ASSERT_TRUE (InitialEncDec (p.width, p.height)); 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_SPS_PPS_ID_STRATEGY, &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 iSkipedBytes; unsigned long long uiEncTimeStamp = 100; while (iIdx <= p.numframes) { EncodeOneFrame (1); //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); uint32_t uiEcIdc = ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE; decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc); dstBufInfo_.uiInBsTimeStamp = uiEncTimeStamp; rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); dstBufInfo_.uiInBsTimeStamp = uiEncTimeStamp; rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction if (dstBufInfo_.iBufferStatus == 1) { EXPECT_EQ (uiEncTimeStamp, dstBufInfo_.uiOutYuvTimeStamp); } iIdx++; uiEncTimeStamp++; } (void) iSkipedBytes; } TEST_P (EncodeDecodeTestAPI, GetOptionIsRefPic) { EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); ASSERT_TRUE (InitialEncDec (p.width, p.height)); int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); int iIdx = 0; int iSkipedBytes; int iIsRefPic; decoder_->GetOption (DECODER_OPTION_IS_REF_PIC, &iIsRefPic); ASSERT_EQ (iIsRefPic, -1); while (iIdx <= p.numframes) { EncodeOneFrame (1); //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); decoder_->GetOption (DECODER_OPTION_IS_REF_PIC, &iIsRefPic); ASSERT_EQ (iIsRefPic, -1); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction if (dstBufInfo_.iBufferStatus == 1) { decoder_->GetOption (DECODER_OPTION_IS_REF_PIC, &iIsRefPic); ASSERT_TRUE (iIsRefPic >= 0); } iIdx++; } (void)iSkipedBytes; } TEST_P (EncodeDecodeTestAPI, GetOptionTid_AVC_NOPREFIX) { SLTRMarkingFeedback m_LTR_Marking_Feedback; SLTRRecoverRequest m_LTR_Recover_Request; m_LTR_Recover_Request.uiIDRPicId = 0; m_LTR_Recover_Request.iLayerId = 0; m_LTR_Marking_Feedback.iLayerId = 0; EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); param_.bPrefixNalAddingCtrl = false; param_.iTemporalLayerNum = (rand() % 4) + 1; encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; ASSERT_TRUE (InitialEncDec (p.width, p.height)); 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_SPS_PPS_ID_STRATEGY, &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) { EncodeOneFrame (1); if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); } //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_); int iTid = -1; decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); if (iTid != -1) { ASSERT_EQ (iTid, 0); } m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); std::vector<SLostSim>::iterator iter = m_SLostSim.begin(); bool bHasVCL = false; for (unsigned int k = 0; k < m_SLostSim.size(); k++) { if (IS_VCL_NAL (iter->eNalType, 0) && iter->isLost == false) { bHasVCL = true; break; } iter++; } (void) bHasVCL; if (iTid != -1) { ASSERT_EQ (iTid, 0); } LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); iIdx++; } } TEST_P (EncodeDecodeTestAPI, GetOptionTid_AVC_WITH_PREFIX_NOLOSS) { SLTRMarkingFeedback m_LTR_Marking_Feedback; SLTRRecoverRequest m_LTR_Recover_Request; m_LTR_Recover_Request.uiIDRPicId = 0; m_LTR_Recover_Request.iLayerId = 0; m_LTR_Marking_Feedback.iLayerId = 0; EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); param_.bPrefixNalAddingCtrl = true; param_.iTemporalLayerNum = (rand() % 4) + 1; param_.iSpatialLayerNum = 1; encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; ASSERT_TRUE (InitialEncDec (p.width, p.height)); 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_SPS_PPS_ID_STRATEGY, &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) { EncodeOneFrame (1); if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); } //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); ExtractDidNal (&info, len, &m_SLostSim, 0); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); int iTid = -1; decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); ASSERT_EQ (iTid, -1); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); ASSERT_EQ (iTid, info.sLayerInfo[0].uiTemporalId); LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); iIdx++; } } TEST_P (EncodeDecodeTestAPI, GetOptionTid_SVC_L1_NOLOSS) { SLTRMarkingFeedback m_LTR_Marking_Feedback; SLTRRecoverRequest m_LTR_Recover_Request; m_LTR_Recover_Request.uiIDRPicId = 0; m_LTR_Recover_Request.iLayerId = 0; m_LTR_Marking_Feedback.iLayerId = 0; EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (2, p.slicenum, p.width, p.height, p.frameRate, ¶m_); param_.iTemporalLayerNum = (rand() % 4) + 1; param_.iSpatialLayerNum = 2; encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; ASSERT_TRUE (InitialEncDec (p.width, p.height)); 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_SPS_PPS_ID_STRATEGY, &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) { EncodeOneFrame (1); if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); } //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); ExtractDidNal (&info, len, &m_SLostSim, 1); rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_); int iTid = -1; decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); ASSERT_EQ (iTid, -1); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid); ASSERT_EQ (iTid, info.sLayerInfo[0].uiTemporalId); LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); iIdx++; } } TEST_P (EncodeDecodeTestAPI, SetOption_Trace) { SLTRMarkingFeedback m_LTR_Marking_Feedback; SLTRRecoverRequest m_LTR_Recover_Request; m_LTR_Recover_Request.uiIDRPicId = 0; m_LTR_Recover_Request.iLayerId = 0; m_LTR_Marking_Feedback.iLayerId = 0; EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); param_.iSpatialLayerNum = 1; int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; ASSERT_TRUE (InitialEncDec (p.width, p.height)); int32_t iTraceLevel = WELS_LOG_QUIET; pFunc = TestOutPutTrace; pTraceInfo = &sTrace; sTrace.iTarLevel = iTraceLevel; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); encoder_->SetOption (ENCODER_OPTION_TRACE_CALLBACK, &pFunc); encoder_->SetOption (ENCODER_OPTION_TRACE_CALLBACK_CONTEXT, &pTraceInfo); decoder_->SetOption (DECODER_OPTION_TRACE_CALLBACK, &pFunc); decoder_->SetOption (DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &pTraceInfo); int32_t iSpsPpsIdAddition = 1; encoder_->SetOption (ENCODER_OPTION_SPS_PPS_ID_STRATEGY, &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) { iTraceLevel = rand() % 33; sTrace.iTarLevel = iTraceLevel; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); EncodeOneFrame (1); if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); } //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); ExtractDidNal (&info, len, &m_SLostSim, 0); 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, true); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); iIdx++; } } TEST_P (EncodeDecodeTestAPI, SetOption_Trace_NULL) { SLTRMarkingFeedback m_LTR_Marking_Feedback; SLTRRecoverRequest m_LTR_Recover_Request; m_LTR_Recover_Request.uiIDRPicId = 0; m_LTR_Recover_Request.iLayerId = 0; m_LTR_Marking_Feedback.iLayerId = 0; EncodeDecodeFileParamBase p = GetParam(); prepareParamDefault (1, p.slicenum, p.width, p.height, p.frameRate, ¶m_); param_.iSpatialLayerNum = 1; int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET; ASSERT_TRUE (InitialEncDec (p.width, p.height)); int32_t iTraceLevel = WELS_LOG_QUIET; pFunc = NULL; pTraceInfo = NULL; encoder_->SetOption (ENCODER_OPTION_TRACE_CALLBACK, &pFunc); encoder_->SetOption (ENCODER_OPTION_TRACE_CALLBACK_CONTEXT, &pTraceInfo); decoder_->SetOption (DECODER_OPTION_TRACE_CALLBACK, &pFunc); decoder_->SetOption (DECODER_OPTION_TRACE_CALLBACK_CONTEXT, &pTraceInfo); encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); int32_t iSpsPpsIdAddition = 1; encoder_->SetOption (ENCODER_OPTION_SPS_PPS_ID_STRATEGY, &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) { iTraceLevel = rand() % 33; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); EncodeOneFrame (1); if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) { ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR); } //decoding after each encoding frame int len = 0; encToDecData (info, len); unsigned char* pData[3] = { NULL }; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); ExtractDidNal (&info, len, &m_SLostSim, 0); 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, true); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, true); LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv); iIdx++; } } class DecodeCrashTestAPI : public ::testing::TestWithParam<EncodeDecodeFileParamBase>, public EncodeDecodeTestBase { public: void SetUp() { EncodeDecodeTestBase::SetUp(); ucBuf_ = NULL; ucBuf_ = new unsigned char [1000000]; ASSERT_TRUE (ucBuf_ != NULL); } void TearDown() { EncodeDecodeTestBase::TearDown(); if (NULL != ucBuf_) { delete[] ucBuf_; ucBuf_ = NULL; } ASSERT_TRUE (ucBuf_ == NULL); } void prepareParam (int iLayerNum, int iSliceNum, int width, int height, float framerate, SEncParamExt* pParam) { memset (pParam, 0, sizeof (SEncParamExt)); EncodeDecodeTestBase::prepareParam (iLayerNum, iSliceNum, width, height, framerate, pParam); } void EncodeOneFrame() { int frameSize = EncPic.iPicWidth * EncPic.iPicHeight * 3 / 2; memset (buf_.data(), iRandValue, (frameSize >> 2)); memset (buf_.data() + (frameSize >> 2), rand() % 256, (frameSize - (frameSize >> 2))); int rv = encoder_->EncodeFrame (&EncPic, &info); ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnknownReason); } protected: unsigned char* ucBuf_; }; struct EncodeDecodeParamBase { int width; int height; float frameRate; int iTarBitrate; }; #define NUM_OF_POSSIBLE_RESOLUTION (9) static const EncodeDecodeParamBase kParamArray[] = { {160, 90, 6.0f, 250000}, {90, 160, 6.0f, 250000}, {320, 180, 12.0f, 500000}, {180, 320, 12.0f, 500000}, {480, 270, 12.0f, 600000}, {270, 480, 12.0f, 600000}, {640, 360, 24.0f, 800000}, {360, 640, 24.0f, 800000}, {1280, 720, 24.0f, 1000000}, }; //#define DEBUG_FILE_SAVE_CRA TEST_F (DecodeCrashTestAPI, DecoderCrashTest) { uint32_t uiGet; encoder_->Uninitialize(); //do tests until crash unsigned int uiLoopRound = 0; unsigned char* pucBuf = ucBuf_; int iDecAuSize; #ifdef DEBUG_FILE_SAVE_CRA //open file to save tested BS FILE* fDataFile = fopen ("test_crash.264", "wb"); FILE* fLenFile = fopen ("test_crash_len.log", "w"); int iFileSize = 0; #endif //set eCurStrategy for one test EParameterSetStrategy eCurStrategy = CONSTANT_ID; switch (rand() % 7) { case 1: eCurStrategy = INCREASING_ID; break; case 2: eCurStrategy = SPS_LISTING; break; case 3: eCurStrategy = SPS_LISTING_AND_PPS_INCREASING; break; case 6: eCurStrategy = SPS_PPS_LISTING; break; default: //using the initial value break; } do { int iTotalFrameNum = (rand() % 100) + 1; int iSeed = rand() % NUM_OF_POSSIBLE_RESOLUTION; EncodeDecodeParamBase p = kParamArray[iSeed]; #ifdef DEBUG_FILE_SAVE_CRA printf ("using param set %d in loop %d\n", iSeed, uiLoopRound); #endif //Initialize Encoder prepareParam (1, 1, p.width, p.height, p.frameRate, ¶m_); param_.iRCMode = RC_TIMESTAMP_MODE; param_.iTargetBitrate = p.iTarBitrate; param_.uiIntraPeriod = 0; param_.eSpsPpsIdStrategy = eCurStrategy; param_.bEnableBackgroundDetection = true; param_.bEnableSceneChangeDetect = (rand() % 3) ? true : false; param_.bPrefixNalAddingCtrl = (rand() % 2) ? true : false; param_.iEntropyCodingModeFlag = 0; param_.bEnableFrameSkip = true; param_.iMultipleThreadIdc = 0; param_.sSpatialLayers[0].iSpatialBitrate = p.iTarBitrate; param_.sSpatialLayers[0].iMaxSpatialBitrate = p.iTarBitrate << 1; param_.sSpatialLayers[0].sSliceArgument.uiSliceMode = (rand() % 2) ? SM_SIZELIMITED_SLICE : SM_SINGLE_SLICE; if (param_.sSpatialLayers[0].sSliceArgument.uiSliceMode == SM_SIZELIMITED_SLICE) { param_.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = 1400; param_.uiMaxNalSize = 1400; } else { param_.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = 0; param_.uiMaxNalSize = 0; } int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet); EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY); //default value should be ERROR_CON_SLICE_COPY int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); //Start for enc/dec int iIdx = 0; unsigned char* pData[3] = { NULL }; EncodeDecodeFileParamBase pInput; //to conform with old functions pInput.width = p.width; pInput.height = p.height; pInput.frameRate = p.frameRate; ASSERT_TRUE (prepareEncDecParam (pInput)); while (iIdx++ < iTotalFrameNum) { // loop in frame EncodeOneFrame(); #ifdef DEBUG_FILE_SAVE_CRA //reset file if file size large if ((info.eFrameType == videoFrameTypeIDR) && (iFileSize >= (1 << 25))) { fclose (fDataFile); fDataFile = fopen ("test_crash.264", "wb"); iFileSize = 0; decoder_->Uninitialize(); SDecodingParam decParam; memset (&decParam, 0, sizeof (SDecodingParam)); decParam.uiTargetDqLayer = UCHAR_MAX; decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; rv = decoder_->Initialize (&decParam); ASSERT_EQ (0, rv); } #endif if (info.eFrameType == videoFrameTypeSkip) continue; //deal with packets unsigned char* pBsBuf; iDecAuSize = 0; pucBuf = ucBuf_; //init buf start pos for decoder usage for (int iLayerNum = 0; iLayerNum < info.iLayerNum; iLayerNum++) { SLayerBSInfo* pLayerBsInfo = &info.sLayerInfo[iLayerNum]; pBsBuf = info.sLayerInfo[iLayerNum].pBsBuf; int iTotalNalCnt = pLayerBsInfo->iNalCount; for (int iNalCnt = 0; iNalCnt < iTotalNalCnt; iNalCnt++) { //loop in NAL int iPacketSize = pLayerBsInfo->pNalLengthInByte[iNalCnt]; //packet loss int iLossRateRange = (uiLoopRound % 100) + 1; //1-100 int iLossRate = (rand() % iLossRateRange); bool bPacketLost = (rand() % 101) > (100 - iLossRate); // [0, (100-iLossRate)] indicates NO LOSS, (100-iLossRate, 100] indicates LOSS if (!bPacketLost) { //no loss memcpy (pucBuf, pBsBuf, iPacketSize); pucBuf += iPacketSize; iDecAuSize += iPacketSize; } #ifdef DEBUG_FILE_SAVE_CRA else { printf ("lost packet size=%d at frame-type=%d at loss rate %d (%d)\n", iPacketSize, info.eFrameType, iLossRate, iLossRateRange); } #endif //update bs info pBsBuf += iPacketSize; } //nal } //layer #ifdef DEBUG_FILE_SAVE_CRA //save to file fwrite (ucBuf_, 1, iDecAuSize, fDataFile); fflush (fDataFile); iFileSize += iDecAuSize; //save to len file unsigned long ulTmp[4]; ulTmp[0] = ulTmp[1] = ulTmp[2] = iIdx; ulTmp[3] = iDecAuSize; fwrite (ulTmp, sizeof (unsigned long), 4, fLenFile); // index, timeStamp, data size fflush (fLenFile); #endif //decode pData[0] = pData[1] = pData[2] = 0; memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); rv = decoder_->DecodeFrame2 (ucBuf_, iDecAuSize, pData, &dstBufInfo_); rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction //guarantee decoder EC status decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet); EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY); } //frame uiLoopRound ++; if (uiLoopRound >= (1 << 30)) uiLoopRound = 0; #ifdef DEBUG_FILE_SAVE_CRA if (uiLoopRound % 100 == 0) printf ("run %d times.\n", uiLoopRound); } while (1); //while (iLoopRound<100); fclose (fDataFile); fclose (fLenFile); #else } while (uiLoopRound < 10); #endif } const uint32_t kiTotalLayer = 3; //DO NOT CHANGE! const uint32_t kiSliceNum = 2; //DO NOT CHANGE! const uint32_t kiWidth = 160; //DO NOT CHANGE! const uint32_t kiHeight = 96; //DO NOT CHANGE! const uint32_t kiFrameRate = 12; //DO NOT CHANGE! const uint32_t kiFrameNum = 100; //DO NOT CHANGE! const char* const pHashStr[][2] = { //DO NOT CHANGE! // Allow for different output depending on whether averaging is done // vertically or horizontally first when downsampling. { "caaaa3352ab8614e3a35836f5d7c9a528294e953", "326cc236e9ba5277aedc5cf0865dd4cbd2f89fe0" }, { "2dc97661e94515d9947a344127062f82814afc2a", "72f36bb33d190979be88077c6166a09767dd2992" }, { "106ec96a90412aabea5c0cfa6bfc654a0b5db33e", "998c2947bccf140bde1e43e29376614038eb7c71" } }; class DecodeParseAPI : public ::testing::TestWithParam<EncodeDecodeFileParamBase>, public EncodeDecodeTestBase { public: DecodeParseAPI() { memset (&BsInfo_, 0, sizeof (SParserBsInfo)); fYuv_ = NULL; iWidth_ = 0; iHeight_ = 0; memset (&ctx_, 0, sizeof (SHA1Context)); } void SetUp() { SHA1Reset (&ctx_); EncodeDecodeTestBase::SetUp(); if (decoder_) decoder_->Uninitialize(); SDecodingParam decParam; memset (&decParam, 0, sizeof (SDecodingParam)); decParam.uiTargetDqLayer = UCHAR_MAX; decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; decParam.bParseOnly = true; decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; int rv = decoder_->Initialize (&decParam); ASSERT_EQ (0, rv); memset (&BsInfo_, 0, sizeof (SParserBsInfo)); const char* sFileName = "res/CiscoVT2people_160x96_6fps.yuv"; #if defined(ANDROID_NDK) std::string filename = std::string ("/sdcard/") + sFileName; ASSERT_TRUE ((fYuv_ = fopen (filename.c_str(), "rb")) != NULL); #else ASSERT_TRUE ((fYuv_ = fopen (sFileName, "rb")) != NULL); #endif iWidth_ = kiWidth; iHeight_ = kiHeight; } void TearDown() { EncodeDecodeTestBase::TearDown(); if (fYuv_ != NULL) { fclose (fYuv_); fYuv_ = NULL; } } bool prepareEncDecParam (const EncodeDecodeFileParamBase p) { if (!EncodeDecodeTestBase::prepareEncDecParam (p)) return false; unsigned char* pTmpPtr = BsInfo_.pDstBuff; //store for restore memset (&BsInfo_, 0, sizeof (SParserBsInfo)); BsInfo_.pDstBuff = pTmpPtr; return true; } void MockInputData (uint8_t* pData, int32_t iSize) { int32_t iCurr = 0; while (iCurr < iSize) { * (pData + iCurr) = (* (pData + iCurr) + (rand() % 20) + 256) & 0x00ff; iCurr++; } } void EncodeOneFrame (bool bMock) { int iFrameSize = iWidth_ * iHeight_ * 3 / 2; int iSize = (int) fread (buf_.data(), sizeof (char), iFrameSize, fYuv_); if (feof (fYuv_) || iSize != iFrameSize) { rewind (fYuv_); iSize = (int) fread (buf_.data(), sizeof (char), iFrameSize, fYuv_); ASSERT_TRUE (iSize == iFrameSize); } if (bMock) { MockInputData (buf_.data(), iWidth_ * iHeight_); } int rv = encoder_->EncodeFrame (&EncPic, &info); ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnknownReason); } void prepareParam (int iLayerNum, int iSliceNum, int width, int height, float framerate, SEncParamExt* pParam) { memset (pParam, 0, sizeof (SEncParamExt)); EncodeDecodeTestBase::prepareParam (iLayerNum, iSliceNum, width, height, framerate, pParam); } protected: SParserBsInfo BsInfo_; FILE* fYuv_; int iWidth_; int iHeight_; SHA1Context ctx_; }; //#define DEBUG_FILE_SAVE_PARSEONLY_GENERAL TEST_F (DecodeParseAPI, ParseOnly_General) { EncodeDecodeFileParamBase p; p.width = iWidth_; p.height = iHeight_; p.frameRate = kiFrameRate; p.numframes = kiFrameNum; prepareParam (kiTotalLayer, kiSliceNum, p.width, p.height, p.frameRate, ¶m_); param_.iSpatialLayerNum = kiTotalLayer; encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == 0); int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); uint32_t uiTargetLayerId = rand() % kiTotalLayer; //run only once #ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL FILE* fDec = fopen ("output.264", "wb"); FILE* fEnc = fopen ("enc.264", "wb"); FILE* fExtract = fopen ("extract.264", "wb"); #endif if (uiTargetLayerId < kiTotalLayer) { //should always be true //Start for enc int iLen = 0; ASSERT_TRUE (prepareEncDecParam (p)); int iFrame = 0; while (iFrame < p.numframes) { //encode EncodeOneFrame (0); //extract target layer data encToDecData (info, iLen); #ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fEnc); #endif ExtractDidNal (&info, iLen, &m_SLostSim, uiTargetLayerId); #ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fExtract); #endif //parseonly //BsInfo_.pDstBuff = new unsigned char [1000000]; rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf, iLen, &BsInfo_); EXPECT_TRUE (rv == 0); EXPECT_TRUE (BsInfo_.iNalNum == 0); rv = decoder_->DecodeParser (NULL, 0, &BsInfo_); EXPECT_TRUE (rv == 0); EXPECT_TRUE (BsInfo_.iNalNum != 0); //get final output bs iLen = 0; int i = 0; while (i < BsInfo_.iNalNum) { iLen += BsInfo_.pNalLenInByte[i]; i++; } #ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL fwrite (BsInfo_.pDstBuff, iLen, 1, fDec); #endif SHA1Input (&ctx_, BsInfo_.pDstBuff, iLen); iFrame++; } //calculate final SHA1 value unsigned char digest[SHA_DIGEST_LENGTH]; SHA1Result (&ctx_, digest); if (!HasFatalFailure()) { CompareHashAnyOf (digest, pHashStr[uiTargetLayerId], sizeof * pHashStr / sizeof** pHashStr); } } //while #ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL fclose (fEnc); fclose (fExtract); fclose (fDec); #endif } //This case is for one layer only, for incomplete frame input //First slice is loss for random one picture with 2 slices per pic TEST_F (DecodeParseAPI, ParseOnly_SpecSliceLoss) { int32_t iLayerNum = 1; int32_t iSliceNum = 2; EncodeDecodeFileParamBase p; p.width = iWidth_; p.height = iHeight_; p.frameRate = kiFrameRate; p.numframes = 5; prepareParam (iLayerNum, iSliceNum, p.width, p.height, p.frameRate, ¶m_); param_.iSpatialLayerNum = iLayerNum; encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == 0); int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); int32_t iMissedPicNum = rand() % (p.numframes - 1) + 1; //IDR no loss //Start for enc int iLen = 0; uint32_t uiGet; ASSERT_TRUE (prepareEncDecParam (p)); int iFrame = 0; while (iFrame < p.numframes) { //encode EncodeOneFrame (0); //parseonly if (iFrame == iMissedPicNum) { //make current frame partly missing //Frame: P, first slice loss int32_t iTotalSliceSize = 0; encToDecSliceData (0, 0, info, iTotalSliceSize); //slice 1 lost encToDecSliceData (0, 1, info, iLen); //slice 2 decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet); EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE); rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, iLen, &BsInfo_); EXPECT_TRUE (rv == 0); EXPECT_TRUE (BsInfo_.iNalNum == 0); rv = decoder_->DecodeParser (NULL, 0, &BsInfo_); EXPECT_TRUE (rv != 0); } else { //normal frame, complete encToDecData (info, iLen); rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf, iLen, &BsInfo_); EXPECT_TRUE (rv == 0); //parse correct EXPECT_TRUE (BsInfo_.iNalNum == 0); rv = decoder_->DecodeParser (NULL, 0, &BsInfo_); if (iFrame < iMissedPicNum) { //correct frames, all OK with output EXPECT_TRUE (rv == 0); EXPECT_TRUE (BsInfo_.iNalNum != 0); } else { //(iFrame > iMissedPicNum), should output nothing as error EXPECT_TRUE (rv != 0); EXPECT_TRUE (BsInfo_.iNalNum == 0); } } iFrame++; } //while } TEST_F (DecodeParseAPI, ParseOnly_SpecStatistics) { //set params int32_t iLayerNum = 1; int32_t iSliceNum = 1; EncodeDecodeFileParamBase p; const int iLoopNum = 10; p.frameRate = kiFrameRate; p.numframes = 2; //encode 2 frames in each test p.width = iWidth_ = 16; p.height = iHeight_ = 16; //default start width/height = 16, will be modified each time int iTotalFrmCnt = 0; for (int i = 0; i < iLoopNum; ++i) { prepareParam (iLayerNum, iSliceNum, p.width, p.height, p.frameRate, ¶m_); param_.iSpatialLayerNum = iLayerNum; param_.sSpatialLayers[0].iDLayerQp = 40; //to revent size too limited to encoding fail encoder_->Uninitialize(); int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == 0); int32_t iTraceLevel = WELS_LOG_QUIET; rv = encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); ASSERT_TRUE (rv == 0); rv = decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); ASSERT_TRUE (rv == 0); //Start for enc int iLen = 0; ASSERT_TRUE (prepareEncDecParam (p)); int iFrame = 0; while (iFrame < p.numframes) { EncodeOneFrame (0); encToDecData (info, iLen); iFrame++; iTotalFrmCnt++; rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf, iLen, &BsInfo_); ASSERT_TRUE (rv == 0); ASSERT_TRUE (BsInfo_.iNalNum == 0); rv = decoder_->DecodeParser (NULL, 0, &BsInfo_); ASSERT_TRUE (rv == 0); ASSERT_TRUE (BsInfo_.iNalNum != 0); SDecoderStatistics sDecStat; rv = decoder_->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStat); ASSERT_TRUE (rv == 0); uint32_t uiProfile, uiLevel; rv = decoder_->GetOption (DECODER_OPTION_PROFILE, &uiProfile); ASSERT_TRUE (rv == 0); rv = decoder_->GetOption (DECODER_OPTION_LEVEL, &uiLevel); ASSERT_TRUE (rv == 0); ASSERT_EQ (sDecStat.uiWidth, (unsigned int) p.width); ASSERT_EQ (sDecStat.uiHeight, (unsigned int) p.height); ASSERT_EQ (sDecStat.uiResolutionChangeTimes, (unsigned int) (i + 1)); EXPECT_EQ (sDecStat.iCurrentActiveSpsId, 0); EXPECT_EQ (sDecStat.iCurrentActivePpsId, 0); ASSERT_EQ (sDecStat.uiDecodedFrameCount, (unsigned int) iTotalFrmCnt); ASSERT_EQ (sDecStat.uiProfile, uiProfile); ASSERT_EQ (sDecStat.uiLevel, uiLevel); EXPECT_TRUE (sDecStat.fActualAverageFrameSpeedInMs != 0.); EXPECT_TRUE (sDecStat.fAverageFrameSpeedInMs != 0.); EXPECT_TRUE (sDecStat.iAvgLumaQp != 0); EXPECT_EQ (sDecStat.uiIDRCorrectNum, (unsigned int) (i + 1)); } //set next width & height p.width += 16; p.height += 16; if ((unsigned int) p.width > kiWidth) //exceeds max frame size p.width = 16; if ((unsigned int) p.height > kiHeight) p.height = 16; iWidth_ = p.width; iHeight_ = p.height; } } //Test parseonly crash cases class DecodeParseCrashAPI : public DecodeParseAPI { public: DecodeParseCrashAPI() { } void SetUp() { DecodeParseAPI::SetUp(); iWidth_ = 1280; iHeight_ = 720; ucBuf_ = NULL; ucBuf_ = new unsigned char[1000000]; ASSERT_TRUE (ucBuf_ != NULL); } void TearDown() { DecodeParseAPI::TearDown(); if (NULL != ucBuf_) { delete[] ucBuf_; ucBuf_ = NULL; } ASSERT_TRUE (ucBuf_ == NULL); } protected: unsigned char* ucBuf_; }; //#define DEBUG_FILE_SAVE_PARSE_CRA1 TEST_F (DecodeParseCrashAPI, ParseOnlyCrash_General) { if (fYuv_) fclose (fYuv_); const char* sFileName = "res/Cisco_Absolute_Power_1280x720_30fps.yuv"; #if defined(ANDROID_NDK) std::string filename = std::string ("/sdcard/") + sFileName; ASSERT_TRUE ((fYuv_ = fopen (filename.c_str(), "rb")) != NULL); #else ASSERT_TRUE ((fYuv_ = fopen (sFileName, "rb")) != NULL); #endif uint32_t uiGet; encoder_->Uninitialize(); //do tests until crash unsigned int uiLoopRound = 0; unsigned char* pucBuf = ucBuf_; int iDecAuSize; #ifdef DEBUG_FILE_SAVE_PARSE_CRA1 //open file to save tested BS FILE* fDataFile = fopen ("test_parseonly_crash.264", "wb"); FILE* fLenFile = fopen ("test_parseonly_crash_len.log", "w"); int iFileSize = 0; #endif do { #ifdef DEBUG_FILE_SAVE_PARSE_CRA1 int iTotalFrameNum = (rand() % 1200) + 1; #else int iTotalFrameNum = (rand() % 100) + 1; #endif EncodeDecodeParamBase p = kParamArray[8]; //720p by default //Initialize Encoder prepareParam (1, 4, p.width, p.height, p.frameRate, ¶m_); param_.iRCMode = RC_TIMESTAMP_MODE; param_.iTargetBitrate = p.iTarBitrate; param_.uiIntraPeriod = 0; param_.eSpsPpsIdStrategy = CONSTANT_ID; param_.bEnableBackgroundDetection = true; param_.bEnableSceneChangeDetect = (rand() % 3) ? true : false; param_.bPrefixNalAddingCtrl = 0;// (rand() % 2) ? true : false; param_.iEntropyCodingModeFlag = 0; param_.bEnableFrameSkip = true; param_.iMultipleThreadIdc = 0; param_.sSpatialLayers[0].iSpatialBitrate = p.iTarBitrate; param_.sSpatialLayers[0].iMaxSpatialBitrate = p.iTarBitrate << 1; param_.sSpatialLayers[0].sSliceArgument.uiSliceMode = SM_FIXEDSLCNUM_SLICE; // (rand() % 2) ? SM_SIZELIMITED_SLICE : SM_SINGLE_SLICE; if (param_.sSpatialLayers[0].sSliceArgument.uiSliceMode == SM_SIZELIMITED_SLICE) { param_.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = 1400; param_.uiMaxNalSize = 1400; } else { param_.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = 0; param_.uiMaxNalSize = 0; } int rv = encoder_->InitializeExt (¶m_); ASSERT_TRUE (rv == cmResultSuccess); decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet); EXPECT_EQ (uiGet, (uint32_t)ERROR_CON_DISABLE); //default value should be ERROR_CON_SLICE_COPY int32_t iTraceLevel = WELS_LOG_QUIET; encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel); decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel); //Start for enc/dec int iIdx = 0; unsigned char* pData[3] = { NULL }; EncodeDecodeFileParamBase pInput; //to conform with old functions pInput.width = p.width; pInput.height = p.height; pInput.frameRate = p.frameRate; prepareEncDecParam (pInput); while (iIdx++ < iTotalFrameNum) { // loop in frame EncodeOneFrame (1); #ifdef DEBUG_FILE_SAVE_PARSE_CRA1 //reset file if file size large if ((info.eFrameType == videoFrameTypeIDR) && (iFileSize >= (1 << 25))) { fclose (fDataFile); fclose (fLenFile); fDataFile = fopen ("test_parseonly_crash.264", "wb"); fLenFile = fopen ("test_parseonly_crash_len.log", "w"); iFileSize = 0; decoder_->Uninitialize(); SDecodingParam decParam; memset (&decParam, 0, sizeof (SDecodingParam)); decParam.uiTargetDqLayer = UCHAR_MAX; decParam.eEcActiveIdc = ERROR_CON_DISABLE; decParam.bParseOnly = true; decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; rv = decoder_->Initialize (&decParam); ASSERT_EQ (0, rv); } #endif if (info.eFrameType == videoFrameTypeSkip) continue; //deal with packets unsigned char* pBsBuf; iDecAuSize = 0; pucBuf = ucBuf_; //init buf start pos for decoder usage for (int iLayerNum = 0; iLayerNum < info.iLayerNum; iLayerNum++) { SLayerBSInfo* pLayerBsInfo = &info.sLayerInfo[iLayerNum]; pBsBuf = info.sLayerInfo[iLayerNum].pBsBuf; int iTotalNalCnt = pLayerBsInfo->iNalCount; for (int iNalCnt = 0; iNalCnt < iTotalNalCnt; iNalCnt++) { //loop in NAL int iPacketSize = pLayerBsInfo->pNalLengthInByte[iNalCnt]; //packet loss int iLossRateRange = (uiLoopRound % 20) + 1; //1-100 int iLossRate = (rand() % iLossRateRange); bool bPacketLost = (rand() % 101) > (100 - iLossRate); // [0, (100-iLossRate)] indicates NO LOSS, (100-iLossRate, 100] indicates LOSS if (!bPacketLost) { //no loss memcpy (pucBuf, pBsBuf, iPacketSize); pucBuf += iPacketSize; iDecAuSize += iPacketSize; } //update bs info pBsBuf += iPacketSize; } //nal } //layer #ifdef DEBUG_FILE_SAVE_PARSE_CRA1 //save to file if (iDecAuSize != 0) { fwrite (ucBuf_, 1, iDecAuSize, fDataFile); fflush (fDataFile); iFileSize += iDecAuSize; } //save to len file unsigned long ulTmp[4]; ulTmp[0] = ulTmp[1] = ulTmp[2] = iIdx; ulTmp[3] = iDecAuSize; fwrite (ulTmp, sizeof (unsigned long), 4, fLenFile); // index, timeStamp, data size fflush (fLenFile); #endif //decode pData[0] = pData[1] = pData[2] = 0; memset (&BsInfo_, 0, sizeof (SParserBsInfo)); rv = decoder_->DecodeParser (ucBuf_, iDecAuSize, &BsInfo_); rv = decoder_->DecodeParser (NULL, 0, &BsInfo_); //reconstruction //guarantee decoder EC status decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet); EXPECT_EQ (uiGet, (uint32_t)ERROR_CON_DISABLE); } //frame uiLoopRound++; if (uiLoopRound >= (1 << 30)) uiLoopRound = 0; #ifdef DEBUG_FILE_SAVE_PARSE_CRA1 if (uiLoopRound % 10 == 0) printf ("run %d times.\n", uiLoopRound); } while (1); fclose (fDataFile); fclose (fLenFile); #else } while (0); #endif }