ref: b231e3f00006240dbc45725f9f93a5ab17d705c9
parent: 53c14dccf0b24a7d42009ebbde5c7094fa4f59d6
author: huili2 <huili2@cisco.com>
date: Sun Nov 23 18:56:39 EST 2014
parse only add and UT
--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -457,6 +457,7 @@
unsigned char uiTargetDqLayer; ///< setting target dq layer id
ERROR_CON_IDC eEcActiveIdc; ///< whether active error concealment feature in decoder
+ bool bParseOnly; ///< decoder for parse only, no reconstruction
SVideoProperty sVideoProperty; ///< video stream property
} SDecodingParam, *PDecodingParam;
@@ -574,7 +575,7 @@
unsigned char* pDstBuff; ///< outputted dst buffer for parsed bitstream
int iSpsWidthInPixel; ///< required SPS width info
int iSpsHeightInPixel; ///< required SPS height info
-} SParserBsInfo, PParserBsInfo;
+} SParserBsInfo, *PParserBsInfo;
/**
* @brief Structure for encoder statistics
--- a/codec/decoder/core/inc/au_parser.h
+++ b/codec/decoder/core/inc/au_parser.h
@@ -86,7 +86,7 @@
uint8_t* ParseNalHeader (PWelsDecoderContext pCtx, SNalUnitHeader* pNalUnitHeader, uint8_t* pSrcRbsp,
int32_t iSrcRbspLen, uint8_t* pSrcNal, int32_t iSrcNalLen, int32_t* pConsumedBytes);
-int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen);
+int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen, uint8_t* pSrcNal, const int32_t kSrcNalLen);
int32_t ParseRefBasePicMarking (PBitStringAux pBs, PRefBasePicMarking pRefBasePicMarking);
@@ -113,7 +113,7 @@
* \note Call it in case eNalUnitType is SPS.
*************************************************************************************
*/
-int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight);
+int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight, uint8_t* pSrcNal, const int32_t kSrcNalLen);
/*!
*************************************************************************************
@@ -129,7 +129,7 @@
* \note Call it in case eNalUnitType is PPS.
*************************************************************************************
*/
-int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux);
+int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux, uint8_t* pSrcNal, const int32_t kSrcNalLen);
/*!
*************************************************************************************
--- a/codec/decoder/core/inc/bit_stream.h
+++ b/codec/decoder/core/inc/bit_stream.h
@@ -65,7 +65,15 @@
int32_t InitReadBits (PBitStringAux pBitString, intX_t iEndOffset);
-
+//The following for writing bs in decoder for Parse Only purpose
+void DecInitBitsForEncoding (PBitStringAux pBitString, uint8_t* kpBuf, const int32_t kiSize);
+int32_t DecBsWriteBits (PBitStringAux pBitString, int32_t iLen, const uint32_t kuiValue);
+int32_t DecBsWriteOneBit (PBitStringAux pBitString, const uint32_t kuiValue);
+int32_t DecBsFlush (PBitStringAux pBitString);
+int32_t DecBsWriteUe (PBitStringAux pBitString, const uint32_t kuiValue);
+int32_t DecBsWriteSe (PBitStringAux pBitString, const int32_t kiValue);
+int32_t DecBsRbspTrailingBits (PBitStringAux pBitString);
+void RBSP2EBSP (uint8_t* pDstBuf, uint8_t* pSrcBuf, const int32_t kiSize);
} // namespace WelsDec
--- a/codec/decoder/core/inc/decoder.h
+++ b/codec/decoder/core/inc/decoder.h
@@ -68,7 +68,7 @@
* \note N/A
*************************************************************************************
*/
-int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx);
+int32_t WelsInitDecoder (PWelsDecoderContext pCtx, const bool bParseOnly, SLogContext* pLogCtx);
/*!
*************************************************************************************
@@ -101,7 +101,7 @@
*/
int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const int32_t kiBsLen,
- uint8_t** ppDst, SBufferInfo* pDstBufInfo);
+ uint8_t** ppDst, SBufferInfo* pDstBufInfo, SParserBsInfo* pDstBsInfo);
/*
* request memory blocks for decoder avc part
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -102,6 +102,19 @@
uint8_t* pCurPos;
} SDataBuffer;
+//limit size for SPS PPS total permitted size for parse_only
+#define SPS_PPS_BS_SIZE 128
+typedef struct TagSpsBsInfo {
+ uint8_t pSpsBsBuf [SPS_PPS_BS_SIZE];
+ int32_t iSpsId;
+ uint16_t uiSpsBsLen;
+} SSpsBsInfo;
+
+typedef struct TagPpsBsInfo {
+ uint8_t pPpsBsBuf [SPS_PPS_BS_SIZE];
+ int32_t iPpsId;
+ uint16_t uiPpsBsLen;
+} SPpsBsInfo;
//#ifdef __cplusplus
//extern "C" {
//#endif//__cplusplus
@@ -210,6 +223,7 @@
void* pArgDec; // structured arguments for decoder, reserved here for extension in the future
SDataBuffer sRawData;
+SDataBuffer sSavedData; //for parse only purpose
// Configuration
SDecodingParam* pParam;
@@ -334,6 +348,14 @@
bool bNextNewSeqBegin;
int iOverwriteFlags;
ERROR_CON_IDC eErrorConMethod; //
+
+//for Parse only
+bool bParseOnly;
+SSpsBsInfo sSpsBsInfo [MAX_SPS_COUNT];
+SSpsBsInfo sSubsetSpsBsInfo [MAX_PPS_COUNT];
+SPpsBsInfo sPpsBsInfo [MAX_PPS_COUNT];
+SParserBsInfo* pParserBsInfo;
+
PPicture pPreviousDecodedPictureInDpb; //pointer to previously decoded picture in DPB for error concealment
PGetIntraPredFunc pGetI16x16LumaPredFunc[7]; //h264_predict_copy_16x16;
PGetIntraPredFunc pGetI4x4LumaPredFunc[14]; // h264_predict_4x4_t
--- a/codec/decoder/core/src/au_parser.cpp
+++ b/codec/decoder/core/src/au_parser.cpp
@@ -43,6 +43,8 @@
#include "error_code.h"
#include "memmgr_nal_unit.h"
#include "decoder_core.h"
+#include "bit_stream.h"
+#include "mem_align.h"
namespace WelsDec {
/*!
@@ -110,6 +112,7 @@
bool bExtensionFlag = false;
int32_t iErr = ERR_NONE;
int32_t iBitSize = 0;
+ SDataBuffer* pSavedData = &pCtx->sSavedData;
SLogContext* pLogCtx = & (pCtx->sLogCtx);
pNalUnitHeader->eNalUnitType = NAL_UNIT_UNSPEC_0;//SHOULD init it. because pCtx->sCurNalHead is common variable.
@@ -296,9 +299,28 @@
iNalSize -= NAL_UNIT_HEADER_EXT_SIZE;
*pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE;
+ if (pCtx->bParseOnly) {
+ pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
+ pCurNal->sNalData.sVclNal.iNalLength = iSrcNalLen - NAL_UNIT_HEADER_EXT_SIZE;
+ if (pCurNal->sNalHeaderExt.bIdrFlag) {
+ * (pSrcNal + 3) &= 0xE0;
+ * (pSrcNal + 3) |= 0x05;
+ } else {
+ * (pSrcNal + 3) &= 0xE0;
+ * (pSrcNal + 3) |= 0x01;
+ }
+ memcpy (pSavedData->pCurPos, pSrcNal, 4);
+ pSavedData->pCurPos += 4;
+ memcpy (pSavedData->pCurPos, pSrcNal + 7, iSrcNalLen - 7);
+ pSavedData->pCurPos += iSrcNalLen - 7;
+ }
} else {
-
-
+ if (pCtx->bParseOnly) {
+ pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
+ pCurNal->sNalData.sVclNal.iNalLength = iSrcNalLen;
+ memcpy (pSavedData->pCurPos, pSrcNal, iSrcNalLen);
+ pSavedData->pCurPos += iSrcNalLen;
+ }
if (NAL_UNIT_PREFIX == pCtx->sPrefixNal.sNalHeaderExt.sNalUnitHeader.eNalUnitType) {
if (pCtx->sPrefixNal.sNalData.sPrefixNal.bPrefixNalCorrectFlag) {
PrefetchNalHeaderExtSyntax (pCtx, pCurNal, &pCtx->sPrefixNal);
@@ -501,7 +523,8 @@
*
*************************************************************************************
*/
-int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen) {
+int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen, uint8_t* pSrcNal,
+ const int32_t kSrcNalLen) {
PBitStringAux pBs = NULL;
EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0; // make initial value as unspecified
int32_t iPicWidth = 0;
@@ -528,7 +551,7 @@
return iErr;
}
}
- iErr = ParseSps (pCtx, pBs, &iPicWidth, &iPicHeight);
+ iErr = ParseSps (pCtx, pBs, &iPicWidth, &iPicHeight, pSrcNal, kSrcNalLen);
if (ERR_NONE != iErr) { // modified for pSps/pSubsetSps invalid, 12/1/2009
if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
pCtx->iErrorCode |= dsNoParamSets;
@@ -550,7 +573,7 @@
return iErr;
}
}
- iErr = ParsePps (pCtx, &pCtx->sPpsBuffer[0], pBs);
+ iErr = ParsePps (pCtx, &pCtx->sPpsBuffer[0], pBs, pSrcNal, kSrcNalLen);
if (ERR_NONE != iErr) { // modified for pps invalid, 12/1/2009
if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
pCtx->iErrorCode |= dsNoParamSets;
@@ -795,7 +818,8 @@
*************************************************************************************
*/
-int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight) {
+int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight,
+ uint8_t* pSrcNal, const int32_t kSrcNalLen) {
PBitStringAux pBs = pBsAux;
SSubsetSps sTempSubsetSps;
PSps pSps = NULL;
@@ -995,6 +1019,79 @@
WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //vui_parameters_present_flag
pSps->bVuiParamPresentFlag = !!uiCode;
+ if (pCtx->bParseOnly) {
+ if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //sps bs exceeds!
+ pCtx->iErrorCode |= dsOutOfMemory;
+ return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
+ }
+ if (!kbUseSubsetFlag) { //SPS
+ SSpsBsInfo* pSpsBs = &pCtx->sSpsBsInfo [iSpsId];
+ pSpsBs->iSpsId = iSpsId;
+ memcpy (pSpsBs->pSpsBsBuf, pSrcNal, kSrcNalLen);
+ pSpsBs->uiSpsBsLen = (uint32_t) kSrcNalLen;
+ } else { //subset SPS
+ SSpsBsInfo* pSpsBs = &pCtx->sSubsetSpsBsInfo [iSpsId];
+ pSpsBs->iSpsId = iSpsId;
+ pSpsBs->pSpsBsBuf [0] = pSpsBs->pSpsBsBuf [1] = pSpsBs->pSpsBsBuf [2] = 0x00;
+ pSpsBs->pSpsBsBuf [3] = 0x01;
+ pSpsBs->pSpsBsBuf [4] = 0x67;
+
+ //re-write subset SPS to SPS
+ SBitStringAux sSubsetSpsBs;
+ uint8_t* pBsBuf = static_cast<uint8_t*> (WelsMalloc (SPS_PPS_BS_SIZE + 4,
+ "Temp buffer for parse only usage.")); //to reserve 4 bytes for UVLC writing buffer
+ if (NULL == pBsBuf) {
+ pCtx->iErrorCode |= dsOutOfMemory;
+ return pCtx->iErrorCode;
+ }
+ DecInitBitsForEncoding (&sSubsetSpsBs, pBsBuf, pBs->pEndBuf - pBs->pStartBuf);
+ DecBsWriteBits (&sSubsetSpsBs, 8, 77); //profile_idc, forced to Main profile
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet0Flag); // constraint_set0_flag
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet1Flag); // constraint_set1_flag
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet2Flag); // constraint_set2_flag
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet3Flag); // constraint_set3_flag
+ DecBsWriteBits (&sSubsetSpsBs, 4, 0); //constraint_set4_flag, constraint_set5_flag, reserved_zero_2bits
+ DecBsWriteBits (&sSubsetSpsBs, 8, pSps->uiLevelIdc); //level_idc
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iSpsId); //sps_id
+ DecBsWriteUe (&sSubsetSpsBs, pSps->uiLog2MaxFrameNum - 4); //log2_max_frame_num_minus4
+ DecBsWriteUe (&sSubsetSpsBs, pSps->uiPocType); //pic_order_cnt_type
+ if (pSps->uiPocType == 0) {
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iLog2MaxPocLsb - 4); //log2_max_pic_order_cnt_lsb_minus4
+ } else if (pSps->uiPocType == 1) {
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDeltaPicOrderAlwaysZeroFlag); //delta_pic_order_always_zero_flag
+ DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForNonRefPic); //offset_for_no_ref_pic
+ DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForTopToBottomField); //offset_for_top_to_bottom_field
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFramesInPocCycle); //num_ref_frames_in_pic_order_cnt_cycle
+ for (int32_t i = 0; i < pSps->iNumRefFramesInPocCycle; ++i) {
+ DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForRefFrame[i]); //offset_for_ref_frame[i]
+ }
+ }
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFrames); //max_num_ref_frames
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bGapsInFrameNumValueAllowedFlag); //gaps_in_frame_num_value_allowed_flag
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iMbWidth - 1); //pic_width_in_mbs_minus1
+ DecBsWriteUe (&sSubsetSpsBs, pSps->iMbHeight - 1); //pic_height_in_map_units_minus1
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameMbsOnlyFlag); //frame_mbs_only_flag
+ if (!pSps->bFrameMbsOnlyFlag) {
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bMbaffFlag); //mb_adaptive_frame_field_flag
+ }
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDirect8x8InferenceFlag); //direct_8x8_inference_flag
+ DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameCroppingFlag); //frame_cropping_flag
+ if (pSps->bFrameCroppingFlag) {
+ DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iLeftOffset); //frame_crop_left_offset
+ DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iRightOffset); //frame_crop_right_offset
+ DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iTopOffset); //frame_crop_top_offset
+ DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iBottomOffset); //frame_crop_bottom_offset
+ }
+ DecBsWriteOneBit (&sSubsetSpsBs, 0); //vui_parameters_present_flag
+ DecBsRbspTrailingBits (&sSubsetSpsBs); //finished, rbsp trailing bit
+ int32_t iRbspSize = sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf;
+ RBSP2EBSP (pSpsBs->pSpsBsBuf + 5, sSubsetSpsBs.pStartBuf, iRbspSize);
+ pSpsBs->uiSpsBsLen = sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf + 5;
+ if (pBsBuf) {
+ WelsFree (pBsBuf, "pBsBuf for parse only usage");
+ }
+ }
+ }
// Check if SPS SVC extension applicated
if (kbUseSubsetFlag && (PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc)) {
if (DecodeSpsSvcExt (pCtx, pSubsetSps, pBs) != ERR_NONE) {
@@ -1080,7 +1177,8 @@
* \note Call it in case eNalUnitType is PPS.
*************************************************************************************
*/
-int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux) {
+int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux, uint8_t* pSrcNal,
+ const int32_t kSrcNalLen) {
PPps pPps = NULL;
SPps sTempPps;
@@ -1193,6 +1291,16 @@
} else {
memcpy (&pCtx->sPpsBuffer[uiPpsId], pPps, sizeof (SPps));
pCtx->bPpsAvailFlags[uiPpsId] = true;
+ }
+ if (pCtx->bParseOnly) {
+ if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //pps bs exceeds
+ pCtx->iErrorCode |= dsOutOfMemory;
+ return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
+ }
+ SPpsBsInfo* pPpsBs = &pCtx->sPpsBsInfo [uiPpsId];
+ pPpsBs->iPpsId = (int32_t) uiPpsId;
+ memcpy (pPpsBs->pPpsBsBuf, pSrcNal, kSrcNalLen);
+ pPpsBs->uiPpsBsLen = kSrcNalLen;
}
return ERR_NONE;
}
--- a/codec/decoder/core/src/bit_stream.cpp
+++ b/codec/decoder/core/src/bit_stream.cpp
@@ -49,7 +49,7 @@
}
int32_t InitReadBits (PBitStringAux pBitString, intX_t iEndOffset) {
- if(pBitString->pCurBuf>=(pBitString->pEndBuf - iEndOffset)) {
+ if (pBitString->pCurBuf >= (pBitString->pEndBuf - iEndOffset)) {
return ERR_INFO_INVALID_ACCESS;
}
pBitString->uiCurBits = GetValue4Bytes (pBitString->pCurBuf);
@@ -79,10 +79,140 @@
pBitString->iBits = kiSize; // count bits of overall bitstreaming inputindex;
pBitString->pCurBuf = pBitString->pStartBuf;
int32_t iErr = InitReadBits (pBitString, 0);
- if(iErr) {
+ if (iErr) {
return iErr;
}
return ERR_NONE;
+}
+
+//Following for write bs in decoder
+void DecInitBitsForEncoding (PBitStringAux pBitString, uint8_t* pBuf, const int32_t kiSize) {
+ uint8_t* pPtr = pBuf;
+ pBitString->pStartBuf = pPtr;
+ pBitString->pCurBuf = pPtr;
+ pBitString->pEndBuf = pPtr + kiSize;
+ pBitString->iLeftBits = 32;
+ pBitString->uiCurBits = 0;
+}
+
+#define WRITE_BE_32(ptr, val) do { \
+ (ptr)[0] = (val) >> 24; \
+ (ptr)[1] = (val) >> 16; \
+ (ptr)[2] = (val) >> 8; \
+ (ptr)[3] = (val) >> 0; \
+ } while (0);
+
+int32_t DecBsWriteBits (PBitStringAux pBitString, int32_t iLen, const uint32_t kuiValue) {
+ if (iLen < pBitString->iLeftBits) {
+ pBitString->uiCurBits = (pBitString->uiCurBits << iLen) | kuiValue;
+ pBitString->iLeftBits -= iLen;
+ } else {
+ iLen -= pBitString->iLeftBits;
+ pBitString->uiCurBits = (pBitString->uiCurBits << pBitString->iLeftBits) | (kuiValue >> iLen);
+ WRITE_BE_32 (pBitString->pCurBuf, pBitString->uiCurBits);
+ pBitString->pCurBuf += 4;
+ pBitString->uiCurBits = kuiValue & ((1 << iLen) - 1);
+ pBitString->iLeftBits = 32 - iLen;
+ }
+ return 0;
+}
+
+int32_t DecBsWriteOneBit (PBitStringAux pBitString, const uint32_t kuiValue) {
+ DecBsWriteBits (pBitString, 1, kuiValue);
+ return 0;
+}
+
+int32_t DecBsFlush (PBitStringAux pBitString) {
+ WRITE_BE_32 (pBitString->pCurBuf, pBitString->uiCurBits << pBitString->iLeftBits);
+ pBitString->pCurBuf += 4 - pBitString->iLeftBits / 8;
+ pBitString->iLeftBits = 32;
+ pBitString->uiCurBits = 0;
+ return 0;
+}
+
+const uint32_t g_kuiDecGolombUELength[256] = {
+ 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, //14
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, //30
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,//46
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,//62
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,//
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 17
+};
+
+int32_t DecBsWriteUe (PBitStringAux pBitString, const uint32_t kuiValue) {
+ uint32_t iTmpValue = kuiValue + 1;
+ if (256 > kuiValue) {
+ DecBsWriteBits (pBitString, g_kuiDecGolombUELength[kuiValue], kuiValue + 1);
+ } else {
+ uint32_t n = 0;
+ if (iTmpValue & 0xffff0000) {
+ iTmpValue >>= 16;
+ n += 16;
+ }
+ if (iTmpValue & 0xff) {
+ iTmpValue >>= 8;
+ n += 8;
+ }
+
+ //n += (g_kuiDecGolombUELength[iTmpValue] >> 1);
+
+ n += (g_kuiDecGolombUELength[iTmpValue - 1] >> 1);
+ DecBsWriteBits (pBitString, (n << 1) + 1, kuiValue + 1);
+ }
+ return 0;
+}
+
+int32_t DecBsWriteSe (PBitStringAux pBitString, const int32_t kiValue) {
+ uint32_t iTmpValue;
+ if (0 == kiValue) {
+ DecBsWriteOneBit (pBitString, 1);
+ } else if (0 < kiValue) {
+ iTmpValue = (kiValue << 1) - 1;
+ DecBsWriteUe (pBitString, iTmpValue);
+ } else {
+ iTmpValue = ((-kiValue) << 1);
+ DecBsWriteUe (pBitString, iTmpValue);
+ }
+ return 0;
+}
+
+int32_t DecBsRbspTrailingBits (PBitStringAux pBitString) {
+ DecBsWriteOneBit (pBitString, 1);
+ DecBsFlush (pBitString);
+
+ return 0;
+}
+
+void RBSP2EBSP (uint8_t* pDstBuf, uint8_t* pSrcBuf, const int32_t kiSize) {
+ uint8_t* pSrcPointer = pSrcBuf;
+ uint8_t* pDstPointer = pDstBuf;
+ uint8_t* pSrcEnd = pSrcBuf + kiSize;
+ int32_t iZeroCount = 0;
+
+ while (pSrcPointer < pSrcEnd) {
+ if (iZeroCount == 2 && *pSrcPointer <= 3) {
+ //add the code 0x03
+ *pDstPointer++ = 3;
+ iZeroCount = 0;
+ }
+ if (*pSrcPointer == 0) {
+ ++ iZeroCount;
+ } else {
+ iZeroCount = 0;
+ }
+ *pDstPointer++ = *pSrcPointer++;
+ }
}
} // namespace WelsDec
--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -350,6 +350,9 @@
return iRet;
pCtx->eErrorConMethod = pCtx->pParam->eEcActiveIdc;
+ if (pCtx->bParseOnly) //parse only, disable EC method
+ pCtx->eErrorConMethod = ERROR_CON_DISABLE;
+
if (VIDEO_BITSTREAM_SVC == pCtx->pParam->sVideoProperty.eVideoBsType ||
VIDEO_BITSTREAM_AVC == pCtx->pParam->sVideoProperty.eVideoBsType) {
pCtx->eVideoType = pCtx->pParam->sVideoProperty.eVideoBsType;
@@ -374,7 +377,7 @@
* \note N/A
*************************************************************************************
*/
-int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx) {
+int32_t WelsInitDecoder (PWelsDecoderContext pCtx, const bool bParseOnly, SLogContext* pLogCtx) {
if (pCtx == NULL) {
return ERR_INFO_INVALID_PTR;
}
@@ -382,6 +385,7 @@
// default
WelsDecoderDefaults (pCtx, pLogCtx);
+ pCtx->bParseOnly = bParseOnly;
// open decoder
return WelsOpenDecoder (pCtx);
}
@@ -427,9 +431,10 @@
*************************************************************************************
*/
int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const int32_t kiBsLen,
- uint8_t** ppDst, SBufferInfo* pDstBufInfo) {
+ uint8_t** ppDst, SBufferInfo* pDstBufInfo, SParserBsInfo* pDstBsInfo) {
if (!pCtx->bEndOfStreamFlag) {
SDataBuffer* pRawData = &pCtx->sRawData;
+ SDataBuffer* pSavedData = NULL;
int32_t iSrcIdx = 0; //the index of source bit-stream till now after parsing one or more NALs
int32_t iSrcConsumed = 0; // consumed bit count of source bs
@@ -457,7 +462,12 @@
pRawData->pCurPos = pRawData->pHead;
}
-
+ if (pCtx->bParseOnly) {
+ pSavedData = &pCtx->sSavedData;
+ if ((kiBsLen + 4) > (pSavedData->pEnd - pSavedData->pCurPos)) {
+ pSavedData->pCurPos = pSavedData->pHead;
+ }
+ }
//copy raw data from source buffer (application) to raw data buffer (codec inside)
//0x03 removal and extract all of NAL Unit from current raw data
pDstNal = pRawData->pCurPos;
@@ -481,7 +491,7 @@
CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
}
if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) {
- iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes);
+ iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes, pSrcNal - 3, iSrcIdx + 3);
}
if (pCtx->bAuReadyFlag) {
ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
@@ -542,7 +552,7 @@
CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
}
if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) {
- iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes);
+ iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes, pSrcNal - 3, iSrcIdx + 3);
}
if (pCtx->bAuReadyFlag) {
ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -88,21 +88,23 @@
pCtx->iTotalNumMbRec = 0;
- //////output:::normal path
- ppDst[0] = pPic->pData[0];
- ppDst[1] = pPic->pData[1];
- ppDst[2] = pPic->pData[2];
+ if (!pCtx->bParseOnly) {
+ //////output:::normal path
+ ppDst[0] = pPic->pData[0];
+ ppDst[1] = pPic->pData[1];
+ ppDst[2] = pPic->pData[2];
- pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420;
+ pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420;
- pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2;
- pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2;
- pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0];
- pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1];
- ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2;
- ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
- ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
- pDstInfo->iBufferStatus = 1;
+ pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2;
+ pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2;
+ pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0];
+ pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1];
+ ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2;
+ ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
+ ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
+ pDstInfo->iBufferStatus = 1;
+ }
bool bOutResChange = (pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth)
|| (pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight);
@@ -114,7 +116,6 @@
else if (pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE && pCtx->iErrorCode && bOutResChange)
pCtx->bFreezeOutput = true;
-
if ((pDstInfo->iBufferStatus == 1) && (pCurDq->sLayerInfo.sNalHeaderExt.bIdrFlag)) {
if (pPic->bIsComplete)
pCtx->sDecoderStatistics.uiIDRRecvNum++;
@@ -331,6 +332,14 @@
}
pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead;
pCtx->sRawData.pEnd = pCtx->sRawData.pHead + pCtx->iMaxBsBufferSizeInByte;
+ if (pCtx->bParseOnly) {
+ if ((pCtx->sSavedData.pHead = static_cast<uint8_t*> (WelsMalloc (pCtx->iMaxBsBufferSizeInByte,
+ "pCtx->sSavedData.pHead"))) == NULL) {
+ return ERR_INFO_OUT_OF_MEMORY;
+ }
+ pCtx->sSavedData.pStartPos = pCtx->sSavedData.pCurPos = pCtx->sSavedData.pHead;
+ pCtx->sSavedData.pEnd = pCtx->sSavedData.pHead + pCtx->iMaxBsBufferSizeInByte;
+ }
return ERR_NONE;
}
@@ -434,6 +443,13 @@
pCtx->sRawData.pEnd = NULL;
pCtx->sRawData.pStartPos = NULL;
pCtx->sRawData.pCurPos = NULL;
+ if (pCtx->sSavedData.pHead) {
+ WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData->pHead");
+ }
+ pCtx->sSavedData.pHead = NULL;
+ pCtx->sSavedData.pEnd = NULL;
+ pCtx->sSavedData.pStartPos = NULL;
+ pCtx->sSavedData.pCurPos = NULL;
}
/*
@@ -1692,7 +1708,8 @@
if (ERR_NONE != iErr) {
ForceResetCurrentAccessUnit (pCtx->pAccessUnitList);
- pDstInfo->iBufferStatus = 0;
+ if (!pCtx->bParseOnly)
+ pDstInfo->iBufferStatus = 0;
return iErr;
}
@@ -1713,6 +1730,53 @@
iErr = DecodeCurrentAccessUnit (pCtx, ppDst, pDstInfo);
+ if (pCtx->bParseOnly) {
+ if (dsErrorFree == pCtx->iErrorCode) {
+ SParserBsInfo* pParser = pCtx->pParserBsInfo;
+ uint8_t* pDstBuf = pParser->pDstBuff;
+ SNalUnit* pCurNal = NULL;
+ int32_t iNalLen = 0;
+ int32_t iIdx = pCurAu->uiStartPos;
+ int32_t iEndIdx = pCurAu->uiEndPos;
+ uint8_t* pNalBs = NULL;
+
+ pParser->iNalNum = 0;
+ pParser->iSpsWidthInPixel = (pCtx->pSps->iMbWidth << 4);
+ pParser->iSpsHeightInPixel = (pCtx->pSps->iMbHeight << 4);
+
+ if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR
+ bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType);
+ SSpsBsInfo* pSpsBs = NULL;
+ SPpsBsInfo* pPpsBs = NULL;
+ int32_t iSpsId = pCtx->pSps->iSpsId;
+ int32_t iPpsId = pCtx->pPps->iPpsId;
+ pCtx->bParamSetsLostFlag = false;
+ //find required sps, pps and write into dst buff
+ pSpsBs = bSubSps ? &pCtx->sSubsetSpsBsInfo [iSpsId] : &pCtx->sSpsBsInfo [iSpsId];
+ memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen);
+ pParser->iNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
+ pDstBuf += pSpsBs->uiSpsBsLen;
+ pPpsBs = &pCtx->sPpsBsInfo [iPpsId];
+ memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen);
+ pParser->iNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
+ pDstBuf += pPpsBs->uiPpsBsLen;
+ } //IDR required SPS, PPS
+ //then VCL data re-write
+ while (iIdx <= iEndIdx) {
+ pCurNal = pCurAu->pNalUnitsList [iIdx ++];
+ iNalLen = pCurNal->sNalData.sVclNal.iNalLength;
+ pNalBs = pCurNal->sNalData.sVclNal.pNalPos;
+ pParser->iNalLenInByte [pParser->iNalNum ++] = iNalLen;
+ memcpy (pDstBuf, pNalBs, iNalLen);
+ pDstBuf += iNalLen;
+ }
+ } else { //error
+ pCtx->pParserBsInfo->iNalNum = 0;
+ pCtx->pParserBsInfo->iSpsWidthInPixel = 0;
+ pCtx->pParserBsInfo->iSpsHeightInPixel = 0;
+ }
+ }
+
WelsDecodeAccessUnitEnd (pCtx);
pCtx->bNewSeqBegin = false;
@@ -1985,10 +2049,13 @@
return iRet;
}
}
- if (bReconstructSlice) {
- if (WelsDecodeConstructSlice (pCtx, pNalCur)) {
- pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false
- return -1;
+
+ if (!pCtx->bParseOnly) {
+ if (bReconstructSlice) {
+ if (WelsDecodeConstructSlice (pCtx, pNalCur)) {
+ pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false
+ return -1;
+ }
}
}
if (bAllRefComplete && (pCtx->sRefPic.uiRefCount[LIST_0] > 0 || pCtx->eSliceType != I_SLICE)) {
@@ -2031,20 +2098,21 @@
#endif//#if !CODEC_FOR_TESTBED
if (dq_cur->uiLayerDqId == kuiTargetLayerDqId) {
- if (!pCtx->bInstantDecFlag) {
- //Do error concealment here
- if ((NeedErrorCon (pCtx)) && (pCtx->eErrorConMethod != ERROR_CON_DISABLE)) {
- ImplementErrorCon (pCtx);
- pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
- pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
- pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
+ if (!pCtx->bParseOnly) {
+ if (!pCtx->bInstantDecFlag) {
+ //Do error concealment here
+ if ((NeedErrorCon (pCtx)) && (pCtx->eErrorConMethod != ERROR_CON_DISABLE)) {
+ ImplementErrorCon (pCtx);
+ pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
+ pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
+ pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
+ }
}
- }
- if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) {
- return ERR_NONE;
+ if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) {
+ return ERR_NONE;
+ }
}
-
if (uiNalRefIdc > 0) {
pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC
iRet = WelsMarkAsRef (pCtx);
--- a/codec/decoder/core/src/manage_dec_ref.cpp
+++ b/codec/decoder/core/src/manage_dec_ref.cpp
@@ -256,6 +256,8 @@
pCtx->pDec->uiQualityId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiQualityId;
pCtx->pDec->uiTemporalId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiTemporalId;
+ pCtx->pDec->iSpsId = pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iSpsId;
+ pCtx->pDec->iPpsId = pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iPpsId;
for (j = pCurAU->uiStartPos; j <= pCurAU->uiEndPos; j++) {
if (pCurAU->pNalUnitsList[j]->sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR
--- a/codec/decoder/plus/inc/welsDecoderExt.h
+++ b/codec/decoder/plus/inc/welsDecoderExt.h
@@ -104,7 +104,7 @@
PWelsDecoderContext m_pDecContext;
welsCodecTrace* m_pWelsTrace;
-int32_t InitDecoder (void);
+int32_t InitDecoder (const bool);
void UninitDecoder (void);
#ifdef OUTPUT_BIT_STREAM
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -197,7 +197,7 @@
}
// H.264 decoder initialization,including memory allocation,then open it ready to decode
- iRet = InitDecoder();
+ iRet = InitDecoder (pParam->bParseOnly);
if (iRet)
return iRet;
@@ -232,16 +232,18 @@
}
// the return value of this function is not suitable, it need report failure info to upper layer.
-int32_t CWelsDecoder::InitDecoder (void) {
+int32_t CWelsDecoder::InitDecoder (const bool bParseOnly) {
WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::init_decoder(), openh264 codec version = %s",
VERSION_NUMBER);
+ if (m_pDecContext) //free
+ UninitDecoder();
m_pDecContext = (PWelsDecoderContext)WelsMalloc (sizeof (SWelsDecoderContext), "m_pDecContext");
if (NULL == m_pDecContext)
return cmMallocMemeError;
- return WelsInitDecoder (m_pDecContext, &m_pWelsTrace->m_sLogCtx);
+ return WelsInitDecoder (m_pDecContext, bParseOnly, &m_pWelsTrace->m_sLogCtx);
}
/*
@@ -422,7 +424,7 @@
m_pDecContext->iFeedbackTidInAu = -1; //initialize
WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, ppDst,
- pDstInfo); //iErrorCode has been modified in this function
+ pDstInfo, NULL); //iErrorCode has been modified in this function
m_pDecContext->bInstantDecFlag = false; //reset no-delay flag
if (m_pDecContext->iErrorCode) {
EWelsNalUnitType eNalType =
@@ -500,7 +502,30 @@
DECODING_STATE CWelsDecoder::DecodeParser (const unsigned char* kpSrc,
const int kiSrcLen,
SParserBsInfo* pDstInfo) {
-//TODO, add function here
+ if (CheckBsBuffer (m_pDecContext, kiSrcLen)) {
+ return dsOutOfMemory;
+ }
+ if (kiSrcLen > 0 && kpSrc != NULL) {
+#ifdef OUTPUT_BITSTREAM
+ if (m_pFBS) {
+ WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS);
+ WelsFflush (m_pFBS);
+ }
+#endif//OUTPUT_BIT_STREAM
+ m_pDecContext->bEndOfStreamFlag = false;
+ } else {
+ //For application MODE, the error detection should be added for safe.
+ //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL.
+ m_pDecContext->bEndOfStreamFlag = true;
+ m_pDecContext->bInstantDecFlag = true;
+ }
+
+ m_pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding.
+ m_pDecContext->pParserBsInfo = pDstInfo;
+ pDstInfo->iNalNum = 0;
+ pDstInfo->iSpsWidthInPixel = pDstInfo->iSpsHeightInPixel = 0;
+ WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, NULL, NULL, pDstInfo);
+
return (DECODING_STATE) m_pDecContext->iErrorCode;
}
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -5,6 +5,7 @@
#include "BaseDecoderTest.h"
#include "BaseEncoderTest.h"
#include "wels_common_defs.h"
+#include "utils/HashFunctions.h"
#include <string>
#include <vector>
using namespace WelsCommon;
@@ -69,6 +70,8 @@
class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFileParamBase>,
public BaseEncoderTest, public BaseDecoderTest {
public:
+ uint8_t iRandValue;
+ public:
virtual void SetUp() {
BaseEncoderTest::SetUp();
BaseDecoderTest::SetUp();
@@ -103,6 +106,26 @@
}
+ virtual void prepareEncDecParam (const EncodeDecodeFileParamBase EncDecFileParam) {
+ //for encoder
+ //I420: 1(Y) + 1/4(U) + 1/4(V)
+ int frameSize = EncDecFileParam.width * EncDecFileParam.height * 3 / 2;
+ buf_.SetLength (frameSize);
+ ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+ memset (&EncPic, 0, sizeof (SSourcePicture));
+ EncPic.iPicWidth = EncDecFileParam.width;
+ EncPic.iPicHeight = EncDecFileParam.height;
+ 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] + EncDecFileParam.width * EncDecFileParam.height;
+ EncPic.pData[2] = EncPic.pData[1] + (EncDecFileParam.width * EncDecFileParam.height >> 2);
+ //for decoder
+ memset (&info, 0, sizeof (SFrameBSInfo));
+ //set a fixed random value
+ iRandValue = rand() % 256;
+ }
virtual void encToDecData (const SFrameBSInfo& info, int& len) {
len = 0;
@@ -1983,7 +2006,6 @@
}
}
-
TEST_F (EncodeDecodeTestAPI, SetOptionEncParamExt) {
int iWidth = (((rand() % MAX_WIDTH) >> 1) + 16) << 1;
int iHeight = (((rand() % MAX_HEIGHT) >> 1) + 16) << 1;
@@ -2237,3 +2259,154 @@
#endif
}
+
+const uint32_t kiTotalLayer = 3; //DO NOT CHANGE!
+const uint32_t kiSliceNum = 2; //DO NOT CHANGE!
+const uint32_t kiWidth = 160; //DO NOT CHANGE!
+const uint32_t kiHeight = 96; //DO NOT CHANGE!
+const uint32_t kiFrameRate = 12; //DO NOT CHANGE!
+const uint32_t kiFrameNum = 100; //DO NOT CHANGE!
+const uint32_t kiMaxBsSize = 10000000; //DO NOT CHANGE!
+const char* pHashStr[] = { //DO NOT CHANGE!
+ "c58322f886a3ba958c6f60b46b98f67b5d860866",
+ "f2799e1e5f6e33c6274f4e1f6273c721475492d0",
+ "8f0fafeaa2746e04d42fb17104efb61c9dbd1a6f"
+};
+
+class DecodeParseAPI : public EncodeDecodeTestBase {
+ public:
+ void SetUp() {
+ SHA1Reset (&ctx_);
+ EncodeDecodeTestBase::SetUp();
+
+ if (decoder_)
+ decoder_->Uninitialize();
+ SDecodingParam decParam;
+ memset (&decParam, 0, sizeof (SDecodingParam));
+ decParam.eOutputColorFormat = videoFormatI420;
+ decParam.uiTargetDqLayer = UCHAR_MAX;
+ decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
+ decParam.bParseOnly = true;
+ decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+ int rv = decoder_->Initialize (&decParam);
+ ASSERT_EQ (0, rv);
+ memset (&BsInfo_, 0, sizeof (SParserBsInfo));
+ BsInfo_.pDstBuff = NULL;
+ BsInfo_.pDstBuff = new unsigned char [kiMaxBsSize];
+ ASSERT_TRUE (BsInfo_.pDstBuff != NULL);
+ fYuv_ = fopen ("./res/CiscoVT2people_160x96_6fps.yuv", "rb");
+ ASSERT_TRUE (fYuv_ != NULL);
+ iWidth_ = kiWidth;
+ iHeight_ = kiHeight;
+ }
+ void TearDown() {
+ EncodeDecodeTestBase::TearDown();
+ if (BsInfo_.pDstBuff) {
+ delete[] BsInfo_.pDstBuff;
+ BsInfo_.pDstBuff = NULL;
+ }
+ fclose (fYuv_);
+ }
+
+ void prepareEncDecParam (const EncodeDecodeFileParamBase p) {
+ EncodeDecodeTestBase::prepareEncDecParam (p);
+ unsigned char* pTmpPtr = BsInfo_.pDstBuff; //store for restore
+ memset (&BsInfo_, 0, sizeof (SParserBsInfo));
+ BsInfo_.pDstBuff = pTmpPtr;
+ }
+
+ void EncodeOneFrame (int iIdx) {
+ int iFrameSize = iWidth_ * iHeight_ * 3 / 2;
+ int iSize = fread (buf_.data(), sizeof (char), iFrameSize, fYuv_);
+ if (feof (fYuv_) || iSize != iFrameSize) {
+ rewind (fYuv_);
+ iSize = fread (buf_.data(), sizeof (char), iFrameSize, fYuv_);
+ ASSERT_TRUE (iSize == iFrameSize);
+ }
+ int rv = encoder_->EncodeFrame (&EncPic, &info);
+ ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+ }
+
+ protected:
+ SParserBsInfo BsInfo_;
+ FILE* fYuv_;
+ int iWidth_;
+ int iHeight_;
+ SHA1Context ctx_;
+};
+
+//#define DEBUG_FILE_SAVE
+TEST_F (DecodeParseAPI, ParseOnly_General) {
+ EncodeDecodeFileParamBase p;
+ p.width = iWidth_;
+ p.height = iHeight_;
+ p.frameRate = kiFrameRate;
+ p.numframes = kiFrameNum;
+ prepareParam (kiTotalLayer, kiSliceNum, p.width, p.height, p.frameRate);
+ param_.iSpatialLayerNum = kiTotalLayer;
+ encoder_->Uninitialize();
+ int rv = encoder_->InitializeExt (¶m_);
+ ASSERT_TRUE (rv == 0);
+ int32_t iTraceLevel = WELS_LOG_QUIET;
+ encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+ decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+ uint32_t uiTargetLayerId = rand() % kiTotalLayer; //run only once
+#ifdef DEBUG_FILE_SAVE
+ FILE* fDec = fopen ("output.264", "wb");
+ FILE* fEnc = fopen ("enc.264", "wb");
+ FILE* fExtract = fopen ("extract.264", "wb");
+#endif
+ if (uiTargetLayerId < kiTotalLayer) { //should always be true
+ //Start for enc
+ int iLen = 0;
+ prepareEncDecParam (p);
+ int iFrame = 0;
+
+ while (iFrame < p.numframes) {
+ //encode
+ EncodeOneFrame (iFrame);
+ //extract target layer data
+ encToDecData (info, iLen);
+#ifdef DEBUG_FILE_SAVE
+ fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fEnc);
+#endif
+ ExtractDidNal (&info, iLen, &m_SLostSim, uiTargetLayerId);
+#ifdef DEBUG_FILE_SAVE
+ fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fExtract);
+#endif
+ //parseonly
+ //BsInfo_.pDstBuff = new unsigned char [1000000];
+ rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf, iLen, &BsInfo_);
+ EXPECT_TRUE (rv == 0);
+ EXPECT_TRUE (BsInfo_.iNalNum == 0);
+ rv = decoder_->DecodeParser (NULL, 0, &BsInfo_);
+ EXPECT_TRUE (rv == 0);
+ EXPECT_TRUE (BsInfo_.iNalNum != 0);
+ //get final output bs
+ iLen = 0;
+ int i = 0;
+ while (i < BsInfo_.iNalNum) {
+ iLen += BsInfo_.iNalLenInByte[i];
+ i++;
+ }
+#ifdef DEBUG_FILE_SAVE
+ fwrite (BsInfo_.pDstBuff, iLen, 1, fDec);
+#endif
+ SHA1Input (&ctx_, BsInfo_.pDstBuff, iLen);
+ iFrame++;
+ }
+ //calculate final SHA1 value
+ unsigned char digest[SHA_DIGEST_LENGTH];
+ SHA1Result (&ctx_, digest);
+ if (!HasFatalFailure()) {
+ CompareHash (digest, pHashStr[uiTargetLayerId]);
+ }
+ } //while
+#ifdef DEBUG_FILE_SAVE
+ fclose (fEnc);
+ fclose (fExtract);
+ fclose (fDec);
+#endif
+}
+