/*! * \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 "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#if defined(MT_ENABLED)#include "slice_multi_threading.h"#endif//MT_ENABLED#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)#include "measure_time.h"#endif//DYNAMIC_SLICE_ASSIGN namespace WelsSVCEnc { int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx, SLayerBSInfo* pLbi, 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 (SWelsSvcCodingParam* pCfg) { float fMaxFrameRate = 0.0f; const float fEpsn = 0.000001f; int32_t i = 0; int32_t iLastSpatialWidth = 0; int32_t iLastSpatialHeight = 0; float fLastFrameRateIn = 0.0f; float fLastFrameRateOut = 0.0f; SDLayerParam* pLastSpatialParam = NULL; assert (pCfg != NULL); for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCfg->sDependencyLayers[i]; if (fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn && fDlp->fInputFrameRate <= fEpsn) || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn)) {#if defined (_DEBUG) fprintf (stderr, "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i);#endif return 1; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) {#if defined (_DEBUG) fprintf (stderr, "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);#endif return 1; } } for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* 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; } for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCfg->sDependencyLayers[i]; pLastSpatialParam = fDlp; iLastSpatialWidth = fDlp->iFrameWidth; iLastSpatialHeight = fDlp->iFrameHeight; fLastFrameRateIn = fDlp->fInputFrameRate; fLastFrameRateOut = fDlp->fOutputFrameRate; } return 0;} int32_t ParamValidationExt (void* pParam) { SWelsSvcCodingParam* pCodingParam = (SWelsSvcCodingParam*)pParam; int8_t i = 0; int32_t iIdx = 0; assert (pCodingParam != NULL); if (NULL == pCodingParam) return 1; if (pCodingParam->iNumDependencyLayer < 1 || pCodingParam->iNumDependencyLayer > MAX_DEPENDENCY_LAYER) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumDependencyLayer: %d!\n", pCodingParam->iNumDependencyLayer);#endif//#if _DEBUG return 1; } if (pCodingParam->iNumTemporalLayer < 1 || pCodingParam->iNumTemporalLayer > MAX_TEMPORAL_LEVEL) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumTemporalLayer: %d!\n", pCodingParam->iNumTemporalLayer);#endif//#if _DEBUG return 1; } if (pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!\n", pCodingParam->uiGopSize);#endif//#if _DEBUG return 1; } if (pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!\n", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);#endif//#if _DEBUG return 1; } if (pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize - 1)) != 0) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!\n", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);#endif//#if _DEBUG return 1; } #ifdef MT_ENABLED //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; }#else pCodingParam->bDeblockingParallelFlag = false;#endif//MT_ENABLED for (i = 0; i < pCodingParam->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCodingParam->sDependencyLayers[i]; const int32_t kiPicWidth = fDlp->iFrameWidth; const int32_t kiPicHeight = fDlp->iFrameHeight; int32_t iMbWidth = 0; int32_t iMbHeight = 0; int32_t iMbNumInFrame = 0; int32_t iMaxSliceNum = MAX_SLICES_NUM; if (kiPicWidth <= 0 || kiPicHeight <= 0) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid %d x %d in dependency layer settings!\n", kiPicWidth, kiPicHeight);#endif//#if _DEBUG return 1; } if ((kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0) {#if defined (_DEBUG) fprintf (stderr, "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);#endif//#if _DEBUG return 1; } if (fDlp->sMso.uiSliceMode >= SM_RESERVED) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", fDlp->sMso.uiSliceMode);#endif//#if _DEBUG return 1; } //check pSlice settings under multi-pSlice if (kiPicWidth <= 16 && kiPicHeight <= 16) { //only have one MB, set to single_slice fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; } switch (fDlp->sMso.uiSliceMode) { case SM_SINGLE_SLICE: fDlp->sMso.sSliceArgument.iSliceNum = 1; fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; fDlp->sMso.sSliceArgument.iSliceNum = 0; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { fDlp->sMso.sSliceArgument.uiSliceMbNum[iIdx] = 0; } break; case SM_FIXEDSLCNUM_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (fDlp->sMso.sSliceArgument.iSliceNum <= 0 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum);#endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum == 1) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!\n", fDlp->sMso.sSliceArgument.iSliceNum);#endif//#if _DEBUG fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; break; } if (pCodingParam->bEnableRc) { // multiple slices verify with gom //check uiSliceNum GomValidCheckSliceNum (iMbWidth, iMbHeight, (int32_t*)&fDlp->sMso.sSliceArgument.iSliceNum); assert (fDlp->sMso.sSliceArgument.iSliceNum > 1); //set uiSliceMbNum with current uiSliceNum GomValidCheckSliceMbNum (iMbWidth, iMbHeight, &fDlp->sMso.sSliceArgument); } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings //check uiSliceMbNum with current uiSliceNum#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]);#endif//#if _DEBUG return 1; } // 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) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; case SM_RASTER_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (fDlp->sMso.sSliceArgument.uiSliceMbNum[0] <= 0) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]);#endif//#if _DEBUG return 1; } if (!CheckRasterMultiSliceSetting (iMbNumInFrame, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]);#endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum <= 0 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum) { // verify interleave mode settings#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!\n", fDlp->sMso.sSliceArgument.iSliceNum);#endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum == 1) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!\n");#endif//#if _DEBUG fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; break; }#ifdef MT_ENABLED if (pCodingParam->bEnableRc && fDlp->sMso.sSliceArgument.iSliceNum > 1) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!\n");#endif//#if _DEBUG }#endif // 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) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; case SM_ROWMB_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMaxSliceNum = MAX_SLICES_NUM; if (iMbHeight > iMaxSliceNum) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX!\n", iMbHeight);#endif//#if _DEBUG return 1; } fDlp->sMso.sSliceArgument.iSliceNum = iMbHeight; if (fDlp->sMso.sSliceArgument.iSliceNum <= 0) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum);#endif//#if _DEBUG return 1; } if (!CheckRowMbMultiSliceSetting (iMbWidth, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]);#endif//#if _DEBUG return 1; } } break; case SM_DYN_SLICE: { iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; if (fDlp->sMso.sSliceArgument.uiSliceSizeConstraint <= 0) {#if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid iSliceSize (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceSizeConstraint);#endif//#if _DEBUG return 1; } // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting if (iMbWidth * iMbHeight <= MIN_NUM_MB_PER_SLICE) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; default: { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pCodingParam->sDependencyLayers[0].sMso.uiSliceMode);#endif//#if _DEBUG return 1; } break; } } return ParamValidation (pCodingParam);} void WelsEncoderApplyFrameRate(SWelsSvcCodingParam* pParam){ SDLayerParam* pLayerParam; const float kfEpsn = 0.000001f; const int32_t kiNumLayer = pParam->iNumDependencyLayer; 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(SWelsSvcCodingParam* pParam){ //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 SDLayerParam* pLayerParam; const int32_t iNumLayers = pParam->iNumDependencyLayer; int32_t i, iOrigTotalBitrate=0; //read old BR for (i=0;i<iNumLayers;i++) { iOrigTotalBitrate += pParam->sDependencyLayers[i].iSpatialBitrate; } //write new BR float fRatio = 0.0; for (i=0;i<iNumLayers;i++) { pLayerParam = &(pParam->sDependencyLayers[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 defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER) int32_t iNumLayersPack = 0;#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER if (NULL == pParam || NULL == ppCtx || NULL == *ppCtx) return 1; iNumDependencyLayers = pParam->iNumDependencyLayer; do { SDLayerParam* pDLayer = &pParam->sDependencyLayers[iDIndex];// pDLayer->ptr_cfg = pParam; int32_t iOrgNumNals = iCountNumNals; //Note: Sep. 2010 //Review this part and suggest no change, since the memory over-use //(1) counts little to the overall performance //(2) should not be critial even under mobile case if (SM_DYN_SLICE == pDLayer->sMso.uiSliceMode) { iCountNumNals += MAX_SLICES_NUM; // plus prefix NALs if (iDIndex == 0) iCountNumNals += MAX_SLICES_NUM; // MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME ensured at svc_enc_slice_segment.h#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER) assert (MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME); // iNumLayersPack += MAX_SLICES_NUM; // do not count it for dynamic slicing mode#else//!MT_ENABLED || !PACKING_ONE_SLICE_PER_LAYER assert (iCountNumNals - iOrgNumNals <= MAX_NAL_UNITS_IN_LAYER);#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER } else { /*if ( SM_SINGLE_SLICE != pDLayer->sMso.uiSliceMode )*/Lines 1–500 of 4007. 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 "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 #if defined(MT_ENABLED) #include "slice_multi_threading.h" #endif//MT_ENABLED #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) #include "measure_time.h" #endif//DYNAMIC_SLICE_ASSIGN namespace WelsSVCEnc { int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx, SLayerBSInfo* pLbi, 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 (SWelsSvcCodingParam* pCfg) { float fMaxFrameRate = 0.0f; const float fEpsn = 0.000001f; int32_t i = 0; int32_t iLastSpatialWidth = 0; int32_t iLastSpatialHeight = 0; float fLastFrameRateIn = 0.0f; float fLastFrameRateOut = 0.0f; SDLayerParam* pLastSpatialParam = NULL; assert (pCfg != NULL); for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCfg->sDependencyLayers[i]; if (fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn && fDlp->fInputFrameRate <= fEpsn) || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn)) { #if defined (_DEBUG) fprintf (stderr, "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..\n", fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i); #endif return 1; } if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) { #if defined (_DEBUG) fprintf (stderr, "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); #endif return 1; } } for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* 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; } for (i = 0; i < pCfg->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCfg->sDependencyLayers[i]; pLastSpatialParam = fDlp; iLastSpatialWidth = fDlp->iFrameWidth; iLastSpatialHeight = fDlp->iFrameHeight; fLastFrameRateIn = fDlp->fInputFrameRate; fLastFrameRateOut = fDlp->fOutputFrameRate; } return 0; } int32_t ParamValidationExt (void* pParam) { SWelsSvcCodingParam* pCodingParam = (SWelsSvcCodingParam*)pParam; int8_t i = 0; int32_t iIdx = 0; assert (pCodingParam != NULL); if (NULL == pCodingParam) return 1; if (pCodingParam->iNumDependencyLayer < 1 || pCodingParam->iNumDependencyLayer > MAX_DEPENDENCY_LAYER) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumDependencyLayer: %d!\n", pCodingParam->iNumDependencyLayer); #endif//#if _DEBUG return 1; } if (pCodingParam->iNumTemporalLayer < 1 || pCodingParam->iNumTemporalLayer > MAX_TEMPORAL_LEVEL) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumTemporalLayer: %d!\n", pCodingParam->iNumTemporalLayer); #endif//#if _DEBUG return 1; } if (pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!\n", pCodingParam->uiGopSize); #endif//#if _DEBUG return 1; } if (pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!\n", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); #endif//#if _DEBUG return 1; } if (pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize - 1)) != 0) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!\n", pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize); #endif//#if _DEBUG return 1; } #ifdef MT_ENABLED //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; } #else pCodingParam->bDeblockingParallelFlag = false; #endif//MT_ENABLED for (i = 0; i < pCodingParam->iNumDependencyLayer; ++ i) { SDLayerParam* fDlp = &pCodingParam->sDependencyLayers[i]; const int32_t kiPicWidth = fDlp->iFrameWidth; const int32_t kiPicHeight = fDlp->iFrameHeight; int32_t iMbWidth = 0; int32_t iMbHeight = 0; int32_t iMbNumInFrame = 0; int32_t iMaxSliceNum = MAX_SLICES_NUM; if (kiPicWidth <= 0 || kiPicHeight <= 0) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid %d x %d in dependency layer settings!\n", kiPicWidth, kiPicHeight); #endif//#if _DEBUG return 1; } if ((kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0) { #if defined (_DEBUG) fprintf (stderr, "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); #endif//#if _DEBUG return 1; } if (fDlp->sMso.uiSliceMode >= SM_RESERVED) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", fDlp->sMso.uiSliceMode); #endif//#if _DEBUG return 1; } //check pSlice settings under multi-pSlice if (kiPicWidth <= 16 && kiPicHeight <= 16) { //only have one MB, set to single_slice fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; } switch (fDlp->sMso.uiSliceMode) { case SM_SINGLE_SLICE: fDlp->sMso.sSliceArgument.iSliceNum = 1; fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; fDlp->sMso.sSliceArgument.iSliceNum = 0; for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) { fDlp->sMso.sSliceArgument.uiSliceMbNum[iIdx] = 0; } break; case SM_FIXEDSLCNUM_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (fDlp->sMso.sSliceArgument.iSliceNum <= 0 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum); #endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum == 1) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!\n", fDlp->sMso.sSliceArgument.iSliceNum); #endif//#if _DEBUG fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; break; } if (pCodingParam->bEnableRc) { // multiple slices verify with gom //check uiSliceNum GomValidCheckSliceNum (iMbWidth, iMbHeight, (int32_t*)&fDlp->sMso.sSliceArgument.iSliceNum); assert (fDlp->sMso.sSliceArgument.iSliceNum > 1); //set uiSliceMbNum with current uiSliceNum GomValidCheckSliceMbNum (iMbWidth, iMbHeight, &fDlp->sMso.sSliceArgument); } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings //check uiSliceMbNum with current uiSliceNum #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]); #endif//#if _DEBUG return 1; } // 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) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; case SM_RASTER_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMbNumInFrame = iMbWidth * iMbHeight; iMaxSliceNum = MAX_SLICES_NUM; if (fDlp->sMso.sSliceArgument.uiSliceMbNum[0] <= 0) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]); #endif//#if _DEBUG return 1; } if (!CheckRasterMultiSliceSetting (iMbNumInFrame, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]); #endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum <= 0 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum) { // verify interleave mode settings #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!\n", fDlp->sMso.sSliceArgument.iSliceNum); #endif//#if _DEBUG return 1; } if (fDlp->sMso.sSliceArgument.iSliceNum == 1) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!\n"); #endif//#if _DEBUG fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; break; } #ifdef MT_ENABLED if (pCodingParam->bEnableRc && fDlp->sMso.sSliceArgument.iSliceNum > 1) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!\n"); #endif//#if _DEBUG } #endif // 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) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; case SM_ROWMB_SLICE: { fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0; iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; iMaxSliceNum = MAX_SLICES_NUM; if (iMbHeight > iMaxSliceNum) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX!\n", iMbHeight); #endif//#if _DEBUG return 1; } fDlp->sMso.sSliceArgument.iSliceNum = iMbHeight; if (fDlp->sMso.sSliceArgument.iSliceNum <= 0) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum); #endif//#if _DEBUG return 1; } if (!CheckRowMbMultiSliceSetting (iMbWidth, &fDlp->sMso.sSliceArgument)) { // verify interleave mode settings #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0]); #endif//#if _DEBUG return 1; } } break; case SM_DYN_SLICE: { iMbWidth = (kiPicWidth + 15) >> 4; iMbHeight = (kiPicHeight + 15) >> 4; if (fDlp->sMso.sSliceArgument.uiSliceSizeConstraint <= 0) { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid iSliceSize (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceSizeConstraint); #endif//#if _DEBUG return 1; } // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting if (iMbWidth * iMbHeight <= MIN_NUM_MB_PER_SLICE) { fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE; fDlp->sMso.sSliceArgument.iSliceNum = 1; break; } } break; default: { #if defined (_DEBUG) fprintf (stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pCodingParam->sDependencyLayers[0].sMso.uiSliceMode); #endif//#if _DEBUG return 1; } break; } } return ParamValidation (pCodingParam); } void WelsEncoderApplyFrameRate(SWelsSvcCodingParam* pParam) { SDLayerParam* pLayerParam; const float kfEpsn = 0.000001f; const int32_t kiNumLayer = pParam->iNumDependencyLayer; 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(SWelsSvcCodingParam* pParam) { //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 SDLayerParam* pLayerParam; const int32_t iNumLayers = pParam->iNumDependencyLayer; int32_t i, iOrigTotalBitrate=0; //read old BR for (i=0;i<iNumLayers;i++) { iOrigTotalBitrate += pParam->sDependencyLayers[i].iSpatialBitrate; } //write new BR float fRatio = 0.0; for (i=0;i<iNumLayers;i++) { pLayerParam = &(pParam->sDependencyLayers[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 defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER) int32_t iNumLayersPack = 0; #endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER if (NULL == pParam || NULL == ppCtx || NULL == *ppCtx) return 1; iNumDependencyLayers = pParam->iNumDependencyLayer; do { SDLayerParam* pDLayer = &pParam->sDependencyLayers[iDIndex]; // pDLayer->ptr_cfg = pParam; int32_t iOrgNumNals = iCountNumNals; //Note: Sep. 2010 //Review this part and suggest no change, since the memory over-use //(1) counts little to the overall performance //(2) should not be critial even under mobile case if (SM_DYN_SLICE == pDLayer->sMso.uiSliceMode) { iCountNumNals += MAX_SLICES_NUM; // plus prefix NALs if (iDIndex == 0) iCountNumNals += MAX_SLICES_NUM; // MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME ensured at svc_enc_slice_segment.h #if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER) assert (MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME); // iNumLayersPack += MAX_SLICES_NUM; // do not count it for dynamic slicing mode #else//!MT_ENABLED || !PACKING_ONE_SLICE_PER_LAYER assert (iCountNumNals - iOrgNumNals <= MAX_NAL_UNITS_IN_LAYER); #endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER } else { /*if ( SM_SINGLE_SLICE != pDLayer->sMso.uiSliceMode )*/