diff --git a/codec/api/svc/codec_app_def.h b/codec/api/svc/codec_app_def.h index fb14472e..f1838ab5 100644 --- a/codec/api/svc/codec_app_def.h +++ b/codec/api/svc/codec_app_def.h @@ -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 diff --git a/codec/decoder/core/inc/au_parser.h b/codec/decoder/core/inc/au_parser.h index 0315c7fa..aa76a615 100644 --- a/codec/decoder/core/inc/au_parser.h +++ b/codec/decoder/core/inc/au_parser.h @@ -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); /*! ************************************************************************************* diff --git a/codec/decoder/core/inc/bit_stream.h b/codec/decoder/core/inc/bit_stream.h index 6a315a89..6f6e6bc6 100644 --- a/codec/decoder/core/inc/bit_stream.h +++ b/codec/decoder/core/inc/bit_stream.h @@ -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 diff --git a/codec/decoder/core/inc/decoder.h b/codec/decoder/core/inc/decoder.h index 8e64f1db..f8e05d92 100644 --- a/codec/decoder/core/inc/decoder.h +++ b/codec/decoder/core/inc/decoder.h @@ -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 diff --git a/codec/decoder/core/inc/decoder_context.h b/codec/decoder/core/inc/decoder_context.h index 7990d5ae..bce3d188 100644 --- a/codec/decoder/core/inc/decoder_context.h +++ b/codec/decoder/core/inc/decoder_context.h @@ -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 diff --git a/codec/decoder/core/src/au_parser.cpp b/codec/decoder/core/src/au_parser.cpp index c64ba4f1..117e262c 100644 --- 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 @@ 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 (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; } diff --git a/codec/decoder/core/src/bit_stream.cpp b/codec/decoder/core/src/bit_stream.cpp index 6aa36d4d..ccd5bfb6 100644 --- a/codec/decoder/core/src/bit_stream.cpp +++ b/codec/decoder/core/src/bit_stream.cpp @@ -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 diff --git a/codec/decoder/core/src/decoder.cpp b/codec/decoder/core/src/decoder.cpp index 8c4722d8..3630f074 100644 --- a/codec/decoder/core/src/decoder.cpp +++ b/codec/decoder/core/src/decoder.cpp @@ -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); diff --git a/codec/decoder/core/src/decoder_core.cpp b/codec/decoder/core/src/decoder_core.cpp index 30555767..fe371eb5 100644 --- a/codec/decoder/core/src/decoder_core.cpp +++ b/codec/decoder/core/src/decoder_core.cpp @@ -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 (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); diff --git a/codec/decoder/core/src/manage_dec_ref.cpp b/codec/decoder/core/src/manage_dec_ref.cpp index e566c5a0..3f867211 100644 --- a/codec/decoder/core/src/manage_dec_ref.cpp +++ b/codec/decoder/core/src/manage_dec_ref.cpp @@ -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 diff --git a/codec/decoder/plus/inc/welsDecoderExt.h b/codec/decoder/plus/inc/welsDecoderExt.h index 763aaeb9..b0de0b31 100644 --- a/codec/decoder/plus/inc/welsDecoderExt.h +++ b/codec/decoder/plus/inc/welsDecoderExt.h @@ -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 diff --git a/codec/decoder/plus/src/welsDecoderExt.cpp b/codec/decoder/plus/src/welsDecoderExt.cpp index ac641e00..d1e50bec 100644 --- a/codec/decoder/plus/src/welsDecoderExt.cpp +++ b/codec/decoder/plus/src/welsDecoderExt.cpp @@ -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; } diff --git a/test/api/encode_decode_api_test.cpp b/test/api/encode_decode_api_test.cpp index c217b746..b5e3373f 100644 --- 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 #include using namespace WelsCommon; @@ -68,6 +69,8 @@ static void TestOutPutTrace (void* ctx, int level, const char* string) { class EncodeDecodeTestBase : public ::testing::TestWithParam, public BaseEncoderTest, public BaseDecoderTest { + public: + uint8_t iRandValue; public: virtual void SetUp() { BaseEncoderTest::SetUp(); @@ -103,6 +106,26 @@ class EncodeDecodeTestBase : public ::testing::TestWithParam> 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 (¶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 +} +