openh264/test/api/encode_decode_api_test.cpp
Martin Storsjö c1b48640fb Don't try to use pow(int,int)
When building for android or older MSVC versions, this makes the build
fail, when it is ambiguous which pow() overload to use, when there
is no function matching pow(int, int).
2014-11-03 11:23:10 +02:00

2034 lines
80 KiB
C++

#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 <string>
#include <vector>
using namespace WelsCommon;
#define TRY_TIME_RANGE (10)
#define ENCODE_FRAME_NUM (30)
#define LEVEL_ID_RANGE (18)
#define MAX_WIDTH (4096)
#define MAX_HEIGHT (2304)
#define MAX_FRAME_RATE (30)
#define MIN_FRAME_RATE (1)
#define FRAME_RATE_RANGE (2*MAX_FRAME_RATE)
#define RC_MODE_RANGE (4)
#define BIT_RATE_RANGE (10000)
#define MAX_QP (51)
#define MIN_QP (0)
#define QP_RANGE (2*MAX_QP)
#define SPATIAL_LAYER_NUM_RANGE (2*MAX_SPATIAL_LAYER_NUM)
#define TEMPORAL_LAYER_NUM_RANGE (2*MAX_TEMPORAL_LAYER_NUM)
#define SAVED_NALUNIT_NUM ( (MAX_SPATIAL_LAYER_NUM*MAX_QUALITY_LAYER_NUM) + 1 + MAX_SPATIAL_LAYER_NUM )
#define MAX_SLICES_NUM ( ( MAX_NAL_UNITS_IN_LAYER - SAVED_NALUNIT_NUM ) / 3 )
#define SLICE_MODE_NUM (6)
#define LOOP_FILTER_IDC_NUM (3)
#define LOOF_FILTER_OFFSET_RANGE (6)
#define MAX_REF_PIC_COUNT (16)
#define MIN_REF_PIC_COUNT (1)
#define LONG_TERM_REF_NUM (2)
#define LONG_TERM_REF_NUM_SCREEN (4)
#define MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA (6)
#define MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN (8)
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;
};
static void welsStderrTraceOrigin (void* ctx, int level, const char* string) {
fprintf (stderr, "%s\n", string);
}
typedef struct STrace_Unit {
int iTarLevel;
} STraceUnit;
static void TestOutPutTrace (void* ctx, int level, const char* string) {
STraceUnit* pTraceUnit = (STraceUnit*) ctx;
EXPECT_LE (level, pTraceUnit->iTarLevel);
}
class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFileParamBase>,
public BaseEncoderTest, public BaseDecoderTest {
public:
virtual void SetUp() {
BaseEncoderTest::SetUp();
BaseDecoderTest::SetUp();
pFunc = welsStderrTraceOrigin;
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);
}
virtual void TearDown() {
BaseEncoderTest::TearDown();
BaseDecoderTest::TearDown();
}
virtual void prepareParam (int iLayers, int iSlices, int width, int height, float framerate) {
memset (&param_, 0, sizeof (SEncParamExt));
param_.iUsageType = CAMERA_VIDEO_REAL_TIME;
param_.iPicWidth = width;
param_.iPicHeight = height;
param_.fMaxFrameRate = framerate;
param_.iRCMode = RC_OFF_MODE; //rc off
param_.iMultipleThreadIdc = 1; //single thread
for (int i = 0; i < iLayers; i++) {
param_.sSpatialLayers[i].iVideoWidth = width >> (iLayers - i - 1);
param_.sSpatialLayers[i].iVideoHeight = height >> (iLayers - i - 1);
param_.sSpatialLayers[i].fFrameRate = framerate;
param_.sSpatialLayers[i].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
param_.sSpatialLayers[i].sSliceCfg.sSliceArgument.uiSliceNum = iSlices;
}
}
virtual void encToDecData (const SFrameBSInfo& info, int& len) {
len = 0;
for (int i = 0; i < info.iLayerNum; ++i) {
const SLayerBSInfo& layerInfo = info.sLayerInfo[i];
for (int j = 0; j < layerInfo.iNalCount; ++j) {
len += layerInfo.pNalLengthInByte[j];
}
}
}
virtual void encToDecSliceData (const int iLayerNum, const int iSliceNum, const SFrameBSInfo& info, int& len) {
ASSERT_TRUE (iLayerNum < MAX_LAYER_NUM_OF_FRAME);
len = 0;
const SLayerBSInfo& layerInfo = info.sLayerInfo[iLayerNum];
if (iSliceNum < layerInfo.iNalCount)
len = layerInfo.pNalLengthInByte[iSliceNum];
}
protected:
SEncParamExt param_;
BufferedData buf_;
SSourcePicture EncPic;
SFrameBSInfo info;
SBufferInfo dstBufInfo_;
std::vector<SLostSim> m_SLostSim;
WelsTraceCallback pFunc;
STraceUnit sTrace;
STraceUnit* pTraceInfo;
};
class EncodeDecodeTestAPI : public EncodeDecodeTestBase {
public:
uint8_t iRandValue;
public:
void SetUp() {
EncodeDecodeTestBase::SetUp();
}
void TearDown() {
EncodeDecodeTestBase::TearDown();
}
void prepareParam (int iLayers, int iSlices, int width, int height, float framerate) {
EncodeDecodeTestBase::prepareParam (iLayers, iSlices, width, height, framerate);
}
void InitialEncDec (int iWidth, int iHeight);
void RandomParamExtCombination();
void ValidateParamExtCombination();
void SliceParamValidationForMode2 (int iSpatialIdx);
void SliceParamValidationForMode3 (int iSpatialIdx);
void SliceParamValidationForMode4();
void EncodeOneFrame (int iCheckTypeIndex) {
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);
if (0 == iCheckTypeIndex)
ASSERT_TRUE (rv == cmResultSuccess);
else if (1 == iCheckTypeIndex)
ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
}
};
void EncodeDecodeTestAPI::InitialEncDec (int iWidth, int iHeight) {
// for encoder
// I420: 1(Y) + 1/4(U) + 1/4(V)
int frameSize = iWidth * iHeight * 3 / 2;
buf_.SetLength (frameSize);
ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
memset (&EncPic, 0, sizeof (SSourcePicture));
EncPic.iPicWidth = iWidth;
EncPic.iPicHeight = iHeight;
EncPic.iColorFormat = videoFormatI420;
EncPic.iStride[0] = EncPic.iPicWidth;
EncPic.iStride[1] = EncPic.iStride[2] = EncPic.iPicWidth >> 1;
EncPic.pData[0] = buf_.data();
EncPic.pData[1] = EncPic.pData[0] + iWidth * iHeight;
EncPic.pData[2] = EncPic.pData[1] + (iWidth * iHeight >> 2);
//for decoder
memset (&info, 0, sizeof (SFrameBSInfo));
//set a fixed random value
iRandValue = rand() % 256;
}
void EncodeDecodeTestAPI::RandomParamExtCombination() {
param_.iPicWidth = WELS_CLIP3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, 2, MAX_WIDTH);
param_.iPicHeight = WELS_CLIP3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, 2, MAX_HEIGHT);
param_.fMaxFrameRate = rand() % FRAME_RATE_RANGE + 0.5f;
param_.iUsageType = static_cast<EUsageType> (rand() % 2);
param_.iTemporalLayerNum = rand() % TEMPORAL_LAYER_NUM_RANGE;
param_.iSpatialLayerNum = rand() % SPATIAL_LAYER_NUM_RANGE;
param_.uiIntraPeriod = rand() - 1;
param_.iNumRefFrame = rand();
param_.iMultipleThreadIdc = rand();
param_.bEnableSpsPpsIdAddition = (rand() % 2 == 0) ? false : true;
param_.bPrefixNalAddingCtrl = (rand() % 2 == 0) ? false : true;
param_.bEnableSSEI = (rand() % 2 == 0) ? false : true;
param_.iPaddingFlag = rand() % 2;
//LTR
param_.bEnableLongTermReference = (rand() % 2 == 0) ? false : true;
param_.bIsLosslessLink = (rand() % 2 == 0) ? false : true;
param_.iLTRRefNum = rand();
param_.iLtrMarkPeriod = rand();
//loop filter
param_.iLoopFilterDisableIdc = rand();
param_.iLoopFilterAlphaC0Offset = rand();
param_.iLoopFilterBetaOffset = rand();
param_.bEnableDenoise = (rand() % 2 == 0) ? false : true;
param_.bEnableBackgroundDetection = (rand() % 2 == 0) ? false : true;
param_.bEnableAdaptiveQuant = (rand() % 2 == 0) ? false : true;
param_.bEnableFrameCroppingFlag = (rand() % 2 == 0) ? false : true;
param_.bEnableSceneChangeDetect = (rand() % 2 == 0) ? false : true;
//for rc
param_.iRCMode = static_cast<RC_MODES> (rand() % RC_MODE_RANGE - 1);
param_.iMaxBitrate = rand() % BIT_RATE_RANGE;
param_.iTargetBitrate = rand() % BIT_RATE_RANGE;
param_.iMaxQp = rand() % QP_RANGE;
param_.iMinQp = rand() % QP_RANGE;
param_.uiMaxNalSize = rand();
param_.bEnableFrameSkip = (rand() % 2 == 0) ? false : true;
for (int iSpatialIdx = 0; iSpatialIdx < param_.iSpatialLayerNum; iSpatialIdx++) {
if (iSpatialIdx < MAX_SPATIAL_LAYER_NUM) {
SSpatialLayerConfig* pSpatialLayer = &param_.sSpatialLayers[iSpatialIdx];
//to do: profile and level id
//pSpatialLayer->uiProfileIdc = 0;
//pSpatialLayer->uiLevelIdc = 0;
pSpatialLayer->iVideoWidth = WELS_CLIP3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, 2, MAX_WIDTH);
pSpatialLayer->iVideoHeight = WELS_CLIP3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, 2, MAX_HEIGHT);
pSpatialLayer->fFrameRate = rand() % FRAME_RATE_RANGE + 0.5f;
pSpatialLayer->iMaxSpatialBitrate = rand() % BIT_RATE_RANGE;
pSpatialLayer->iSpatialBitrate = rand() % BIT_RATE_RANGE;
pSpatialLayer->sSliceCfg.uiSliceMode = static_cast<SliceModeEnum> (rand() % SLICE_MODE_NUM);
pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = rand();
pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = rand();
}
}
}
void EncodeDecodeTestAPI::ValidateParamExtCombination() {
bool bDynSliceModeFlag = false;
unsigned int uiGOPSize = 0;
unsigned int uiSliceNum = 0;
int iTotalBitRate = 0;
int iMinQP = 0;
param_.iPicWidth = WELS_CLIP3 (param_.iPicWidth, 2, MAX_WIDTH);
param_.iPicHeight = WELS_CLIP3 (param_.iPicHeight, 2, MAX_HEIGHT);
param_.fMaxFrameRate = WELS_CLIP3 (param_.fMaxFrameRate, MIN_FRAME_RATE, MAX_FRAME_RATE);
param_.iTemporalLayerNum = WELS_CLIP3 (param_.iTemporalLayerNum, 1, MAX_TEMPORAL_LAYER_NUM);
if (CAMERA_VIDEO_REAL_TIME == param_.iUsageType)
param_.iSpatialLayerNum = WELS_CLIP3 (param_.iSpatialLayerNum, 1, MAX_SPATIAL_LAYER_NUM);
else
param_.iSpatialLayerNum = 1;
//IntraPeriod
uiGOPSize = 1 << (param_.iTemporalLayerNum - 1);
param_.uiIntraPeriod -= param_.uiIntraPeriod % uiGOPSize;
//RefNum
int32_t iRefUpperBound = (param_.iUsageType == CAMERA_VIDEO_REAL_TIME) ?
MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA : MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN;
param_.iNumRefFrame = WELS_CLIP3 (param_.iNumRefFrame, MIN_REF_PIC_COUNT, iRefUpperBound);
//to do: will add more validate logic for thread number
param_.iMultipleThreadIdc = 1;
//LTR
//iLTRRefNum: not supported to set it arbitrary yet
if (true == param_.bEnableLongTermReference) {
param_.iLTRRefNum = (SCREEN_CONTENT_REAL_TIME == param_.iUsageType) ? LONG_TERM_REF_NUM_SCREEN : LONG_TERM_REF_NUM;
param_.iLtrMarkPeriod = (0 == param_.iLtrMarkPeriod) ? 1 : param_.iLtrMarkPeriod;
} else {
param_.iLTRRefNum = 0;
}
//loop filter
param_.iLoopFilterDisableIdc = param_.iLoopFilterDisableIdc % LOOP_FILTER_IDC_NUM;
param_.iLoopFilterAlphaC0Offset = param_.iLoopFilterAlphaC0Offset % (2 * LOOF_FILTER_OFFSET_RANGE + 1) -
LOOF_FILTER_OFFSET_RANGE;
param_.iLoopFilterBetaOffset = param_.iLoopFilterBetaOffset % (2 * LOOF_FILTER_OFFSET_RANGE + 1) -
LOOF_FILTER_OFFSET_RANGE;
for (int iSpatialIdx = 0; iSpatialIdx < param_.iSpatialLayerNum; iSpatialIdx++) {
SSpatialLayerConfig* pSpatialLayer = &param_.sSpatialLayers[iSpatialIdx];
pSpatialLayer->iVideoWidth = param_.iPicWidth >> (param_.iSpatialLayerNum - 1 - iSpatialIdx);
pSpatialLayer->iVideoHeight = param_.iPicHeight >> (param_.iSpatialLayerNum - 1 - iSpatialIdx);
pSpatialLayer->fFrameRate = param_.fMaxFrameRate;
pSpatialLayer->iMaxSpatialBitrate = WELS_CLIP3 (pSpatialLayer->iMaxSpatialBitrate, 1, BIT_RATE_RANGE);
pSpatialLayer->iSpatialBitrate = WELS_CLIP3 (pSpatialLayer->iSpatialBitrate, 1, pSpatialLayer->iMaxSpatialBitrate);
iTotalBitRate += pSpatialLayer->iSpatialBitrate;
uiSliceNum = pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum;
pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = WELS_CLIP3 (uiSliceNum, 1, MAX_SLICES_NUM);
pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0;
//for SM_FIXEDSLCNUM_SLICE
// to do will add this when GOM bug fixed
if (SM_FIXEDSLCNUM_SLICE == pSpatialLayer->sSliceCfg.uiSliceMode) {
pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE;
}
//for slice mode = SM_DYN_SLICE
if (SM_DYN_SLICE == pSpatialLayer->sSliceCfg.uiSliceMode) {
bDynSliceModeFlag = true;
}
//for slice mode = SM_RASTER_SLICE
if (SM_RASTER_SLICE == pSpatialLayer->sSliceCfg.uiSliceMode) {
SliceParamValidationForMode2 (iSpatialIdx);
}
//for slice mode = SM_ROWMB_SLICE
if (SM_ROWMB_SLICE == pSpatialLayer->sSliceCfg.uiSliceMode) {
SliceParamValidationForMode3 (iSpatialIdx);
}
}
//for RC
if ((RC_QUALITY_MODE == param_.iRCMode) || (RC_BITRATE_MODE == param_.iRCMode)) {
param_.bEnableFrameSkip = true;
}
if (param_.iTargetBitrate < iTotalBitRate) {
param_.iTargetBitrate = iTotalBitRate;
}
if (param_.iMaxBitrate < param_.iTargetBitrate) {
param_.iMaxBitrate = param_.iTargetBitrate;
}
param_.iMaxQp = WELS_CLIP3 (param_.iMaxQp, MIN_QP, MAX_QP);
param_.iMinQp = WELS_CLIP3 (param_.iMinQp, MIN_QP, MAX_QP);
iMinQP = (param_.iMaxQp < param_.iMinQp) ? param_.iMaxQp : param_.iMinQp;
param_.iMaxQp = (param_.iMaxQp > param_.iMinQp) ? param_.iMaxQp : param_.iMinQp;
param_.iMinQp = iMinQP;
param_.uiMaxNalSize = 0;
//for slice mode = SM_DYN_SLICE
if (true == bDynSliceModeFlag) {
SliceParamValidationForMode4();
}
}
void EncodeDecodeTestAPI::SliceParamValidationForMode2 (int iSpatialIdx) {
unsigned int uiMbWidth = 0;
unsigned int uiMbHeight = 0;
unsigned int uiMbNumInFrame = 0;
unsigned int uiCountMb = 0;
unsigned int uiSliceIdx = 0;
unsigned int uiActualSliceCount = 0;
uiMbWidth = (param_.iPicWidth + 15) >> 4;
uiMbHeight = (param_.iPicHeight + 15) >> 4;
uiMbNumInFrame = uiMbWidth * uiMbHeight;
uiSliceIdx = 0;
while (uiSliceIdx < MAX_SLICES_NUM) {
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceMbNum[uiSliceIdx] = rand() % uiMbNumInFrame;
uiCountMb += param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceMbNum[uiSliceIdx];
uiActualSliceCount = uiSliceIdx + 1;
if (uiCountMb >= uiMbNumInFrame) {
break;
}
++ uiSliceIdx;
}
if (uiCountMb >= uiMbNumInFrame) {
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceMbNum[uiActualSliceCount - 1] -=
(uiCountMb - uiMbNumInFrame);
} else {
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceMbNum[uiActualSliceCount - 1 ] +=
(uiMbNumInFrame - uiCountMb);
}
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceNum = uiActualSliceCount;
}
void EncodeDecodeTestAPI::SliceParamValidationForMode3 (int iSpatialIdx) {
unsigned int uiMbHeight = 0;
uiMbHeight = (param_.iPicHeight + 15) >> 4;
//change slice mode to SM_SINGLE_SLICE
if (uiMbHeight > MAX_SLICES_NUM) {
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.uiSliceMode = SM_SINGLE_SLICE;
}
}
void EncodeDecodeTestAPI::SliceParamValidationForMode4() {
//slice mode of all spatial layer should be set as SM_DYN_SLICE
for (int iSpatialIdx = 0; iSpatialIdx < param_.iSpatialLayerNum; iSpatialIdx++) {
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 600;
param_.sSpatialLayers[iSpatialIdx].sSliceCfg.uiSliceMode = SM_DYN_SLICE;
}
param_.uiMaxNalSize = 1500;
}
static const EncodeDecodeFileParamBase kFileParamArray[] = {
{300, 160, 96, 6.0f, 2, 1, "000000000000001010101010101010101010101001101010100000010101000011"},
{300, 140, 96, 6.0f, 4, 1, "000000000000001010101010101010101010101001101010100000010101000011"},
{300, 140, 96, 6.0f, 4, 1, "000000000000001010111010101011101010101001101010100000010101110011010101"},
};
TEST_P (EncodeDecodeTestAPI, DecoderVclNal) {
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
int32_t iTraceLevel = WELS_LOG_QUIET;
encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
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();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
int32_t iTraceLevel = WELS_LOG_QUIET;
encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
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();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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);
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;
iIDRPeriod = (rand() % 150) + 1;
encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod);
encoder_->SetOption (ENCODER_OPTION_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition);
EncodeOneFrame (0);
if (info.eFrameType == videoFrameTypeIDR) {
iEncCurIdrPicId = (iSpsPpsIdAddition == 0) ? 0 : (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
}
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 != (unsigned int) 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, bool m_P2PmodeFlag) {
long bKLost = IsKeyFrameLost (pDecoder, p_LTR_Recover_Request, hr);
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;
pEncoder->ForceIntraFrame (true);
}
}
}
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);
}
}
bool ToRemainDidNal (const unsigned char* pSrc, EWelsNalUnitType eNalType, int iTarDid) {
uint8_t uiCurByte = *pSrc;
if (IS_NEW_INTRODUCED_SVC_NAL (eNalType)) {
int iDid = (uiCurByte & 0x70) >> 4;
return iDid == iTarDid;
} else if ((IS_VCL_NAL_AVC_BASE (eNalType)) && iTarDid != 0) {
return false;
} else {
return true;
}
}
void ExtractDidNal (SFrameBSInfo* pBsInfo, int& iSrcLen, std::vector<SLostSim>* p_SLostSim, int iTarDid) {
unsigned char* pDst = new unsigned char[iSrcLen];
const unsigned char* pSrc = pBsInfo->sLayerInfo[0].pBsBuf;
int iDstLen = 0;
bool bLost;
SLostSim tmpSLostSim;
p_SLostSim->clear();
int iPrefix;
unsigned char* pSrcPtr = pBsInfo->sLayerInfo[0].pBsBuf;
for (int j = 0; j < pBsInfo->iLayerNum; j++) {
for (int k = 0; k < pBsInfo->sLayerInfo[j].iNalCount; k++) {
if (pSrcPtr[0] == 0 && pSrcPtr[1] == 0 && pSrcPtr[2] == 0 && pSrcPtr[3] == 1) {
iPrefix = 4;
} else if (pSrcPtr[0] == 0 && pSrcPtr[1] == 0 && pSrcPtr[2] == 1) {
iPrefix = 3;
} else {
iPrefix = 0;
}
tmpSLostSim.eNalType = (EWelsNalUnitType) ((* (pSrcPtr + iPrefix)) & 0x1f); // eNalUnitType
bLost = (ToRemainDidNal ((pSrcPtr + iPrefix + 2), tmpSLostSim.eNalType, iTarDid)) ? false : true;
tmpSLostSim.isLost = bLost;
p_SLostSim->push_back (tmpSLostSim);
if (!bLost) {
memcpy (pDst + iDstLen, pSrcPtr, pBsInfo->sLayerInfo[j].pNalLengthInByte[k]);
iDstLen += (pBsInfo->sLayerInfo[j].pNalLengthInByte[k]);
}
pSrcPtr += pBsInfo->sLayerInfo[j].pNalLengthInByte[k];
}
}
memset ((void*)pSrc, 0, iSrcLen);
memcpy ((void*)pSrc, pDst, iDstLen);
iSrcLen = iDstLen;
delete [] pDst;
}
int SimulateNALLoss (const unsigned char* pSrc, int& iSrcLen, std::vector<SLostSim>* 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 (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
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_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition);
int32_t iIDRPeriod = pow(2.0f, (param_.iTemporalLayerNum-1)) * ((rand() % 5) + 1);
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 (0);
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 (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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_);
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, SetOptionECFlag_ERROR_CON_DISABLE) {
SLTRMarkingFeedback m_LTR_Marking_Feedback;
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.bEnableLongTermReference = true;
param_.iLTRRefNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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;
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_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) {
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));
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, 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);
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;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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));
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, 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++;
}
(void) iSkipedBytes;
}
TEST_P (EncodeDecodeTestAPI, GetOptionTid_AVC_NOPREFIX) {
SLTRMarkingFeedback m_LTR_Marking_Feedback;
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.bPrefixNalAddingCtrl = false;
param_.iTemporalLayerNum = (rand() % 4) + 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.bPrefixNalAddingCtrl = true;
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (2, p.slicenum, p.width, p.height, p.frameRate);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 2;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
InitialEncDec (p.width, p.height);
int32_t iTraceLevel = WELS_LOG_QUIET;
pFunc = TestOutPutTrace;
pTraceInfo = &sTrace;
sTrace.iTarLevel = 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);
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) {
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;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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++;
}
}
INSTANTIATE_TEST_CASE_P (EncodeDecodeTestBase, EncodeDecodeTestAPI,
::testing::ValuesIn (kFileParamArray));
TEST_P (EncodeDecodeTestAPI, SetOptionECIDC_GeneralSliceChange) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = GetParam();
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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
uiEcIdc = 0;
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Start for enc/dec
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;
bool bVCLLoss = false;
int iPacketNum;
int len;
int iTotalSliceSize;
//enc/dec pictures
while (iIdx <= p.numframes) {
EncodeOneFrame (1);
//decoding after each encoding frame
len = 0;
iPacketNum = 0;
iTotalSliceSize = 0;
unsigned char* pData[3] = { NULL };
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
while (iPacketNum < info.sLayerInfo[0].iNalCount) {
encToDecSliceData (0, iPacketNum, info, len);
uiEcIdc = (ERROR_CON_IDC) (rand() % 2);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
bVCLLoss = rand() & 1; //loss or not
if (!bVCLLoss) { //not loss
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize,
info.sLayerInfo[0].pNalLengthInByte[iPacketNum], pData, &dstBufInfo_);
if (uiEcIdc == ERROR_CON_DISABLE)
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
}
//EC_IDC should not change till now
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Set again inside
uiEcIdc = (ERROR_CON_IDC) (rand() % 2);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
//EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
if (uiEcIdc == ERROR_CON_DISABLE && rv != 0)
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
//deal with next slice
iTotalSliceSize += len;
iPacketNum++;
} //while slice
iIdx++;
} //while frame
}
//This case contain 1 slice per picture
//coding order: 0 1 2 3 4 5 6 7
//frame type: IDR P P P P P P P
//EC_IDC: 0 0 0 2 0 0 1 1
//loss: N Y N N N Y Y N
TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificFrameChange) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, p.slicenum, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (ERROR_CON_IDC) 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);
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Start for enc/dec
int iIdx = 0;
int len = 0;
unsigned char* pData[3] = { NULL };
InitialEncDec (p.width, p.height);
//Frame 0: IDR, EC_IDC=DISABLE, loss = 0
EncodeOneFrame (1);
encToDecData (info, len);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (ERROR_CON_IDC) ERROR_CON_DISABLE);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_EQ (rv, 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
iIdx++;
//Frame 1: P, EC_IDC=DISABLE, loss = 1
EncodeOneFrame (1);
iIdx++;
//Frame 2: P, EC_IDC=DISABLE, loss = 0
EncodeOneFrame (1);
encToDecData (info, len);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv != 0); //construction error due to data loss
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output due to EC DISABLE
iIdx++;
//set EC=SLICE_COPY
uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 3: P, EC_IDC=SLICE_COPY, loss = 0
EncodeOneFrame (1);
encToDecData (info, len);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv != 0); //construction error due to data loss
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
iIdx++;
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 4: P, EC_IDC=DISABLE, loss = 0
EncodeOneFrame (1);
encToDecData (info, len);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
//Ref picture is ECed, so current status is ECed, when EC disable, NO output
EXPECT_TRUE (rv & 32);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
iIdx++;
//Frame 5: P, EC_IDC=DISABLE, loss = 1
EncodeOneFrame (1);
iIdx++;
//set EC=FRAME_COPY
uiEcIdc = (uint32_t) (ERROR_CON_FRAME_COPY);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 6: P, EC_IDC=FRAME_COPY, loss = 1
EncodeOneFrame (1);
EXPECT_EQ (uiGet, uiEcIdc);
iIdx++;
//Frame 7: P, EC_IDC=FRAME_COPY, loss = 0
EncodeOneFrame (1);
encToDecData (info, len);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_FRAME_COPY);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_TRUE (rv == 0); // Now the parse process is Error_None, and the reconstruction will has error return
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv != 0); //not sure if previous data drop would be detected in construction
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
iIdx++;
}
//This case contain 2 slices per picture for IDR loss
//coding order: 0 1 2 3 4
//frame type IDR P P P P
//EC_IDC 2 2 0 1 0
//loss (2 slice: 1,2): 2 0 0 1 0
TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRLoss) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, 2, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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;
int len = 0;
unsigned char* pData[3] = { NULL };
int iTotalSliceSize = 0;
InitialEncDec (p.width, p.height);
//Frame 0: IDR, EC_IDC=2, loss = 2
EncodeOneFrame (1);
iTotalSliceSize = 0;
encToDecSliceData (0, 0, info, len); //SPS
iTotalSliceSize = len;
encToDecSliceData (0, 1, info, len); //PPS
iTotalSliceSize += len;
encToDecSliceData (1, 0, info, len); //first slice
iTotalSliceSize += len;
//second slice loss
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iTotalSliceSize, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_EQ (rv, 0); // Reconstruct first slice OK
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice incomplete, no output
iIdx++;
//Frame 1: P, EC_IDC=2, loss = 0
//will clean SPS/PPS status
EncodeOneFrame (1);
encToDecData (info, len); //all slice together
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_TRUE (rv & 32); //parse correct, but reconstruct ECed
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 0
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //ECed status, reconstruction current frame 1
EXPECT_TRUE (rv & 32); //decoder ECed status
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 1
iIdx++;
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 2: P, EC_IDC=0, loss = 0
/////will clean SPS/PPS status
EncodeOneFrame (1);
encToDecData (info, len); //all slice together
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
// Ref picture is ECed, so reconstructed picture is ECed
EXPECT_TRUE (rv & 32);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
iIdx++;
//set EC=SLICE_COPY
uiEcIdc = (uint32_t) (ERROR_CON_FRAME_COPY);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 3: P, EC_IDC=2, loss = 1
EncodeOneFrame (1);
encToDecSliceData (0, 0, info, iTotalSliceSize); //slice 1 lost
encToDecSliceData (0, 1, info, len); //slice 2
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_FRAME_COPY);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv & 32);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice loss
iIdx++;
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 4: P, EC_IDC=0, loss = 0
EncodeOneFrame (1);
encToDecData (info, len); //all slice
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_TRUE (rv != 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); // EC_IDC=0, previous picture slice lost, no output
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv != 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); // No ref picture, no output
iIdx++;
}
//This case contain 2 slices per picture for no IDR loss
//coding order: 0 1 2 3 4 5
//frame type IDR P P P P IDR
//EC_IDC 0 2 0 2 0 ^2^
//loss (2 slice: 1,2): 0 0 1 2 0 0
TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRNoLoss) {
uint32_t uiEcIdc;
uint32_t uiGet;
EncodeDecodeFileParamBase p = kFileParamArray[0];
prepareParam (1, 2, p.width, p.height, p.frameRate);
param_.iSpatialLayerNum = 1;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
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;
int len = 0;
unsigned char* pData[3] = { NULL };
int iTotalSliceSize = 0;
InitialEncDec (p.width, p.height);
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 0: IDR, EC_IDC=0, loss = 0
//Expected result: all OK, 2nd Output
EncodeOneFrame (1);
encToDecData (info, len); //all slice
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //output frame 0
iIdx++;
//Frame 1: P, EC_IDC=0, loss = 0
//Expected result: all OK, 2nd Output
EncodeOneFrame (1);
encToDecData (info, len); //all slice together
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //ECed output for frame 0
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction current frame 1
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 1
iIdx++;
//Frame 2: P, EC_IDC=0, loss = 1
//Expected result: all OK, no Output
EncodeOneFrame (1);
encToDecSliceData (0, 0, info, iTotalSliceSize); // slice 1 lost
encToDecSliceData (0, 1, info, len); // slice 2 only
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_EQ (rv, 0); //parse correct
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
iIdx++;
//set EC=SLICE_COPY
uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 3: P, EC_IDC=2, loss = 2
//Expected result: neither OK, 1st Output
EncodeOneFrame (1);
encToDecSliceData (0, 0, info, len); //slice 1 only
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_TRUE (rv & 32); //parse OK but frame 2 ECed
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //slice loss but ECed output Frame 2
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
EXPECT_TRUE (rv & 32);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice loss
iIdx++;
//set EC=DISABLE
uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
//Frame 4: P, EC_IDC=0, loss = 0
//Expected result: depends on DecodeFrame2 result. If OK, output; else ,no output
EncodeOneFrame (1);
encToDecData (info, len); //all slice
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
EXPECT_TRUE (rv != 0); //previous slice not outputted, will return error due to incomplete frame
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
// previous frame NOT output, no ref
EXPECT_TRUE (rv != 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
iIdx++;
//Frame 5: IDR, EC_IDC=2->0, loss = 0
//Expected result: depends on DecodeFrame2 result. If OK, output; else ,no output
int32_t iIDRPeriod = 1;
encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod);
EncodeOneFrame (1);
EXPECT_TRUE (info.eFrameType == videoFrameTypeIDR);
encToDecSliceData (0, 0, info, len); //SPS
iTotalSliceSize = len;
encToDecSliceData (0, 1, info, len); //PPS
iTotalSliceSize += len;
encToDecSliceData (1, 0, info, len); //slice 1
iTotalSliceSize += len;
//set EC=SLICE_COPY for slice 1
uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iTotalSliceSize, pData, &dstBufInfo_);
EXPECT_TRUE (rv == 0); // IDR status return error_free
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //frame incomplete
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
EXPECT_TRUE (rv == 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
//set EC=DISABLE for slice 2
encToDecSliceData (1, 1, info, len); //slice 1
uiEcIdc = (int) (ERROR_CON_DISABLE);
decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
EXPECT_EQ (uiGet, uiEcIdc);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
EXPECT_EQ (rv, 0); //Parse correct under no EC
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //frame incomplete
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
EXPECT_EQ (rv, 0);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //output previous pic
iIdx++;
}
static const EncodeDecodeFileParamBase kSVCSwitch[] = {
{300, 160, 96, 6.0f, 2, 1, "120012130101012311201221323"},
};
TEST_F (EncodeDecodeTestAPI, Engine_SVC_Switch_I) {
SLTRMarkingFeedback m_LTR_Marking_Feedback;
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = kSVCSwitch[0];
p.width = p.width << 2;
p.height = p.height << 2;
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_ENABLE_SPS_PPS_ID_ADDITION, &iSpsPpsIdAddition);
int32_t iIDRPeriod = pow(2.0f, (param_.iTemporalLayerNum-1)) * ((rand() % 5) + 1);
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 iTarDid = 0;
while (iIdx <= p.numframes) {
EncodeOneFrame (1);
if (m_LTR_Recover_Request.uiFeedbackType == IDR_RECOVERY_REQUEST) {
ASSERT_TRUE (info.eFrameType == videoFrameTypeIDR);
}
if (info.eFrameType == videoFrameTypeIDR) {
iTarDid = rand() % 4;
}
//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, iTarDid);
rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
ASSERT_EQ (rv, 0);
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
ASSERT_EQ (rv, 0);
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_F (EncodeDecodeTestAPI, Engine_SVC_Switch_P) {
SLTRMarkingFeedback m_LTR_Marking_Feedback;
SLTRRecoverRequest m_LTR_Recover_Request;
m_LTR_Recover_Request.uiIDRPicId = 0;
EncodeDecodeFileParamBase p = kSVCSwitch[0];
int iTarDid = 0;
int iLastDid = 0;
p.width = p.width << 2;
p.height = p.height << 2;
prepareParam (4, p.slicenum, p.width, p.height, p.frameRate);
param_.iTemporalLayerNum = (rand() % 4) + 1;
param_.iSpatialLayerNum = 4;
encoder_->Uninitialize();
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
m_LTR_Recover_Request.uiFeedbackType = NO_RECOVERY_REQUSET;
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_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) {
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));
if (iIdx < (int) strlen (p.pLossSequence)) {
switch (p.pLossSequence[iIdx]) {
case '0':
iTarDid = 0;
break;
case '1':
iTarDid = 1;
break;
case '2':
iTarDid = 2;
break;
case '3':
iTarDid = 3;
break;
default :
iTarDid = rand() % 4;
break;
}
} else {
iTarDid = rand() % 4;
}
ExtractDidNal (&info, len, &m_SLostSim, iTarDid);
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, false);
rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
if (info.eFrameType == videoFrameTypeP && iIdx > 0 && iLastDid != iTarDid) {
ASSERT_NE (rv, 0);
} else if (info.eFrameType == videoFrameTypeIDR) {
ASSERT_EQ (rv, 0);
}
decoder_->GetOption (DECODER_OPTION_TEMPORAL_ID, &iTid);
ASSERT_EQ (iTid, info.sLayerInfo[0].uiTemporalId);
LTRRecoveryRequest (decoder_, encoder_, &m_LTR_Recover_Request, rv, false);
LTRMarkFeedback (decoder_, encoder_, &m_LTR_Marking_Feedback, rv);
iIdx++;
iLastDid = iTarDid;
}
}
TEST_F (EncodeDecodeTestAPI, SetOptionEncParamExt) {
int iWidth = (((rand() % MAX_WIDTH) >> 1) + 16) << 1;
int iHeight = (((rand() % MAX_HEIGHT) >> 1) + 16) << 1;
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = WELS_CLIP3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
int iSpatialLayerNum = 4;
int iSliceNum = 1;
encoder_->GetDefaultParams (&param_);
prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate);
int rv = encoder_->InitializeExt (&param_);
ASSERT_TRUE (rv == cmResultSuccess);
int32_t iTraceLevel = WELS_LOG_QUIET;
encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
for (int i = 0; i < iEncFrameNum; i++) {
int iResult;
int len = 0;
unsigned char* pData[3] = { NULL };
int iTotalSliceSize = 0;
RandomParamExtCombination();
iResult = encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &param_);
//ValidateParamExtCombination();
//ASSERT_TRUE (iResult == cmResultSuccess);
//to do
// currently, there are still some error cases even though under condition cmResultSuccess == iResult
// so need to enhance the validation check for any random value of each variable in ParamExt
if (cmResultSuccess == iResult) {
InitialEncDec (param_.iPicWidth, param_.iPicHeight);
EncodeOneFrame (0);
encToDecData (info, len);
pData[0] = pData[1] = pData[2] = 0;
memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
iResult = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iTotalSliceSize, pData, &dstBufInfo_);
ASSERT_TRUE (iResult == cmResultSuccess);
iResult = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_);
ASSERT_TRUE (iResult == cmResultSuccess);
EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
}
}
iTraceLevel = WELS_LOG_ERROR;
encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
}