pParam->iPicWidth, pParam->iPicHeight, pParam->iTargetBitrate, pParam->iMaxBitrate, pParam->iRCMode, pParam->iPaddingFlag, pParam->iTemporalLayerNum, pParam->iSpatialLayerNum, pParam->fMaxFrameRate, pParam->uiIntraPeriod, pParam->eSpsPpsIdStrategy, pParam->bPrefixNalAddingCtrl, pParam->bSimulcastAVC, pParam->bEnableDenoise, pParam->bEnableBackgroundDetection, pParam->bEnableSceneChangeDetect, pParam->bEnableAdaptiveQuant, pParam->bEnableFrameSkip, pParam->bEnableLongTermReference, pParam->iLtrMarkPeriod, pParam->bIsLosslessLink, pParam->iComplexityMode, pParam->iNumRefFrame, pParam->iEntropyCodingModeFlag, pParam->uiMaxNalSize, pParam->iLTRRefNum, pParam->iMultipleThreadIdc, pParam->iLoopFilterDisableIdc, pParam->iLoopFilterAlphaC0Offset, pParam->iLoopFilterBetaOffset, pParam->iComplexityMode, pParam->iMaxQp, pParam->iMinQp ); int32_t i = 0; int32_t iSpatialLayers = (pParam->iSpatialLayerNum < MAX_SPATIAL_LAYER_NUM) ? (pParam->iSpatialLayerNum) : MAX_SPATIAL_LAYER_NUM; while (i < iSpatialLayers) { SSpatialLayerConfig* pSpatialCfg = &pParam->sSpatialLayers[i]; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "sSpatialLayers[%d]: .iVideoWidth= %d; .iVideoHeight= %d; .fFrameRate= %.6ff; .iSpatialBitrate= %d; .iMaxSpatialBitrate= %d; .sSliceArgument.uiSliceMode= %d; .sSliceArgument.iSliceNum= %d; .sSliceArgument.uiSliceSizeConstraint= %d;" "uiProfileIdc = %d;uiLevelIdc = %d", i, pSpatialCfg->iVideoWidth, pSpatialCfg->iVideoHeight, pSpatialCfg->fFrameRate, pSpatialCfg->iSpatialBitrate, pSpatialCfg->iMaxSpatialBitrate, pSpatialCfg->sSliceArgument.uiSliceMode, pSpatialCfg->sSliceArgument.uiSliceNum, pSpatialCfg->sSliceArgument.uiSliceSizeConstraint, pSpatialCfg->uiProfileIdc, pSpatialCfg->uiLevelIdc ); ++ i; }} void CWelsH264SVCEncoder::LogStatistics (const int64_t kiCurrentFrameTs, int32_t iMaxDid) { for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) { SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "EncoderStatistics: SpatialId = %d,%dx%d, SpeedInMs: %f, fAverageFrameRate=%f, " "LastFrameRate=%f, LatestBitRate=%d, LastFrameQP=%d, uiInputFrameCount=%d, uiSkippedFrameCount=%d, " "uiResolutionChangeTimes=%d, uIDRReqNum=%d, uIDRSentNum=%d, uLTRSentNum=NA, iTotalEncodedBytes=%lu at Ts = %" PRId64, iDid, pStatistics->uiWidth, pStatistics->uiHeight, pStatistics->fAverageFrameSpeedInMs, pStatistics->fAverageFrameRate, pStatistics->fLatestFrameRate, pStatistics->uiBitRate, pStatistics->uiAverageFrameQP, pStatistics->uiInputFrameCount, pStatistics->uiSkippedFrameCount, pStatistics->uiResolutionChangeTimes, pStatistics->uiIDRReqNum, pStatistics->uiIDRSentNum, pStatistics->iTotalEncodedBytes, kiCurrentFrameTs); }} void CWelsH264SVCEncoder::UpdateStatistics (SFrameBSInfo* pBsInfo, const int64_t kiCurrentFrameMs) { const int64_t kiCurrentFrameTs = m_pEncContext->uiLastTimestamp = pBsInfo->uiTimeStamp; const int64_t kiTimeDiff = kiCurrentFrameTs - m_pEncContext->iLastStatisticsLogTs; int32_t iMaxDid = m_pEncContext->pSvcParam->iSpatialLayerNum - 1; SLayerBSInfo* pLayerInfo = &pBsInfo->sLayerInfo[0]; uint32_t iMaxInputFrame = 0; float iMaxFrameRate = 0; for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) { EVideoFrameType eFrameType = videoFrameTypeSkip; int32_t kiCurrentFrameSize = 0; for (int32_t iLayerNum = 0; iLayerNum < pBsInfo->iLayerNum; iLayerNum++) { pLayerInfo = &pBsInfo->sLayerInfo[iLayerNum]; if ((pLayerInfo->uiLayerType == VIDEO_CODING_LAYER) && (pLayerInfo->uiSpatialId == iDid)) { eFrameType = pLayerInfo->eFrameType; for (int32_t iNalIdx = 0; iNalIdx < pLayerInfo->iNalCount; iNalIdx++) { kiCurrentFrameSize += pLayerInfo->pNalLengthInByte[iNalIdx]; } } } SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]); SSpatialLayerInternal* pSpatialLayerInternalParam = & (m_pEncContext->pSvcParam->sDependencyLayers[iDid]); if ((0 != pStatistics->uiWidth && 0 != pStatistics->uiHeight) && (pStatistics->uiWidth != (unsigned int) pSpatialLayerInternalParam->iActualWidth || pStatistics->uiHeight != (unsigned int) pSpatialLayerInternalParam->iActualHeight)) { pStatistics->uiResolutionChangeTimes ++; } pStatistics->uiWidth = pSpatialLayerInternalParam->iActualWidth; pStatistics->uiHeight = pSpatialLayerInternalParam->iActualHeight; const bool kbCurrentFrameSkipped = (videoFrameTypeSkip == eFrameType); pStatistics->uiInputFrameCount ++; pStatistics->uiSkippedFrameCount += (kbCurrentFrameSkipped ? 1 : 0); iMaxInputFrame = WELS_MAX (pStatistics->uiInputFrameCount, iMaxInputFrame); int32_t iProcessedFrameCount = pStatistics->uiInputFrameCount - pStatistics->uiSkippedFrameCount; if (!kbCurrentFrameSkipped && iProcessedFrameCount != 0) { pStatistics->fAverageFrameSpeedInMs += (kiCurrentFrameMs - pStatistics->fAverageFrameSpeedInMs) / iProcessedFrameCount; } // rate control related if (0 != m_pEncContext->uiStartTimestamp) { if (kiCurrentFrameTs > m_pEncContext->uiStartTimestamp + 800) { pStatistics->fAverageFrameRate = (static_cast<float> (pStatistics->uiInputFrameCount) * 1000 / (kiCurrentFrameTs - m_pEncContext->uiStartTimestamp)); } } else { m_pEncContext->uiStartTimestamp = kiCurrentFrameTs; } iMaxFrameRate = WELS_MAX (iMaxFrameRate, pStatistics->fAverageFrameRate); //pStatistics->fLatestFrameRate = m_pEncContext->pWelsSvcRc->fLatestFrameRate; //TODO: finish the calculation in RC //pStatistics->uiBitRate = m_pEncContext->pWelsSvcRc->iActualBitRate; //TODO: finish the calculation in RC pStatistics->uiAverageFrameQP = m_pEncContext->pWelsSvcRc[iDid].iAverageFrameQp; if (videoFrameTypeIDR == eFrameType || videoFrameTypeI == eFrameType) { pStatistics->uiIDRSentNum ++; } if (m_pEncContext->pLtr->bLTRMarkingFlag) { pStatistics->uiLTRSentNum ++; } pStatistics->iTotalEncodedBytes += kiCurrentFrameSize; const int32_t kiDeltaFrames = static_cast<int32_t> (pStatistics->uiInputFrameCount - pStatistics->iLastStatisticsFrameCount); if (kiDeltaFrames > (m_pEncContext->pSvcParam->fMaxFrameRate * 2)) { if (kiTimeDiff >= m_pEncContext->iStatisticsLogInterval) { pStatistics->fLatestFrameRate = static_cast<float> ((pStatistics->uiInputFrameCount - pStatistics->iLastStatisticsFrameCount) * 1000 / kiTimeDiff); pStatistics->uiBitRate = static_cast<unsigned int> ((pStatistics->iTotalEncodedBytes - pStatistics->iLastStatisticsBytes) * 8 * 1000 / kiTimeDiff); if (WELS_ABS (pStatistics->fLatestFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input fLatestFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), cur_Ts = %" PRId64 " start_Ts = %" PRId64, pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, kiCurrentFrameTs, static_cast<int64_t> (m_pEncContext->iLastStatisticsLogTs)); } if (m_pEncContext->pSvcParam->iRCMode == RC_QUALITY_MODE || m_pEncContext->pSvcParam->iRCMode == RC_BITRATE_MODE) { if ((pStatistics->fLatestFrameRate > 0) && WELS_ABS (m_pEncContext->pSvcParam->fMaxFrameRate - pStatistics->fLatestFrameRate) > 5) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input framerate %f is different from framerate in setting %f, suggest to use other rate control modes", pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate); } } // update variables pStatistics->iLastStatisticsBytes = pStatistics->iTotalEncodedBytes; pStatistics->iLastStatisticsFrameCount = pStatistics->uiInputFrameCount; //TODO: the following statistics will be calculated and added later //pStatistics->uiLTRSentNum } } } if (((m_pEncContext->iStatisticsLogInterval > 0) && (kiTimeDiff >= m_pEncContext->iStatisticsLogInterval)) || (0 == iMaxInputFrame % 300)) { if ((iMaxFrameRate > 0) && WELS_ABS (iMaxFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input framerate fAverageFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), start_Ts = %" PRId64, iMaxFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, m_pEncContext->uiStartTimestamp); } LogStatistics (kiCurrentFrameTs, iMaxDid); m_pEncContext->iLastStatisticsLogTs = kiCurrentFrameTs; } } /************************************************************************* InDataFormat, IDRInterval, SVC Encode Param, Frame Rate, Bitrate,..************************************************************************/int CWelsH264SVCEncoder::SetOption (ENCODER_OPTION eOptionId, void* pOption) { if (NULL == pOption) { return cmInitParaError; } if ((NULL == m_pEncContext || false == m_bInitialFlag) && eOptionId != ENCODER_OPTION_TRACE_LEVEL && eOptionId != ENCODER_OPTION_TRACE_CALLBACK && eOptionId != ENCODER_OPTION_TRACE_CALLBACK_CONTEXT) { return cmInitExpected; } switch (eOptionId) { case ENCODER_OPTION_INTER_SPATIAL_PRED: { // Inter spatial layer prediction flag WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ENCODER_OPTION_INTER_SPATIAL_PRED, this feature not supported at present."); } break; case ENCODER_OPTION_DATAFORMAT: { // Input color space int32_t iValue = * ((int32_t*)pOption); int32_t iColorspace = iValue; if (iColorspace == 0) { return cmInitParaError; } m_iCspInternal = iColorspace; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_DATAFORMAT, m_iCspInternal = 0x%x", m_iCspInternal); } break; case ENCODER_OPTION_IDR_INTERVAL: { // IDR Interval int32_t iValue = * ((int32_t*)pOption); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_IDR_INTERVAL iValue = %d", iValue); if (iValue <= -1 || iValue == 0) { iValue = 0; } if (iValue == (int32_t)m_pEncContext->pSvcParam->uiIntraPeriod) { return cmResultSuccess; } m_pEncContext->pSvcParam->uiIntraPeriod = (uint32_t)iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_IDR_INTERVAL uiIntraPeriod updated to %d", m_pEncContext->pSvcParam->uiIntraPeriod); } break; case ENCODER_OPTION_SVC_ENCODE_PARAM_BASE: { // SVC Encoding Parameter SEncParamBase sEncodingParam; SWelsSvcCodingParam sConfig; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; memcpy (&sEncodingParam, pOption, sizeof (SEncParamBase)); // confirmed_safe_unsafe_usage#ifdef OUTPUT_BIT_STREAM if ((sEncodingParam.iPicWidth != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualWidth) || (sEncodingParam.iPicHeight != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualHeight)) { ++m_iSwitchTimes; m_bSwitch = true; }#endif//OUTPUT_BIT_STREAM if (sConfig.ParamBaseTranscode (sEncodingParam)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, ParamTranscode failed!"); return cmInitParaError; } /* New configuration available here */ iTargetWidth = sConfig.iPicWidth; iTargetHeight = sConfig.iPicHeight; if (m_iMaxPicWidth != iTargetWidth || m_iMaxPicHeight != iTargetHeight) { m_iMaxPicWidth = iTargetWidth; m_iMaxPicHeight = iTargetHeight; } if (sConfig.DetermineTemporalSettings()) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, DetermineTemporalSettings failed!"); return cmInitParaError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE iUsageType = %d,iPicWidth= %d;iPicHeight= %d;iTargetBitrate= %d;fMaxFrameRate= %.6ff;iRCMode= %d", sEncodingParam.iUsageType, sEncodingParam.iPicWidth, sEncodingParam.iPicHeight, sEncodingParam.iTargetBitrate, sEncodingParam.fMaxFrameRate, sEncodingParam.iRCMode); if (WelsEncoderParamAdjust (&m_pEncContext, &sConfig)) { return cmInitParaError; } //LogStatistics WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, LogStatisticsBeforeNewEncoding"); LogStatistics (m_pEncContext->iLastStatisticsLogTs, 0); } break; case ENCODER_OPTION_SVC_ENCODE_PARAM_EXT: { // SVC Encoding Parameter SEncParamExt sEncodingParam; SWelsSvcCodingParam sConfig; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; memcpy (&sEncodingParam, pOption, sizeof (SEncParamExt)); // confirmed_safe_unsafe_usage TraceParamInfo (&sEncodingParam);#ifdef OUTPUT_BIT_STREAM if ((sEncodingParam.sSpatialLayers[sEncodingParam.iSpatialLayerNum - 1].iVideoWidth != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualWidth) || (sEncodingParam.sSpatialLayers[sEncodingParam.iSpatialLayerNum - 1].iVideoHeight != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualHeight)) { ++ m_iSwitchTimes; m_bSwitch = true; }#endif//OUTPUT_BIT_STREAM if (sEncodingParam.iSpatialLayerNum < 1 || sEncodingParam.iSpatialLayerNum > MAX_SPATIAL_LAYER_NUM) { // verify number of spatial layer WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!", sEncodingParam.iSpatialLayerNum); return cmInitParaError; } if (sConfig.ParamTranscode (sEncodingParam)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, ParamTranscode failed!"); return cmInitParaError; } if (sConfig.iSpatialLayerNum < 1) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!", sConfig.iSpatialLayerNum); return cmInitParaError; } if (sConfig.DetermineTemporalSettings()) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, DetermineTemporalSettings failed!"); return cmInitParaError; } /* New configuration available here */ iTargetWidth = sConfig.iPicWidth; iTargetHeight = sConfig.iPicHeight; if (m_iMaxPicWidth != iTargetWidth || m_iMaxPicHeight != iTargetHeight) { m_iMaxPicWidth = iTargetWidth; m_iMaxPicHeight = iTargetHeight; } /* Check every field whether there is new request for memory block changed or else, Oct. 24, 2008 */ if (WelsEncoderParamAdjust (&m_pEncContext, &sConfig)) { return cmInitParaError; } //LogStatistics WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, LogStatisticsBeforeNewEncoding"); LogStatistics (m_pEncContext->iLastStatisticsLogTs, sEncodingParam.iSpatialLayerNum - 1); } break; case ENCODER_OPTION_FRAME_RATE: { // Maximal input frame rate float iValue = * ((float*)pOption); if (iValue <= 0) { return cmInitParaError; } //adjust to valid range m_pEncContext->pSvcParam->fMaxFrameRate = WELS_CLIP3 (iValue, MIN_FRAME_RATE, MAX_FRAME_RATE); WelsEncoderApplyFrameRate (m_pEncContext->pSvcParam); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_FRAME_RATE,m_pEncContext->pSvcParam->fMaxFrameRate= %f", m_pEncContext->pSvcParam->fMaxFrameRate); } break; case ENCODER_OPTION_BITRATE: { // Target bit-rate SBitrateInfo* pInfo = (static_cast<SBitrateInfo*> (pOption)); int32_t iBitrate = pInfo->iBitrate; if (iBitrate <= 0) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE,iBitrate = %d", iBitrate); return cmInitParaError; } iBitrate = WELS_CLIP3 (iBitrate, MIN_BIT_RATE, MAX_BIT_RATE); switch (pInfo->iLayer) { case SPATIAL_LAYER_ALL: m_pEncContext->pSvcParam->iTargetBitrate = iBitrate; break; case SPATIAL_LAYER_0: m_pEncContext->pSvcParam->sSpatialLayers[0].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_1: m_pEncContext->pSvcParam->sSpatialLayers[1].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_2: m_pEncContext->pSvcParam->sSpatialLayers[2].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_3: m_pEncContext->pSvcParam->sSpatialLayers[3].iSpatialBitrate = iBitrate; break; default: WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE,iLayer = %d", pInfo->iLayer); return cmInitParaError; break; } //adjust to valid range if (WelsEncoderApplyBitRate (&m_pWelsTrace->m_sLogCtx, m_pEncContext->pSvcParam, pInfo->iLayer)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iSpatialBitrate = %d", pInfo->iLayer, iBitrate); return cmInitParaError; } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iSpatialBitrate = %d", pInfo->iLayer, iBitrate); } } break; case ENCODER_OPTION_MAX_BITRATE: { // Target bit-rate SBitrateInfo* pInfo = (static_cast<SBitrateInfo*> (pOption)); int32_t iBitrate = pInfo->iBitrate; if (iBitrate <= 0) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_MAX_BITRATE,iBitrate = %d", iBitrate); return cmInitParaError; } iBitrate = WELS_CLIP3 (iBitrate, MIN_BIT_RATE, MAX_BIT_RATE); switch (pInfo->iLayer) { case SPATIAL_LAYER_ALL: m_pEncContext->pSvcParam->iMaxBitrate = iBitrate; break; case SPATIAL_LAYER_0: m_pEncContext->pSvcParam->sSpatialLayers[0].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_1: m_pEncContext->pSvcParam->sSpatialLayers[1].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_2: m_pEncContext->pSvcParam->sSpatialLayers[2].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_3: m_pEncContext->pSvcParam->sSpatialLayers[3].iMaxSpatialBitrate = iBitrate; break; default: WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_MAX_BITRATE,iLayer = %d", pInfo->iLayer); return cmInitParaError; break; } //adjust to valid range if (WelsEncoderApplyBitRate (&m_pWelsTrace->m_sLogCtx, m_pEncContext->pSvcParam, pInfo->iLayer)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iMaxSpatialBitrate = %d", pInfo->iLayer, iBitrate); return cmInitParaError; } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iMaxSpatialBitrate = %d", pInfo->iLayer, iBitrate); } } break; case ENCODER_OPTION_RC_MODE: { // 0:quality mode;1:bit-rate mode;2:bitrate limited mode int32_t iValue = * ((int32_t*)pOption); m_pEncContext->pSvcParam->iRCMode = (RC_MODES) iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_MODE iRCMode= %d (Note: not suggest changing RC-mode in middle of encoding)", iValue); WelsRcInitFuncPointers (m_pEncContext, m_pEncContext->pSvcParam->iRCMode); } break; case ENCODER_OPTION_RC_FRAME_SKIP: { // 0:FRAME-SKIP disabled;1:FRAME-SKIP enabled bool bValue = * ((bool*)pOption); if (m_pEncContext->pSvcParam->iRCMode != RC_OFF_MODE) { m_pEncContext->pSvcParam->bEnableFrameSkip = bValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_FRAME_SKIP, frame-skip setting(%d)", bValue); } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_FRAME_SKIP, rc off, frame-skip setting(%d) un-useful", bValue); } } break; case ENCODER_PADDING_PADDING: { // 0:disable padding;1:padding int32_t iValue = * ((int32_t*)pOption); m_pEncContext->pSvcParam->iPaddingFlag = iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_PADDING_PADDING iPaddingFlag= %d ", iValue); } break; case ENCODER_LTR_RECOVERY_REQUEST: { SLTRRecoverRequest* pLTR_Recover_Request = (SLTRRecoverRequest*) (pOption); FilterLTRRecoveryRequest (m_pEncContext, pLTR_Recover_Request); } break; case ENCODER_LTR_MARKING_FEEDBACK: { SLTRMarkingFeedback* fb = (SLTRMarkingFeedback*) (pOption); FilterLTRMarkingFeedback (m_pEncContext, fb); } break; case ENCODER_LTR_MARKING_PERIOD: { uint32_t iValue = * ((uint32_t*) (pOption)); m_pEncContext->pSvcParam->iLtrMarkPeriod = iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_LTR_MARKING_PERIOD iLtrMarkPeriod= %d ", iValue);Lines 501–1000 of 1399. Previous lines Load more
pParam->iPicWidth, pParam->iPicHeight, pParam->iTargetBitrate, pParam->iMaxBitrate, pParam->iRCMode, pParam->iPaddingFlag, pParam->iTemporalLayerNum, pParam->iSpatialLayerNum, pParam->fMaxFrameRate, pParam->uiIntraPeriod, pParam->eSpsPpsIdStrategy, pParam->bPrefixNalAddingCtrl, pParam->bSimulcastAVC, pParam->bEnableDenoise, pParam->bEnableBackgroundDetection, pParam->bEnableSceneChangeDetect, pParam->bEnableAdaptiveQuant, pParam->bEnableFrameSkip, pParam->bEnableLongTermReference, pParam->iLtrMarkPeriod, pParam->bIsLosslessLink, pParam->iComplexityMode, pParam->iNumRefFrame, pParam->iEntropyCodingModeFlag, pParam->uiMaxNalSize, pParam->iLTRRefNum, pParam->iMultipleThreadIdc, pParam->iLoopFilterDisableIdc, pParam->iLoopFilterAlphaC0Offset, pParam->iLoopFilterBetaOffset, pParam->iComplexityMode, pParam->iMaxQp, pParam->iMinQp ); int32_t i = 0; int32_t iSpatialLayers = (pParam->iSpatialLayerNum < MAX_SPATIAL_LAYER_NUM) ? (pParam->iSpatialLayerNum) : MAX_SPATIAL_LAYER_NUM; while (i < iSpatialLayers) { SSpatialLayerConfig* pSpatialCfg = &pParam->sSpatialLayers[i]; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "sSpatialLayers[%d]: .iVideoWidth= %d; .iVideoHeight= %d; .fFrameRate= %.6ff; .iSpatialBitrate= %d; .iMaxSpatialBitrate= %d; .sSliceArgument.uiSliceMode= %d; .sSliceArgument.iSliceNum= %d; .sSliceArgument.uiSliceSizeConstraint= %d;" "uiProfileIdc = %d;uiLevelIdc = %d", i, pSpatialCfg->iVideoWidth, pSpatialCfg->iVideoHeight, pSpatialCfg->fFrameRate, pSpatialCfg->iSpatialBitrate, pSpatialCfg->iMaxSpatialBitrate, pSpatialCfg->sSliceArgument.uiSliceMode, pSpatialCfg->sSliceArgument.uiSliceNum, pSpatialCfg->sSliceArgument.uiSliceSizeConstraint, pSpatialCfg->uiProfileIdc, pSpatialCfg->uiLevelIdc ); ++ i; } } void CWelsH264SVCEncoder::LogStatistics (const int64_t kiCurrentFrameTs, int32_t iMaxDid) { for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) { SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "EncoderStatistics: SpatialId = %d,%dx%d, SpeedInMs: %f, fAverageFrameRate=%f, " "LastFrameRate=%f, LatestBitRate=%d, LastFrameQP=%d, uiInputFrameCount=%d, uiSkippedFrameCount=%d, " "uiResolutionChangeTimes=%d, uIDRReqNum=%d, uIDRSentNum=%d, uLTRSentNum=NA, iTotalEncodedBytes=%lu at Ts = %" PRId64, iDid, pStatistics->uiWidth, pStatistics->uiHeight, pStatistics->fAverageFrameSpeedInMs, pStatistics->fAverageFrameRate, pStatistics->fLatestFrameRate, pStatistics->uiBitRate, pStatistics->uiAverageFrameQP, pStatistics->uiInputFrameCount, pStatistics->uiSkippedFrameCount, pStatistics->uiResolutionChangeTimes, pStatistics->uiIDRReqNum, pStatistics->uiIDRSentNum, pStatistics->iTotalEncodedBytes, kiCurrentFrameTs); } } void CWelsH264SVCEncoder::UpdateStatistics (SFrameBSInfo* pBsInfo, const int64_t kiCurrentFrameMs) { const int64_t kiCurrentFrameTs = m_pEncContext->uiLastTimestamp = pBsInfo->uiTimeStamp; const int64_t kiTimeDiff = kiCurrentFrameTs - m_pEncContext->iLastStatisticsLogTs; int32_t iMaxDid = m_pEncContext->pSvcParam->iSpatialLayerNum - 1; SLayerBSInfo* pLayerInfo = &pBsInfo->sLayerInfo[0]; uint32_t iMaxInputFrame = 0; float iMaxFrameRate = 0; for (int32_t iDid = 0; iDid <= iMaxDid; iDid++) { EVideoFrameType eFrameType = videoFrameTypeSkip; int32_t kiCurrentFrameSize = 0; for (int32_t iLayerNum = 0; iLayerNum < pBsInfo->iLayerNum; iLayerNum++) { pLayerInfo = &pBsInfo->sLayerInfo[iLayerNum]; if ((pLayerInfo->uiLayerType == VIDEO_CODING_LAYER) && (pLayerInfo->uiSpatialId == iDid)) { eFrameType = pLayerInfo->eFrameType; for (int32_t iNalIdx = 0; iNalIdx < pLayerInfo->iNalCount; iNalIdx++) { kiCurrentFrameSize += pLayerInfo->pNalLengthInByte[iNalIdx]; } } } SEncoderStatistics* pStatistics = & (m_pEncContext->sEncoderStatistics[iDid]); SSpatialLayerInternal* pSpatialLayerInternalParam = & (m_pEncContext->pSvcParam->sDependencyLayers[iDid]); if ((0 != pStatistics->uiWidth && 0 != pStatistics->uiHeight) && (pStatistics->uiWidth != (unsigned int) pSpatialLayerInternalParam->iActualWidth || pStatistics->uiHeight != (unsigned int) pSpatialLayerInternalParam->iActualHeight)) { pStatistics->uiResolutionChangeTimes ++; } pStatistics->uiWidth = pSpatialLayerInternalParam->iActualWidth; pStatistics->uiHeight = pSpatialLayerInternalParam->iActualHeight; const bool kbCurrentFrameSkipped = (videoFrameTypeSkip == eFrameType); pStatistics->uiInputFrameCount ++; pStatistics->uiSkippedFrameCount += (kbCurrentFrameSkipped ? 1 : 0); iMaxInputFrame = WELS_MAX (pStatistics->uiInputFrameCount, iMaxInputFrame); int32_t iProcessedFrameCount = pStatistics->uiInputFrameCount - pStatistics->uiSkippedFrameCount; if (!kbCurrentFrameSkipped && iProcessedFrameCount != 0) { pStatistics->fAverageFrameSpeedInMs += (kiCurrentFrameMs - pStatistics->fAverageFrameSpeedInMs) / iProcessedFrameCount; } // rate control related if (0 != m_pEncContext->uiStartTimestamp) { if (kiCurrentFrameTs > m_pEncContext->uiStartTimestamp + 800) { pStatistics->fAverageFrameRate = (static_cast<float> (pStatistics->uiInputFrameCount) * 1000 / (kiCurrentFrameTs - m_pEncContext->uiStartTimestamp)); } } else { m_pEncContext->uiStartTimestamp = kiCurrentFrameTs; } iMaxFrameRate = WELS_MAX (iMaxFrameRate, pStatistics->fAverageFrameRate); //pStatistics->fLatestFrameRate = m_pEncContext->pWelsSvcRc->fLatestFrameRate; //TODO: finish the calculation in RC //pStatistics->uiBitRate = m_pEncContext->pWelsSvcRc->iActualBitRate; //TODO: finish the calculation in RC pStatistics->uiAverageFrameQP = m_pEncContext->pWelsSvcRc[iDid].iAverageFrameQp; if (videoFrameTypeIDR == eFrameType || videoFrameTypeI == eFrameType) { pStatistics->uiIDRSentNum ++; } if (m_pEncContext->pLtr->bLTRMarkingFlag) { pStatistics->uiLTRSentNum ++; } pStatistics->iTotalEncodedBytes += kiCurrentFrameSize; const int32_t kiDeltaFrames = static_cast<int32_t> (pStatistics->uiInputFrameCount - pStatistics->iLastStatisticsFrameCount); if (kiDeltaFrames > (m_pEncContext->pSvcParam->fMaxFrameRate * 2)) { if (kiTimeDiff >= m_pEncContext->iStatisticsLogInterval) { pStatistics->fLatestFrameRate = static_cast<float> ((pStatistics->uiInputFrameCount - pStatistics->iLastStatisticsFrameCount) * 1000 / kiTimeDiff); pStatistics->uiBitRate = static_cast<unsigned int> ((pStatistics->iTotalEncodedBytes - pStatistics->iLastStatisticsBytes) * 8 * 1000 / kiTimeDiff); if (WELS_ABS (pStatistics->fLatestFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input fLatestFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), cur_Ts = %" PRId64 " start_Ts = %" PRId64, pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, kiCurrentFrameTs, static_cast<int64_t> (m_pEncContext->iLastStatisticsLogTs)); } if (m_pEncContext->pSvcParam->iRCMode == RC_QUALITY_MODE || m_pEncContext->pSvcParam->iRCMode == RC_BITRATE_MODE) { if ((pStatistics->fLatestFrameRate > 0) && WELS_ABS (m_pEncContext->pSvcParam->fMaxFrameRate - pStatistics->fLatestFrameRate) > 5) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input framerate %f is different from framerate in setting %f, suggest to use other rate control modes", pStatistics->fLatestFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate); } } // update variables pStatistics->iLastStatisticsBytes = pStatistics->iTotalEncodedBytes; pStatistics->iLastStatisticsFrameCount = pStatistics->uiInputFrameCount; //TODO: the following statistics will be calculated and added later //pStatistics->uiLTRSentNum } } } if (((m_pEncContext->iStatisticsLogInterval > 0) && (kiTimeDiff >= m_pEncContext->iStatisticsLogInterval)) || (0 == iMaxInputFrame % 300)) { if ((iMaxFrameRate > 0) && WELS_ABS (iMaxFrameRate - m_pEncContext->pSvcParam->fMaxFrameRate) > 30) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "Actual input framerate fAverageFrameRate = %f is quite different from framerate in setting %f, please check setting or timestamp unit (ms), start_Ts = %" PRId64, iMaxFrameRate, m_pEncContext->pSvcParam->fMaxFrameRate, m_pEncContext->uiStartTimestamp); } LogStatistics (kiCurrentFrameTs, iMaxDid); m_pEncContext->iLastStatisticsLogTs = kiCurrentFrameTs; } } /************************************************************************ * InDataFormat, IDRInterval, SVC Encode Param, Frame Rate, Bitrate,.. ************************************************************************/ int CWelsH264SVCEncoder::SetOption (ENCODER_OPTION eOptionId, void* pOption) { if (NULL == pOption) { return cmInitParaError; } if ((NULL == m_pEncContext || false == m_bInitialFlag) && eOptionId != ENCODER_OPTION_TRACE_LEVEL && eOptionId != ENCODER_OPTION_TRACE_CALLBACK && eOptionId != ENCODER_OPTION_TRACE_CALLBACK_CONTEXT) { return cmInitExpected; } switch (eOptionId) { case ENCODER_OPTION_INTER_SPATIAL_PRED: { // Inter spatial layer prediction flag WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ENCODER_OPTION_INTER_SPATIAL_PRED, this feature not supported at present."); } break; case ENCODER_OPTION_DATAFORMAT: { // Input color space int32_t iValue = * ((int32_t*)pOption); int32_t iColorspace = iValue; if (iColorspace == 0) { return cmInitParaError; } m_iCspInternal = iColorspace; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_DATAFORMAT, m_iCspInternal = 0x%x", m_iCspInternal); } break; case ENCODER_OPTION_IDR_INTERVAL: { // IDR Interval int32_t iValue = * ((int32_t*)pOption); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_IDR_INTERVAL iValue = %d", iValue); if (iValue <= -1 || iValue == 0) { iValue = 0; } if (iValue == (int32_t)m_pEncContext->pSvcParam->uiIntraPeriod) { return cmResultSuccess; } m_pEncContext->pSvcParam->uiIntraPeriod = (uint32_t)iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_IDR_INTERVAL uiIntraPeriod updated to %d", m_pEncContext->pSvcParam->uiIntraPeriod); } break; case ENCODER_OPTION_SVC_ENCODE_PARAM_BASE: { // SVC Encoding Parameter SEncParamBase sEncodingParam; SWelsSvcCodingParam sConfig; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; memcpy (&sEncodingParam, pOption, sizeof (SEncParamBase)); // confirmed_safe_unsafe_usage #ifdef OUTPUT_BIT_STREAM if ((sEncodingParam.iPicWidth != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualWidth) || (sEncodingParam.iPicHeight != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualHeight)) { ++m_iSwitchTimes; m_bSwitch = true; } #endif//OUTPUT_BIT_STREAM if (sConfig.ParamBaseTranscode (sEncodingParam)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, ParamTranscode failed!"); return cmInitParaError; } /* New configuration available here */ iTargetWidth = sConfig.iPicWidth; iTargetHeight = sConfig.iPicHeight; if (m_iMaxPicWidth != iTargetWidth || m_iMaxPicHeight != iTargetHeight) { m_iMaxPicWidth = iTargetWidth; m_iMaxPicHeight = iTargetHeight; } if (sConfig.DetermineTemporalSettings()) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, DetermineTemporalSettings failed!"); return cmInitParaError; } WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE iUsageType = %d,iPicWidth= %d;iPicHeight= %d;iTargetBitrate= %d;fMaxFrameRate= %.6ff;iRCMode= %d", sEncodingParam.iUsageType, sEncodingParam.iPicWidth, sEncodingParam.iPicHeight, sEncodingParam.iTargetBitrate, sEncodingParam.fMaxFrameRate, sEncodingParam.iRCMode); if (WelsEncoderParamAdjust (&m_pEncContext, &sConfig)) { return cmInitParaError; } //LogStatistics WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_BASE, LogStatisticsBeforeNewEncoding"); LogStatistics (m_pEncContext->iLastStatisticsLogTs, 0); } break; case ENCODER_OPTION_SVC_ENCODE_PARAM_EXT: { // SVC Encoding Parameter SEncParamExt sEncodingParam; SWelsSvcCodingParam sConfig; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; memcpy (&sEncodingParam, pOption, sizeof (SEncParamExt)); // confirmed_safe_unsafe_usage TraceParamInfo (&sEncodingParam); #ifdef OUTPUT_BIT_STREAM if ((sEncodingParam.sSpatialLayers[sEncodingParam.iSpatialLayerNum - 1].iVideoWidth != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualWidth) || (sEncodingParam.sSpatialLayers[sEncodingParam.iSpatialLayerNum - 1].iVideoHeight != m_pEncContext->pSvcParam->sDependencyLayers[m_pEncContext->pSvcParam->iSpatialLayerNum - 1].iActualHeight)) { ++ m_iSwitchTimes; m_bSwitch = true; } #endif//OUTPUT_BIT_STREAM if (sEncodingParam.iSpatialLayerNum < 1 || sEncodingParam.iSpatialLayerNum > MAX_SPATIAL_LAYER_NUM) { // verify number of spatial layer WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!", sEncodingParam.iSpatialLayerNum); return cmInitParaError; } if (sConfig.ParamTranscode (sEncodingParam)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, ParamTranscode failed!"); return cmInitParaError; } if (sConfig.iSpatialLayerNum < 1) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, iSpatialLayerNum(%d) failed!", sConfig.iSpatialLayerNum); return cmInitParaError; } if (sConfig.DetermineTemporalSettings()) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, DetermineTemporalSettings failed!"); return cmInitParaError; } /* New configuration available here */ iTargetWidth = sConfig.iPicWidth; iTargetHeight = sConfig.iPicHeight; if (m_iMaxPicWidth != iTargetWidth || m_iMaxPicHeight != iTargetHeight) { m_iMaxPicWidth = iTargetWidth; m_iMaxPicHeight = iTargetHeight; } /* Check every field whether there is new request for memory block changed or else, Oct. 24, 2008 */ if (WelsEncoderParamAdjust (&m_pEncContext, &sConfig)) { return cmInitParaError; } //LogStatistics WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, LogStatisticsBeforeNewEncoding"); LogStatistics (m_pEncContext->iLastStatisticsLogTs, sEncodingParam.iSpatialLayerNum - 1); } break; case ENCODER_OPTION_FRAME_RATE: { // Maximal input frame rate float iValue = * ((float*)pOption); if (iValue <= 0) { return cmInitParaError; } //adjust to valid range m_pEncContext->pSvcParam->fMaxFrameRate = WELS_CLIP3 (iValue, MIN_FRAME_RATE, MAX_FRAME_RATE); WelsEncoderApplyFrameRate (m_pEncContext->pSvcParam); WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_FRAME_RATE,m_pEncContext->pSvcParam->fMaxFrameRate= %f", m_pEncContext->pSvcParam->fMaxFrameRate); } break; case ENCODER_OPTION_BITRATE: { // Target bit-rate SBitrateInfo* pInfo = (static_cast<SBitrateInfo*> (pOption)); int32_t iBitrate = pInfo->iBitrate; if (iBitrate <= 0) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE,iBitrate = %d", iBitrate); return cmInitParaError; } iBitrate = WELS_CLIP3 (iBitrate, MIN_BIT_RATE, MAX_BIT_RATE); switch (pInfo->iLayer) { case SPATIAL_LAYER_ALL: m_pEncContext->pSvcParam->iTargetBitrate = iBitrate; break; case SPATIAL_LAYER_0: m_pEncContext->pSvcParam->sSpatialLayers[0].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_1: m_pEncContext->pSvcParam->sSpatialLayers[1].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_2: m_pEncContext->pSvcParam->sSpatialLayers[2].iSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_3: m_pEncContext->pSvcParam->sSpatialLayers[3].iSpatialBitrate = iBitrate; break; default: WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE,iLayer = %d", pInfo->iLayer); return cmInitParaError; break; } //adjust to valid range if (WelsEncoderApplyBitRate (&m_pWelsTrace->m_sLogCtx, m_pEncContext->pSvcParam, pInfo->iLayer)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iSpatialBitrate = %d", pInfo->iLayer, iBitrate); return cmInitParaError; } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iSpatialBitrate = %d", pInfo->iLayer, iBitrate); } } break; case ENCODER_OPTION_MAX_BITRATE: { // Target bit-rate SBitrateInfo* pInfo = (static_cast<SBitrateInfo*> (pOption)); int32_t iBitrate = pInfo->iBitrate; if (iBitrate <= 0) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_MAX_BITRATE,iBitrate = %d", iBitrate); return cmInitParaError; } iBitrate = WELS_CLIP3 (iBitrate, MIN_BIT_RATE, MAX_BIT_RATE); switch (pInfo->iLayer) { case SPATIAL_LAYER_ALL: m_pEncContext->pSvcParam->iMaxBitrate = iBitrate; break; case SPATIAL_LAYER_0: m_pEncContext->pSvcParam->sSpatialLayers[0].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_1: m_pEncContext->pSvcParam->sSpatialLayers[1].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_2: m_pEncContext->pSvcParam->sSpatialLayers[2].iMaxSpatialBitrate = iBitrate; break; case SPATIAL_LAYER_3: m_pEncContext->pSvcParam->sSpatialLayers[3].iMaxSpatialBitrate = iBitrate; break; default: WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_MAX_BITRATE,iLayer = %d", pInfo->iLayer); return cmInitParaError; break; } //adjust to valid range if (WelsEncoderApplyBitRate (&m_pWelsTrace->m_sLogCtx, m_pEncContext->pSvcParam, pInfo->iLayer)) { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iMaxSpatialBitrate = %d", pInfo->iLayer, iBitrate); return cmInitParaError; } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_BITRATE layerId= %d,iMaxSpatialBitrate = %d", pInfo->iLayer, iBitrate); } } break; case ENCODER_OPTION_RC_MODE: { // 0:quality mode;1:bit-rate mode;2:bitrate limited mode int32_t iValue = * ((int32_t*)pOption); m_pEncContext->pSvcParam->iRCMode = (RC_MODES) iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_MODE iRCMode= %d (Note: not suggest changing RC-mode in middle of encoding)", iValue); WelsRcInitFuncPointers (m_pEncContext, m_pEncContext->pSvcParam->iRCMode); } break; case ENCODER_OPTION_RC_FRAME_SKIP: { // 0:FRAME-SKIP disabled;1:FRAME-SKIP enabled bool bValue = * ((bool*)pOption); if (m_pEncContext->pSvcParam->iRCMode != RC_OFF_MODE) { m_pEncContext->pSvcParam->bEnableFrameSkip = bValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_FRAME_SKIP, frame-skip setting(%d)", bValue); } else { WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_OPTION_RC_FRAME_SKIP, rc off, frame-skip setting(%d) un-useful", bValue); } } break; case ENCODER_PADDING_PADDING: { // 0:disable padding;1:padding int32_t iValue = * ((int32_t*)pOption); m_pEncContext->pSvcParam->iPaddingFlag = iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_PADDING_PADDING iPaddingFlag= %d ", iValue); } break; case ENCODER_LTR_RECOVERY_REQUEST: { SLTRRecoverRequest* pLTR_Recover_Request = (SLTRRecoverRequest*) (pOption); FilterLTRRecoveryRequest (m_pEncContext, pLTR_Recover_Request); } break; case ENCODER_LTR_MARKING_FEEDBACK: { SLTRMarkingFeedback* fb = (SLTRMarkingFeedback*) (pOption); FilterLTRMarkingFeedback (m_pEncContext, fb); } break; case ENCODER_LTR_MARKING_PERIOD: { uint32_t iValue = * ((uint32_t*) (pOption)); m_pEncContext->pSvcParam->iLtrMarkPeriod = iValue; WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption():ENCODER_LTR_MARKING_PERIOD iLtrMarkPeriod= %d ", iValue);