ref: 74c02a500ba9c0f3be6947f7bac4fe7233cbf846
parent: b84f056cf2345ce447f9ab6d17c6289f083c0538
parent: 17139510a354b3f5aec036b8d583d188cb04aa10
author: ruil2 <ruil2@cisco.com>
date: Mon Feb 20 04:40:18 EST 2017
Merge pull request #2657 from huili2/parseonly_length_overflow_crashfix_final fix parseonly length overflow
--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -710,7 +710,7 @@
*/
typedef struct TagParserBsInfo {
int iNalNum; ///< total NAL number in current AU
- int iNalLenInByte [MAX_NAL_UNITS_IN_LAYER]; ///< each nal length
+ int *pNalLenInByte; ///< each nal length
unsigned char* pDstBuff; ///< outputted dst buffer for parsed bitstream
int iSpsWidthInPixel; ///< required SPS width info
int iSpsHeightInPixel; ///< required SPS height info
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -378,7 +378,7 @@
bool bFramePending;
bool bFrameFinish;
int32_t iNalNum;
- int32_t iNalLenInByte[MAX_NAL_UNITS_IN_LAYER];
+ int32_t iMaxNalNum; //permitted max NAL num stored in parser
SSpsBsInfo sSpsBsInfo [MAX_SPS_COUNT];
SSpsBsInfo sSubsetSpsBsInfo [MAX_PPS_COUNT];
SPpsBsInfo sPpsBsInfo [MAX_PPS_COUNT];
--- a/codec/decoder/core/inc/decoder_core.h
+++ b/codec/decoder/core/inc/decoder_core.h
@@ -66,6 +66,16 @@
int32_t ExpandBsBuffer (PWelsDecoderContext pCtx, const int32_t kiSrcLen);
/*
+ * ExpandBsLenBuffer
+ * Expand current BS length buffer to double size or maximum, due to max slice number exceeding
+ * Parameter:
+ * kiCurrLen: current value of total nal number (including non-VCL nal)
+ * return:
+ * 0 - success; otherwise returned error_no defined in error_no.h.
+ */
+int32_t ExpandBsLenBuffer (PWelsDecoderContext pCtx, const int32_t kiCurrLen);
+
+/*
* CheckBsBuffer
* Check if current buffer size is enough
*/
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -81,7 +81,7 @@
int32_t iNalLen = 0;
int32_t iNum = 0;
while (iNum < pParser->iNalNum) {
- iTotalNalLen += pParser->iNalLenInByte[iNum++];
+ iTotalNalLen += pParser->pNalLenInByte[iNum++];
}
uint8_t* pDstBuf = pParser->pDstBuff + iTotalNalLen;
int32_t iIdx = pCurAu->uiStartPos;
@@ -96,6 +96,12 @@
if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR
if (pCtx->bFrameFinish) { //add required sps/pps
+ if (pParser->iNalNum > pCtx->iMaxNalNum - 2) { //2 reserved for sps+pps
+ WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO,
+ "DecodeFrameConstruction(): current NAL num (%d) plus sps & pps exceeds permitted num (%d). Will expand",
+ pParser->iNalNum, pCtx->iMaxNalNum);
+ WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, ExpandBsLenBuffer (pCtx, pParser->iNalNum + 2))
+ }
bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType);
SSpsBsInfo* pSpsBs = NULL;
SPpsBsInfo* pPpsBs = NULL;
@@ -114,21 +120,26 @@
return ERR_INFO_OUT_OF_MEMORY;
}
memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen);
- pParser->iNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
- pCtx->iNalLenInByte[pCtx->iNalNum ++] = pSpsBs->uiSpsBsLen;
+ pParser->pNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
pDstBuf += pSpsBs->uiSpsBsLen;
memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen);
- pParser->iNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
+ pParser->pNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
pDstBuf += pPpsBs->uiPpsBsLen;
pCtx->bFrameFinish = false;
}
}
//then VCL data re-write
+ if (pParser->iNalNum + iEndIdx - iIdx + 1 > pCtx->iMaxNalNum) { //calculate total NAL num
+ WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO,
+ "DecodeFrameConstruction(): current NAL num (%d) exceeds permitted num (%d). Will expand",
+ pParser->iNalNum + iEndIdx - iIdx + 1, pCtx->iMaxNalNum);
+ WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, ExpandBsLenBuffer (pCtx, pParser->iNalNum + iEndIdx - iIdx + 1))
+ }
while (iIdx <= iEndIdx) {
pCurNal = pCurAu->pNalUnitsList [iIdx ++];
iNalLen = pCurNal->sNalData.sVclNal.iNalLength;
pNalBs = pCurNal->sNalData.sVclNal.pNalPos;
- pParser->iNalLenInByte [pParser->iNalNum ++] = iNalLen;
+ pParser->pNalLenInByte [pParser->iNalNum ++] = iNalLen;
if (pDstBuf - pParser->pDstBuff + iNalLen >= MAX_ACCESS_UNIT_CAPACITY) {
WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
"DecodeFrameConstruction(): composed output size (%ld) exceeds (%d). Failed to parse. current data pos %d out of %d:, previously accumulated num: %d, total num: %d, previously accumulated len: %d, current len: %d, current buf pos: %p, header buf pos: %p \n",
@@ -504,6 +515,13 @@
}
pCtx->sSavedData.pStartPos = pCtx->sSavedData.pCurPos = pCtx->sSavedData.pHead;
pCtx->sSavedData.pEnd = pCtx->sSavedData.pHead + pCtx->iMaxBsBufferSizeInByte;
+
+ pCtx->iMaxNalNum = MAX_NAL_UNITS_IN_LAYER + 2; //2 reserved for SPS+PPS
+ pCtx->pParserBsInfo->pNalLenInByte = static_cast<int*> (pMa->WelsMallocz (pCtx->iMaxNalNum * sizeof (int),
+ "pCtx->pParserBsInfo->pNalLenInByte"));
+ if (pCtx->pParserBsInfo->pNalLenInByte == NULL) {
+ return ERR_INFO_OUT_OF_MEMORY;
+ }
}
return ERR_NONE;
}
@@ -562,6 +580,37 @@
return ERR_NONE;
}
+int32_t ExpandBsLenBuffer (PWelsDecoderContext pCtx, const int kiCurrLen) {
+ SParserBsInfo* pParser = pCtx->pParserBsInfo;
+ if (!pParser->pNalLenInByte)
+ return ERR_INFO_INVALID_ACCESS;
+
+ int iNewLen = kiCurrLen;
+ if (kiCurrLen >= MAX_MB_SIZE + 2) { //exceeds the max MB number of level 5.2
+ WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "Current nal num (%d) exceededs %d.", kiCurrLen, MAX_MB_SIZE);
+ pCtx->iErrorCode |= dsOutOfMemory;
+ return ERR_INFO_OUT_OF_MEMORY;
+ } else {
+ iNewLen = kiCurrLen << 1;
+ iNewLen = WELS_MIN (iNewLen, MAX_MB_SIZE + 2);
+ }
+
+ CMemoryAlign* pMa = pCtx->pMemAlign;
+ int* pNewLenBuffer = static_cast<int*> (pMa->WelsMallocz (iNewLen * sizeof (int),
+ "pCtx->pParserBsInfo->pNalLenInByte"));
+ if (pNewLenBuffer == NULL) {
+ pCtx->iErrorCode |= dsOutOfMemory;
+ return ERR_INFO_OUT_OF_MEMORY;
+ }
+
+ //copy existing data from old length buffer to new
+ memcpy (pNewLenBuffer, pParser->pNalLenInByte, pCtx->iMaxNalNum * sizeof (int));
+ pMa->WelsFree (pParser->pNalLenInByte, "pCtx->pParserBsInfo->pNalLenInByte");
+ pParser->pNalLenInByte = pNewLenBuffer;
+ pCtx->iMaxNalNum = iNewLen;
+ return ERR_NONE;
+}
+
int32_t CheckBsBuffer (PWelsDecoderContext pCtx, const int32_t kiSrcLen) {
if (kiSrcLen > MAX_ACCESS_UNIT_CAPACITY) { //exceeds max allowed data
WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "Max AU size exceeded. Allowed size = %d, current size = %d",
@@ -633,6 +682,11 @@
pCtx->sSavedData.pStartPos = NULL;
pCtx->sSavedData.pCurPos = NULL;
if (pCtx->pParserBsInfo) {
+ if (pCtx->pParserBsInfo->pNalLenInByte) {
+ pMa->WelsFree (pCtx->pParserBsInfo->pNalLenInByte, "pCtx->pParserBsInfo->pNalLenInByte");
+ pCtx->pParserBsInfo->pNalLenInByte = NULL;
+ pCtx->iMaxNalNum = 0;
+ }
if (pCtx->pParserBsInfo->pDstBuff) {
pMa->WelsFree (pCtx->pParserBsInfo->pDstBuff, "pCtx->pParserBsInfo->pDstBuff");
pCtx->pParserBsInfo->pDstBuff = NULL;
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -726,7 +726,7 @@
m_pDecContext->pParam->eEcActiveIdc = ERROR_CON_DISABLE; //add protection to disable EC here.
if (!m_pDecContext->bFramePending) { //frame complete
m_pDecContext->pParserBsInfo->iNalNum = 0;
- memset (m_pDecContext->pParserBsInfo->iNalLenInByte, 0, MAX_NAL_UNITS_IN_LAYER);
+ memset (m_pDecContext->pParserBsInfo->pNalLenInByte, 0, MAX_NAL_UNITS_IN_LAYER);
}
pDstInfo->iNalNum = 0;
pDstInfo->iSpsWidthInPixel = pDstInfo->iSpsHeightInPixel = 0;
binary files /dev/null b/res/jm_1080p_allslice.264 differ
--- a/test/api/decode_api_test.cpp
+++ b/test/api/decode_api_test.cpp
@@ -801,8 +801,13 @@
int rv = decoder_->Initialize (&decParam);
ASSERT_EQ (0, rv);
memset (&BsInfo_, 0, sizeof (SParserBsInfo));
- fYuv_ = fopen ("./res/CiscoVT2people_160x96_6fps.yuv", "rb");
- ASSERT_TRUE (fYuv_ != NULL);
+ 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;
}
@@ -810,6 +815,7 @@
EncodeDecodeTestBase::TearDown();
if (fYuv_ != NULL) {
fclose (fYuv_);
+ fYuv_ = NULL;
}
}
@@ -820,7 +826,15 @@
BsInfo_.pDstBuff = pTmpPtr;
}
- void EncodeOneFrame (int iIdx) {
+ 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) {
@@ -828,6 +842,9 @@
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);
}
@@ -845,7 +862,7 @@
SHA1Context ctx_;
};
-//#define DEBUG_FILE_SAVE
+//#define DEBUG_FILE_SAVE_PARSEONLY_GENERAL
TEST_F (DecodeParseAPI, ParseOnly_General) {
EncodeDecodeFileParamBase p;
p.width = iWidth_;
@@ -861,7 +878,7 @@
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
+#ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL
FILE* fDec = fopen ("output.264", "wb");
FILE* fEnc = fopen ("enc.264", "wb");
FILE* fExtract = fopen ("extract.264", "wb");
@@ -874,14 +891,14 @@
while (iFrame < p.numframes) {
//encode
- EncodeOneFrame (iFrame);
+ EncodeOneFrame (0);
//extract target layer data
encToDecData (info, iLen);
-#ifdef DEBUG_FILE_SAVE
+#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
+#ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL
fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fExtract);
#endif
//parseonly
@@ -896,10 +913,10 @@
iLen = 0;
int i = 0;
while (i < BsInfo_.iNalNum) {
- iLen += BsInfo_.iNalLenInByte[i];
+ iLen += BsInfo_.pNalLenInByte[i];
i++;
}
-#ifdef DEBUG_FILE_SAVE
+#ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL
fwrite (BsInfo_.pDstBuff, iLen, 1, fDec);
#endif
SHA1Input (&ctx_, BsInfo_.pDstBuff, iLen);
@@ -909,10 +926,10 @@
unsigned char digest[SHA_DIGEST_LENGTH];
SHA1Result (&ctx_, digest);
if (!HasFatalFailure()) {
- CompareHashAnyOf (digest, pHashStr[uiTargetLayerId], sizeof *pHashStr / sizeof **pHashStr);
+ CompareHashAnyOf (digest, pHashStr[uiTargetLayerId], sizeof * pHashStr / sizeof** pHashStr);
}
} //while
-#ifdef DEBUG_FILE_SAVE
+#ifdef DEBUG_FILE_SAVE_PARSEONLY_GENERAL
fclose (fEnc);
fclose (fExtract);
fclose (fDec);
@@ -947,7 +964,7 @@
while (iFrame < p.numframes) {
//encode
- EncodeOneFrame (iFrame);
+ EncodeOneFrame (0);
//parseonly
if (iFrame == iMissedPicNum) { //make current frame partly missing
//Frame: P, first slice loss
@@ -979,5 +996,197 @@
} //while
}
+//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
+
+}
--- a/test/decoder/DecUT_ParseSyntax.cpp
+++ b/test/decoder/DecUT_ParseSyntax.cpp
@@ -58,7 +58,7 @@
return dsErrorFree;
}
-void UninitDecoder (PWelsDecoderContext pCtx) {
+void UninitDecoder (PWelsDecoderContext& pCtx) {
if (NULL == pCtx)
return;
@@ -132,11 +132,13 @@
//Uninit members
void Uninit();
//Decoder real bitstream
-// void DecoderBs (const char* sFileName);
- //Parse real bitstream
void DecodeBs (const char* sFileName);
+ //Parse real bitstream
+ void ParseBs (const char* sFileName);
//Scalinglist
void TestScalingList();
+ //specific bitstream test
+ void TestSpecificBs();
//Do whole tests here
void DecoderParseSyntaxTestAll();
@@ -250,6 +252,66 @@
}
+void DecoderParseSyntaxTest::ParseBs (const char* sFileName) {
+
+ uint8_t* pBuf = NULL;
+ int32_t iBufPos = 0;
+ int32_t iFileSize;
+ int32_t i = 0;
+ int32_t iSliceSize;
+ int32_t iSliceIndex = 0;
+ int32_t iEndOfStreamFlag = 0;
+ FILE* pH264File;
+ uint8_t uiStartCode[4] = { 0, 0, 0, 1 };
+ int iRet;
+
+#if defined(ANDROID_NDK)
+ std::string filename = std::string ("/sdcard/") + sFileName;
+ ASSERT_TRUE ((pH264File = fopen (filename.c_str(), "rb")) != NULL);
+#else
+ ASSERT_TRUE ((pH264File = fopen (sFileName, "rb")) != NULL);
+#endif
+ fseek (pH264File, 0L, SEEK_END);
+ iFileSize = (int32_t)ftell (pH264File);
+ fseek (pH264File, 0L, SEEK_SET);
+ pBuf = new uint8_t[iFileSize + 4];
+ ASSERT_EQ (fread (pBuf, 1, iFileSize, pH264File), (unsigned int)iFileSize);
+ memcpy (pBuf + iFileSize, &uiStartCode[0], 4); //confirmed_safe_unsafe_usage
+ while (true) {
+ if (iBufPos >= iFileSize) {
+ iEndOfStreamFlag = true;
+ if (iEndOfStreamFlag)
+ m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, (void*)&iEndOfStreamFlag);
+ break;
+ }
+ for (i = 0; i < iFileSize; i++) {
+ if ((pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 0 && pBuf[iBufPos + i + 3] == 1
+ && i > 0)) {
+ break;
+ }
+ }
+ iSliceSize = i;
+ memset (&m_sParserBsInfo, 0, sizeof (SParserBsInfo));
+ iRet = m_pDec->DecodeParser (pBuf + iBufPos, iSliceSize, &m_sParserBsInfo);
+ EXPECT_TRUE (iRet == dsErrorFree || iRet == dsFramePending);
+ iRet = m_pDec->DecodeParser (NULL, 0, &m_sParserBsInfo);
+ EXPECT_TRUE (iRet == dsErrorFree || iRet == dsFramePending);
+ iBufPos += iSliceSize;
+ ++iSliceIndex;
+ if (iSliceIndex == 4)
+ break;
+ }
+
+ fclose (pH264File);
+ if (pBuf) {
+ delete[] pBuf;
+ pBuf = NULL;
+ }
+
+
+}
+
+
void DecoderParseSyntaxTest::TestScalingList() {
uint8_t iScalingList[6][16] = {
{17, 17, 16, 16, 17, 16, 15, 15, 16, 15, 15, 15, 16, 15, 15, 15 },
@@ -295,11 +357,22 @@
Uninit();
}
+void DecoderParseSyntaxTest::TestSpecificBs() {
+ int32_t iRet = ERR_NONE;
+ Uninit();
+ m_sDecParam.bParseOnly = true;
+ m_sDecParam.eEcActiveIdc = ERROR_CON_DISABLE;
+ iRet = m_pDec->Initialize (&m_sDecParam);
+ ASSERT_EQ (iRet, ERR_NONE);
+ ParseBs ("res/jm_1080p_allslice.264");
+ m_pDec->Uninitialize();
+ //Uninit();
+}
//TEST here for whole tests
TEST_F (DecoderParseSyntaxTest, DecoderParseSyntaxTestAll) {
TestScalingList();
-
+ TestSpecificBs();
}