PWelsDecoderContext pDecContext = m_pDecThrCtx[i].pCtx; if (pDecContext == NULL && eOptID != DECODER_OPTION_TRACE_LEVEL && eOptID != DECODER_OPTION_TRACE_CALLBACK && eOptID != DECODER_OPTION_TRACE_CALLBACK_CONTEXT) return dsInitialOptExpected; if (eOptID == DECODER_OPTION_END_OF_STREAM) { // Indicate bit-stream of the final frame to be decoded if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); // boolean value for whether enabled End Of Stream flag if (pDecContext == NULL) return dsInitialOptExpected; pDecContext->bEndOfStreamFlag = iVal ? true : false; return cmResultSuccess; } else if (eOptID == DECODER_OPTION_ERROR_CON_IDC) { // Indicate error concealment status if (pOption == NULL) return cmInitParaError; if (pDecContext == NULL) return dsInitialOptExpected; iVal = * ((int*)pOption); // int value for error concealment idc iVal = WELS_CLIP3 (iVal, (int32_t)ERROR_CON_DISABLE, (int32_t)ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE); if ((pDecContext->pParam->bParseOnly) && (iVal != (int32_t)ERROR_CON_DISABLE)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption for ERROR_CON_IDC = %d not allowd for parse only!.", iVal); return cmInitParaError; } pDecContext->pParam->eEcActiveIdc = (ERROR_CON_IDC)iVal; InitErrorCon (pDecContext); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption for ERROR_CON_IDC = %d.", iVal); return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_LEVEL) { if (m_pWelsTrace) { uint32_t level = * ((uint32_t*)pOption); m_pWelsTrace->SetTraceLevel (level); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK) { if (m_pWelsTrace) { WelsTraceCallback callback = * ((WelsTraceCallback*)pOption); m_pWelsTrace->SetTraceCallback (callback); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption():DECODER_OPTION_TRACE_CALLBACK callback = %p.", callback); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK_CONTEXT) { if (m_pWelsTrace) { void* ctx = * ((void**)pOption); m_pWelsTrace->SetTraceCallbackContext (ctx); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_GET_STATISTICS) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsDecoder::SetOption():DECODER_OPTION_GET_STATISTICS: this option is get-only!"); return cmInitParaError; } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { if (pOption) { if (pDecContext == NULL) return dsInitialOptExpected; pDecContext->pDecoderStatistics->iStatisticsLogInterval = (* ((unsigned int*)pOption)); return cmResultSuccess; } } else if (eOptID == DECODER_OPTION_GET_SAR_INFO) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsDecoder::SetOption():DECODER_OPTION_GET_SAR_INFO: this option is get-only!"); return cmInitParaError; } } return cmInitParaError;} /* * Get Option */long CWelsDecoder::GetOption (DECODER_OPTION eOptID, void* pOption) { int iVal = 0; if (DECODER_OPTION_NUM_OF_THREADS == eOptID) { * ((int*)pOption) = m_iThreadCount; return cmResultSuccess; } PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; if (pDecContext == NULL) return cmInitExpected; if (pOption == NULL) return cmInitParaError; if (DECODER_OPTION_END_OF_STREAM == eOptID) { iVal = pDecContext->bEndOfStreamFlag; * ((int*)pOption) = iVal; return cmResultSuccess; }#ifdef LONG_TERM_REF else if (DECODER_OPTION_IDR_PIC_ID == eOptID) { iVal = pDecContext->uiCurIdrPicId; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_FRAME_NUM == eOptID) { iVal = pDecContext->iFrameNum; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKING_FLAG == eOptID) { iVal = pDecContext->bCurAuContainLtrMarkSeFlag; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKED_FRAME_NUM == eOptID) { iVal = pDecContext->iFrameNumOfAuMarkedLtr; * ((int*)pOption) = iVal; return cmResultSuccess; }#endif else if (DECODER_OPTION_VCL_NAL == eOptID) { //feedback whether or not have VCL NAL in current AU iVal = pDecContext->iFeedbackVclNalInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_TEMPORAL_ID == eOptID) { //if have VCL NAL in current AU, then feedback the temporal ID iVal = pDecContext->iFeedbackTidInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_IS_REF_PIC == eOptID) { iVal = pDecContext->iFeedbackNalRefIdc; if (iVal > 0) iVal = 1; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_ERROR_CON_IDC == eOptID) { iVal = (int)pDecContext->pParam->eEcActiveIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_GET_STATISTICS == eOptID) { // get decoder statistics info for real time debugging SDecoderStatistics* pDecoderStatistics = (static_cast<SDecoderStatistics*> (pOption)); memcpy (pDecoderStatistics, pDecContext->pDecoderStatistics, sizeof (SDecoderStatistics)); if (pDecContext->pDecoderStatistics->uiDecodedFrameCount != 0) { //not original status pDecoderStatistics->fAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / (pDecContext->pDecoderStatistics->uiDecodedFrameCount); pDecoderStatistics->fActualAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / (pDecContext->pDecoderStatistics->uiDecodedFrameCount + pDecContext->pDecoderStatistics->uiFreezingIDRNum + pDecContext->pDecoderStatistics->uiFreezingNonIDRNum); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { if (pOption) { iVal = pDecContext->pDecoderStatistics->iStatisticsLogInterval; * ((unsigned int*)pOption) = iVal; return cmResultSuccess; } } else if (DECODER_OPTION_GET_SAR_INFO == eOptID) { //get decoder SAR info in VUI PVuiSarInfo pVuiSarInfo = (static_cast<PVuiSarInfo> (pOption)); memset (pVuiSarInfo, 0, sizeof (SVuiSarInfo)); if (!pDecContext->pSps) { return cmInitExpected; } else { pVuiSarInfo->uiSarWidth = pDecContext->pSps->sVui.uiSarWidth; pVuiSarInfo->uiSarHeight = pDecContext->pSps->sVui.uiSarHeight; pVuiSarInfo->bOverscanAppropriateFlag = pDecContext->pSps->sVui.bOverscanAppropriateFlag; return cmResultSuccess; } } else if (DECODER_OPTION_PROFILE == eOptID) { if (!pDecContext->pSps) { return cmInitExpected; } iVal = (int)pDecContext->pSps->uiProfileIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LEVEL == eOptID) { if (!pDecContext->pSps) { return cmInitExpected; } iVal = (int)pDecContext->pSps->uiLevelIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER == eOptID) { for (int32_t activeThread = 0; activeThread < m_DecCtxActiveCount; ++activeThread) { WAIT_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); RELEASE_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle); } * ((int*)pOption) = m_sReoderingStatus.iNumOfPicts; return cmResultSuccess; } return cmInitParaError;} DECODING_STATE CWelsDecoder::DecodeFrameNoDelay (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { int iRet = dsErrorFree; if (m_iThreadCount >= 1) { iRet = ThreadDecodeFrameInternal (kpSrc, kiSrcLen, ppDst, pDstInfo); if (m_sReoderingStatus.iNumOfPicts) { WAIT_EVENT (&m_sBufferingEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sReleaseBufferEvent); ReleaseBufferedReadyPicture (NULL, ppDst, pDstInfo); SET_EVENT (&m_sReleaseBufferEvent); } return (DECODING_STATE)iRet; } //SBufferInfo sTmpBufferInfo; //unsigned char* ppTmpDst[3] = {NULL, NULL, NULL}; iRet = (int)DecodeFrame2 (kpSrc, kiSrcLen, ppDst, pDstInfo); //memcpy (&sTmpBufferInfo, pDstInfo, sizeof (SBufferInfo)); //ppTmpDst[0] = ppDst[0]; //ppTmpDst[1] = ppDst[1]; //ppTmpDst[2] = ppDst[2]; iRet |= DecodeFrame2 (NULL, 0, ppDst, pDstInfo); //if ((pDstInfo->iBufferStatus == 0) && (sTmpBufferInfo.iBufferStatus == 1)) { //memcpy (pDstInfo, &sTmpBufferInfo, sizeof (SBufferInfo)); //ppDst[0] = ppTmpDst[0]; //ppDst[1] = ppTmpDst[1]; //ppDst[2] = ppTmpDst[2]; //} return (DECODING_STATE)iRet;} DECODING_STATE CWelsDecoder::DecodeFrame2WithCtx (PWelsDecoderContext pDecContext, const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { if (pDecContext == NULL || pDecContext->pParam == NULL) { if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "Call DecodeFrame2 without Initialize.\n"); } return dsInitialOptExpected; } if (pDecContext->pParam->bParseOnly) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "bParseOnly should be false for this API calling! \n"); pDecContext->iErrorCode |= dsInvalidArgument; return dsInvalidArgument; } if (CheckBsBuffer (pDecContext, kiSrcLen)) { if (ResetDecoder (pDecContext)) return dsOutOfMemory; return dsErrorFree; } if (kiSrcLen > 0 && kpSrc != NULL) {#ifdef OUTPUT_BIT_STREAM if (m_pFBS) { WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS); WelsFflush (m_pFBS); } if (m_pFBSSize) { WelsFwrite (&kiSrcLen, sizeof (int), 1, m_pFBSSize); WelsFflush (m_pFBSSize); }#endif//OUTPUT_BIT_STREAM pDecContext->bEndOfStreamFlag = false; if (GetThreadCount (pDecContext) <= 0) { pDecContext->uiDecodingTimeStamp = ++m_uiDecodeTimeStamp; } } else { //For application MODE, the error detection should be added for safe. //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL. pDecContext->bEndOfStreamFlag = true; pDecContext->bInstantDecFlag = true; } int64_t iStart, iEnd; iStart = WelsTime(); if (GetThreadCount (pDecContext) <= 1) { ppDst[0] = ppDst[1] = ppDst[2] = NULL; } pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding. pDecContext->iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL; //initialize unsigned long long uiInBsTimeStamp = pDstInfo->uiInBsTimeStamp; if (GetThreadCount (pDecContext) <= 1) { memset (pDstInfo, 0, sizeof (SBufferInfo)); } pDstInfo->uiInBsTimeStamp = uiInBsTimeStamp;#ifdef LONG_TERM_REF pDecContext->bReferenceLostAtT0Flag = false; //initialize for LTR pDecContext->bCurAuContainLtrMarkSeFlag = false; pDecContext->iFrameNumOfAuMarkedLtr = 0; pDecContext->iFrameNum = -1; //initialize#endif pDecContext->iFeedbackTidInAu = -1; //initialize pDecContext->iFeedbackNalRefIdc = -1; //initialize if (pDstInfo) { pDstInfo->uiOutYuvTimeStamp = 0; pDecContext->uiTimeStamp = pDstInfo->uiInBsTimeStamp; } else { pDecContext->uiTimeStamp = 0; } WelsDecodeBs (pDecContext, kpSrc, kiSrcLen, ppDst, pDstInfo, NULL); //iErrorCode has been modified in this function pDecContext->bInstantDecFlag = false; //reset no-delay flag if (pDecContext->iErrorCode) { EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0; //for NBR, IDR frames are expected to decode as followed if error decoding an IDR currently eNalType = pDecContext->sCurNalHead.eNalUnitType; if (pDecContext->iErrorCode & dsOutOfMemory) { if (ResetDecoder (pDecContext)) { return dsOutOfMemory; } return dsErrorFree; } if (pDecContext->iErrorCode & dsRefListNullPtrs) { if (ResetDecoder (pDecContext)) { return dsRefListNullPtrs; } return dsErrorFree; } //for AVC bitstream (excluding AVC with temporal scalability, including TP), as long as error occur, SHOULD notify upper layer key frame loss. if ((IS_PARAM_SETS_NALS (eNalType) || NAL_UNIT_CODED_SLICE_IDR == eNalType) || (VIDEO_BITSTREAM_AVC == pDecContext->eVideoType)) { if (pDecContext->pParam->eEcActiveIdc == ERROR_CON_DISABLE) {#ifdef LONG_TERM_REF pDecContext->bParamSetsLostFlag = true;#else pDecContext->bReferenceLostAtT0Flag = true;#endif } } if (pDecContext->bPrintFrameErrorTraceFlag) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "decode failed, failure type:%d \n", pDecContext->iErrorCode); pDecContext->bPrintFrameErrorTraceFlag = false; } else { pDecContext->iIgnoredErrorInfoPacketCount++; if (pDecContext->iIgnoredErrorInfoPacketCount == INT_MAX) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "continuous error reached INT_MAX! Restart as 0."); pDecContext->iIgnoredErrorInfoPacketCount = 0; } } if ((pDecContext->pParam->eEcActiveIdc != ERROR_CON_DISABLE) && (pDstInfo->iBufferStatus == 1)) { //TODO after dec status updated pDecContext->iErrorCode |= dsDataErrorConcealed; pDecContext->pDecoderStatistics->uiDecodedFrameCount++; if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t ResetDecStatNums (pDecContext->pDecoderStatistics); pDecContext->pDecoderStatistics->uiDecodedFrameCount++; } int32_t iMbConcealedNum = pDecContext->iMbEcedNum + pDecContext->iMbEcedPropNum; pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->iMbNum == 0 ? (pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( iMbConcealedNum * 100) / pDecContext->iMbNum)); pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->iMbNum == 0 ? (pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( pDecContext->iMbEcedPropNum * 100) / pDecContext->iMbNum)); pDecContext->pDecoderStatistics->uiEcFrameNum += (iMbConcealedNum == 0 ? 0 : 1); pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : pDecContext->pDecoderStatistics->uiAvgEcRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : pDecContext->pDecoderStatistics->uiAvgEcPropRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; } iEnd = WelsTime(); pDecContext->dDecTime += (iEnd - iStart) / 1e3; OutputStatisticsLog (*pDecContext->pDecoderStatistics); if (GetThreadCount (pDecContext) >= 1) { WAIT_EVENT (&m_sReleaseBufferEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sBufferingEvent); BufferingReadyPicture (pDecContext, ppDst, pDstInfo); SET_EVENT (&m_sBufferingEvent); } else { ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); } return (DECODING_STATE)pDecContext->iErrorCode; } // else Error free, the current codec works well if (pDstInfo->iBufferStatus == 1) { pDecContext->pDecoderStatistics->uiDecodedFrameCount++; if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t ResetDecStatNums (pDecContext->pDecoderStatistics); pDecContext->pDecoderStatistics->uiDecodedFrameCount++; } OutputStatisticsLog (*pDecContext->pDecoderStatistics); } iEnd = WelsTime(); pDecContext->dDecTime += (iEnd - iStart) / 1e3; if (GetThreadCount (pDecContext) >= 1) { WAIT_EVENT (&m_sReleaseBufferEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sBufferingEvent); BufferingReadyPicture (pDecContext, ppDst, pDstInfo); SET_EVENT (&m_sBufferingEvent); } else { ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); } return dsErrorFree;} DECODING_STATE CWelsDecoder::DecodeFrame2 (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; return DecodeFrame2WithCtx (pDecContext, kpSrc, kiSrcLen, ppDst, pDstInfo);} DECODING_STATE CWelsDecoder::FlushFrame (unsigned char** ppDst, SBufferInfo* pDstInfo) { bool bEndOfStreamFlag = true; if (m_iThreadCount <= 1) { for (int32_t j = 0; j < m_iCtxCount; ++j) { if (!m_pDecThrCtx[j].pCtx->bEndOfStreamFlag) { bEndOfStreamFlag = false; } } } if (bEndOfStreamFlag && m_sReoderingStatus.iNumOfPicts > 0) { m_sReoderingStatus.iMinPOC = IMinInt32; if (m_bIsBaseline) { uint32_t uiDecodingTimeStamp = 0; int32_t firstValidIdx = -1; for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (m_sPictInfoList[i].iPOC > IMinInt32) { uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; firstValidIdx = i; break; } } for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (i == firstValidIdx) continue; if (m_sPictInfoList[i].iPOC > IMinInt32 && m_sPictInfoList[i].uiDecodingTimeStamp < uiDecodingTimeStamp) { uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; } } } else { int32_t firstValidIdx = -1; for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (m_sReoderingStatus.iMinPOC == IMinInt32 && m_sPictInfoList[i].iPOC > IMinInt32) { m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; firstValidIdx = i; break; } } for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (i == firstValidIdx) continue; if (m_sPictInfoList[i].iPOC > IMinInt32 && m_sPictInfoList[i].iPOC < m_sReoderingStatus.iMinPOC) { m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; } } } } if (m_sReoderingStatus.iMinPOC > IMinInt32) { m_sReoderingStatus.iLastWrittenPOC = m_sReoderingStatus.iMinPOC;#if defined (_DEBUG)#ifdef _MOTION_VECTOR_DUMP_ fprintf (stderr, "Output POC: #%d uiDecodingTimeStamp=%d\n", m_sReoderingStatus.iLastWrittenPOC, m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].uiDecodingTimeStamp);#endif#endif memcpy (pDstInfo, &m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].sBufferInfo, sizeof (SBufferInfo)); ppDst[0] = pDstInfo->pDst[0]; ppDst[1] = pDstInfo->pDst[1]; ppDst[2] = pDstInfo->pDst[2]; m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC = IMinInt32; PPicBuff pPicBuff = m_iThreadCount <= 1 ? m_pDecThrCtx[0].pCtx->pPicBuff : m_pPicBuff; if (m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx < pPicBuff->iCapacity) { PPicture pPic = pPicBuff->ppPic[m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx]; --pPic->iRefCount; } m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].bLastGOP = false; m_sReoderingStatus.iMinPOC = IMinInt32; --m_sReoderingStatus.iNumOfPicts; } return dsErrorFree;} void CWelsDecoder::OutputStatisticsLog (SDecoderStatistics& sDecoderStatistics) { if ((sDecoderStatistics.uiDecodedFrameCount > 0) && (sDecoderStatistics.iStatisticsLogInterval > 0) && ((sDecoderStatistics.uiDecodedFrameCount % sDecoderStatistics.iStatisticsLogInterval) == 0)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "DecoderStatistics: uiWidth=%d, uiHeight=%d, fAverageFrameSpeedInMs=%.1f, fActualAverageFrameSpeedInMs=%.1f, \ uiDecodedFrameCount=%d, uiResolutionChangeTimes=%d, uiIDRCorrectNum=%d, \ uiAvgEcRatio=%d, uiAvgEcPropRatio=%d, uiEcIDRNum=%d, uiEcFrameNum=%d, \ uiIDRLostNum=%d, uiFreezingIDRNum=%d, uiFreezingNonIDRNum=%d, iAvgLumaQp=%d, \ iSpsReportErrorNum=%d, iSubSpsReportErrorNum=%d, iPpsReportErrorNum=%d, iSpsNoExistNalNum=%d, iSubSpsNoExistNalNum=%d, iPpsNoExistNalNum=%d, \ uiProfile=%d, uiLevel=%d, \ iCurrentActiveSpsId=%d, iCurrentActivePpsId=%d,", sDecoderStatistics.uiWidth, sDecoderStatistics.uiHeight,Lines 501–1000 of 1501. Previous lines Load more
PWelsDecoderContext pDecContext = m_pDecThrCtx[i].pCtx; if (pDecContext == NULL && eOptID != DECODER_OPTION_TRACE_LEVEL && eOptID != DECODER_OPTION_TRACE_CALLBACK && eOptID != DECODER_OPTION_TRACE_CALLBACK_CONTEXT) return dsInitialOptExpected; if (eOptID == DECODER_OPTION_END_OF_STREAM) { // Indicate bit-stream of the final frame to be decoded if (pOption == NULL) return cmInitParaError; iVal = * ((int*)pOption); // boolean value for whether enabled End Of Stream flag if (pDecContext == NULL) return dsInitialOptExpected; pDecContext->bEndOfStreamFlag = iVal ? true : false; return cmResultSuccess; } else if (eOptID == DECODER_OPTION_ERROR_CON_IDC) { // Indicate error concealment status if (pOption == NULL) return cmInitParaError; if (pDecContext == NULL) return dsInitialOptExpected; iVal = * ((int*)pOption); // int value for error concealment idc iVal = WELS_CLIP3 (iVal, (int32_t)ERROR_CON_DISABLE, (int32_t)ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE); if ((pDecContext->pParam->bParseOnly) && (iVal != (int32_t)ERROR_CON_DISABLE)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption for ERROR_CON_IDC = %d not allowd for parse only!.", iVal); return cmInitParaError; } pDecContext->pParam->eEcActiveIdc = (ERROR_CON_IDC)iVal; InitErrorCon (pDecContext); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption for ERROR_CON_IDC = %d.", iVal); return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_LEVEL) { if (m_pWelsTrace) { uint32_t level = * ((uint32_t*)pOption); m_pWelsTrace->SetTraceLevel (level); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK) { if (m_pWelsTrace) { WelsTraceCallback callback = * ((WelsTraceCallback*)pOption); m_pWelsTrace->SetTraceCallback (callback); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::SetOption():DECODER_OPTION_TRACE_CALLBACK callback = %p.", callback); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK_CONTEXT) { if (m_pWelsTrace) { void* ctx = * ((void**)pOption); m_pWelsTrace->SetTraceCallbackContext (ctx); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_GET_STATISTICS) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsDecoder::SetOption():DECODER_OPTION_GET_STATISTICS: this option is get-only!"); return cmInitParaError; } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { if (pOption) { if (pDecContext == NULL) return dsInitialOptExpected; pDecContext->pDecoderStatistics->iStatisticsLogInterval = (* ((unsigned int*)pOption)); return cmResultSuccess; } } else if (eOptID == DECODER_OPTION_GET_SAR_INFO) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "CWelsDecoder::SetOption():DECODER_OPTION_GET_SAR_INFO: this option is get-only!"); return cmInitParaError; } } return cmInitParaError; } /* * Get Option */ long CWelsDecoder::GetOption (DECODER_OPTION eOptID, void* pOption) { int iVal = 0; if (DECODER_OPTION_NUM_OF_THREADS == eOptID) { * ((int*)pOption) = m_iThreadCount; return cmResultSuccess; } PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; if (pDecContext == NULL) return cmInitExpected; if (pOption == NULL) return cmInitParaError; if (DECODER_OPTION_END_OF_STREAM == eOptID) { iVal = pDecContext->bEndOfStreamFlag; * ((int*)pOption) = iVal; return cmResultSuccess; } #ifdef LONG_TERM_REF else if (DECODER_OPTION_IDR_PIC_ID == eOptID) { iVal = pDecContext->uiCurIdrPicId; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_FRAME_NUM == eOptID) { iVal = pDecContext->iFrameNum; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKING_FLAG == eOptID) { iVal = pDecContext->bCurAuContainLtrMarkSeFlag; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LTR_MARKED_FRAME_NUM == eOptID) { iVal = pDecContext->iFrameNumOfAuMarkedLtr; * ((int*)pOption) = iVal; return cmResultSuccess; } #endif else if (DECODER_OPTION_VCL_NAL == eOptID) { //feedback whether or not have VCL NAL in current AU iVal = pDecContext->iFeedbackVclNalInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_TEMPORAL_ID == eOptID) { //if have VCL NAL in current AU, then feedback the temporal ID iVal = pDecContext->iFeedbackTidInAu; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_IS_REF_PIC == eOptID) { iVal = pDecContext->iFeedbackNalRefIdc; if (iVal > 0) iVal = 1; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_ERROR_CON_IDC == eOptID) { iVal = (int)pDecContext->pParam->eEcActiveIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_GET_STATISTICS == eOptID) { // get decoder statistics info for real time debugging SDecoderStatistics* pDecoderStatistics = (static_cast<SDecoderStatistics*> (pOption)); memcpy (pDecoderStatistics, pDecContext->pDecoderStatistics, sizeof (SDecoderStatistics)); if (pDecContext->pDecoderStatistics->uiDecodedFrameCount != 0) { //not original status pDecoderStatistics->fAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / (pDecContext->pDecoderStatistics->uiDecodedFrameCount); pDecoderStatistics->fActualAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / (pDecContext->pDecoderStatistics->uiDecodedFrameCount + pDecContext->pDecoderStatistics->uiFreezingIDRNum + pDecContext->pDecoderStatistics->uiFreezingNonIDRNum); } return cmResultSuccess; } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { if (pOption) { iVal = pDecContext->pDecoderStatistics->iStatisticsLogInterval; * ((unsigned int*)pOption) = iVal; return cmResultSuccess; } } else if (DECODER_OPTION_GET_SAR_INFO == eOptID) { //get decoder SAR info in VUI PVuiSarInfo pVuiSarInfo = (static_cast<PVuiSarInfo> (pOption)); memset (pVuiSarInfo, 0, sizeof (SVuiSarInfo)); if (!pDecContext->pSps) { return cmInitExpected; } else { pVuiSarInfo->uiSarWidth = pDecContext->pSps->sVui.uiSarWidth; pVuiSarInfo->uiSarHeight = pDecContext->pSps->sVui.uiSarHeight; pVuiSarInfo->bOverscanAppropriateFlag = pDecContext->pSps->sVui.bOverscanAppropriateFlag; return cmResultSuccess; } } else if (DECODER_OPTION_PROFILE == eOptID) { if (!pDecContext->pSps) { return cmInitExpected; } iVal = (int)pDecContext->pSps->uiProfileIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_LEVEL == eOptID) { if (!pDecContext->pSps) { return cmInitExpected; } iVal = (int)pDecContext->pSps->uiLevelIdc; * ((int*)pOption) = iVal; return cmResultSuccess; } else if (DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER == eOptID) { for (int32_t activeThread = 0; activeThread < m_DecCtxActiveCount; ++activeThread) { WAIT_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); RELEASE_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle); } * ((int*)pOption) = m_sReoderingStatus.iNumOfPicts; return cmResultSuccess; } return cmInitParaError; } DECODING_STATE CWelsDecoder::DecodeFrameNoDelay (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { int iRet = dsErrorFree; if (m_iThreadCount >= 1) { iRet = ThreadDecodeFrameInternal (kpSrc, kiSrcLen, ppDst, pDstInfo); if (m_sReoderingStatus.iNumOfPicts) { WAIT_EVENT (&m_sBufferingEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sReleaseBufferEvent); ReleaseBufferedReadyPicture (NULL, ppDst, pDstInfo); SET_EVENT (&m_sReleaseBufferEvent); } return (DECODING_STATE)iRet; } //SBufferInfo sTmpBufferInfo; //unsigned char* ppTmpDst[3] = {NULL, NULL, NULL}; iRet = (int)DecodeFrame2 (kpSrc, kiSrcLen, ppDst, pDstInfo); //memcpy (&sTmpBufferInfo, pDstInfo, sizeof (SBufferInfo)); //ppTmpDst[0] = ppDst[0]; //ppTmpDst[1] = ppDst[1]; //ppTmpDst[2] = ppDst[2]; iRet |= DecodeFrame2 (NULL, 0, ppDst, pDstInfo); //if ((pDstInfo->iBufferStatus == 0) && (sTmpBufferInfo.iBufferStatus == 1)) { //memcpy (pDstInfo, &sTmpBufferInfo, sizeof (SBufferInfo)); //ppDst[0] = ppTmpDst[0]; //ppDst[1] = ppTmpDst[1]; //ppDst[2] = ppTmpDst[2]; //} return (DECODING_STATE)iRet; } DECODING_STATE CWelsDecoder::DecodeFrame2WithCtx (PWelsDecoderContext pDecContext, const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { if (pDecContext == NULL || pDecContext->pParam == NULL) { if (m_pWelsTrace != NULL) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "Call DecodeFrame2 without Initialize.\n"); } return dsInitialOptExpected; } if (pDecContext->pParam->bParseOnly) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "bParseOnly should be false for this API calling! \n"); pDecContext->iErrorCode |= dsInvalidArgument; return dsInvalidArgument; } if (CheckBsBuffer (pDecContext, kiSrcLen)) { if (ResetDecoder (pDecContext)) return dsOutOfMemory; return dsErrorFree; } if (kiSrcLen > 0 && kpSrc != NULL) { #ifdef OUTPUT_BIT_STREAM if (m_pFBS) { WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS); WelsFflush (m_pFBS); } if (m_pFBSSize) { WelsFwrite (&kiSrcLen, sizeof (int), 1, m_pFBSSize); WelsFflush (m_pFBSSize); } #endif//OUTPUT_BIT_STREAM pDecContext->bEndOfStreamFlag = false; if (GetThreadCount (pDecContext) <= 0) { pDecContext->uiDecodingTimeStamp = ++m_uiDecodeTimeStamp; } } else { //For application MODE, the error detection should be added for safe. //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL. pDecContext->bEndOfStreamFlag = true; pDecContext->bInstantDecFlag = true; } int64_t iStart, iEnd; iStart = WelsTime(); if (GetThreadCount (pDecContext) <= 1) { ppDst[0] = ppDst[1] = ppDst[2] = NULL; } pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding. pDecContext->iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL; //initialize unsigned long long uiInBsTimeStamp = pDstInfo->uiInBsTimeStamp; if (GetThreadCount (pDecContext) <= 1) { memset (pDstInfo, 0, sizeof (SBufferInfo)); } pDstInfo->uiInBsTimeStamp = uiInBsTimeStamp; #ifdef LONG_TERM_REF pDecContext->bReferenceLostAtT0Flag = false; //initialize for LTR pDecContext->bCurAuContainLtrMarkSeFlag = false; pDecContext->iFrameNumOfAuMarkedLtr = 0; pDecContext->iFrameNum = -1; //initialize #endif pDecContext->iFeedbackTidInAu = -1; //initialize pDecContext->iFeedbackNalRefIdc = -1; //initialize if (pDstInfo) { pDstInfo->uiOutYuvTimeStamp = 0; pDecContext->uiTimeStamp = pDstInfo->uiInBsTimeStamp; } else { pDecContext->uiTimeStamp = 0; } WelsDecodeBs (pDecContext, kpSrc, kiSrcLen, ppDst, pDstInfo, NULL); //iErrorCode has been modified in this function pDecContext->bInstantDecFlag = false; //reset no-delay flag if (pDecContext->iErrorCode) { EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0; //for NBR, IDR frames are expected to decode as followed if error decoding an IDR currently eNalType = pDecContext->sCurNalHead.eNalUnitType; if (pDecContext->iErrorCode & dsOutOfMemory) { if (ResetDecoder (pDecContext)) { return dsOutOfMemory; } return dsErrorFree; } if (pDecContext->iErrorCode & dsRefListNullPtrs) { if (ResetDecoder (pDecContext)) { return dsRefListNullPtrs; } return dsErrorFree; } //for AVC bitstream (excluding AVC with temporal scalability, including TP), as long as error occur, SHOULD notify upper layer key frame loss. if ((IS_PARAM_SETS_NALS (eNalType) || NAL_UNIT_CODED_SLICE_IDR == eNalType) || (VIDEO_BITSTREAM_AVC == pDecContext->eVideoType)) { if (pDecContext->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { #ifdef LONG_TERM_REF pDecContext->bParamSetsLostFlag = true; #else pDecContext->bReferenceLostAtT0Flag = true; #endif } } if (pDecContext->bPrintFrameErrorTraceFlag) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "decode failed, failure type:%d \n", pDecContext->iErrorCode); pDecContext->bPrintFrameErrorTraceFlag = false; } else { pDecContext->iIgnoredErrorInfoPacketCount++; if (pDecContext->iIgnoredErrorInfoPacketCount == INT_MAX) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "continuous error reached INT_MAX! Restart as 0."); pDecContext->iIgnoredErrorInfoPacketCount = 0; } } if ((pDecContext->pParam->eEcActiveIdc != ERROR_CON_DISABLE) && (pDstInfo->iBufferStatus == 1)) { //TODO after dec status updated pDecContext->iErrorCode |= dsDataErrorConcealed; pDecContext->pDecoderStatistics->uiDecodedFrameCount++; if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t ResetDecStatNums (pDecContext->pDecoderStatistics); pDecContext->pDecoderStatistics->uiDecodedFrameCount++; } int32_t iMbConcealedNum = pDecContext->iMbEcedNum + pDecContext->iMbEcedPropNum; pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->iMbNum == 0 ? (pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( iMbConcealedNum * 100) / pDecContext->iMbNum)); pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->iMbNum == 0 ? (pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( pDecContext->iMbEcedPropNum * 100) / pDecContext->iMbNum)); pDecContext->pDecoderStatistics->uiEcFrameNum += (iMbConcealedNum == 0 ? 0 : 1); pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : pDecContext->pDecoderStatistics->uiAvgEcRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : pDecContext->pDecoderStatistics->uiAvgEcPropRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; } iEnd = WelsTime(); pDecContext->dDecTime += (iEnd - iStart) / 1e3; OutputStatisticsLog (*pDecContext->pDecoderStatistics); if (GetThreadCount (pDecContext) >= 1) { WAIT_EVENT (&m_sReleaseBufferEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sBufferingEvent); BufferingReadyPicture (pDecContext, ppDst, pDstInfo); SET_EVENT (&m_sBufferingEvent); } else { ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); } return (DECODING_STATE)pDecContext->iErrorCode; } // else Error free, the current codec works well if (pDstInfo->iBufferStatus == 1) { pDecContext->pDecoderStatistics->uiDecodedFrameCount++; if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t ResetDecStatNums (pDecContext->pDecoderStatistics); pDecContext->pDecoderStatistics->uiDecodedFrameCount++; } OutputStatisticsLog (*pDecContext->pDecoderStatistics); } iEnd = WelsTime(); pDecContext->dDecTime += (iEnd - iStart) / 1e3; if (GetThreadCount (pDecContext) >= 1) { WAIT_EVENT (&m_sReleaseBufferEvent, WELS_DEC_THREAD_WAIT_INFINITE); RESET_EVENT (&m_sBufferingEvent); BufferingReadyPicture (pDecContext, ppDst, pDstInfo); SET_EVENT (&m_sBufferingEvent); } else { ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); } return dsErrorFree; } DECODING_STATE CWelsDecoder::DecodeFrame2 (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, SBufferInfo* pDstInfo) { PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; return DecodeFrame2WithCtx (pDecContext, kpSrc, kiSrcLen, ppDst, pDstInfo); } DECODING_STATE CWelsDecoder::FlushFrame (unsigned char** ppDst, SBufferInfo* pDstInfo) { bool bEndOfStreamFlag = true; if (m_iThreadCount <= 1) { for (int32_t j = 0; j < m_iCtxCount; ++j) { if (!m_pDecThrCtx[j].pCtx->bEndOfStreamFlag) { bEndOfStreamFlag = false; } } } if (bEndOfStreamFlag && m_sReoderingStatus.iNumOfPicts > 0) { m_sReoderingStatus.iMinPOC = IMinInt32; if (m_bIsBaseline) { uint32_t uiDecodingTimeStamp = 0; int32_t firstValidIdx = -1; for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (m_sPictInfoList[i].iPOC > IMinInt32) { uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; firstValidIdx = i; break; } } for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (i == firstValidIdx) continue; if (m_sPictInfoList[i].iPOC > IMinInt32 && m_sPictInfoList[i].uiDecodingTimeStamp < uiDecodingTimeStamp) { uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; } } } else { int32_t firstValidIdx = -1; for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (m_sReoderingStatus.iMinPOC == IMinInt32 && m_sPictInfoList[i].iPOC > IMinInt32) { m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; firstValidIdx = i; break; } } for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { if (i == firstValidIdx) continue; if (m_sPictInfoList[i].iPOC > IMinInt32 && m_sPictInfoList[i].iPOC < m_sReoderingStatus.iMinPOC) { m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; m_sReoderingStatus.iPictInfoIndex = i; } } } } if (m_sReoderingStatus.iMinPOC > IMinInt32) { m_sReoderingStatus.iLastWrittenPOC = m_sReoderingStatus.iMinPOC; #if defined (_DEBUG) #ifdef _MOTION_VECTOR_DUMP_ fprintf (stderr, "Output POC: #%d uiDecodingTimeStamp=%d\n", m_sReoderingStatus.iLastWrittenPOC, m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].uiDecodingTimeStamp); #endif #endif memcpy (pDstInfo, &m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].sBufferInfo, sizeof (SBufferInfo)); ppDst[0] = pDstInfo->pDst[0]; ppDst[1] = pDstInfo->pDst[1]; ppDst[2] = pDstInfo->pDst[2]; m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC = IMinInt32; PPicBuff pPicBuff = m_iThreadCount <= 1 ? m_pDecThrCtx[0].pCtx->pPicBuff : m_pPicBuff; if (m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx < pPicBuff->iCapacity) { PPicture pPic = pPicBuff->ppPic[m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx]; --pPic->iRefCount; } m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].bLastGOP = false; m_sReoderingStatus.iMinPOC = IMinInt32; --m_sReoderingStatus.iNumOfPicts; } return dsErrorFree; } void CWelsDecoder::OutputStatisticsLog (SDecoderStatistics& sDecoderStatistics) { if ((sDecoderStatistics.uiDecodedFrameCount > 0) && (sDecoderStatistics.iStatisticsLogInterval > 0) && ((sDecoderStatistics.uiDecodedFrameCount % sDecoderStatistics.iStatisticsLogInterval) == 0)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "DecoderStatistics: uiWidth=%d, uiHeight=%d, fAverageFrameSpeedInMs=%.1f, fActualAverageFrameSpeedInMs=%.1f, \ uiDecodedFrameCount=%d, uiResolutionChangeTimes=%d, uiIDRCorrectNum=%d, \ uiAvgEcRatio=%d, uiAvgEcPropRatio=%d, uiEcIDRNum=%d, uiEcFrameNum=%d, \ uiIDRLostNum=%d, uiFreezingIDRNum=%d, uiFreezingNonIDRNum=%d, iAvgLumaQp=%d, \ iSpsReportErrorNum=%d, iSubSpsReportErrorNum=%d, iPpsReportErrorNum=%d, iSpsNoExistNalNum=%d, iSubSpsNoExistNalNum=%d, iPpsNoExistNalNum=%d, \ uiProfile=%d, uiLevel=%d, \ iCurrentActiveSpsId=%d, iCurrentActivePpsId=%d,", sDecoderStatistics.uiWidth, sDecoderStatistics.uiHeight,