/*!
* \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 <string.h>
#include <stdlib.h>
#include <assert.h>
#include "encoder.h"
#include "extern.h"
#include "encoder_context.h"
#include "typedefs.h"
#include "wels_const.h"
#include "wels_common_basis.h"
#include "codec_def.h"
#include "param_svc.h"
#include "cpu_core.h"
#include "cpu.h"
#include "utils.h"
#include "svc_enc_frame.h"
#include "svc_enc_golomb.h"
#include "svc_enc_slice_segment.h"
#include "au_set.h"
#include "picture_handle.h"
#include "codec_app_def.h"
#include "svc_base_layer_md.h"
#include "svc_encode_slice.h"
#include "decode_mb_aux.h"
#include "deblocking.h"
#include "rc.h"
#include "ref_list_mgr_svc.h"
#include "md.h"
#include "ls_defines.h"
#include "set_mb_syn_cavlc.h"
#include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms
#include "array_stack_align.h"
// for MT, 4/22/2010
#include "slice_multi_threading.h"
#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);
}
/*!
* \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 )*/
{
const int32_t kiNumOfSlice = GetInitialSliceNum( (pDLayer->iFrameWidth+0x0f)>>4,
(pDLayer->iFrameHeight+0x0f)>>4,
&pDLayer->sMso );
// NEED check iCountNals value in case multiple slices is used
iCountNumNals += kiNumOfSlice; // for pSlice VCL NALs
// plus prefix NALs
if ( iDIndex == 0 )
iCountNumNals += kiNumOfSlice;
#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
Lines 1–500 of 4250. 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 <string.h> #include <stdlib.h> #include <assert.h> #include "encoder.h" #include "extern.h" #include "encoder_context.h" #include "typedefs.h" #include "wels_const.h" #include "wels_common_basis.h" #include "codec_def.h" #include "param_svc.h" #include "cpu_core.h" #include "cpu.h" #include "utils.h" #include "svc_enc_frame.h" #include "svc_enc_golomb.h" #include "svc_enc_slice_segment.h" #include "au_set.h" #include "picture_handle.h" #include "codec_app_def.h" #include "svc_base_layer_md.h" #include "svc_encode_slice.h" #include "decode_mb_aux.h" #include "deblocking.h" #include "rc.h" #include "ref_list_mgr_svc.h" #include "md.h" #include "ls_defines.h" #include "set_mb_syn_cavlc.h" #include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms #include "array_stack_align.h" // for MT, 4/22/2010 #include "slice_multi_threading.h" #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); } /*! * \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 )*/ { const int32_t kiNumOfSlice = GetInitialSliceNum( (pDLayer->iFrameWidth+0x0f)>>4, (pDLayer->iFrameHeight+0x0f)>>4, &pDLayer->sMso ); // NEED check iCountNals value in case multiple slices is used iCountNumNals += kiNumOfSlice; // for pSlice VCL NALs // plus prefix NALs if ( iDIndex == 0 ) iCountNumNals += kiNumOfSlice; #if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)