/*! * \copy * Copyright (c) 2009-2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * \file encoder_ext.c * * \brief core encoder for SVC * * \date 7/24/2009 Created * ************************************************************************************* */ #include "encoder.h"#include "cpu.h"#include "utils.h"#include "svc_enc_golomb.h"#include "au_set.h"#include "picture_handle.h"#include "svc_base_layer_md.h"#include "svc_encode_slice.h"#include "svc_mode_decision.h"#include "decode_mb_aux.h"#include "deblocking.h"#include "ref_list_mgr_svc.h"#include "ls_defines.h"#include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms#include "slice_multi_threading.h"#include "measure_time.h"#include "svc_set_mb_syn.h" namespace WelsEnc { int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx, SFrameBSInfo* pFrameBsInfo, SLayerBSInfo* pLayerBsInfo, int32_t* pNalIdxInLayer, int32_t* pLayerSize, int32_t iFirstMbInPartition, // first mb inclusive in partition int32_t iEndMbInPartition, // end mb exclusive in partition int32_t iStartSliceIdx ); int32_t WelsBitRateVerification (SLogContext* pLogCtx, SSpatialLayerConfig* pLayerParam, int32_t iLayerId) { if ((pLayerParam->iSpatialBitrate <= 0) || (static_cast<float> (pLayerParam->iSpatialBitrate) < pLayerParam->fFrameRate)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in layer %d, bitrate= %d at FrameRate(%f)", iLayerId, pLayerParam->iSpatialBitrate, pLayerParam->fFrameRate); return ENC_RETURN_UNSUPPORTED_PARA; } // deal with LEVEL_MAX_BR and MAX_BR setting const int32_t iLevelMaxBitrate = (pLayerParam->uiLevelIdc != LEVEL_UNKNOWN) ? (g_ksLevelLimits[pLayerParam->uiLevelIdc - 1].uiMaxBR * CpbBrNalFactor) : UNSPECIFIED_BIT_RATE; const int32_t iLevel52MaxBitrate = g_ksLevelLimits[LEVEL_NUMBER - 1].uiMaxBR * CpbBrNalFactor; if (UNSPECIFIED_BIT_RATE != iLevelMaxBitrate) { if ((pLayerParam->iMaxSpatialBitrate == UNSPECIFIED_BIT_RATE) || (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) { pLayerParam->iMaxSpatialBitrate = iLevelMaxBitrate; WelsLog (pLogCtx, WELS_LOG_INFO, "Current MaxSpatialBitrate is invalid (UNSPECIFIED_BIT_RATE or larger than LEVEL5_2) but level setting is valid, set iMaxSpatialBitrate to %d from level (%d)", pLayerParam->iMaxSpatialBitrate, pLayerParam->uiLevelIdc); } else if (pLayerParam->iMaxSpatialBitrate > iLevelMaxBitrate) { ELevelIdc iCurLevel = pLayerParam->uiLevelIdc; WelsAdjustLevel (pLayerParam); WelsLog (pLogCtx, WELS_LOG_INFO, "LevelIdc is changed from (%d) to (%d) according to the iMaxSpatialBitrate(%d)", iCurLevel, pLayerParam->uiLevelIdc, pLayerParam->iMaxSpatialBitrate); } } else if ((pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE) && (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) { // no level limitation, just need to check if iMaxSpatialBitrate is too big from reasonable WelsLog (pLogCtx, WELS_LOG_WARNING, "No LevelIdc setting and iMaxSpatialBitrate (%d) is considered too big to be valid, changed to UNSPECIFIED_BIT_RATE", pLayerParam->iMaxSpatialBitrate); pLayerParam->iMaxSpatialBitrate = UNSPECIFIED_BIT_RATE; } // deal with iSpatialBitrate and iMaxSpatialBitrate setting if (pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE) { if (pLayerParam->iMaxSpatialBitrate == pLayerParam->iSpatialBitrate) { WelsLog (pLogCtx, WELS_LOG_INFO, "Setting MaxSpatialBitrate (%d) the same at SpatialBitrate (%d) will make the actual bit rate lower than SpatialBitrate", pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate); } else if (pLayerParam->iMaxSpatialBitrate < pLayerParam->iSpatialBitrate) { WelsLog (pLogCtx, WELS_LOG_ERROR, "MaxSpatialBitrate (%d) should be larger than SpatialBitrate (%d), considering it as error setting", pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate); return ENC_RETURN_UNSUPPORTED_PARA; } } return ENC_RETURN_SUCCESS;} void CheckProfileSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, EProfileIdc uiProfileIdc) { SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer]; if (PRO_UNKNOWN == uiProfileIdc) { pLayerInfo->uiProfileIdc = (((iLayer == SPATIAL_LAYER_0) || pParam->bSimulcastAVC) ? PRO_BASELINE : PRO_SCALABLE_BASELINE); } else { pLayerInfo->uiProfileIdc = uiProfileIdc; if ((iLayer == SPATIAL_LAYER_0) && (uiProfileIdc != PRO_BASELINE)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d), change to baseline profile", uiProfileIdc); pLayerInfo->uiProfileIdc = PRO_BASELINE; } if (iLayer > SPATIAL_LAYER_0) { if (pParam->bSimulcastAVC && (uiProfileIdc != PRO_BASELINE)) { pLayerInfo->uiProfileIdc = PRO_BASELINE; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d) with bSimulcastAVC, change to baseline profile", uiProfileIdc); } if ((uiProfileIdc != PRO_BASELINE) || (uiProfileIdc != PRO_SCALABLE_BASELINE)) { pLayerInfo->uiProfileIdc = PRO_BASELINE; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d), change to baseline profile", uiProfileIdc); } } }}void CheckLevelSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, ELevelIdc uiLevelIdc) { SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer]; pLayerInfo->uiLevelIdc = uiLevelIdc; if (uiLevelIdc > LEVEL_5_2) { WelsLog (pLogCtx, WELS_LOG_INFO, "change unexpected levelidc(%d) setting to LEVEL_UNKNOWN", pLayerInfo->uiLevelIdc); pLayerInfo->uiLevelIdc = LEVEL_UNKNOWN; }}void CheckReferenceNumSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iNumRef) { int32_t iRefUpperBound = (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME) ? MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA : MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN; pParam->iNumRefFrame = iNumRef; if ((iNumRef < MIN_REF_PIC_COUNT) || (iNumRef > iRefUpperBound)) { pParam->iNumRefFrame = AUTO_REF_PIC_COUNT; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support the number of reference frame(%d) change to auto select mode", iNumRef); }} int32_t SliceArgumentValidationFixedSliceMode (SLogContext* pLogCtx, SSliceArgument* pSliceArgument, const RC_MODES kiRCMode, const int32_t kiPicWidth, const int32_t kiPicHeight) { int32_t iCpuCores = 0; int32_t iIdx = 0; const int32_t iMbWidth = (kiPicWidth + 15) >> 4; const int32_t iMbHeight = (kiPicHeight + 15) >> 4; const int32_t iMbNumInFrame = iMbWidth * iMbHeight; bool bSingleMode = false; pSliceArgument->uiSliceSizeConstraint = 0; if (pSliceArgument->uiSliceNum == 0) { WelsCPUFeatureDetect (&iCpuCores); if (0 == iCpuCores) { // cpuid not supported or doesn't expose the number of cores, // use high level system API as followed to detect number of pysical/logic processor iCpuCores = DynamicDetectCpuCores(); } pSliceArgument->uiSliceNum = iCpuCores; } if (pSliceArgument->uiSliceNum <= 1) { WelsLog (pLogCtx, WELS_LOG_INFO, "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!", pSliceArgument->uiSliceNum); bSingleMode = true; } // considering the coding efficient and performance, // iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting if (iMbNumInFrame <= MIN_NUM_MB_PER_SLICE) { WelsLog (pLogCtx, WELS_LOG_INFO, "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type as CountMbNum less than MIN_NUM_MB_PER_SLICE!", pSliceArgument->uiSliceNum); bSingleMode = true; } if (bSingleMode) { pSliceArgument->uiSliceMode = SM_SINGLE_SLICE; pSliceArgument->uiSliceNum = 1; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSliceArgument->uiSliceMbNum[iIdx] = 0; } return ENC_RETURN_SUCCESS; } if (pSliceArgument->uiSliceNum > MAX_SLICES_NUM) { pSliceArgument->uiSliceNum = MAX_SLICES_NUM; WelsLog (pLogCtx, WELS_LOG_WARNING, "SliceArgumentValidationFixedSliceMode(), uiSliceNum exceed MAX_SLICES_NUM! So setting slice num eqaul to MAX_SLICES_NUM(%d)!", pSliceArgument->uiSliceNum); } if (kiRCMode != RC_OFF_MODE) { // multiple slices verify with gom //check uiSliceNum and set uiSliceMbNum with current uiSliceNum if (!GomValidCheckSliceNum (iMbWidth, iMbHeight, &pSliceArgument->uiSliceNum)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum combination under RC on! So uiSliceNum is changed to %d!", pSliceArgument->uiSliceNum); } if (pSliceArgument->uiSliceNum <= 1 || !GomValidCheckSliceMbNum (iMbWidth, iMbHeight, pSliceArgument)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum (%d) combination under RC on! Consider setting single slice with this resolution!", pSliceArgument->uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, pSliceArgument)) { //check uiSliceMbNum with current uiSliceNum WelsLog (pLogCtx, WELS_LOG_ERROR, "SliceArgumentValidationFixedSliceMode(), invalid uiSliceMbNum (%d) settings!,now turn to SM_SINGLE_SLICE type", pSliceArgument->uiSliceMbNum[0]); pSliceArgument->uiSliceMode = SM_SINGLE_SLICE; pSliceArgument->uiSliceNum = 1; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSliceArgument->uiSliceMbNum[iIdx] = 0; } } return ENC_RETURN_SUCCESS;} /*! * \brief validate checking in parameter configuration * \pParam pParam SWelsSvcCodingParam* * \return successful - 0; otherwise none 0 for failed */int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) { const float fEpsn = 0.000001f; int32_t i = 0; assert (pCfg != NULL); if ((pCfg->iUsageType != CAMERA_VIDEO_REAL_TIME) && (pCfg->iUsageType != SCREEN_CONTENT_REAL_TIME)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid usage type = %d", pCfg->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { if (pCfg->iSpatialLayerNum > 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid the number of Spatial layer(%d)for screen content", pCfg->iSpatialLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCfg->bEnableAdaptiveQuant) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidation(), AdaptiveQuant(%d) is not supported yet for screen content, auto turned off", pCfg->bEnableAdaptiveQuant); pCfg->bEnableAdaptiveQuant = false; } if (pCfg->bEnableSceneChangeDetect == false) { pCfg->bEnableSceneChangeDetect = true; WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidation(), screen change detection should be turned on, change bEnableSceneChangeDetect as true"); } } if (pCfg->iSpatialLayerNum > 1) { for (i = pCfg->iSpatialLayerNum - 1; i > 0; i--) { SSpatialLayerConfig* fDlpUp = &pCfg->sSpatialLayers[i]; SSpatialLayerConfig* fDlp = &pCfg->sSpatialLayers[i - 1]; if ((fDlp->iVideoWidth > fDlpUp->iVideoWidth) || (fDlp->iVideoHeight > fDlpUp->iVideoHeight)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation,Invalid resolution layer(%d) resolution(%d x %d) should be less than the upper spatial layer resolution(%d x %d) ", i, fDlp->iVideoWidth, fDlp->iVideoHeight, fDlpUp->iVideoWidth, fDlpUp->iVideoHeight); return ENC_RETURN_UNSUPPORTED_PARA; } } } if (!CheckInRangeCloseOpen (pCfg->iLoopFilterDisableIdc, DEBLOCKING_IDC_0, DEBLOCKING_IDC_2 + 1) || !CheckInRangeCloseOpen (pCfg->iLoopFilterAlphaC0Offset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1) || !CheckInRangeCloseOpen (pCfg->iLoopFilterBetaOffset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation, Invalid iLoopFilterDisableIdc(%d) or iLoopFilterAlphaC0Offset(%d) or iLoopFilterBetaOffset(%d)!", pCfg->iLoopFilterDisableIdc, pCfg->iLoopFilterAlphaC0Offset, pCfg->iLoopFilterBetaOffset); return ENC_RETURN_UNSUPPORTED_PARA; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[i]; SSpatialLayerConfig* pConfig = &pCfg->sSpatialLayers[i]; if (fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn && fDlp->fInputFrameRate <= fEpsn) || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "AUTO CORRECT: Invalid settings in input frame rate(%.6f) and output frame rate(%.6f) of layer #%d config file: iResult of output frame rate divided by input frame rate should be power of 2(i.e,in/pOut=2^n). \n Auto correcting Output Framerate to Input Framerate %f!\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i, fDlp->fInputFrameRate); fDlp->fOutputFrameRate = fDlp->fInputFrameRate; pConfig->fFrameRate = fDlp->fOutputFrameRate; } } if ((pCfg->iRCMode != RC_OFF_MODE) && (pCfg->iRCMode != RC_QUALITY_MODE) && (pCfg->iRCMode != RC_BUFFERBASED_MODE) && (pCfg->iRCMode != RC_BITRATE_MODE) && (pCfg->iRCMode != RC_TIMESTAMP_MODE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid iRCMode = %d", pCfg->iRCMode); return ENC_RETURN_UNSUPPORTED_PARA; } //bitrate setting validation if (pCfg->iRCMode != RC_OFF_MODE) { int32_t iTotalBitrate = 0; if (pCfg->iTargetBitrate <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in total configure, bitrate= %d", pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCfg->sSpatialLayers[i]; iTotalBitrate += pSpatialLayer->iSpatialBitrate; if (WelsBitRateVerification (pLogCtx, pSpatialLayer, i) != ENC_RETURN_SUCCESS) return ENC_RETURN_INVALIDINPUT; } if (iTotalBitrate > pCfg->iTargetBitrate) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid settings in bitrate. the sum of each layer bitrate(%d) is larger than total bitrate setting(%d)", iTotalBitrate, pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } if ((pCfg->iRCMode == RC_QUALITY_MODE) || (pCfg->iRCMode == RC_BITRATE_MODE) || (pCfg->iRCMode == RC_TIMESTAMP_MODE)) if (!pCfg->bEnableFrameSkip) WelsLog (pLogCtx, WELS_LOG_WARNING, "bEnableFrameSkip = %d,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.", pCfg->bEnableFrameSkip); if (pCfg->iRCMode == RC_QUALITY_MODE) { pCfg->iMinQp = GOM_MIN_QP_MODE; pCfg->iMaxQp = GOM_MAX_QP_MODE; } else if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { pCfg->iMinQp = MIN_SCREEN_QP; pCfg->iMaxQp = MAX_SCREEN_QP; } else { pCfg->iMinQp = WELS_CLIP3 (pCfg->iMinQp , GOM_MIN_QP_MODE, 51); pCfg->iMaxQp = WELS_CLIP3 (pCfg->iMaxQp , 0, 51); if (pCfg->iMaxQp <= pCfg->iMinQp) pCfg->iMaxQp = 51; } } // ref-frames validation if (((pCfg->iUsageType == CAMERA_VIDEO_REAL_TIME) || (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME)) ? WelsCheckRefFrameLimitationNumRefFirst (pLogCtx, pCfg) : WelsCheckRefFrameLimitationLevelIdcFirst (pLogCtx, pCfg)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsCheckRefFrameLimitation failed"); return ENC_RETURN_INVALIDINPUT; } return ENC_RETURN_SUCCESS;} int32_t ParamValidationExt (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingParam) { int8_t i = 0; int32_t iIdx = 0; assert (pCodingParam != NULL); if (NULL == pCodingParam) return ENC_RETURN_INVALIDINPUT; if ((pCodingParam->iUsageType != CAMERA_VIDEO_REAL_TIME) && (pCodingParam->iUsageType != SCREEN_CONTENT_REAL_TIME)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(),Invalid usage type = %d", pCodingParam->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if ((pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME) && (!pCodingParam->bIsLosslessLink && pCodingParam->bEnableLongTermReference)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), setting lossy link for LTR under screen, which is not supported yet! Auto disabled LTR!"); pCodingParam->bEnableLongTermReference = false; } if (pCodingParam->iSpatialLayerNum < 1 || pCodingParam->iSpatialLayerNum > MAX_DEPENDENCY_LAYER) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iSpatialLayerNum: %d!", pCodingParam->iSpatialLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->iTemporalLayerNum < 1 || pCodingParam->iTemporalLayerNum > MAX_TEMPORAL_LEVEL) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iTemporalLayerNum: %d!", pCodingParam->iTemporalLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!", pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize - 1)) != 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } //about iMultipleThreadIdc, bDeblockingParallelFlag, iLoopFilterDisableIdc, & uiSliceMode // (1) Single Thread // if (THREAD==1)//single thread // no parallel_deblocking: bDeblockingParallelFlag = 0; // (2) Multi Thread: see uiSliceMode decision if (pCodingParam->iMultipleThreadIdc == 1) { //now is single thread. no parallel deblocking, set flag=0 pCodingParam->bDeblockingParallelFlag = false; } else { pCodingParam->bDeblockingParallelFlag = true; } // eSpsPpsIdStrategy checkings if (pCodingParam->iSpatialLayerNum > 1 && (!pCodingParam->bSimulcastAVC) && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with multiple svc SpatialLayers (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->iSpatialLayerNum); pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID; } if (pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with iUsageType (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->iUsageType); pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID; } if (pCodingParam->bSimulcastAVC && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_INFO, "ParamValidationExt(), eSpsPpsIdStrategy(%d) under bSimulcastAVC(%d) not supported yet, adjusted to INCREASING_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC); pCodingParam->eSpsPpsIdStrategy = INCREASING_ID; } if (pCodingParam->bSimulcastAVC && pCodingParam->bPrefixNalAddingCtrl) { WelsLog (pLogCtx, WELS_LOG_INFO, "ParamValidationExt(), bSimulcastAVC(%d) is not compatible with bPrefixNalAddingCtrl(%d) true, adjusted bPrefixNalAddingCtrl to false", pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC); pCodingParam->bPrefixNalAddingCtrl = false; } for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCodingParam->sSpatialLayers[i]; const int32_t kiPicWidth = pSpatialLayer->iVideoWidth; const int32_t kiPicHeight = pSpatialLayer->iVideoHeight; uint32_t iMbWidth = 0; uint32_t iMbHeight = 0; int32_t iMbNumInFrame = 0; uint32_t iMaxSliceNum = MAX_SLICES_NUM; int32_t iReturn = 0; if ((kiPicWidth <= 0) || (kiPicHeight <= 0) || (kiPicWidth > MAX_WIDTH) || (kiPicHeight > MAX_HEIGHT)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(),width(1-%d),height(1-%d)invalid %d x %d in dependency layer settings!", MAX_WIDTH, MAX_HEIGHT, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; } if ((kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), in layer #%d iWidth x iHeight(%d x %d) both should be multiple of 16, can not support with arbitrary size currently!", i, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; } Lines 1–500 of 4997. Load more
/*! * \copy * Copyright (c) 2009-2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * \file encoder_ext.c * * \brief core encoder for SVC * * \date 7/24/2009 Created * ************************************************************************************* */ #include "encoder.h" #include "cpu.h" #include "utils.h" #include "svc_enc_golomb.h" #include "au_set.h" #include "picture_handle.h" #include "svc_base_layer_md.h" #include "svc_encode_slice.h" #include "svc_mode_decision.h" #include "decode_mb_aux.h" #include "deblocking.h" #include "ref_list_mgr_svc.h" #include "ls_defines.h" #include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms #include "slice_multi_threading.h" #include "measure_time.h" #include "svc_set_mb_syn.h" namespace WelsEnc { int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx, SFrameBSInfo* pFrameBsInfo, SLayerBSInfo* pLayerBsInfo, int32_t* pNalIdxInLayer, int32_t* pLayerSize, int32_t iFirstMbInPartition, // first mb inclusive in partition int32_t iEndMbInPartition, // end mb exclusive in partition int32_t iStartSliceIdx ); int32_t WelsBitRateVerification (SLogContext* pLogCtx, SSpatialLayerConfig* pLayerParam, int32_t iLayerId) { if ((pLayerParam->iSpatialBitrate <= 0) || (static_cast<float> (pLayerParam->iSpatialBitrate) < pLayerParam->fFrameRate)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in layer %d, bitrate= %d at FrameRate(%f)", iLayerId, pLayerParam->iSpatialBitrate, pLayerParam->fFrameRate); return ENC_RETURN_UNSUPPORTED_PARA; } // deal with LEVEL_MAX_BR and MAX_BR setting const int32_t iLevelMaxBitrate = (pLayerParam->uiLevelIdc != LEVEL_UNKNOWN) ? (g_ksLevelLimits[pLayerParam->uiLevelIdc - 1].uiMaxBR * CpbBrNalFactor) : UNSPECIFIED_BIT_RATE; const int32_t iLevel52MaxBitrate = g_ksLevelLimits[LEVEL_NUMBER - 1].uiMaxBR * CpbBrNalFactor; if (UNSPECIFIED_BIT_RATE != iLevelMaxBitrate) { if ((pLayerParam->iMaxSpatialBitrate == UNSPECIFIED_BIT_RATE) || (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) { pLayerParam->iMaxSpatialBitrate = iLevelMaxBitrate; WelsLog (pLogCtx, WELS_LOG_INFO, "Current MaxSpatialBitrate is invalid (UNSPECIFIED_BIT_RATE or larger than LEVEL5_2) but level setting is valid, set iMaxSpatialBitrate to %d from level (%d)", pLayerParam->iMaxSpatialBitrate, pLayerParam->uiLevelIdc); } else if (pLayerParam->iMaxSpatialBitrate > iLevelMaxBitrate) { ELevelIdc iCurLevel = pLayerParam->uiLevelIdc; WelsAdjustLevel (pLayerParam); WelsLog (pLogCtx, WELS_LOG_INFO, "LevelIdc is changed from (%d) to (%d) according to the iMaxSpatialBitrate(%d)", iCurLevel, pLayerParam->uiLevelIdc, pLayerParam->iMaxSpatialBitrate); } } else if ((pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE) && (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) { // no level limitation, just need to check if iMaxSpatialBitrate is too big from reasonable WelsLog (pLogCtx, WELS_LOG_WARNING, "No LevelIdc setting and iMaxSpatialBitrate (%d) is considered too big to be valid, changed to UNSPECIFIED_BIT_RATE", pLayerParam->iMaxSpatialBitrate); pLayerParam->iMaxSpatialBitrate = UNSPECIFIED_BIT_RATE; } // deal with iSpatialBitrate and iMaxSpatialBitrate setting if (pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE) { if (pLayerParam->iMaxSpatialBitrate == pLayerParam->iSpatialBitrate) { WelsLog (pLogCtx, WELS_LOG_INFO, "Setting MaxSpatialBitrate (%d) the same at SpatialBitrate (%d) will make the actual bit rate lower than SpatialBitrate", pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate); } else if (pLayerParam->iMaxSpatialBitrate < pLayerParam->iSpatialBitrate) { WelsLog (pLogCtx, WELS_LOG_ERROR, "MaxSpatialBitrate (%d) should be larger than SpatialBitrate (%d), considering it as error setting", pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate); return ENC_RETURN_UNSUPPORTED_PARA; } } return ENC_RETURN_SUCCESS; } void CheckProfileSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, EProfileIdc uiProfileIdc) { SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer]; if (PRO_UNKNOWN == uiProfileIdc) { pLayerInfo->uiProfileIdc = (((iLayer == SPATIAL_LAYER_0) || pParam->bSimulcastAVC) ? PRO_BASELINE : PRO_SCALABLE_BASELINE); } else { pLayerInfo->uiProfileIdc = uiProfileIdc; if ((iLayer == SPATIAL_LAYER_0) && (uiProfileIdc != PRO_BASELINE)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d), change to baseline profile", uiProfileIdc); pLayerInfo->uiProfileIdc = PRO_BASELINE; } if (iLayer > SPATIAL_LAYER_0) { if (pParam->bSimulcastAVC && (uiProfileIdc != PRO_BASELINE)) { pLayerInfo->uiProfileIdc = PRO_BASELINE; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d) with bSimulcastAVC, change to baseline profile", uiProfileIdc); } if ((uiProfileIdc != PRO_BASELINE) || (uiProfileIdc != PRO_SCALABLE_BASELINE)) { pLayerInfo->uiProfileIdc = PRO_BASELINE; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support profile(%d), change to baseline profile", uiProfileIdc); } } } } void CheckLevelSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, ELevelIdc uiLevelIdc) { SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer]; pLayerInfo->uiLevelIdc = uiLevelIdc; if (uiLevelIdc > LEVEL_5_2) { WelsLog (pLogCtx, WELS_LOG_INFO, "change unexpected levelidc(%d) setting to LEVEL_UNKNOWN", pLayerInfo->uiLevelIdc); pLayerInfo->uiLevelIdc = LEVEL_UNKNOWN; } } void CheckReferenceNumSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iNumRef) { int32_t iRefUpperBound = (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME) ? MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA : MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN; pParam->iNumRefFrame = iNumRef; if ((iNumRef < MIN_REF_PIC_COUNT) || (iNumRef > iRefUpperBound)) { pParam->iNumRefFrame = AUTO_REF_PIC_COUNT; WelsLog (pLogCtx, WELS_LOG_WARNING, "doesn't support the number of reference frame(%d) change to auto select mode", iNumRef); } } int32_t SliceArgumentValidationFixedSliceMode (SLogContext* pLogCtx, SSliceArgument* pSliceArgument, const RC_MODES kiRCMode, const int32_t kiPicWidth, const int32_t kiPicHeight) { int32_t iCpuCores = 0; int32_t iIdx = 0; const int32_t iMbWidth = (kiPicWidth + 15) >> 4; const int32_t iMbHeight = (kiPicHeight + 15) >> 4; const int32_t iMbNumInFrame = iMbWidth * iMbHeight; bool bSingleMode = false; pSliceArgument->uiSliceSizeConstraint = 0; if (pSliceArgument->uiSliceNum == 0) { WelsCPUFeatureDetect (&iCpuCores); if (0 == iCpuCores) { // cpuid not supported or doesn't expose the number of cores, // use high level system API as followed to detect number of pysical/logic processor iCpuCores = DynamicDetectCpuCores(); } pSliceArgument->uiSliceNum = iCpuCores; } if (pSliceArgument->uiSliceNum <= 1) { WelsLog (pLogCtx, WELS_LOG_INFO, "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!", pSliceArgument->uiSliceNum); bSingleMode = true; } // considering the coding efficient and performance, // iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting if (iMbNumInFrame <= MIN_NUM_MB_PER_SLICE) { WelsLog (pLogCtx, WELS_LOG_INFO, "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type as CountMbNum less than MIN_NUM_MB_PER_SLICE!", pSliceArgument->uiSliceNum); bSingleMode = true; } if (bSingleMode) { pSliceArgument->uiSliceMode = SM_SINGLE_SLICE; pSliceArgument->uiSliceNum = 1; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSliceArgument->uiSliceMbNum[iIdx] = 0; } return ENC_RETURN_SUCCESS; } if (pSliceArgument->uiSliceNum > MAX_SLICES_NUM) { pSliceArgument->uiSliceNum = MAX_SLICES_NUM; WelsLog (pLogCtx, WELS_LOG_WARNING, "SliceArgumentValidationFixedSliceMode(), uiSliceNum exceed MAX_SLICES_NUM! So setting slice num eqaul to MAX_SLICES_NUM(%d)!", pSliceArgument->uiSliceNum); } if (kiRCMode != RC_OFF_MODE) { // multiple slices verify with gom //check uiSliceNum and set uiSliceMbNum with current uiSliceNum if (!GomValidCheckSliceNum (iMbWidth, iMbHeight, &pSliceArgument->uiSliceNum)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum combination under RC on! So uiSliceNum is changed to %d!", pSliceArgument->uiSliceNum); } if (pSliceArgument->uiSliceNum <= 1 || !GomValidCheckSliceMbNum (iMbWidth, iMbHeight, pSliceArgument)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum (%d) combination under RC on! Consider setting single slice with this resolution!", pSliceArgument->uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, pSliceArgument)) { //check uiSliceMbNum with current uiSliceNum WelsLog (pLogCtx, WELS_LOG_ERROR, "SliceArgumentValidationFixedSliceMode(), invalid uiSliceMbNum (%d) settings!,now turn to SM_SINGLE_SLICE type", pSliceArgument->uiSliceMbNum[0]); pSliceArgument->uiSliceMode = SM_SINGLE_SLICE; pSliceArgument->uiSliceNum = 1; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSliceArgument->uiSliceMbNum[iIdx] = 0; } } return ENC_RETURN_SUCCESS; } /*! * \brief validate checking in parameter configuration * \pParam pParam SWelsSvcCodingParam* * \return successful - 0; otherwise none 0 for failed */ int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) { const float fEpsn = 0.000001f; int32_t i = 0; assert (pCfg != NULL); if ((pCfg->iUsageType != CAMERA_VIDEO_REAL_TIME) && (pCfg->iUsageType != SCREEN_CONTENT_REAL_TIME)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid usage type = %d", pCfg->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { if (pCfg->iSpatialLayerNum > 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid the number of Spatial layer(%d)for screen content", pCfg->iSpatialLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCfg->bEnableAdaptiveQuant) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidation(), AdaptiveQuant(%d) is not supported yet for screen content, auto turned off", pCfg->bEnableAdaptiveQuant); pCfg->bEnableAdaptiveQuant = false; } if (pCfg->bEnableSceneChangeDetect == false) { pCfg->bEnableSceneChangeDetect = true; WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidation(), screen change detection should be turned on, change bEnableSceneChangeDetect as true"); } } if (pCfg->iSpatialLayerNum > 1) { for (i = pCfg->iSpatialLayerNum - 1; i > 0; i--) { SSpatialLayerConfig* fDlpUp = &pCfg->sSpatialLayers[i]; SSpatialLayerConfig* fDlp = &pCfg->sSpatialLayers[i - 1]; if ((fDlp->iVideoWidth > fDlpUp->iVideoWidth) || (fDlp->iVideoHeight > fDlpUp->iVideoHeight)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation,Invalid resolution layer(%d) resolution(%d x %d) should be less than the upper spatial layer resolution(%d x %d) ", i, fDlp->iVideoWidth, fDlp->iVideoHeight, fDlpUp->iVideoWidth, fDlpUp->iVideoHeight); return ENC_RETURN_UNSUPPORTED_PARA; } } } if (!CheckInRangeCloseOpen (pCfg->iLoopFilterDisableIdc, DEBLOCKING_IDC_0, DEBLOCKING_IDC_2 + 1) || !CheckInRangeCloseOpen (pCfg->iLoopFilterAlphaC0Offset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1) || !CheckInRangeCloseOpen (pCfg->iLoopFilterBetaOffset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation, Invalid iLoopFilterDisableIdc(%d) or iLoopFilterAlphaC0Offset(%d) or iLoopFilterBetaOffset(%d)!", pCfg->iLoopFilterDisableIdc, pCfg->iLoopFilterAlphaC0Offset, pCfg->iLoopFilterBetaOffset); return ENC_RETURN_UNSUPPORTED_PARA; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[i]; SSpatialLayerConfig* pConfig = &pCfg->sSpatialLayers[i]; if (fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn && fDlp->fInputFrameRate <= fEpsn) || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "AUTO CORRECT: Invalid settings in input frame rate(%.6f) and output frame rate(%.6f) of layer #%d config file: iResult of output frame rate divided by input frame rate should be power of 2(i.e,in/pOut=2^n). \n Auto correcting Output Framerate to Input Framerate %f!\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i, fDlp->fInputFrameRate); fDlp->fOutputFrameRate = fDlp->fInputFrameRate; pConfig->fFrameRate = fDlp->fOutputFrameRate; } } if ((pCfg->iRCMode != RC_OFF_MODE) && (pCfg->iRCMode != RC_QUALITY_MODE) && (pCfg->iRCMode != RC_BUFFERBASED_MODE) && (pCfg->iRCMode != RC_BITRATE_MODE) && (pCfg->iRCMode != RC_TIMESTAMP_MODE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid iRCMode = %d", pCfg->iRCMode); return ENC_RETURN_UNSUPPORTED_PARA; } //bitrate setting validation if (pCfg->iRCMode != RC_OFF_MODE) { int32_t iTotalBitrate = 0; if (pCfg->iTargetBitrate <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in total configure, bitrate= %d", pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCfg->sSpatialLayers[i]; iTotalBitrate += pSpatialLayer->iSpatialBitrate; if (WelsBitRateVerification (pLogCtx, pSpatialLayer, i) != ENC_RETURN_SUCCESS) return ENC_RETURN_INVALIDINPUT; } if (iTotalBitrate > pCfg->iTargetBitrate) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid settings in bitrate. the sum of each layer bitrate(%d) is larger than total bitrate setting(%d)", iTotalBitrate, pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } if ((pCfg->iRCMode == RC_QUALITY_MODE) || (pCfg->iRCMode == RC_BITRATE_MODE) || (pCfg->iRCMode == RC_TIMESTAMP_MODE)) if (!pCfg->bEnableFrameSkip) WelsLog (pLogCtx, WELS_LOG_WARNING, "bEnableFrameSkip = %d,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.", pCfg->bEnableFrameSkip); if (pCfg->iRCMode == RC_QUALITY_MODE) { pCfg->iMinQp = GOM_MIN_QP_MODE; pCfg->iMaxQp = GOM_MAX_QP_MODE; } else if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) { pCfg->iMinQp = MIN_SCREEN_QP; pCfg->iMaxQp = MAX_SCREEN_QP; } else { pCfg->iMinQp = WELS_CLIP3 (pCfg->iMinQp , GOM_MIN_QP_MODE, 51); pCfg->iMaxQp = WELS_CLIP3 (pCfg->iMaxQp , 0, 51); if (pCfg->iMaxQp <= pCfg->iMinQp) pCfg->iMaxQp = 51; } } // ref-frames validation if (((pCfg->iUsageType == CAMERA_VIDEO_REAL_TIME) || (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME)) ? WelsCheckRefFrameLimitationNumRefFirst (pLogCtx, pCfg) : WelsCheckRefFrameLimitationLevelIdcFirst (pLogCtx, pCfg)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsCheckRefFrameLimitation failed"); return ENC_RETURN_INVALIDINPUT; } return ENC_RETURN_SUCCESS; } int32_t ParamValidationExt (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingParam) { int8_t i = 0; int32_t iIdx = 0; assert (pCodingParam != NULL); if (NULL == pCodingParam) return ENC_RETURN_INVALIDINPUT; if ((pCodingParam->iUsageType != CAMERA_VIDEO_REAL_TIME) && (pCodingParam->iUsageType != SCREEN_CONTENT_REAL_TIME)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(),Invalid usage type = %d", pCodingParam->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if ((pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME) && (!pCodingParam->bIsLosslessLink && pCodingParam->bEnableLongTermReference)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), setting lossy link for LTR under screen, which is not supported yet! Auto disabled LTR!"); pCodingParam->bEnableLongTermReference = false; } if (pCodingParam->iSpatialLayerNum < 1 || pCodingParam->iSpatialLayerNum > MAX_DEPENDENCY_LAYER) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iSpatialLayerNum: %d!", pCodingParam->iSpatialLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->iTemporalLayerNum < 1 || pCodingParam->iTemporalLayerNum > MAX_TEMPORAL_LEVEL) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iTemporalLayerNum: %d!", pCodingParam->iTemporalLayerNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!", pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize - 1)) != 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); return ENC_RETURN_UNSUPPORTED_PARA; } //about iMultipleThreadIdc, bDeblockingParallelFlag, iLoopFilterDisableIdc, & uiSliceMode // (1) Single Thread // if (THREAD==1)//single thread // no parallel_deblocking: bDeblockingParallelFlag = 0; // (2) Multi Thread: see uiSliceMode decision if (pCodingParam->iMultipleThreadIdc == 1) { //now is single thread. no parallel deblocking, set flag=0 pCodingParam->bDeblockingParallelFlag = false; } else { pCodingParam->bDeblockingParallelFlag = true; } // eSpsPpsIdStrategy checkings if (pCodingParam->iSpatialLayerNum > 1 && (!pCodingParam->bSimulcastAVC) && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with multiple svc SpatialLayers (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->iSpatialLayerNum); pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID; } if (pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with iUsageType (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->iUsageType); pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID; } if (pCodingParam->bSimulcastAVC && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { WelsLog (pLogCtx, WELS_LOG_INFO, "ParamValidationExt(), eSpsPpsIdStrategy(%d) under bSimulcastAVC(%d) not supported yet, adjusted to INCREASING_ID", pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC); pCodingParam->eSpsPpsIdStrategy = INCREASING_ID; } if (pCodingParam->bSimulcastAVC && pCodingParam->bPrefixNalAddingCtrl) { WelsLog (pLogCtx, WELS_LOG_INFO, "ParamValidationExt(), bSimulcastAVC(%d) is not compatible with bPrefixNalAddingCtrl(%d) true, adjusted bPrefixNalAddingCtrl to false", pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC); pCodingParam->bPrefixNalAddingCtrl = false; } for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCodingParam->sSpatialLayers[i]; const int32_t kiPicWidth = pSpatialLayer->iVideoWidth; const int32_t kiPicHeight = pSpatialLayer->iVideoHeight; uint32_t iMbWidth = 0; uint32_t iMbHeight = 0; int32_t iMbNumInFrame = 0; uint32_t iMaxSliceNum = MAX_SLICES_NUM; int32_t iReturn = 0; if ((kiPicWidth <= 0) || (kiPicHeight <= 0) || (kiPicWidth > MAX_WIDTH) || (kiPicHeight > MAX_HEIGHT)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(),width(1-%d),height(1-%d)invalid %d x %d in dependency layer settings!", MAX_WIDTH, MAX_HEIGHT, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; } if ((kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), in layer #%d iWidth x iHeight(%d x %d) both should be multiple of 16, can not support with arbitrary size currently!", i, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; }