ref: 9b70a6dbafa2e17c04f51b12e3abb3d76493732b
dir: /codec/encoder/core/src/slice_multi_threading.cpp/
/*! * \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> #if defined(__GNUC__) && !defined(_WIN32) #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; } pSmt->pFSliceDiff = fopen ("slice_time.txt", "wt+"); #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) { #if defined(__GNUC__) && !defined(_WIN32) // for posix threading str_t name[SEM_NAME_MAX] = {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 WelsSnprintf (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 WelsSnprintf (name, SEM_NAME_MAX, "fu%d%p", iIdx, (void*) (*ppCtx)); 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 WelsSnprintf (name, SEM_NAME_MAX, "sc%d%p", iIdx, (void*) (*ppCtx)); 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); #endif WelsSnprintf (name, SEM_NAME_MAX, "rc%d%p", iIdx, (void*) (*ppCtx)); err = WelsEventOpen (&pSmt->pReadySliceCodingEvent[iIdx], name); #if defined(ENABLE_TRACE_MT) WelsLog ((*ppCtx), WELS_LOG_INFO, "[MT] Open pReadySliceCodingEvent%d = 0x%p named(%s) ret%d err%d\n", iIdx, (void*)pSmt->pReadySliceCodingEvent[iIdx], (void*) (*ppCtx), err, errno); #endif #endif//_WIN32 ++ iIdx; } #ifdef PACKING_ONE_SLICE_PER_LAYER pSmt->pCountBsSizeInPartition = (uint32_t*)pMa->WelsMalloc (sizeof (uint32_t) * iThreadNum, "pCountBsSizeInPartition"); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pSmt->pCountBsSizeInPartition), FreeMemorySvc (ppCtx)) #endif//PACKING_ONE_SLICE_PER_LAYER WelsMutexInit (&pSmt->mutexSliceNumUpdate); (*ppCtx)->pSliceBs = (SWelsSliceBs*)pMa->WelsMalloc (sizeof (SWelsSliceBs) * iMaxSliceNum, "pSliceBs"); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSliceBs), FreeMemorySvc (ppCtx)) pBsBase = (*ppCtx)->pFrameBs + iCountBsLen; pSliceB = (*ppCtx)->pSliceBs; iSliceBsBufferSize = iTargetSpatialBsSize; iIdx = 0; while (iIdx < iMaxSliceNum) { pSliceB->pBsBuffer = (uint8_t*)pMa->WelsMalloc (iSliceBsBufferSize, "pSliceB->pBsBuffer"); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pSliceB->pBsBuffer), FreeMemorySvc (ppCtx)) pSliceB->uiSize = iSliceBsBufferSize; if (iIdx > 0) { pSliceB->pBs = pBsBase; pSliceB->uiBsPos = 0; pBsBase += iSliceBsBufferSize; } else { pSliceB->pBs = NULL; pSliceB->uiBsPos = 0; } ++ pSliceB; ++ iIdx; } #if defined(ENABLE_TRACE_MT) WelsLog ((*ppCtx), WELS_LOG_INFO, "RequestMtResource(), iThreadNum=%d, iCountSliceNum= %d\n", pPara->iCountThreadsNum, iMaxSliceNum); #endif return 0; } void ReleaseMtResource (sWelsEncCtx** ppCtx) { SWelsSliceBs* pSliceB = NULL; SWelsSvcCodingParam* pCodingParam = NULL; SSliceThreading* pSmt = NULL; CMemoryAlign* pMa = NULL; int32_t iIdx = 0; int32_t iThreadNum = 0; int16_t uiSliceNum = 0; if (NULL == ppCtx || NULL == *ppCtx) return; pMa = (*ppCtx)->pMemAlign; pCodingParam = (*ppCtx)->pSvcParam; uiSliceNum = (*ppCtx)->iMaxSliceCount; iThreadNum = (*ppCtx)->pSvcParam->iCountThreadsNum; pSmt = (*ppCtx)->pSliceThreading; if (NULL == pSmt) return; while (iIdx < iThreadNum) { #ifdef _WIN32 if (pSmt->pThreadHandles != NULL && pSmt->pThreadHandles[iIdx] != NULL) WelsThreadDestroy (&pSmt->pThreadHandles[iIdx]); if (pSmt->pSliceCodedEvent != NULL) WelsEventDestroy (&pSmt->pSliceCodedEvent[iIdx]); if (pSmt->pReadySliceCodingEvent != NULL) WelsEventDestroy (&pSmt->pReadySliceCodingEvent[iIdx]); if (pSmt->pFinSliceCodingEvent != NULL) WelsEventDestroy (&pSmt->pFinSliceCodingEvent[iIdx]); if (pSmt->pExitEncodeEvent != NULL) WelsEventDestroy (&pSmt->pExitEncodeEvent[iIdx]); #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) if (pSmt->pUpdateMbListEvent != NULL) WelsEventDestroy (&pSmt->pUpdateMbListEvent[iIdx]); if (pSmt->pFinUpdateMbListEvent != NULL) WelsEventDestroy (&pSmt->pFinUpdateMbListEvent[iIdx]); #endif//DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE #else str_t ename[SEM_NAME_MAX] = {0}; // length of semaphore name should be system constrained at least on mac 10.7 WelsSnprintf (ename, SEM_NAME_MAX, "sc%d%p", iIdx, (void*) (*ppCtx)); WelsEventClose (pSmt->pSliceCodedEvent[iIdx], ename); WelsSnprintf (ename, SEM_NAME_MAX, "rc%d%p", iIdx, (void*) (*ppCtx)); WelsEventClose (pSmt->pReadySliceCodingEvent[iIdx], ename); #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) WelsSnprintf (ename, SEM_NAME_MAX, "ud%d%p", iIdx, (void*) (*ppCtx)); WelsEventClose (pSmt->pUpdateMbListEvent[iIdx], ename); WelsSnprintf (ename, SEM_NAME_MAX, "fu%d%p", iIdx, (void*) (*ppCtx)); WelsEventClose (pSmt->pFinUpdateMbListEvent[iIdx], ename); #endif//DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE #endif//_WIN32 ++ iIdx; } #ifdef _WIN32 if (pSmt->pExitEncodeEvent != NULL) { pMa->WelsFree (pSmt->pExitEncodeEvent, "pExitEncodeEvent"); pSmt->pExitEncodeEvent = NULL; } if (pSmt->pSliceCodedEvent != NULL) { pMa->WelsFree (pSmt->pSliceCodedEvent, "pSliceCodedEvent"); pSmt->pSliceCodedEvent = NULL; } if (pSmt->pReadySliceCodingEvent != NULL) { pMa->WelsFree (pSmt->pReadySliceCodingEvent, "pReadySliceCodingEvent"); pSmt->pReadySliceCodingEvent = NULL; } if (pSmt->pFinSliceCodingEvent != NULL) { pMa->WelsFree (pSmt->pFinSliceCodingEvent, "pFinSliceCodingEvent"); pSmt->pFinSliceCodingEvent = NULL; } #endif//_WIN32 #ifdef PACKING_ONE_SLICE_PER_LAYER if (NULL != pSmt->pCountBsSizeInPartition) { pMa->WelsFree (pSmt->pCountBsSizeInPartition, "pCountBsSizeInPartition"); pSmt->pCountBsSizeInPartition = NULL; } #endif//PACKING_ONE_SLICE_PER_LAYER WelsMutexDestroy (&pSmt->mutexSliceNumUpdate); if (pSmt->pThreadPEncCtx != NULL) { pMa->WelsFree (pSmt->pThreadPEncCtx, "pThreadPEncCtx"); pSmt->pThreadPEncCtx = NULL; } if (pSmt->pThreadHandles != NULL) { pMa->WelsFree (pSmt->pThreadHandles, "pThreadHandles"); pSmt->pThreadHandles = NULL; } pSliceB = (*ppCtx)->pSliceBs; iIdx = 0; while (pSliceB != NULL && iIdx < uiSliceNum) { if (pSliceB->pBsBuffer) { pMa->WelsFree (pSliceB->pBsBuffer, "pSliceB->pBsBuffer"); pSliceB->pBsBuffer = NULL; pSliceB->uiSize = 0; } ++ iIdx; ++ pSliceB; } if ((*ppCtx)->pSliceBs != NULL) { pMa->WelsFree ((*ppCtx)->pSliceBs, "pSliceBs"); (*ppCtx)->pSliceBs = NULL; } #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) iIdx = 0; while (iIdx < pCodingParam->iNumDependencyLayer) { if (pSmt->pSliceConsumeTime[iIdx]) { pMa->WelsFree (pSmt->pSliceConsumeTime[iIdx], "pSliceConsumeTime[]"); pSmt->pSliceConsumeTime[iIdx] = NULL; } #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) if (pSmt->pSliceComplexRatio[iIdx] != NULL) { pMa->WelsFree (pSmt->pSliceComplexRatio[iIdx], "pSliceComplexRatio[]"); pSmt->pSliceComplexRatio[iIdx] = NULL; } #endif//TRY_SLICING_BALANCE ++ iIdx; } #endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef _WIN32 if (pSmt->pUpdateMbListEvent != NULL) { pMa->WelsFree (pSmt->pUpdateMbListEvent, "pUpdateMbListEvent"); pSmt->pUpdateMbListEvent = NULL; } if (pSmt->pFinUpdateMbListEvent != NULL) { pMa->WelsFree (pSmt->pFinUpdateMbListEvent, "pFinUpdateMbListEvent"); pSmt->pFinUpdateMbListEvent = NULL; } #else if (pSmt->pUpdateMbListThrdHandles) { pMa->WelsFree (pSmt->pUpdateMbListThrdHandles, "pUpdateMbListThrdHandles"); pSmt->pUpdateMbListThrdHandles = NULL; } #endif//_WIN32 #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #ifdef MT_DEBUG // file handle for debug if (pSmt->pFSliceDiff) { fclose (pSmt->pFSliceDiff); pSmt->pFSliceDiff = NULL; } #endif//MT_DEBUG pMa->WelsFree ((*ppCtx)->pSliceThreading, "SSliceThreading"); (*ppCtx)->pSliceThreading = NULL; } int32_t AppendSliceToFrameBs (sWelsEncCtx* pCtx, SLayerBSInfo* pLbi, const int32_t iSliceCount) { SWelsSvcCodingParam* pCodingParam = pCtx->pSvcParam; SDLayerParam* pDlp = &pCodingParam->sDependencyLayers[pCtx->uiDependencyId]; SWelsSliceBs* pSliceBs = NULL; const BOOL_T kbIsDynamicSlicingMode = (pDlp->sMso.uiSliceMode == SM_DYN_SLICE); int32_t iLayerSize = 0; int32_t iNalIdxBase = pLbi->iNalCount; int32_t iSliceIdx = 0; if (!kbIsDynamicSlicingMode) { pSliceBs = &pCtx->pSliceBs[0]; iLayerSize = pSliceBs->uiBsPos; // assign with base pSlice first iSliceIdx = 1; // pSlice 0 bs has been written to pFrameBs yet by now, so uiSliceIdx base should be 1 while (iSliceIdx < iSliceCount) { ++ pSliceBs; if (pSliceBs != NULL && pSliceBs->uiBsPos > 0) { int32_t iNalIdx = 0; const int32_t iCountNal = pSliceBs->iNalIndex; #if MT_DEBUG_BS_WR assert (pSliceBs->bSliceCodedFlag); #endif//MT_DEBUG_BS_WR memmove (pCtx->pFrameBs + pCtx->iPosBsBuffer, pSliceBs->pBs, pSliceBs->uiBsPos); // confirmed_safe_unsafe_usage pCtx->iPosBsBuffer += pSliceBs->uiBsPos; iLayerSize += pSliceBs->uiBsPos; while (iNalIdx < iCountNal) { pLbi->iNalLengthInByte[iNalIdxBase + iNalIdx] = pSliceBs->iNalLen[iNalIdx]; ++ iNalIdx; } pLbi->iNalCount += iCountNal; iNalIdxBase += iCountNal; } ++ iSliceIdx; } } else { // for SM_DYN_SLICE const int32_t kiPartitionCnt = iSliceCount; int32_t iPartitionIdx = 0; // due partition_0 has been written to pFrameBsBuffer // so iLayerSize need add it while (iPartitionIdx < kiPartitionCnt) { const int32_t kiCountSlicesCoded = pCtx->pCurDqLayer->pNumSliceCodedOfPartition[iPartitionIdx]; int32_t iIdx = 0; iSliceIdx = iPartitionIdx; while (iIdx < kiCountSlicesCoded) { pSliceBs = &pCtx->pSliceBs[iSliceIdx]; if (pSliceBs != NULL && pSliceBs->uiBsPos > 0) { if (iPartitionIdx > 0) { int32_t iNalIdx = 0; const int32_t iCountNal = pSliceBs->iNalIndex; memmove (pCtx->pFrameBs + pCtx->iPosBsBuffer, pSliceBs->pBs, pSliceBs->uiBsPos); // confirmed_safe_unsafe_usage pCtx->iPosBsBuffer += pSliceBs->uiBsPos; iLayerSize += pSliceBs->uiBsPos; while (iNalIdx < iCountNal) { pLbi->iNalLengthInByte[iNalIdxBase + iNalIdx] = pSliceBs->iNalLen[iNalIdx]; ++ iNalIdx; } pLbi->iNalCount += iCountNal; iNalIdxBase += iCountNal; } else { iLayerSize += pSliceBs->uiBsPos; } } iSliceIdx += kiPartitionCnt; ++ iIdx; } ++ iPartitionIdx; } } return iLayerSize; } int32_t WriteSliceToFrameBs (sWelsEncCtx* pCtx, SLayerBSInfo* pLbi, uint8_t* pFrameBsBuffer, const int32_t iSliceIdx) { SWelsSliceBs* pSliceBs = &pCtx->pSliceBs[iSliceIdx]; SNalUnitHeaderExt* pNalHdrExt = &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt; uint8_t* pDst = pFrameBsBuffer; int32_t pNalLen[2]; int32_t iSliceSize = 0; const int32_t kiNalCnt = pSliceBs->iNalIndex; int32_t iNalIdx = 0; #if !defined(PACKING_ONE_SLICE_PER_LAYER) const int32_t iFirstSlice = (iSliceIdx == 0); int32_t iNalBase = iFirstSlice ? 0 : pLbi->iNalCount; #else int32_t iNalBase = 0; #endif//!PACKING_ONE_SLICE_PER_LAYER while (iNalIdx < kiNalCnt) { iSliceSize += WelsEncodeNalExt (&pSliceBs->sNalList[iNalIdx], pNalHdrExt, pDst, &pNalLen[iNalIdx]); pDst += pNalLen[iNalIdx]; pLbi->iNalLengthInByte[iNalBase + iNalIdx] = pNalLen[iNalIdx]; ++ iNalIdx; } #if !defined(PACKING_ONE_SLICE_PER_LAYER) pSliceBs->uiBsPos = iSliceSize; if (iFirstSlice) { // pBsBuffer has been updated at coding_slice_0_in_encoder_mother_thread() pLbi->uiLayerType = VIDEO_CODING_LAYER; pLbi->uiSpatialId = pNalHdrExt->uiDependencyId; pLbi->uiTemporalId = pNalHdrExt->uiTemporalId; pLbi->uiQualityId = 0; pLbi->uiPriorityId = 0; pLbi->iNalCount = kiNalCnt; } else { pLbi->iNalCount += kiNalCnt; } #else pLbi->uiLayerType = VIDEO_CODING_LAYER; pLbi->uiSpatialId = pNalHdrExt->uiDependencyId; pLbi->uiTemporalId = pNalHdrExt->uiTemporalId; pLbi->uiQualityId = 0; pLbi->uiPriorityId = 0; pLbi->iNalCount = kiNalCnt; #endif//PACKING_ONE_SLICE_PER_LAYER return iSliceSize; } int32_t WriteSliceBs (sWelsEncCtx* pCtx, uint8_t* pSliceBsBuf, const int32_t iSliceIdx) { SWelsSliceBs* pSliceBs = &pCtx->pSliceBs[iSliceIdx]; SNalUnitHeaderExt* pNalHdrExt = &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt; uint8_t* pDst = pSliceBsBuf; int32_t* pNalLen = &pSliceBs->iNalLen[0]; int32_t iSliceSize = 0; const int32_t kiNalCnt = pSliceBs->iNalIndex; int32_t iNalIdx = 0; assert (kiNalCnt <= 2); if (kiNalCnt > 2) return 0; while (iNalIdx < kiNalCnt) { iSliceSize += WelsEncodeNalExt (&pSliceBs->sNalList[iNalIdx], pNalHdrExt, pDst, &pNalLen[iNalIdx]); pDst += pNalLen[iNalIdx]; ++ iNalIdx; } pSliceBs->uiBsPos = iSliceSize; return iSliceSize; } #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #if defined(__GNUC__) && !defined(_WIN32) WELS_THREAD_ROUTINE_TYPE UpdateMbListThreadProc (void* arg) { SSliceThreadPrivateData* pPrivateData = (SSliceThreadPrivateData*)arg; sWelsEncCtx* pEncPEncCtx = NULL; SDqLayer* pCurDq = NULL; int32_t iSliceIdx = -1; int32_t iEventIdx = -1; WELS_THREAD_ERROR_CODE iWaitRet = WELS_THREAD_ERROR_GENERAL; uint32_t uiThrdRet = 0; if (NULL == pPrivateData) WELS_THREAD_ROUTINE_RETURN (1); pEncPEncCtx = (sWelsEncCtx*)pPrivateData->pWelsPEncCtx; iSliceIdx = pPrivateData->iSliceIndex; iEventIdx = pPrivateData->iThreadIndex; do { #if defined(ENABLE_TRACE_MT) WelsLog (pEncPEncCtx, WELS_LOG_INFO, "[MT] UpdateMbListThreadProc(), try to wait (pUpdateMbListEvent[%d])!\n", iEventIdx); #endif iWaitRet = WelsEventWait (pEncPEncCtx->pSliceThreading->pUpdateMbListEvent[iEventIdx]); if (WELS_THREAD_ERROR_WAIT_OBJECT_0 == iWaitRet) { pCurDq = pEncPEncCtx->pCurDqLayer; UpdateMbListNeighborParallel (pCurDq->pSliceEncCtx, pCurDq->sMbDataP, iSliceIdx); WelsEventSignal ( pEncPEncCtx->pSliceThreading->pFinUpdateMbListEvent[iEventIdx]); // mean finished update pMb list for this pSlice } else { WelsLog (pEncPEncCtx, WELS_LOG_WARNING, "[MT] UpdateMbListThreadProc(), waiting pUpdateMbListEvent[%d] failed(%d) and thread%d terminated!\n", iEventIdx, iWaitRet, iEventIdx); uiThrdRet = 1; break; } } while (1); WELS_THREAD_ROUTINE_RETURN (uiThrdRet); } #endif//__GNUC__ #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) // thread process for coding one pSlice WELS_THREAD_ROUTINE_TYPE CodingSliceThreadProc (void* arg) { SSliceThreadPrivateData* pPrivateData = (SSliceThreadPrivateData*)arg; sWelsEncCtx* pEncPEncCtx = NULL; SDqLayer* pCurDq = NULL; SSlice* pSlice = NULL; SWelsSliceBs* pSliceBs = NULL; #ifdef _WIN32 WELS_EVENT pEventsList[3]; int32_t iEventCount = 0; #endif WELS_THREAD_ERROR_CODE iWaitRet = WELS_THREAD_ERROR_GENERAL; uint32_t uiThrdRet = 0; int32_t iSliceSize = 0; int32_t iSliceIdx = -1; int32_t iThreadIdx = -1; int32_t iEventIdx = -1; bool_t bNeedPrefix = false; EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0; EWelsNalRefIdc eNalRefIdc = NRI_PRI_LOWEST; if (NULL == pPrivateData) WELS_THREAD_ROUTINE_RETURN (1); WelsSetThreadCancelable(); pEncPEncCtx = (sWelsEncCtx*)pPrivateData->pWelsPEncCtx; iThreadIdx = pPrivateData->iThreadIndex; iEventIdx = iThreadIdx; #ifdef _WIN32 pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pReadySliceCodingEvent[iEventIdx]; pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pExitEncodeEvent[iEventIdx]; #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pUpdateMbListEvent[iEventIdx]; #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #endif//_WIN32 do { #ifdef _WIN32 iWaitRet = WelsMultipleEventsWaitSingleBlocking (iEventCount, &pEventsList[0], (uint32_t) - 1); // blocking until at least one event is #else #if defined(ENABLE_TRACE_MT) WelsLog (pEncPEncCtx, WELS_LOG_INFO, "[MT] CodingSliceThreadProc(), try to call WelsEventWait(pReadySliceCodingEvent[%d]= 0x%p), pEncPEncCtx= 0x%p!\n", iEventIdx, (void*) (pEncPEncCtx->pReadySliceCodingEvent[iEventIdx]), (void*)pEncPEncCtx); #endif iWaitRet = WelsEventWait (pEncPEncCtx->pSliceThreading->pReadySliceCodingEvent[iEventIdx]); #endif//WIN32 if (WELS_THREAD_ERROR_WAIT_OBJECT_0 == iWaitRet) { // start pSlice coding signal waited SLayerBSInfo* pLbi = pPrivateData->pLayerBs; const int32_t kiCurDid = pEncPEncCtx->uiDependencyId; const int32_t kiCurTid = pEncPEncCtx->uiTemporalId; SWelsSvcCodingParam* pCodingParam = pEncPEncCtx->pSvcParam; SDLayerParam* pParamD = &pCodingParam->sDependencyLayers[kiCurDid]; pCurDq = pEncPEncCtx->pCurDqLayer; eNalType = pEncPEncCtx->eNalType; eNalRefIdc = pEncPEncCtx->eNalPriority; bNeedPrefix = pEncPEncCtx->bNeedPrefixNalFlag; if (pParamD->sMso.uiSliceMode != SM_DYN_SLICE) { int64_t iSliceStart = 0; bool_t bDsaFlag = false; iSliceIdx = pPrivateData->iSliceIndex; pSlice = &pCurDq->sLayerInfo.pSliceInLayer[iSliceIdx]; pSliceBs = &pEncPEncCtx->pSliceBs[iSliceIdx]; #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) bDsaFlag = (pParamD->sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pCodingParam->iMultipleThreadIdc > 1 && pCodingParam->iMultipleThreadIdc >= pParamD->sMso.sSliceArgument.iSliceNum); if (bDsaFlag) iSliceStart = WelsTime(); #endif//DYNAMIC_SLICE_ASSIGN || MT_DEBUG #if !defined(PACKING_ONE_SLICE_PER_LAYER) pSliceBs->uiBsPos = 0; #endif//!PACKING_ONE_SLICE_PER_LAYER pSliceBs->iNalIndex = 0; assert ((void*) (&pSliceBs->sBsWrite) == (void*)pSlice->pSliceBsa); InitBits (&pSliceBs->sBsWrite, pSliceBs->pBsBuffer, pSliceBs->uiSize); #if MT_DEBUG_BS_WR pSliceBs->bSliceCodedFlag = FALSE; #endif//MT_DEBUG_BS_WR if (bNeedPrefix) { if (eNalRefIdc != NRI_PRI_LOWEST) { WelsLoadNalForSlice (pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc); WelsWriteSVCPrefixNal (&pSliceBs->sBsWrite, eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == eNalType)); WelsUnloadNalForSlice (pSliceBs); } else { // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension WelsLoadNalForSlice (pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc); // No need write any syntax of prefix NAL Unit RBSP here WelsUnloadNalForSlice (pSliceBs); } } WelsLoadNalForSlice (pSliceBs, eNalType, eNalRefIdc); WelsCodeOneSlice (pEncPEncCtx, iSliceIdx, eNalType); WelsUnloadNalForSlice (pSliceBs); #if !defined(PACKING_ONE_SLICE_PER_LAYER) if (0 == iSliceIdx) { pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx); pEncPEncCtx->iPosBsBuffer += iSliceSize; } else iSliceSize = WriteSliceBs (pEncPEncCtx, pSliceBs->pBs, iSliceIdx); #else// PACKING_ONE_SLICE_PER_LAYER if (0 == iSliceIdx) { pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx); pEncPEncCtx->iPosBsBuffer += iSliceSize; } else { pLbi->pBsBuf = pSliceBs->bs + pSliceBs->uiBsPos; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx); pSliceBs->uiBsPos += iSliceSize; } #endif//!PACKING_ONE_SLICE_PER_LAYER if (pCurDq->bDeblockingParallelFlag && pSlice->sSliceHeaderExt.sSliceHeader.uiDisableDeblockingFilterIdc != 1 #if !defined(ENABLE_FRAME_DUMP) && (eNalRefIdc != NRI_PRI_LOWEST) && (pParamD->iHighestTemporalId == 0 || kiCurTid < pParamD->iHighestTemporalId) #endif// !ENABLE_FRAME_DUMP ) { DeblockingFilterSliceAvcbase (pCurDq, pEncPEncCtx->pFuncList, iSliceIdx); } #if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) if (bDsaFlag) { pEncPEncCtx->pSliceThreading->pSliceConsumeTime[pEncPEncCtx->uiDependencyId][iSliceIdx] = (uint32_t) ( WelsTime() - iSliceStart); #if defined(ENABLE_TRACE_MT) WelsLog (pEncPEncCtx, WELS_LOG_INFO, "[MT] CodingSliceThreadProc(), coding_idx %d, uiSliceIdx %d, pSliceConsumeTime %d, iSliceSize %d, pFirstMbInSlice %d, count_num_mb_in_slice %d\n", pEncPEncCtx->iCodingIndex, iSliceIdx, pEncPEncCtx->pSliceThreading->pSliceConsumeTime[pEncPEncCtx->uiDependencyId][iSliceIdx], iSliceSize, pCurDq->pSliceEncCtx->pFirstMbInSlice[iSliceIdx], pCurDq->pSliceEncCtx->pCountMbNumInSlice[iSliceIdx]); #endif//ENABLE_TRACE_MT } #endif//DYNAMIC_SLICE_ASSIGN || MT_DEBUG #if defined(SLICE_INFO_OUTPUT) fprintf (stderr, "@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n", iSliceIdx, (pEncPEncCtx->eSliceType == P_SLICE ? 'P' : 'I'), eNalRefIdc, iSliceSize ); #endif//SLICE_INFO_OUTPUT #if MT_DEBUG_BS_WR pSliceBs->bSliceCodedFlag = TRUE; #endif//MT_DEBUG_BS_WR #ifdef _WIN32 WelsEventSignal ( &pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx]); // mean finished coding current pSlice #else WelsEventSignal (pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx]); // mean finished coding current pSlice #endif//WIN32 } else { // for SM_DYN_SLICE parallelization #ifdef PACKING_ONE_SLICE_PER_LAYER SLayerBSInfo* pLbiPacking = NULL; #endif//PACKING_ONE_SLICE_PER_LAYER SSliceCtx* pSliceCtx = pCurDq->pSliceEncCtx; const int32_t kiPartitionId = iThreadIdx; const int32_t kiSliceIdxStep = pEncPEncCtx->iActiveThreadsNum; const int32_t kiFirstMbInPartition = pPrivateData->iStartMbIndex; // inclusive const int32_t kiEndMbInPartition = pPrivateData->iEndMbIndex; // exclusive int32_t iAnyMbLeftInPartition = kiEndMbInPartition - kiFirstMbInPartition; iSliceIdx = pPrivateData->iSliceIndex; pSliceCtx->pFirstMbInSlice[iSliceIdx] = kiFirstMbInPartition; pCurDq->pNumSliceCodedOfPartition[kiPartitionId] = 1; // one pSlice per partition intialized, dynamic slicing inside pCurDq->pLastMbIdxOfPartition[kiPartitionId] = kiEndMbInPartition - 1; pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId] = 0; while (iAnyMbLeftInPartition > 0) { if (iSliceIdx >= pSliceCtx->iMaxSliceNumConstraint) { // TODO: need exception handler for not large enough of MAX_SLICES_NUM related memory usage // No idea about its solution due MAX_SLICES_NUM is fixed lenght in relevent pData structure uiThrdRet = 1; break; } pSlice = &pCurDq->sLayerInfo.pSliceInLayer[iSliceIdx]; pSliceBs = &pEncPEncCtx->pSliceBs[iSliceIdx]; #if !defined(PACKING_ONE_SLICE_PER_LAYER) pSliceBs->uiBsPos = 0; #endif//!PACKING_ONE_SLICE_PER_LAYER pSliceBs->iNalIndex = 0; InitBits (&pSliceBs->sBsWrite, pSliceBs->pBsBuffer, pSliceBs->uiSize); if (bNeedPrefix) { if (eNalRefIdc != NRI_PRI_LOWEST) { WelsLoadNalForSlice (pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc); WelsWriteSVCPrefixNal (&pSliceBs->sBsWrite, eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == eNalType)); WelsUnloadNalForSlice (pSliceBs); } else { // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension WelsLoadNalForSlice (pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc); // No need write any syntax of prefix NAL Unit RBSP here WelsUnloadNalForSlice (pSliceBs); } } WelsLoadNalForSlice (pSliceBs, eNalType, eNalRefIdc); WelsCodeOneSlice (pEncPEncCtx, iSliceIdx, eNalType); WelsUnloadNalForSlice (pSliceBs); #if !defined(PACKING_ONE_SLICE_PER_LAYER) if (0 == kiPartitionId) { if (0 == iSliceIdx) pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbi, pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer, iSliceIdx); pEncPEncCtx->iPosBsBuffer += iSliceSize; } else iSliceSize = WriteSliceBs (pEncPEncCtx, pSliceBs->pBs, iSliceIdx); #else// PACKING_ONE_SLICE_PER_LAYER pLbiPacking = pLbi + (iSliceIdx - kiPartitionId); if (0 == kiPartitionId) { pLbiPacking->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbiPacking, pLbiPacking->pBsBuf, iSliceIdx); pEncPEncCtx->iPosBsBuffer += iSliceSize; } else { pLbiPacking->pBsBuf = pSliceBs->bs + pSliceBs->uiBsPos; iSliceSize = WriteSliceToFrameBs (pEncPEncCtx, pLbiPacking, pLbiPacking->pBsBuf, iSliceIdx); pSliceBs->uiBsPos += iSliceSize; } pEncPEncCtx->pSliceThreading->pCountBsSizeInPartition[kiPartitionId] += iSliceSize; #endif//!PACKING_ONE_SLICE_PER_LAYER if (pCurDq->bDeblockingParallelFlag && pSlice->sSliceHeaderExt.sSliceHeader.uiDisableDeblockingFilterIdc != 1 #if !defined(ENABLE_FRAME_DUMP) && (eNalRefIdc != NRI_PRI_LOWEST) && (pParamD->iHighestTemporalId == 0 || kiCurTid < pParamD->iHighestTemporalId) #endif// !ENABLE_FRAME_DUMP ) { DeblockingFilterSliceAvcbase (pCurDq, pEncPEncCtx->pFuncList, iSliceIdx); } #if defined(SLICE_INFO_OUTPUT) fprintf (stderr, "@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n", iSliceIdx, (pEncPEncCtx->eSliceType == P_SLICE ? 'P' : 'I'), eNalRefIdc, iSliceSize ); #endif//SLICE_INFO_OUTPUT #if defined(ENABLE_TRACE_MT) WelsLog (pEncPEncCtx, WELS_LOG_INFO, "[MT] CodingSliceThreadProc(), coding_idx %d, iPartitionId %d, uiSliceIdx %d, iSliceSize %d, count_mb_slice %d, iEndMbInPartition %d, pCurDq->pLastCodedMbIdxOfPartition[%d] %d\n", pEncPEncCtx->iCodingIndex, kiPartitionId, iSliceIdx, iSliceSize, pCurDq->pSliceEncCtx->pCountMbNumInSlice[iSliceIdx], kiEndMbInPartition, kiPartitionId, pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId]); #endif//ENABLE_TRACE_MT iAnyMbLeftInPartition = kiEndMbInPartition - (1 + pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId]); iSliceIdx += kiSliceIdxStep; } if (uiThrdRet) // any exception?? break; #ifdef _WIN32 WelsEventSignal (&pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx]); // mean finished coding current pSlice #else WelsEventSignal (pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx]); // mean finished coding current pSlice #endif//WIN32 } } #ifdef _WIN32 else if (WELS_THREAD_ERROR_WAIT_OBJECT_0 + 1 == iWaitRet) { // exit thread signal uiThrdRet = 0; break; } #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) else if (WELS_THREAD_ERROR_WAIT_OBJECT_0 + 2 == iWaitRet) { // update pMb list singal iSliceIdx = iEventIdx; // pPrivateData->iSliceIndex; old threads can not be terminated, pPrivateData is not correct for applicable pCurDq = pEncPEncCtx->pCurDqLayer; UpdateMbListNeighborParallel (pCurDq->pSliceEncCtx, pCurDq->sMbDataP, iSliceIdx); WelsEventSignal ( &pEncPEncCtx->pSliceThreading->pFinUpdateMbListEvent[iEventIdx]); // mean finished update pMb list for this pSlice } #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #endif//WIN32 else { // WELS_THREAD_ERROR_WAIT_TIMEOUT, or WELS_THREAD_ERROR_WAIT_FAILED WelsLog (pEncPEncCtx, WELS_LOG_WARNING, "[MT] CodingSliceThreadProc(), waiting pReadySliceCodingEvent[%d] failed(%d) and thread%d terminated!\n", iEventIdx, iWaitRet, iThreadIdx); uiThrdRet = 1; break; } } while (1); #ifdef _WIN32 WelsEventSignal (&pEncPEncCtx->pSliceThreading->pFinSliceCodingEvent[iEventIdx]); // notify to mother encoding threading #endif//WIN32 WELS_THREAD_ROUTINE_RETURN (uiThrdRet); } int32_t CreateSliceThreads (sWelsEncCtx* pCtx) { const int32_t kiThreadCount = pCtx->pSvcParam->iCountThreadsNum; int32_t iIdx = 0; #if defined(_WIN32) && defined(BIND_CPU_CORES_TO_THREADS) DWORD dwProcessAffinity; DWORD dwSystemAffinity; GetProcessAffinityMask (GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); #endif//WIN32 && BIND_CPU_CORES_TO_THREADS while (iIdx < kiThreadCount) { WelsThreadCreate (&pCtx->pSliceThreading->pThreadHandles[iIdx], CodingSliceThreadProc, &pCtx->pSliceThreading->pThreadPEncCtx[iIdx], 0); #if defined(_WIN32) && defined(BIND_CPU_CORES_TO_THREADS) if (dwProcessAffinity > 1 && pCtx->pSliceThreading->pThreadHandles[iIdx] != NULL) { // multiple cores and thread created successfully DWORD dw = 0; DWORD dwAffinityMask = 1 << iIdx; if (dwAffinityMask & dwProcessAffinity) { // check if cpu is available dw = SetThreadAffinityMask (pCtx->pSliceThreading->pThreadHandles[iIdx], dwAffinityMask); //1 << iIdx if (dw == 0) { str_t str[64] = {0}; WelsSnprintf (str, 64, "SetThreadAffinityMask iIdx:%d", iIdx); } } } #endif//WIN32 && BIND_CPU_CORES_TO_THREADS // We need extra threads for update_mb_list_proc on __GNUC__ like OS (mac/linux) // due to WelsMultipleEventsWaitSingleBlocking implememtation can not work well // in case waiting pUpdateMbListEvent and pReadySliceCodingEvent events at the same time #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #if defined(__GNUC__) && !defined(_WIN32) WelsThreadCreate (&pCtx->pSliceThreading->pUpdateMbListThrdHandles[iIdx], UpdateMbListThreadProc, &pCtx->pSliceThreading->pThreadPEncCtx[iIdx], 0); #endif//__GNUC__ #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) ++ iIdx; } #if defined(ENABLE_TRACE_MT) WelsLog (pCtx, WELS_LOG_INFO, "CreateSliceThreads() exit..\n"); #endif return 0; } #ifdef PACKING_ONE_SLICE_PER_LAYER void ResetCountBsSizeInPartitions (uint32_t* pCountBsSizeList, const int32_t iPartitionCnt) { if (pCountBsSizeList != NULL && iPartitionCnt > 0) { memset (pCountBsSizeList, 0, sizeof (pCountBsSizeList[0]) * iPartitionCnt); } } #endif//PACKING_ONE_SLICE_PER_LAYER #ifdef _WIN32 int32_t FiredSliceThreads (SSliceThreadPrivateData* pPriData, WELS_EVENT* pEventsList, SLayerBSInfo* pLbi, const uint32_t uiNumThreads, SSliceCtx* pSliceCtx, const BOOL_T bIsDynamicSlicingMode) #else int32_t FiredSliceThreads (SSliceThreadPrivateData* pPriData, WELS_EVENT** pEventsList, SLayerBSInfo* pLbi, const uint32_t uiNumThreads, SSliceCtx* pSliceCtx, const BOOL_T bIsDynamicSlicingMode) #endif//WIN32 { int32_t iEndMbIdx = 0; int32_t iIdx = 0; const int32_t kiEventCnt = uiNumThreads; if (pPriData == NULL || pLbi == NULL || kiEventCnt <= 0 || pEventsList == NULL) { WelsLog (NULL, WELS_LOG_ERROR, "FiredSliceThreads(), fail due pPriData == %p || pLbi == %p || iEventCnt(%d) <= 0 || pEventsList == %p!!\n", (void*)pPriData, (void*)pLbi, uiNumThreads, (void*)pEventsList); return 1; } #if defined(PACKING_ONE_SLICE_PER_LAYER) //////////////////////////////////////// if (bIsDynamicSlicingMode) { iEndMbIdx = pSliceCtx->iMbNumInFrame; for (iIdx = kiEventCnt - 1; iIdx >= 0; --iIdx) { const int32_t kiFirstMbIdx = pSliceCtx->pFirstMbInSlice[iIdx]; pPriData[iIdx].iStartMbIndex = kiFirstMbIdx; pPriData[iIdx].iEndMbIndex = iEndMbIdx; iEndMbIdx = kiFirstMbIdx; } } iIdx = 0; while (iIdx < kiEventCnt) { pPriData[iIdx].pLayerBs = pLbi; pPriData[iIdx].iSliceIndex = iIdx; #ifdef _WIN32 if (pEventsList[iIdx]) WelsEventSignal (&pEventsList[iIdx]); #else WelsEventSignal (pEventsList[iIdx]); #endif//WIN32 ++ pLbi; ++ iIdx; } //////////////////////////////////////// #else //////////////////////////////////////// if (bIsDynamicSlicingMode) { iEndMbIdx = pSliceCtx->iMbNumInFrame; for (iIdx = kiEventCnt - 1; iIdx >= 0; --iIdx) { const int32_t iFirstMbIdx = pSliceCtx->pFirstMbInSlice[iIdx]; pPriData[iIdx].iStartMbIndex = iFirstMbIdx; pPriData[iIdx].iEndMbIndex = iEndMbIdx; iEndMbIdx = iFirstMbIdx; } } iIdx = 0; while (iIdx < kiEventCnt) { pPriData[iIdx].pLayerBs = pLbi; pPriData[iIdx].iSliceIndex = iIdx; #ifdef _WIN32 if (pEventsList[iIdx]) WelsEventSignal (&pEventsList[iIdx]); #else WelsEventSignal (pEventsList[iIdx]); #endif//WIN32 ++ iIdx; } //////////////////////////////////////// #endif//PACKING_ONE_SLICE_PER_LAYER return 0; } int32_t DynamicDetectCpuCores() { WelsLogicalProcessInfo info; WelsQueryLogicalProcessInfo (&info); return info.ProcessorCount; } #if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) int32_t AdjustBaseLayer (sWelsEncCtx* pCtx) { SDqLayer* pCurDq = pCtx->ppDqLayerList[0]; int32_t iNeedAdj = 1; #ifdef MT_DEBUG int64_t iT0 = WelsTime(); #endif//MT_DEBUG #ifdef TRY_SLICING_BALANCE pCtx->pCurDqLayer = pCurDq; #ifdef NOT_ABSOLUTE_BALANCING // do not need adjust due to not different at both slices of consumed time iNeedAdj = NeedDynamicAdjust (pCtx->pSliceThreading->pSliceConsumeTime[0], pCurDq->pSliceEncCtx->iSliceNumInFrame); if (iNeedAdj) #endif//NOT_ABSOLUTE_BALANCING DynamicAdjustSlicing (pCtx, pCurDq, pCtx->pSliceThreading->pSliceComplexRatio[0], 0); #endif//TRY_SLICING_BALANCE #ifdef MT_DEBUG iT0 = WelsTime() - iT0; if (pCtx->pSliceThreading->pFSliceDiff) { fprintf (pCtx->pSliceThreading->pFSliceDiff, #ifdef _WIN32 "%6I64d us adjust time at base spatial layer, iNeedAdj %d, DynamicAdjustSlicing()\n", #else "%6lld us adjust time at base spatial layer, iNeedAdj %d, DynamicAdjustSlicing()\n", #endif//WIN32 iT0, iNeedAdj); } #endif//MT_DEBUG return iNeedAdj; } int32_t AdjustEnhanceLayer (sWelsEncCtx* pCtx, int32_t iCurDid) { #ifdef MT_DEBUG int64_t iT1 = WelsTime(); #endif//MT_DEBUG int32_t iNeedAdj = 1; // uiSliceMode of referencing spatial should be SM_FIXEDSLCNUM_SLICE // if using spatial base layer for complexity estimation const BOOL_T kbModelingFromSpatial = (pCtx->pCurDqLayer->pRefLayer != NULL && iCurDid > 0) && (pCtx->pSvcParam->sDependencyLayers[iCurDid - 1].sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pCtx->pSvcParam->iMultipleThreadIdc >= pCtx->pSvcParam->sDependencyLayers[iCurDid - 1].sMso.sSliceArgument.iSliceNum); if (kbModelingFromSpatial) { // using spatial base layer for complexity estimation #ifdef TRY_SLICING_BALANCE #ifdef NOT_ABSOLUTE_BALANCING // do not need adjust due to not different at both slices of consumed time iNeedAdj = NeedDynamicAdjust (pCtx->pSliceThreading->pSliceConsumeTime[iCurDid - 1], pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame); if (iNeedAdj) #endif//NOT_ABSOLUTE_BALANCING DynamicAdjustSlicing (pCtx, pCtx->pCurDqLayer, pCtx->pSliceThreading->pSliceComplexRatio[iCurDid - 1], iCurDid ); #endif//TRY_SLICING_BALANCE } else { // use temporal layer for complexity estimation #ifdef TRY_SLICING_BALANCE #ifdef NOT_ABSOLUTE_BALANCING // do not need adjust due to not different at both slices of consumed time iNeedAdj = NeedDynamicAdjust (pCtx->pSliceThreading->pSliceConsumeTime[iCurDid], pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame); if (iNeedAdj) #endif//NOT_ABSOLUTE_BALANCING DynamicAdjustSlicing (pCtx, pCtx->pCurDqLayer, pCtx->pSliceThreading->pSliceComplexRatio[iCurDid], iCurDid ); #endif//TRY_SLICING_BALANCE } #ifdef MT_DEBUG iT1 = WelsTime() - iT1; if (pCtx->pSliceThreading->pFSliceDiff) { fprintf (pCtx->pSliceThreading->pFSliceDiff, #ifdef _WIN32 "%6I64d us adjust time at spatial layer %d, iNeedAdj %d, DynamicAdjustSlicing()\n", #else "%6lld us adjust time at spatial layer %d, iNeedAdj %d, DynamicAdjustSlicing()\n", #endif//WIN32 iT1, iCurDid, iNeedAdj); } #endif//MT_DEBUG return iNeedAdj; } #endif//#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) #if defined(MT_ENABLED) #if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) && defined(MT_DEBUG) void TrackSliceComplexities (sWelsEncCtx* pCtx, const int32_t iCurDid) { const int32_t kiCountSliceNum = pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame; if (kiCountSliceNum > 0) { int32_t iSliceIdx = 0; do { fprintf (pCtx->pSliceThreading->pFSliceDiff, "%6.3f complexity pRatio at iDid %d pSlice %d\n", pCtx->pSliceThreading->pSliceComplexRatio[iCurDid][iSliceIdx], iCurDid, iSliceIdx); ++ iSliceIdx; } while (iSliceIdx < kiCountSliceNum); } } #endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) #if defined(DYNAMIC_SLICE_ASSIGN) && defined(MT_DEBUG) void TrackSliceConsumeTime (sWelsEncCtx* pCtx, int32_t* pDidList, const int32_t iSpatialNum) { SWelsSvcCodingParam* pPara = NULL; int32_t iSpatialIdx = 0; if (iSpatialNum > MAX_DEPENDENCY_LAYER) return; pPara = pCtx->pSvcParam; while (iSpatialIdx < iSpatialNum) { const int32_t kiDid = pDidList[iSpatialIdx]; SDLayerParam* pDlp = &pPara->sDependencyLayers[kiDid]; SMulSliceOption* pMso = &pDlp->sMso; SDqLayer* pCurDq = pCtx->ppDqLayerList[kiDid]; SSliceCtx* pSliceCtx = pCurDq->pSliceEncCtx; const uint32_t kuiCountSliceNum = pSliceCtx->iSliceNumInFrame; if (pCtx->pSliceThreading) { if (pCtx->pSliceThreading->pFSliceDiff && pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE && pPara->iMultipleThreadIdc > 1 && pPara->iMultipleThreadIdc >= kuiCountSliceNum) { uint32_t i = 0; uint32_t uiMaxT = 0; int32_t iMaxI = 0; while (i < kuiCountSliceNum) { if (pCtx->pSliceThreading->pSliceConsumeTime[kiDid] != NULL) fprintf (pCtx->pSliceThreading->pFSliceDiff, "%6d us consume_time coding_idx %d iDid %d pSlice %d\n", pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i], pCtx->iCodingIndex, kiDid, i /*/ 1000*/); if (pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i] > uiMaxT) { uiMaxT = pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i]; iMaxI = i; } ++ i; } fprintf (pCtx->pSliceThreading->pFSliceDiff, "%6d us consume_time_max coding_idx %d iDid %d pSlice %d\n", uiMaxT, pCtx->iCodingIndex, kiDid, iMaxI /*/ 1000*/); } } ++ iSpatialIdx; } } #endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG) #endif//MT_ENABLED } #endif//MT_ENABLED