parse only add and UT

This commit is contained in:
huili2 2014-11-23 23:56:39 -08:00
parent 53c14dccf0
commit b231e3f000
13 changed files with 606 additions and 59 deletions

View File

@ -457,6 +457,7 @@ typedef struct TagSVCDecodingParam {
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 @@ typedef struct TagParserBsInfo {
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

View File

@ -86,7 +86,7 @@ uint8_t* DetectStartCodePrefix (const uint8_t* kpBuf, int32_t* pOffset, int32_t
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 @@ bool CheckNextAuNewSeq (PWelsDecoderContext pCtx, const PNalUnit kpCurNal, const
* \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 @@ int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicW
* \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);
/*!
*************************************************************************************

View File

@ -65,7 +65,15 @@ int32_t InitBits (PBitStringAux pBitString, const uint8_t* kpBuf, const int32_t
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

View File

@ -68,7 +68,7 @@ int32_t DecoderConfigParam (PWelsDecoderContext pCtx, const SDecodingParam* kpPa
* \note N/A
*************************************************************************************
*/
int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx);
int32_t WelsInitDecoder (PWelsDecoderContext pCtx, const bool bParseOnly, SLogContext* pLogCtx);
/*!
*************************************************************************************
@ -101,7 +101,7 @@ void WelsEndDecoder (PWelsDecoderContext pCtx);
*/
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

View File

@ -102,6 +102,19 @@ uint8_t* pStartPos;
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 @@ SLogContext sLogCtx;
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 bNewSeqBegin;
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

View File

@ -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 @@ uint8_t* ParseNalHeader (PWelsDecoderContext pCtx, SNalUnitHeader* pNalUnitHeade
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 @@ uint8_t* ParseNalHeader (PWelsDecoderContext pCtx, SNalUnitHeader* pNalUnitHeade
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 @@ bool CheckNextAuNewSeq (PWelsDecoderContext pCtx, const PNalUnit kpCurNal, const
*
*************************************************************************************
*/
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 @@ int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t
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 @@ int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t
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 @@ bool CheckSpsActive (PWelsDecoderContext pCtx, PSps pSps) {
*************************************************************************************
*/
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 @@ int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicW
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 @@ int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicW
* \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;
@ -1194,6 +1292,16 @@ int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux)
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;
}

View File

@ -49,7 +49,7 @@ inline uint32_t GetValue4Bytes (uint8_t* pDstNal) {
}
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,11 +79,141 @@ int32_t InitBits (PBitStringAux pBitString, const uint8_t* kpBuf, const int32_t
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

View File

@ -350,6 +350,9 @@ int32_t DecoderConfigParam (PWelsDecoderContext pCtx, const SDecodingParam* kpPa
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 @@ int32_t DecoderConfigParam (PWelsDecoderContext pCtx, const SDecodingParam* kpPa
* \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 @@ int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx) {
// default
WelsDecoderDefaults (pCtx, pLogCtx);
pCtx->bParseOnly = bParseOnly;
// open decoder
return WelsOpenDecoder (pCtx);
}
@ -427,9 +431,10 @@ void GetVclNalTemporalId (PWelsDecoderContext pCtx) {
*************************************************************************************
*/
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 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in
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 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in
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 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in
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);

View File

@ -88,21 +88,23 @@ static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t
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 @@ static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t
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 @@ int32_t InitBsBuffer (PWelsDecoderContext pCtx) {
}
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 @@ void WelsFreeMemory (PWelsDecoderContext pCtx) {
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 @@ int32_t ConstructAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferI
if (ERR_NONE != iErr) {
ForceResetCurrentAccessUnit (pCtx->pAccessUnitList);
pDstInfo->iBufferStatus = 0;
if (!pCtx->bParseOnly)
pDstInfo->iBufferStatus = 0;
return iErr;
}
@ -1713,6 +1730,53 @@ int32_t ConstructAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferI
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 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf
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 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf
#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);

View File

@ -256,6 +256,8 @@ int32_t WelsMarkAsRef (PWelsDecoderContext pCtx) {
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

View File

@ -104,7 +104,7 @@ virtual long EXTAPI GetOption (DECODER_OPTION eOptID, void* pOption);
PWelsDecoderContext m_pDecContext;
welsCodecTrace* m_pWelsTrace;
int32_t InitDecoder (void);
int32_t InitDecoder (const bool);
void UninitDecoder (void);
#ifdef OUTPUT_BIT_STREAM

View File

@ -197,7 +197,7 @@ long CWelsDecoder::Initialize (const SDecodingParam* pParam) {
}
// 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 @@ void CWelsDecoder::UninitDecoder (void) {
}
// 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 @@ DECODING_STATE CWelsDecoder::DecodeFrame2 (const unsigned char* kpSrc,
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::DecodeFrame2 (const unsigned char* kpSrc,
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;
}

View File

@ -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;
@ -68,6 +69,8 @@ static void TestOutPutTrace (void* ctx, int level, const char* string) {
class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFileParamBase>,
public BaseEncoderTest, public BaseDecoderTest {
public:
uint8_t iRandValue;
public:
virtual void SetUp() {
BaseEncoderTest::SetUp();
@ -103,6 +106,26 @@ class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFilePar
}
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, Engine_SVC_Switch_P) {
}
}
TEST_F (EncodeDecodeTestAPI, SetOptionEncParamExt) {
int iWidth = (((rand() % MAX_WIDTH) >> 1) + 16) << 1;
int iHeight = (((rand() % MAX_HEIGHT) >> 1) + 16) << 1;
@ -2237,3 +2259,154 @@ TEST_F (DecodeCrashTestAPI, DecoderCrashTest) {
#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 (&param_);
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
}