Ethan HuggInitial Commit70e5e6212 years agoHistory
4250 lines · 155.9 KB · C++
RawDownload
/*!
 * \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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t