/*! * \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" namespace WelsSVCEnc { 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 ); /*! * \brief validate checking in parameter configuration * \pParam pParam SWelsSvcCodingParam* * \return successful - 0; otherwise none 0 for failed */int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) { float fMaxFrameRate = 0.0f; 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\n", 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\n", 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\n", 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\n"); } } if (pCfg->iSpatialLayerNum > 1) { int32_t iFinalWidth = pCfg->sSpatialLayers[pCfg->iSpatialLayerNum - 1].iVideoWidth; int32_t iFinalHeight = pCfg->sSpatialLayers[pCfg->iSpatialLayerNum - 1].iVideoHeight; for (i = 0; i < (pCfg->iSpatialLayerNum - 1); i++) { SSpatialLayerConfig* fDlp = &pCfg->sSpatialLayers[i]; if ((fDlp->iVideoWidth > iFinalWidth) || (fDlp->iVideoHeight > iFinalHeight)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation,Invalid resolution layer(%d) resolution(%d x %d) shoudl be less than the highest spatial layer resolution(%d x %d)\n ", i, fDlp->iVideoWidth, fDlp->iVideoHeight, iFinalWidth, iFinalHeight); return ENC_RETURN_UNSUPPORTED_PARA; } } } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[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..\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "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", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[i]; if (fDlp->fInputFrameRate > fMaxFrameRate) fMaxFrameRate = fDlp->fInputFrameRate; } if (fMaxFrameRate > fEpsn && (fMaxFrameRate - pCfg->fMaxFrameRate > fEpsn || fMaxFrameRate - pCfg->fMaxFrameRate < -fEpsn)) { pCfg->fMaxFrameRate = fMaxFrameRate; } if ((pCfg->iRCMode != RC_OFF_MODE) && (pCfg->iRCMode != RC_QUALITY_MODE) && (pCfg->iRCMode != RC_BUFFERBASED_MODE) && (pCfg->iRCMode != RC_BITRATE_MODE) && (pCfg->iRCMode != RC_LOW_BW_MODE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid iRCMode = %d\n", 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\n", pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCfg->sSpatialLayers[i]; iTotalBitrate += pSpatialLayer->iSpatialBitrate; if (pSpatialLayer->iSpatialBitrate <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in layer %d, bitrate= %d\n", i, pSpatialLayer->iSpatialBitrate); 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)\n", iTotalBitrate, pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } } return WelsCheckRefFrameLimitation (pLogCtx, pCfg);} 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\n", pCodingParam->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->iSpatialLayerNum < 1 || pCodingParam->iSpatialLayerNum > MAX_DEPENDENCY_LAYER) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iSpatialLayerNum: %d!\n", 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!\n", 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!\n", 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!\n", 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!\n", 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; } 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; 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!\n", 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!\n", i, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.uiSliceMode >= SM_RESERVED) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pSpatialLayer->sSliceCfg.uiSliceMode); return ENC_RETURN_UNSUPPORTED_PARA; } if ((pCodingParam->uiMaxNalSize != 0) && (pSpatialLayer->sSliceCfg.uiSliceMode != SM_DYN_SLICE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!,MaxNalSize = %d\n", pSpatialLayer->sSliceCfg.uiSliceMode, pCodingParam->uiMaxNalSize); return ENC_RETURN_UNSUPPORTED_PARA; } //check pSlice settings under multi-pSlice if (kiPicWidth <= 16 && kiPicHeight <= 16) { //only have one MB, set to single_slice pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; } switch (pSpatialLayer->sSliceCfg.uiSliceMode) { case SM_SINGLE_SLICE: pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[iIdx] = 0; } break; case SM_FIXEDSLCNUM_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0 || pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > iMaxSliceNum) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum == 1) { WelsLog (pLogCtx, WELS_LOG_DEBUG, "ParamValidationExt(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; break; } if (pCodingParam->iRCMode != RC_OFF_MODE) { // multiple slices verify with gom //check uiSliceNum GomValidCheckSliceNum (iMbWidth, iMbHeight, &pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); assert (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > 1); //set uiSliceMbNum with current uiSliceNum GomValidCheckSliceMbNum (iMbWidth, iMbHeight, &pSpatialLayer->sSliceCfg.sSliceArgument); } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings //check uiSliceMbNum with current uiSliceNum WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } // 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) { pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; break; } } break; case SM_AUTO_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; } break; case SM_RASTER_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0] <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } if (!CheckRasterMultiSliceSetting (iMbNumInFrame, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0 || pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > iMaxSliceNum) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum == 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!\n"); pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; break; } if ((pCodingParam->iRCMode != RC_OFF_MODE) && pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!\n"); } // 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) { pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; break; } } break; case SM_ROWMB_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMaxSliceNum = MAX_SLICES_NUM; if (iMbHeight > iMaxSliceNum) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX!\n", iMbHeight); return ENC_RETURN_UNSUPPORTED_PARA; } pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = iMbHeight; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (!CheckRowMbMultiSliceSetting (iMbWidth, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } } break; case SM_DYN_SLICE: { iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid iSliceSize (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiMaxNalSize <= NAL_HEADER_ADD_0X30BYTES) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiMaxNalSize (%d) settings!\n", pCodingParam->uiMaxNalSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint > (pCodingParam->uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), slice mode = SM_DYN_SLICE, uiSliceSizeConstraint = %d ,uiMaxNalsize = %d!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint, pCodingParam->uiMaxNalSize); pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = pCodingParam->uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES; } } break; default: { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pCodingParam->sSpatialLayers[0].sSliceCfg.uiSliceMode); return ENC_RETURN_UNSUPPORTED_PARA; } break; } } return ParamValidation (pLogCtx, pCodingParam);} void WelsEncoderApplyFrameRate (SWelsSvcCodingParam* pParam) { SSpatialLayerInternal* pLayerParam; const float kfEpsn = 0.000001f; const int32_t kiNumLayer = pParam->iSpatialLayerNum; int32_t i; const float kfMaxFrameRate = pParam->fMaxFrameRate; float fRatio; float fTargetOutputFrameRate; //set input frame rate to each layer for (i = 0; i < kiNumLayer; i++) { pLayerParam = & (pParam->sDependencyLayers[i]); fRatio = pLayerParam->fOutputFrameRate / pLayerParam->fInputFrameRate; if ((kfMaxFrameRate - pLayerParam->fInputFrameRate) > kfEpsn || (kfMaxFrameRate - pLayerParam->fInputFrameRate) < -kfEpsn) { pLayerParam->fInputFrameRate = kfMaxFrameRate; fTargetOutputFrameRate = kfMaxFrameRate * fRatio; pLayerParam->fOutputFrameRate = (fTargetOutputFrameRate >= 6) ? fTargetOutputFrameRate : (pLayerParam->fInputFrameRate); //TODO:{Sijia} from design, there is no sense to have temporal layer when under 6fps even with such setting? } }} void WelsEncoderApplyBitRate (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int iLayer) { //TODO (Sijia): this is a temporary solution which keep the ratio between layers //but it is also possible to fulfill the bitrate of lower layer first SSpatialLayerConfig* pLayerParam; const int32_t iNumLayers = pParam->iSpatialLayerNum; int32_t i, iOrigTotalBitrate = 0; if (iLayer == SPATIAL_LAYER_ALL) { //read old BR for (i = 0; i < iNumLayers; i++) { iOrigTotalBitrate += pParam->sSpatialLayers[i].iSpatialBitrate; } //write new BR float fRatio = 0.0; for (i = 0; i < iNumLayers; i++) { pLayerParam = & (pParam->sSpatialLayers[i]); fRatio = pLayerParam->iSpatialBitrate / (static_cast<float> (iOrigTotalBitrate)); pLayerParam->iSpatialBitrate = static_cast<int32_t> (pParam->iTargetBitrate * fRatio); } }}/*! * \brief acquire count number of layers and NALs based on configurable paramters dependency * \pParam pCtx sWelsEncCtx* * \pParam pParam SWelsSvcCodingParam* * \pParam pCountLayers pointer of count number of layers indeed * \pParam iCountNals pointer of count number of nals indeed * \return 0 - successful; otherwise failed */static inline int32_t AcquireLayersNals (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pParam, int32_t* pCountLayers, int32_t* pCountNals) { int32_t iCountNumLayers = 0; int32_t iCountNumNals = 0; int32_t iNumDependencyLayers = 0; int32_t iDIndex = 0; if (NULL == pParam || NULL == ppCtx || NULL == *ppCtx) return 1; Lines 1–500 of 4000. 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" namespace WelsSVCEnc { 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 ); /*! * \brief validate checking in parameter configuration * \pParam pParam SWelsSvcCodingParam* * \return successful - 0; otherwise none 0 for failed */ int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) { float fMaxFrameRate = 0.0f; 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\n", 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\n", 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\n", 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\n"); } } if (pCfg->iSpatialLayerNum > 1) { int32_t iFinalWidth = pCfg->sSpatialLayers[pCfg->iSpatialLayerNum - 1].iVideoWidth; int32_t iFinalHeight = pCfg->sSpatialLayers[pCfg->iSpatialLayerNum - 1].iVideoHeight; for (i = 0; i < (pCfg->iSpatialLayerNum - 1); i++) { SSpatialLayerConfig* fDlp = &pCfg->sSpatialLayers[i]; if ((fDlp->iVideoWidth > iFinalWidth) || (fDlp->iVideoHeight > iFinalHeight)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation,Invalid resolution layer(%d) resolution(%d x %d) shoudl be less than the highest spatial layer resolution(%d x %d)\n ", i, fDlp->iVideoWidth, fDlp->iVideoHeight, iFinalWidth, iFinalHeight); return ENC_RETURN_UNSUPPORTED_PARA; } } } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[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..\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "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", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); return ENC_RETURN_INVALIDINPUT; } } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[i]; if (fDlp->fInputFrameRate > fMaxFrameRate) fMaxFrameRate = fDlp->fInputFrameRate; } if (fMaxFrameRate > fEpsn && (fMaxFrameRate - pCfg->fMaxFrameRate > fEpsn || fMaxFrameRate - pCfg->fMaxFrameRate < -fEpsn)) { pCfg->fMaxFrameRate = fMaxFrameRate; } if ((pCfg->iRCMode != RC_OFF_MODE) && (pCfg->iRCMode != RC_QUALITY_MODE) && (pCfg->iRCMode != RC_BUFFERBASED_MODE) && (pCfg->iRCMode != RC_BITRATE_MODE) && (pCfg->iRCMode != RC_LOW_BW_MODE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid iRCMode = %d\n", 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\n", pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCfg->sSpatialLayers[i]; iTotalBitrate += pSpatialLayer->iSpatialBitrate; if (pSpatialLayer->iSpatialBitrate <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in layer %d, bitrate= %d\n", i, pSpatialLayer->iSpatialBitrate); 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)\n", iTotalBitrate, pCfg->iTargetBitrate); return ENC_RETURN_INVALIDINPUT; } } return WelsCheckRefFrameLimitation (pLogCtx, pCfg); } 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\n", pCodingParam->iUsageType); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->iSpatialLayerNum < 1 || pCodingParam->iSpatialLayerNum > MAX_DEPENDENCY_LAYER) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iSpatialLayerNum: %d!\n", 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!\n", 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!\n", 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!\n", 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!\n", 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; } 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; 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!\n", 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!\n", i, kiPicWidth, kiPicHeight); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.uiSliceMode >= SM_RESERVED) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pSpatialLayer->sSliceCfg.uiSliceMode); return ENC_RETURN_UNSUPPORTED_PARA; } if ((pCodingParam->uiMaxNalSize != 0) && (pSpatialLayer->sSliceCfg.uiSliceMode != SM_DYN_SLICE)) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!,MaxNalSize = %d\n", pSpatialLayer->sSliceCfg.uiSliceMode, pCodingParam->uiMaxNalSize); return ENC_RETURN_UNSUPPORTED_PARA; } //check pSlice settings under multi-pSlice if (kiPicWidth <= 16 && kiPicHeight <= 16) { //only have one MB, set to single_slice pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; } switch (pSpatialLayer->sSliceCfg.uiSliceMode) { case SM_SINGLE_SLICE: pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[iIdx] = 0; } break; case SM_FIXEDSLCNUM_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0 || pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > iMaxSliceNum) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum == 1) { WelsLog (pLogCtx, WELS_LOG_DEBUG, "ParamValidationExt(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; break; } if (pCodingParam->iRCMode != RC_OFF_MODE) { // multiple slices verify with gom //check uiSliceNum GomValidCheckSliceNum (iMbWidth, iMbHeight, &pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); assert (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > 1); //set uiSliceMbNum with current uiSliceNum GomValidCheckSliceMbNum (iMbWidth, iMbHeight, &pSpatialLayer->sSliceCfg.sSliceArgument); } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings //check uiSliceMbNum with current uiSliceNum WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } // 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) { pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; break; } } break; case SM_AUTO_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; } break; case SM_RASTER_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0] <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } if (!CheckRasterMultiSliceSetting (iMbNumInFrame, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0 || pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > iMaxSliceNum) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum == 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!\n"); pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; break; } if ((pCodingParam->iRCMode != RC_OFF_MODE) && pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum > 1) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!\n"); } // 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) { pSpatialLayer->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = 1; break; } } break; case SM_ROWMB_SLICE: { pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMaxSliceNum = MAX_SLICES_NUM; if (iMbHeight > iMaxSliceNum) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX!\n", iMbHeight); return ENC_RETURN_UNSUPPORTED_PARA; } pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum = iMbHeight; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceNum); return ENC_RETURN_UNSUPPORTED_PARA; } if (!CheckRowMbMultiSliceSetting (iMbWidth, &pSpatialLayer->sSliceCfg.sSliceArgument)) { // verify interleave mode settings WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0]); return ENC_RETURN_UNSUPPORTED_PARA; } } break; case SM_DYN_SLICE: { iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint <= 0) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid iSliceSize (%d) settings!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint); return ENC_RETURN_UNSUPPORTED_PARA; } if (pCodingParam->uiMaxNalSize <= NAL_HEADER_ADD_0X30BYTES) { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiMaxNalSize (%d) settings!\n", pCodingParam->uiMaxNalSize); return ENC_RETURN_UNSUPPORTED_PARA; } if (pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint > (pCodingParam->uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParamValidationExt(), slice mode = SM_DYN_SLICE, uiSliceSizeConstraint = %d ,uiMaxNalsize = %d!\n", pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint, pCodingParam->uiMaxNalSize); pSpatialLayer->sSliceCfg.sSliceArgument.uiSliceSizeConstraint = pCodingParam->uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES; } } break; default: { WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pCodingParam->sSpatialLayers[0].sSliceCfg.uiSliceMode); return ENC_RETURN_UNSUPPORTED_PARA; } break; } } return ParamValidation (pLogCtx, pCodingParam); } void WelsEncoderApplyFrameRate (SWelsSvcCodingParam* pParam) { SSpatialLayerInternal* pLayerParam; const float kfEpsn = 0.000001f; const int32_t kiNumLayer = pParam->iSpatialLayerNum; int32_t i; const float kfMaxFrameRate = pParam->fMaxFrameRate; float fRatio; float fTargetOutputFrameRate; //set input frame rate to each layer for (i = 0; i < kiNumLayer; i++) { pLayerParam = & (pParam->sDependencyLayers[i]); fRatio = pLayerParam->fOutputFrameRate / pLayerParam->fInputFrameRate; if ((kfMaxFrameRate - pLayerParam->fInputFrameRate) > kfEpsn || (kfMaxFrameRate - pLayerParam->fInputFrameRate) < -kfEpsn) { pLayerParam->fInputFrameRate = kfMaxFrameRate; fTargetOutputFrameRate = kfMaxFrameRate * fRatio; pLayerParam->fOutputFrameRate = (fTargetOutputFrameRate >= 6) ? fTargetOutputFrameRate : (pLayerParam->fInputFrameRate); //TODO:{Sijia} from design, there is no sense to have temporal layer when under 6fps even with such setting? } } } void WelsEncoderApplyBitRate (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int iLayer) { //TODO (Sijia): this is a temporary solution which keep the ratio between layers //but it is also possible to fulfill the bitrate of lower layer first SSpatialLayerConfig* pLayerParam; const int32_t iNumLayers = pParam->iSpatialLayerNum; int32_t i, iOrigTotalBitrate = 0; if (iLayer == SPATIAL_LAYER_ALL) { //read old BR for (i = 0; i < iNumLayers; i++) { iOrigTotalBitrate += pParam->sSpatialLayers[i].iSpatialBitrate; } //write new BR float fRatio = 0.0; for (i = 0; i < iNumLayers; i++) { pLayerParam = & (pParam->sSpatialLayers[i]); fRatio = pLayerParam->iSpatialBitrate / (static_cast<float> (iOrigTotalBitrate)); pLayerParam->iSpatialBitrate = static_cast<int32_t> (pParam->iTargetBitrate * fRatio); } } } /*! * \brief acquire count number of layers and NALs based on configurable paramters dependency * \pParam pCtx sWelsEncCtx* * \pParam pParam SWelsSvcCodingParam* * \pParam pCountLayers pointer of count number of layers indeed * \pParam iCountNals pointer of count number of nals indeed * \return 0 - successful; otherwise failed */ static inline int32_t AcquireLayersNals (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pParam, int32_t* pCountLayers, int32_t* pCountNals) { int32_t iCountNumLayers = 0; int32_t iCountNumNals = 0; int32_t iNumDependencyLayers = 0; int32_t iDIndex = 0; if (NULL == pParam || NULL == ppCtx || NULL == *ppCtx) return 1;