/*!
* \copy
* Copyright (c) 2010-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 slice_multi_threading.h
*
* \brief pSlice based multiple threading
*
* \date 04/16/2010 Created
*
*************************************************************************************
*/
#if defined(MT_ENABLED)
#include <assert.h>
#ifdef __GNUC__
#include <semaphore.h>
#ifndef SEM_NAME_MAX
// length of semaphore name should be system constrained at least on mac 10.7
#define SEM_NAME_MAX 32
#endif//SEM_NAME_MAX
#endif//__GNUC__
#include "slice_multi_threading.h"
#include "mt_defs.h"
#include "nal_encap.h"
#include "utils.h"
#include "encoder.h"
#include "svc_encode_slice.h"
#include "deblocking.h"
#include "svc_enc_golomb.h"
#include "crt_util_safe_x.h" // for safe crt like calls
#include "rc.h"
#if defined(X86_ASM)
#include "cpu.h"
#endif//X86_ASM
#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
#include "measure_time.h"
#endif//DYNAMIC_SLICE_ASSIGN
namespace WelsSVCEnc {
void UpdateMbListNeighborParallel( SSliceCtx *pSliceCtx,
SMB *pMbList,
const int32_t uiSliceIdc )
{
const uint8_t *kpMbMap = pSliceCtx->pOverallMbMap;
const int32_t kiMbWidth = pSliceCtx->iMbWidth;
int32_t iIdx = pSliceCtx->pFirstMbInSlice[uiSliceIdc];
const int32_t kiEndMbInSlice = iIdx + pSliceCtx->pCountMbNumInSlice[uiSliceIdc] - 1;
do {
SMB *pMb = &pMbList[iIdx];
uint32_t uiNeighborAvailFlag = 0;
const int32_t kiMbXY = pMb->iMbXY;
const int32_t kiMbX = pMb->iMbX;
const int32_t kiMbY = pMb->iMbY;
BOOL_T bLeft;
BOOL_T bTop;
BOOL_T bLeftTop;
BOOL_T bRightTop;
int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;
iLeftXY = kiMbXY - 1;
iTopXY = kiMbXY - kiMbWidth;
iLeftTopXY = iTopXY - 1;
iRightTopXY = iTopXY + 1;
bLeft = (kiMbX > 0) && (uiSliceIdc == kpMbMap[iLeftXY]);
bTop = (kiMbY > 0) && (uiSliceIdc == kpMbMap[iTopXY]);
bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iLeftTopXY]);
bRightTop = (kiMbX < (kiMbWidth-1)) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iRightTopXY]);
if( bLeft ){
uiNeighborAvailFlag |= LEFT_MB_POS;
}
if( bTop ){
uiNeighborAvailFlag |= TOP_MB_POS;
}
if( bLeftTop ){
uiNeighborAvailFlag |= TOPLEFT_MB_POS;
}
if( bRightTop ){
uiNeighborAvailFlag |= TOPRIGHT_MB_POS;
}
pMb->uiNeighborAvail = (uint8_t)uiNeighborAvailFlag;
pMb->uiSliceIdc = uiSliceIdc;
++ iIdx;
} while(iIdx <= kiEndMbInSlice);
}
void CalcSliceComplexRatio( void *pRatio, SSliceCtx *pSliceCtx, uint32_t *pSliceConsume )
{
float *pRatioList = (float *)pRatio;
float fAvI[MAX_SLICES_NUM];
float fSumAv = .0f;
uint32_t *pSliceTime = (uint32_t *)pSliceConsume;
int32_t *pCountMbInSlice = (int32_t *)pSliceCtx->pCountMbNumInSlice;
const int32_t kiSliceCount = pSliceCtx->iSliceNumInFrame;
int32_t iSliceIdx = 0;
#if defined(X86_ASM)
WelsEmms();
#endif //X86_ASM
while ( iSliceIdx < kiSliceCount )
{
fAvI[iSliceIdx] = 1.0f * pCountMbInSlice[iSliceIdx] / pSliceTime[iSliceIdx];
#if defined(ENABLE_TRACE_MT)
WelsLog(NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), pSliceConsumeTime[%d]= %d us, slice_run= %d\n", iSliceIdx, pSliceTime[iSliceIdx], pCountMbInSlice[iSliceIdx]);
#endif//ENABLE_TRACE_MT
fSumAv += fAvI[iSliceIdx];
++ iSliceIdx;
}
while ( -- iSliceIdx >= 0 )
{
pRatioList[iSliceIdx] = fAvI[iSliceIdx] / fSumAv;
}
}
#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) && defined(NOT_ABSOLUTE_BALANCING)
int32_t NeedDynamicAdjust( void *pConsumeTime, const int32_t iSliceNum )
{
#if !defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING)
const float fRatioLower = TOLERANT_BALANCING_RATIO_LOWER( uiSliceNum );
const float fRatioUpper = TOLERANT_BALANCING_RATIO_UPPER( uiSliceNum );
#endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING
uint32_t *pSliceConsume = (uint32_t *)pConsumeTime;
uint32_t uiTotalConsume = 0;
int32_t iSliceIdx = 0;
int32_t iNeedAdj = false;
#if defined(X86_ASM)
WelsEmms();
#endif //X86_ASM
while( iSliceIdx < iSliceNum )
{
uiTotalConsume += pSliceConsume[iSliceIdx] + pSliceConsume[1+iSliceIdx];
iSliceIdx += 2;
}
if (uiTotalConsume == 0)
{
#if defined(ENABLE_TRACE_MT)
WelsLog( NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein do no adjust due first picture, iCountSliceNum= %d\n", iSliceNum );
#endif//ENABLE_TRACE_MT
return false;
}
iSliceIdx = 0;
#if defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING)
float fThr = EPSN; // threshold for various cores cases
float fRmse = .0f; // root mean square error of pSlice consume ratios
const float kfMeanRatio = 1.0f / iSliceNum;
do{
const float fRatio = 1.0f * pSliceConsume[iSliceIdx] / uiTotalConsume;
const float fDiffRatio = fRatio - kfMeanRatio;
fRmse += (fDiffRatio * fDiffRatio);
++ iSliceIdx;
} while ( iSliceIdx+1 < iSliceNum );
fRmse = sqrtf(fRmse/iSliceNum);
if ( iSliceNum >= 8 )
{
fThr += THRESHOLD_RMSE_CORE8;
}
else if ( iSliceNum >= 4 )
{
fThr += THRESHOLD_RMSE_CORE4;
}
else if ( iSliceNum >= 2 )
{
fThr += THRESHOLD_RMSE_CORE2;
}
else
fThr = 1.0f;
if ( fRmse > fThr )
iNeedAdj = true;
#if defined(ENABLE_TRACE_MT)
WelsLog(NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein adjustment decision is made (iNeedAdj= %d) by: fRmse of pSlice complexity ratios %.6f, the corresponding threshold %.6f, iCountSliceNum %d\n",
iNeedAdj, fRmse, fThr, iSliceNum);
#endif//ENABLE_TRACE_MT
#else
do{
const float kfRatio = 1.0f * pSliceConsume[uiSliceIdx] / uiTotalConsume;
if ( kfRatio+EPSN < fRatioLower || kfRatio > ratio_upper+EPSN )
{
#if defined(ENABLE_TRACE_MT)
WelsLog(NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein adjustment decision is made by pSlice consume time not balanced at all, uiSliceIdx= %d, comp_ratio= %.6f, pSliceConsumeTime= %d, total_consume_time= %d, iCountSliceNum= %d\n",
uiSliceIdx, kfRatio, pSliceConsume[uiSliceIdx], uiTotalConsume, uiSliceNum);
#endif//ENABLE_TRACE_MT
iNeedAdj = true;
break;
}
++ uiSliceIdx;
} while ( uiSliceIdx+1 < uiSliceNum );
#endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING
return iNeedAdj;
}
#endif//..
#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
void DynamicAdjustSlicing( sWelsEncCtx *pCtx,
SDqLayer *pCurDqLayer,
void *pComplexRatio,
int32_t iCurDid )
{
SSliceCtx *pSliceCtx = pCurDqLayer->pSliceEncCtx;
const int32_t kiCountSliceNum = pSliceCtx->iSliceNumInFrame;
const int32_t kiCountNumMb = pSliceCtx->iMbNumInFrame;
int32_t iMinimalMbNum = pSliceCtx->iMbWidth; // in theory we need only 1 SMB, here let it as one SMB row required
int32_t iMaximalMbNum = 0; // dynamically assign later
float *pSliceComplexRatio = (float *)pComplexRatio;
int32_t iMbNumLeft = kiCountNumMb;
int32_t iRunLen[MAX_THREADS_NUM] = {0};
int32_t iSliceIdx = 0;
int32_t iNumMbInEachGom;
SWelsSvcRc *pWelsSvcRc = &pCtx->pWelsSvcRc[iCurDid];
if(pCtx->pSvcParam->bEnableRc)
{
iNumMbInEachGom = pWelsSvcRc->iNumberMbGom;
if ( iNumMbInEachGom <= 0 )
{
WelsLog(pCtx, WELS_LOG_ERROR, "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d\n", iNumMbInEachGom, iCurDid, kiCountNumMb);
return;
}
// do not adjust in case no extra iNumMbInEachGom based left for slicing adjustment,
// extra MB of non integrated GOM assigned at the last pSlice in default, keep up on early initial result.
if ( iNumMbInEachGom * kiCountSliceNum >= kiCountNumMb )
{
return;
}
iMinimalMbNum = iNumMbInEachGom;
}
if ( kiCountSliceNum < 2 || (kiCountSliceNum & 0x01) ) // we need suppose uiSliceNum is even for multiple threading
return;
iMaximalMbNum = kiCountNumMb - (kiCountSliceNum - 1) * iMinimalMbNum;
#if defined(X86_ASM)
WelsEmms();
#endif //X86_ASM
#if defined(ENABLE_TRACE_MT)
WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iDid= %d, iCountNumMb= %d\n", iCurDid, kiCountNumMb);
#endif//ENABLE_TRACE_MT
iSliceIdx = 0;
while (iSliceIdx+1 < kiCountSliceNum) {
int32_t iNumMbAssigning = (int32_t)(kiCountNumMb * pSliceComplexRatio[iSliceIdx] + EPSN);
// GOM boundary aligned
if(pCtx->pSvcParam->bEnableRc)
{
iNumMbAssigning=(int32_t)(1.0f * iNumMbAssigning / iNumMbInEachGom + 0.5f + EPSN) * iNumMbInEachGom;
}
// make sure one GOM at least in each pSlice for safe
if ( iNumMbAssigning < iMinimalMbNum )
iNumMbAssigning = iMinimalMbNum;
else if ( iNumMbAssigning > iMaximalMbNum )
iNumMbAssigning = iMaximalMbNum;
assert( iNumMbAssigning > 0 );
iMbNumLeft -= iNumMbAssigning;
if ( iMbNumLeft <= 0 ) // error due to we can not support slice_skip now yet, do not adjust this time
{
assert( 0 );
return;
}
iRunLen[iSliceIdx] = iNumMbAssigning;
#if defined(ENABLE_TRACE_MT)
WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), uiSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n",
iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iNumMbAssigning);
#endif//ENABLE_TRACE_MT
++ iSliceIdx;
iMaximalMbNum = iMbNumLeft - (kiCountSliceNum - iSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts
}
iRunLen[iSliceIdx] = iMbNumLeft;
#if defined(ENABLE_TRACE_MT)
WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n",
iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iMbNumLeft);
#endif//ENABLE_TRACE_MT
if ( DynamicAdjustSlicePEncCtxAll( pSliceCtx, iRunLen ) == 0 )
{
const int32_t kiThreadNum = pCtx->pSvcParam->iCountThreadsNum;
int32_t iThreadIdx = 0;
do {
#ifdef WIN32
WelsEventSignal( &pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] );
#else
WelsEventSignal( pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] );
#endif//WIN32
++ iThreadIdx;
} while(iThreadIdx < kiThreadNum);
WelsMultipleEventsWaitAllBlocking( kiThreadNum, &pCtx->pSliceThreading->pFinUpdateMbListEvent[0] );
}
}
#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
#ifdef PACKING_ONE_SLICE_PER_LAYER
void ResetEnvMt( sWelsEncCtx *pCtx)
{
const int16_t kiSliceCount = pCtx->iMaxSliceCount;
int32_t iIdx = 0;
while ( iIdx < kiSliceCount )
{
SWelsSliceBs *pSliceBs = &pCtx->pSliceBs[iIdx];
pSliceBs->uiBsPos = 0;
++ iIdx;
}
}
#endif//PACKING_ONE_SLICE_PER_LAYER
int32_t RequestMtResource( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pCodingParam, const int32_t iCountBsLen, const int32_t iTargetSpatialBsSize )
{
CMemoryAlign *pMa = NULL;
SWelsSvcCodingParam *pPara= NULL;
SSliceThreading *pSmt = NULL;
SWelsSliceBs *pSliceB = NULL;
uint8_t *pBsBase = NULL;
int32_t iNumSpatialLayers = 0;
int32_t iThreadNum = 0;
int32_t iIdx = 0;
int32_t iSliceBsBufferSize= 0;
int16_t iMaxSliceNum = 1;
if ( NULL == ppCtx || NULL == pCodingParam || NULL == *ppCtx || iCountBsLen <= 0 )
return 1;
pMa = (*ppCtx)->pMemAlign;
pPara= pCodingParam;
iNumSpatialLayers = pPara->iNumDependencyLayer;
iThreadNum = pPara->iCountThreadsNum;
iMaxSliceNum = (*ppCtx)->iMaxSliceCount;
pSmt = (SSliceThreading *)pMa->WelsMalloc(sizeof(SSliceThreading), "SSliceThreading");
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt), FreeMemorySvc(ppCtx) )
(*ppCtx)->pSliceThreading = pSmt;
pSmt->pThreadPEncCtx = (SSliceThreadPrivateData *)pMa->WelsMalloc( sizeof(SSliceThreadPrivateData) * iThreadNum, "pThreadPEncCtx" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadPEncCtx), FreeMemorySvc(ppCtx) )
pSmt->pThreadHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pThreadHandles" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadHandles), FreeMemorySvc(ppCtx) )
#ifdef WIN32
pSmt->pSliceCodedEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pSliceCodedEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceCodedEvent), FreeMemorySvc(ppCtx) )
pSmt->pReadySliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pReadySliceCodingEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pReadySliceCodingEvent), FreeMemorySvc(ppCtx) )
pSmt->pFinSliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinSliceCodingEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinSliceCodingEvent), FreeMemorySvc(ppCtx) )
#endif//WIN32
#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
#if defined(__GNUC__)
pSmt->pUpdateMbListThrdHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pUpdateMbListThrdHandles" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListThrdHandles), FreeMemorySvc(ppCtx) )
#endif//__GNUC__
#ifdef WIN32
pSmt->pUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pUpdateMbListEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListEvent), FreeMemorySvc(ppCtx) )
pSmt->pFinUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinUpdateMbListEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinUpdateMbListEvent), FreeMemorySvc(ppCtx) )
#endif//WIN32
#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
#ifdef WIN32
pSmt->pExitEncodeEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pExitEncodeEvent" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pExitEncodeEvent), FreeMemorySvc(ppCtx) )
#endif//WIN32
#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
iIdx = 0;
while ( iIdx < iNumSpatialLayers )
{
SMulSliceOption *pMso = &pPara->sDependencyLayers[iIdx].sMso;
const int32_t kiSliceNum= pMso->sSliceArgument.iSliceNum;
if (pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE && pPara->iMultipleThreadIdc > 1 && pPara->iMultipleThreadIdc >= kiSliceNum )
{
pSmt->pSliceConsumeTime[iIdx] = (uint32_t *)pMa->WelsMallocz( kiSliceNum * sizeof(uint32_t), "pSliceConsumeTime[]" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceConsumeTime[iIdx]), FreeMemorySvc(ppCtx) )
#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
pSmt->pSliceComplexRatio[iIdx] = (float *)pMa->WelsMalloc( kiSliceNum * sizeof(float), "pSliceComplexRatio[]" );
WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceComplexRatio[iIdx]), FreeMemorySvc(ppCtx) )
#endif//TRY_SLICING_BALANCE
}
else
{
pSmt->pSliceConsumeTime[iIdx] = NULL;
#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
pSmt->pSliceComplexRatio[iIdx] = NULL;
#endif//TRY_SLICING_BALANCE
}
++ iIdx;
}
// NULL for pSliceConsumeTime[iIdx]: iIdx from iNumSpatialLayers to MAX_DEPENDENCY_LAYERS
#endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
#ifdef MT_DEBUG
// file handle for MT debug
pSmt->pFSliceDiff = NULL;
if ( pSmt->pFSliceDiff )
{
fclose( pSmt->pFSliceDiff );
pSmt->pFSliceDiff = NULL;
}
#ifdef WIN32
pSmt->pFSliceDiff = fopen(".\\slice_time.txt", "wt+" );
#else
pSmt->pFSliceDiff = fopen("/tmp/slice_time.txt", "wt+" );
#endif//WIN32
#endif//MT_DEBUG
#if defined(ENABLE_TRACE_MT)
WelsLog((*ppCtx), WELS_LOG_INFO, "encpEncCtx= 0x%p\n", (void *)(*ppCtx));
#endif//ENABLE_TRACE_MT
iIdx = 0;
while ( iIdx < iThreadNum )
{
#ifdef __GNUC__ // for posix threading
str_t name[SEM_NAME_MAX] = {0};
int32_t used_len = 0;
WELS_THREAD_ERROR_CODE err = 0;
#endif//__GNUC__
pSmt->pThreadPEncCtx[iIdx].pWelsPEncCtx = (void *)(*ppCtx);
pSmt->pThreadPEncCtx[iIdx].iSliceIndex = iIdx;
pSmt->pThreadPEncCtx[iIdx].iThreadIndex = iIdx;
pSmt->pThreadHandles[iIdx] = 0;
#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
#ifdef WIN32
WelsEventInit( &pSmt->pUpdateMbListEvent[iIdx] );
WelsEventInit( &pSmt->pFinUpdateMbListEvent[iIdx] );
#else
// length of semaphore name should be system constrained at least on mac 10.7
SNPRINTF( name, SEM_NAME_MAX, "ud%d%p", iIdx, (void *)(*ppCtx) );
err = WelsEventOpen( &pSmt->pUpdateMbListEvent[iIdx], name );
#if defined(ENABLE_TRACE_MT)
WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
#endif
used_len = SNPRINTF( name, SEM_NAME_MAX, "fu%d%p", iIdx, (void *)(*ppCtx) );
name[used_len] = '\0';
err = WelsEventOpen( &pSmt->pFinUpdateMbListEvent[iIdx], name );
#if defined(ENABLE_TRACE_MT)
WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pFinUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
#endif
#endif//WIN32
#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
#ifdef WIN32
WelsEventInit( &pSmt->pSliceCodedEvent[iIdx] );
WelsEventInit( &pSmt->pReadySliceCodingEvent[iIdx] );
WelsEventInit( &pSmt->pFinSliceCodingEvent[iIdx] );
WelsEventInit( &pSmt->pExitEncodeEvent[iIdx] );
#else
used_len = SNPRINTF( name, SEM_NAME_MAX, "sc%d%p", iIdx, (void *)(*ppCtx) );
name[used_len] = '\0';
err = WelsEventOpen( &pSmt->pSliceCodedEvent[iIdx], name );
#if defined(ENABLE_TRACE_MT)
WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pSliceCodedEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
Lines 1–500 of 1592. Load more
/*! * \copy * Copyright (c) 2010-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 slice_multi_threading.h * * \brief pSlice based multiple threading * * \date 04/16/2010 Created * ************************************************************************************* */ #if defined(MT_ENABLED) #include <assert.h> #ifdef __GNUC__ #include <semaphore.h> #ifndef SEM_NAME_MAX // length of semaphore name should be system constrained at least on mac 10.7 #define SEM_NAME_MAX 32 #endif//SEM_NAME_MAX #endif//__GNUC__ #include "slice_multi_threading.h" #include "mt_defs.h" #include "nal_encap.h" #include "utils.h" #include "encoder.h" #include "svc_encode_slice.h" #include "deblocking.h" #include "svc_enc_golomb.h" #include "crt_util_safe_x.h" // for safe crt like calls #include "rc.h" #if defined(X86_ASM) #include "cpu.h" #endif//X86_ASM #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) #include "measure_time.h" #endif//DYNAMIC_SLICE_ASSIGN namespace WelsSVCEnc { void UpdateMbListNeighborParallel( SSliceCtx *pSliceCtx, SMB *pMbList, const int32_t uiSliceIdc ) { const uint8_t *kpMbMap = pSliceCtx->pOverallMbMap; const int32_t kiMbWidth = pSliceCtx->iMbWidth; int32_t iIdx = pSliceCtx->pFirstMbInSlice[uiSliceIdc]; const int32_t kiEndMbInSlice = iIdx + pSliceCtx->pCountMbNumInSlice[uiSliceIdc] - 1; do { SMB *pMb = &pMbList[iIdx]; uint32_t uiNeighborAvailFlag = 0; const int32_t kiMbXY = pMb->iMbXY; const int32_t kiMbX = pMb->iMbX; const int32_t kiMbY = pMb->iMbY; BOOL_T bLeft; BOOL_T bTop; BOOL_T bLeftTop; BOOL_T bRightTop; int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY; iLeftXY = kiMbXY - 1; iTopXY = kiMbXY - kiMbWidth; iLeftTopXY = iTopXY - 1; iRightTopXY = iTopXY + 1; bLeft = (kiMbX > 0) && (uiSliceIdc == kpMbMap[iLeftXY]); bTop = (kiMbY > 0) && (uiSliceIdc == kpMbMap[iTopXY]); bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iLeftTopXY]); bRightTop = (kiMbX < (kiMbWidth-1)) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iRightTopXY]); if( bLeft ){ uiNeighborAvailFlag |= LEFT_MB_POS; } if( bTop ){ uiNeighborAvailFlag |= TOP_MB_POS; } if( bLeftTop ){ uiNeighborAvailFlag |= TOPLEFT_MB_POS; } if( bRightTop ){ uiNeighborAvailFlag |= TOPRIGHT_MB_POS; } pMb->uiNeighborAvail = (uint8_t)uiNeighborAvailFlag; pMb->uiSliceIdc = uiSliceIdc; ++ iIdx; } while(iIdx <= kiEndMbInSlice); } void CalcSliceComplexRatio( void *pRatio, SSliceCtx *pSliceCtx, uint32_t *pSliceConsume ) { float *pRatioList = (float *)pRatio; float fAvI[MAX_SLICES_NUM]; float fSumAv = .0f; uint32_t *pSliceTime = (uint32_t *)pSliceConsume; int32_t *pCountMbInSlice = (int32_t *)pSliceCtx->pCountMbNumInSlice; const int32_t kiSliceCount = pSliceCtx->iSliceNumInFrame; int32_t iSliceIdx = 0; #if defined(X86_ASM) WelsEmms(); #endif //X86_ASM while ( iSliceIdx < kiSliceCount ) { fAvI[iSliceIdx] = 1.0f * pCountMbInSlice[iSliceIdx] / pSliceTime[iSliceIdx]; #if defined(ENABLE_TRACE_MT) WelsLog(NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), pSliceConsumeTime[%d]= %d us, slice_run= %d\n", iSliceIdx, pSliceTime[iSliceIdx], pCountMbInSlice[iSliceIdx]); #endif//ENABLE_TRACE_MT fSumAv += fAvI[iSliceIdx]; ++ iSliceIdx; } while ( -- iSliceIdx >= 0 ) { pRatioList[iSliceIdx] = fAvI[iSliceIdx] / fSumAv; } } #if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) && defined(NOT_ABSOLUTE_BALANCING) int32_t NeedDynamicAdjust( void *pConsumeTime, const int32_t iSliceNum ) { #if !defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING) const float fRatioLower = TOLERANT_BALANCING_RATIO_LOWER( uiSliceNum ); const float fRatioUpper = TOLERANT_BALANCING_RATIO_UPPER( uiSliceNum ); #endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING uint32_t *pSliceConsume = (uint32_t *)pConsumeTime; uint32_t uiTotalConsume = 0; int32_t iSliceIdx = 0; int32_t iNeedAdj = false; #if defined(X86_ASM) WelsEmms(); #endif //X86_ASM while( iSliceIdx < iSliceNum ) { uiTotalConsume += pSliceConsume[iSliceIdx] + pSliceConsume[1+iSliceIdx]; iSliceIdx += 2; } if (uiTotalConsume == 0) { #if defined(ENABLE_TRACE_MT) WelsLog( NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein do no adjust due first picture, iCountSliceNum= %d\n", iSliceNum ); #endif//ENABLE_TRACE_MT return false; } iSliceIdx = 0; #if defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING) float fThr = EPSN; // threshold for various cores cases float fRmse = .0f; // root mean square error of pSlice consume ratios const float kfMeanRatio = 1.0f / iSliceNum; do{ const float fRatio = 1.0f * pSliceConsume[iSliceIdx] / uiTotalConsume; const float fDiffRatio = fRatio - kfMeanRatio; fRmse += (fDiffRatio * fDiffRatio); ++ iSliceIdx; } while ( iSliceIdx+1 < iSliceNum ); fRmse = sqrtf(fRmse/iSliceNum); if ( iSliceNum >= 8 ) { fThr += THRESHOLD_RMSE_CORE8; } else if ( iSliceNum >= 4 ) { fThr += THRESHOLD_RMSE_CORE4; } else if ( iSliceNum >= 2 ) { fThr += THRESHOLD_RMSE_CORE2; } else fThr = 1.0f; if ( fRmse > fThr ) iNeedAdj = true; #if defined(ENABLE_TRACE_MT) WelsLog(NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein adjustment decision is made (iNeedAdj= %d) by: fRmse of pSlice complexity ratios %.6f, the corresponding threshold %.6f, iCountSliceNum %d\n", iNeedAdj, fRmse, fThr, iSliceNum); #endif//ENABLE_TRACE_MT #else do{ const float kfRatio = 1.0f * pSliceConsume[uiSliceIdx] / uiTotalConsume; if ( kfRatio+EPSN < fRatioLower || kfRatio > ratio_upper+EPSN ) { #if defined(ENABLE_TRACE_MT) WelsLog(NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein adjustment decision is made by pSlice consume time not balanced at all, uiSliceIdx= %d, comp_ratio= %.6f, pSliceConsumeTime= %d, total_consume_time= %d, iCountSliceNum= %d\n", uiSliceIdx, kfRatio, pSliceConsume[uiSliceIdx], uiTotalConsume, uiSliceNum); #endif//ENABLE_TRACE_MT iNeedAdj = true; break; } ++ uiSliceIdx; } while ( uiSliceIdx+1 < uiSliceNum ); #endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING return iNeedAdj; } #endif//.. #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) void DynamicAdjustSlicing( sWelsEncCtx *pCtx, SDqLayer *pCurDqLayer, void *pComplexRatio, int32_t iCurDid ) { SSliceCtx *pSliceCtx = pCurDqLayer->pSliceEncCtx; const int32_t kiCountSliceNum = pSliceCtx->iSliceNumInFrame; const int32_t kiCountNumMb = pSliceCtx->iMbNumInFrame; int32_t iMinimalMbNum = pSliceCtx->iMbWidth; // in theory we need only 1 SMB, here let it as one SMB row required int32_t iMaximalMbNum = 0; // dynamically assign later float *pSliceComplexRatio = (float *)pComplexRatio; int32_t iMbNumLeft = kiCountNumMb; int32_t iRunLen[MAX_THREADS_NUM] = {0}; int32_t iSliceIdx = 0; int32_t iNumMbInEachGom; SWelsSvcRc *pWelsSvcRc = &pCtx->pWelsSvcRc[iCurDid]; if(pCtx->pSvcParam->bEnableRc) { iNumMbInEachGom = pWelsSvcRc->iNumberMbGom; if ( iNumMbInEachGom <= 0 ) { WelsLog(pCtx, WELS_LOG_ERROR, "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d\n", iNumMbInEachGom, iCurDid, kiCountNumMb); return; } // do not adjust in case no extra iNumMbInEachGom based left for slicing adjustment, // extra MB of non integrated GOM assigned at the last pSlice in default, keep up on early initial result. if ( iNumMbInEachGom * kiCountSliceNum >= kiCountNumMb ) { return; } iMinimalMbNum = iNumMbInEachGom; } if ( kiCountSliceNum < 2 || (kiCountSliceNum & 0x01) ) // we need suppose uiSliceNum is even for multiple threading return; iMaximalMbNum = kiCountNumMb - (kiCountSliceNum - 1) * iMinimalMbNum; #if defined(X86_ASM) WelsEmms(); #endif //X86_ASM #if defined(ENABLE_TRACE_MT) WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iDid= %d, iCountNumMb= %d\n", iCurDid, kiCountNumMb); #endif//ENABLE_TRACE_MT iSliceIdx = 0; while (iSliceIdx+1 < kiCountSliceNum) { int32_t iNumMbAssigning = (int32_t)(kiCountNumMb * pSliceComplexRatio[iSliceIdx] + EPSN); // GOM boundary aligned if(pCtx->pSvcParam->bEnableRc) { iNumMbAssigning=(int32_t)(1.0f * iNumMbAssigning / iNumMbInEachGom + 0.5f + EPSN) * iNumMbInEachGom; } // make sure one GOM at least in each pSlice for safe if ( iNumMbAssigning < iMinimalMbNum ) iNumMbAssigning = iMinimalMbNum; else if ( iNumMbAssigning > iMaximalMbNum ) iNumMbAssigning = iMaximalMbNum; assert( iNumMbAssigning > 0 ); iMbNumLeft -= iNumMbAssigning; if ( iMbNumLeft <= 0 ) // error due to we can not support slice_skip now yet, do not adjust this time { assert( 0 ); return; } iRunLen[iSliceIdx] = iNumMbAssigning; #if defined(ENABLE_TRACE_MT) WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), uiSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n", iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iNumMbAssigning); #endif//ENABLE_TRACE_MT ++ iSliceIdx; iMaximalMbNum = iMbNumLeft - (kiCountSliceNum - iSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts } iRunLen[iSliceIdx] = iMbNumLeft; #if defined(ENABLE_TRACE_MT) WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n", iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iMbNumLeft); #endif//ENABLE_TRACE_MT if ( DynamicAdjustSlicePEncCtxAll( pSliceCtx, iRunLen ) == 0 ) { const int32_t kiThreadNum = pCtx->pSvcParam->iCountThreadsNum; int32_t iThreadIdx = 0; do { #ifdef WIN32 WelsEventSignal( &pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] ); #else WelsEventSignal( pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] ); #endif//WIN32 ++ iThreadIdx; } while(iThreadIdx < kiThreadNum); WelsMultipleEventsWaitAllBlocking( kiThreadNum, &pCtx->pSliceThreading->pFinUpdateMbListEvent[0] ); } } #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef PACKING_ONE_SLICE_PER_LAYER void ResetEnvMt( sWelsEncCtx *pCtx) { const int16_t kiSliceCount = pCtx->iMaxSliceCount; int32_t iIdx = 0; while ( iIdx < kiSliceCount ) { SWelsSliceBs *pSliceBs = &pCtx->pSliceBs[iIdx]; pSliceBs->uiBsPos = 0; ++ iIdx; } } #endif//PACKING_ONE_SLICE_PER_LAYER int32_t RequestMtResource( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pCodingParam, const int32_t iCountBsLen, const int32_t iTargetSpatialBsSize ) { CMemoryAlign *pMa = NULL; SWelsSvcCodingParam *pPara= NULL; SSliceThreading *pSmt = NULL; SWelsSliceBs *pSliceB = NULL; uint8_t *pBsBase = NULL; int32_t iNumSpatialLayers = 0; int32_t iThreadNum = 0; int32_t iIdx = 0; int32_t iSliceBsBufferSize= 0; int16_t iMaxSliceNum = 1; if ( NULL == ppCtx || NULL == pCodingParam || NULL == *ppCtx || iCountBsLen <= 0 ) return 1; pMa = (*ppCtx)->pMemAlign; pPara= pCodingParam; iNumSpatialLayers = pPara->iNumDependencyLayer; iThreadNum = pPara->iCountThreadsNum; iMaxSliceNum = (*ppCtx)->iMaxSliceCount; pSmt = (SSliceThreading *)pMa->WelsMalloc(sizeof(SSliceThreading), "SSliceThreading"); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt), FreeMemorySvc(ppCtx) ) (*ppCtx)->pSliceThreading = pSmt; pSmt->pThreadPEncCtx = (SSliceThreadPrivateData *)pMa->WelsMalloc( sizeof(SSliceThreadPrivateData) * iThreadNum, "pThreadPEncCtx" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadPEncCtx), FreeMemorySvc(ppCtx) ) pSmt->pThreadHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pThreadHandles" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadHandles), FreeMemorySvc(ppCtx) ) #ifdef WIN32 pSmt->pSliceCodedEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pSliceCodedEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceCodedEvent), FreeMemorySvc(ppCtx) ) pSmt->pReadySliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pReadySliceCodingEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pReadySliceCodingEvent), FreeMemorySvc(ppCtx) ) pSmt->pFinSliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinSliceCodingEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinSliceCodingEvent), FreeMemorySvc(ppCtx) ) #endif//WIN32 #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #if defined(__GNUC__) pSmt->pUpdateMbListThrdHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pUpdateMbListThrdHandles" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListThrdHandles), FreeMemorySvc(ppCtx) ) #endif//__GNUC__ #ifdef WIN32 pSmt->pUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pUpdateMbListEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListEvent), FreeMemorySvc(ppCtx) ) pSmt->pFinUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinUpdateMbListEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinUpdateMbListEvent), FreeMemorySvc(ppCtx) ) #endif//WIN32 #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef WIN32 pSmt->pExitEncodeEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pExitEncodeEvent" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pExitEncodeEvent), FreeMemorySvc(ppCtx) ) #endif//WIN32 #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) iIdx = 0; while ( iIdx < iNumSpatialLayers ) { SMulSliceOption *pMso = &pPara->sDependencyLayers[iIdx].sMso; const int32_t kiSliceNum= pMso->sSliceArgument.iSliceNum; if (pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE && pPara->iMultipleThreadIdc > 1 && pPara->iMultipleThreadIdc >= kiSliceNum ) { pSmt->pSliceConsumeTime[iIdx] = (uint32_t *)pMa->WelsMallocz( kiSliceNum * sizeof(uint32_t), "pSliceConsumeTime[]" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceConsumeTime[iIdx]), FreeMemorySvc(ppCtx) ) #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) pSmt->pSliceComplexRatio[iIdx] = (float *)pMa->WelsMalloc( kiSliceNum * sizeof(float), "pSliceComplexRatio[]" ); WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceComplexRatio[iIdx]), FreeMemorySvc(ppCtx) ) #endif//TRY_SLICING_BALANCE } else { pSmt->pSliceConsumeTime[iIdx] = NULL; #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) pSmt->pSliceComplexRatio[iIdx] = NULL; #endif//TRY_SLICING_BALANCE } ++ iIdx; } // NULL for pSliceConsumeTime[iIdx]: iIdx from iNumSpatialLayers to MAX_DEPENDENCY_LAYERS #endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) #ifdef MT_DEBUG // file handle for MT debug pSmt->pFSliceDiff = NULL; if ( pSmt->pFSliceDiff ) { fclose( pSmt->pFSliceDiff ); pSmt->pFSliceDiff = NULL; } #ifdef WIN32 pSmt->pFSliceDiff = fopen(".\\slice_time.txt", "wt+" ); #else pSmt->pFSliceDiff = fopen("/tmp/slice_time.txt", "wt+" ); #endif//WIN32 #endif//MT_DEBUG #if defined(ENABLE_TRACE_MT) WelsLog((*ppCtx), WELS_LOG_INFO, "encpEncCtx= 0x%p\n", (void *)(*ppCtx)); #endif//ENABLE_TRACE_MT iIdx = 0; while ( iIdx < iThreadNum ) { #ifdef __GNUC__ // for posix threading str_t name[SEM_NAME_MAX] = {0}; int32_t used_len = 0; WELS_THREAD_ERROR_CODE err = 0; #endif//__GNUC__ pSmt->pThreadPEncCtx[iIdx].pWelsPEncCtx = (void *)(*ppCtx); pSmt->pThreadPEncCtx[iIdx].iSliceIndex = iIdx; pSmt->pThreadPEncCtx[iIdx].iThreadIndex = iIdx; pSmt->pThreadHandles[iIdx] = 0; #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef WIN32 WelsEventInit( &pSmt->pUpdateMbListEvent[iIdx] ); WelsEventInit( &pSmt->pFinUpdateMbListEvent[iIdx] ); #else // length of semaphore name should be system constrained at least on mac 10.7 SNPRINTF( name, SEM_NAME_MAX, "ud%d%p", iIdx, (void *)(*ppCtx) ); err = WelsEventOpen( &pSmt->pUpdateMbListEvent[iIdx], name ); #if defined(ENABLE_TRACE_MT) WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno); #endif used_len = SNPRINTF( name, SEM_NAME_MAX, "fu%d%p", iIdx, (void *)(*ppCtx) ); name[used_len] = '\0'; err = WelsEventOpen( &pSmt->pFinUpdateMbListEvent[iIdx], name ); #if defined(ENABLE_TRACE_MT) WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pFinUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno); #endif #endif//WIN32 #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef WIN32 WelsEventInit( &pSmt->pSliceCodedEvent[iIdx] ); WelsEventInit( &pSmt->pReadySliceCodingEvent[iIdx] ); WelsEventInit( &pSmt->pFinSliceCodingEvent[iIdx] ); WelsEventInit( &pSmt->pExitEncodeEvent[iIdx] ); #else used_len = SNPRINTF( name, SEM_NAME_MAX, "sc%d%p", iIdx, (void *)(*ppCtx) ); name[used_len] = '\0'; err = WelsEventOpen( &pSmt->pSliceCodedEvent[iIdx], name ); #if defined(ENABLE_TRACE_MT) WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pSliceCodedEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);