History

Initial Commit

Ethan Hugg committed 12 years ago

Commit 70e5e621 parent bd509b2308 files · +97095 −-5Browse files

Showing the changes to codec/encoder/core/src/slice_multi_threading.cpp (1 of 308 files). Show all

Unified · Split

codec/encoder/core/src/slice_multi_threading.cpp+1592−0
@@ -0,0 +1,1592 @@
1+/*!
2+ * \copy
3+ * Copyright (c) 2010-2013, Cisco Systems
4+ * All rights reserved.
5+ *
6+ * Redistribution and use in source and binary forms, with or without
7+ * modification, are permitted provided that the following conditions
8+ * are met:
9+ *
10+ * * Redistributions of source code must retain the above copyright
11+ * notice, this list of conditions and the following disclaimer.
12+ *
13+ * * Redistributions in binary form must reproduce the above copyright
14+ * notice, this list of conditions and the following disclaimer in
15+ * the documentation and/or other materials provided with the
16+ * distribution.
17+ *
18+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+ * POSSIBILITY OF SUCH DAMAGE.
30+ *
31+ *
32+ * \file slice_multi_threading.h
33+ *
34+ * \brief pSlice based multiple threading
35+ *
36+ * \date 04/16/2010 Created
37+ *
38+ *************************************************************************************
39+ */
40+
41+#if defined(MT_ENABLED)
42+
43+#include <assert.h>
44+#ifdef __GNUC__
45+#include <semaphore.h>
46+#ifndef SEM_NAME_MAX
47+// length of semaphore name should be system constrained at least on mac 10.7
48+#define SEM_NAME_MAX 32
49+#endif//SEM_NAME_MAX
50+#endif//__GNUC__
51+#include "slice_multi_threading.h"
52+#include "mt_defs.h"
53+#include "nal_encap.h"
54+#include "utils.h"
55+#include "encoder.h"
56+#include "svc_encode_slice.h"
57+#include "deblocking.h"
58+#include "svc_enc_golomb.h"
59+#include "crt_util_safe_x.h" // for safe crt like calls
60+#include "rc.h"
61+
62+#if defined(X86_ASM)
63+#include "cpu.h"
64+#endif//X86_ASM
65+
66+#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
67+#include "measure_time.h"
68+#endif//DYNAMIC_SLICE_ASSIGN
69+namespace WelsSVCEnc {
70+void UpdateMbListNeighborParallel( SSliceCtx *pSliceCtx,
71+ SMB *pMbList,
72+ const int32_t uiSliceIdc )
73+{
74+ const uint8_t *kpMbMap = pSliceCtx->pOverallMbMap;
75+ const int32_t kiMbWidth = pSliceCtx->iMbWidth;
76+ int32_t iIdx = pSliceCtx->pFirstMbInSlice[uiSliceIdc];
77+ const int32_t kiEndMbInSlice = iIdx + pSliceCtx->pCountMbNumInSlice[uiSliceIdc] - 1;
78+
79+ do {
80+ SMB *pMb = &pMbList[iIdx];
81+ uint32_t uiNeighborAvailFlag = 0;
82+ const int32_t kiMbXY = pMb->iMbXY;
83+ const int32_t kiMbX = pMb->iMbX;
84+ const int32_t kiMbY = pMb->iMbY;
85+ BOOL_T bLeft;
86+ BOOL_T bTop;
87+ BOOL_T bLeftTop;
88+ BOOL_T bRightTop;
89+ int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;
90+
91+ iLeftXY = kiMbXY - 1;
92+ iTopXY = kiMbXY - kiMbWidth;
93+ iLeftTopXY = iTopXY - 1;
94+ iRightTopXY = iTopXY + 1;
95+
96+ bLeft = (kiMbX > 0) && (uiSliceIdc == kpMbMap[iLeftXY]);
97+ bTop = (kiMbY > 0) && (uiSliceIdc == kpMbMap[iTopXY]);
98+ bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iLeftTopXY]);
99+ bRightTop = (kiMbX < (kiMbWidth-1)) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iRightTopXY]);
100+
101+ if( bLeft ){
102+ uiNeighborAvailFlag |= LEFT_MB_POS;
103+ }
104+ if( bTop ){
105+ uiNeighborAvailFlag |= TOP_MB_POS;
106+ }
107+ if( bLeftTop ){
108+ uiNeighborAvailFlag |= TOPLEFT_MB_POS;
109+ }
110+ if( bRightTop ){
111+ uiNeighborAvailFlag |= TOPRIGHT_MB_POS;
112+ }
113+ pMb->uiNeighborAvail = (uint8_t)uiNeighborAvailFlag;
114+ pMb->uiSliceIdc = uiSliceIdc;
115+
116+ ++ iIdx;
117+ } while(iIdx <= kiEndMbInSlice);
118+}
119+
120+void CalcSliceComplexRatio( void *pRatio, SSliceCtx *pSliceCtx, uint32_t *pSliceConsume )
121+{
122+ float *pRatioList = (float *)pRatio;
123+ float fAvI[MAX_SLICES_NUM];
124+ float fSumAv = .0f;
125+ uint32_t *pSliceTime = (uint32_t *)pSliceConsume;
126+ int32_t *pCountMbInSlice = (int32_t *)pSliceCtx->pCountMbNumInSlice;
127+ const int32_t kiSliceCount = pSliceCtx->iSliceNumInFrame;
128+ int32_t iSliceIdx = 0;
129+
130+#if defined(X86_ASM)
131+ WelsEmms();
132+#endif //X86_ASM
133+
134+ while ( iSliceIdx < kiSliceCount )
135+ {
136+ fAvI[iSliceIdx] = 1.0f * pCountMbInSlice[iSliceIdx] / pSliceTime[iSliceIdx];
137+#if defined(ENABLE_TRACE_MT)
138+ WelsLog(NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), pSliceConsumeTime[%d]= %d us, slice_run= %d\n", iSliceIdx, pSliceTime[iSliceIdx], pCountMbInSlice[iSliceIdx]);
139+#endif//ENABLE_TRACE_MT
140+ fSumAv += fAvI[iSliceIdx];
141+
142+ ++ iSliceIdx;
143+ }
144+ while ( -- iSliceIdx >= 0 )
145+ {
146+ pRatioList[iSliceIdx] = fAvI[iSliceIdx] / fSumAv;
147+ }
148+}
149+
150+#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) && defined(NOT_ABSOLUTE_BALANCING)
151+int32_t NeedDynamicAdjust( void *pConsumeTime, const int32_t iSliceNum )
152+{
153+#if !defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING)
154+ const float fRatioLower = TOLERANT_BALANCING_RATIO_LOWER( uiSliceNum );
155+ const float fRatioUpper = TOLERANT_BALANCING_RATIO_UPPER( uiSliceNum );
156+#endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING
157+ uint32_t *pSliceConsume = (uint32_t *)pConsumeTime;
158+ uint32_t uiTotalConsume = 0;
159+ int32_t iSliceIdx = 0;
160+ int32_t iNeedAdj = false;
161+
162+#if defined(X86_ASM)
163+ WelsEmms();
164+#endif //X86_ASM
165+
166+ while( iSliceIdx < iSliceNum )
167+ {
168+ uiTotalConsume += pSliceConsume[iSliceIdx] + pSliceConsume[1+iSliceIdx];
169+ iSliceIdx += 2;
170+ }
171+ if (uiTotalConsume == 0)
172+ {
173+#if defined(ENABLE_TRACE_MT)
174+ WelsLog( NULL, WELS_LOG_DEBUG, "[MT] NeedDynamicAdjust(), herein do no adjust due first picture, iCountSliceNum= %d\n", iSliceNum );
175+#endif//ENABLE_TRACE_MT
176+ return false;
177+ }
178+
179+ iSliceIdx = 0;
180+#if defined(USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING)
181+ float fThr = EPSN; // threshold for various cores cases
182+ float fRmse = .0f; // root mean square error of pSlice consume ratios
183+ const float kfMeanRatio = 1.0f / iSliceNum;
184+ do{
185+ const float fRatio = 1.0f * pSliceConsume[iSliceIdx] / uiTotalConsume;
186+ const float fDiffRatio = fRatio - kfMeanRatio;
187+ fRmse += (fDiffRatio * fDiffRatio);
188+ ++ iSliceIdx;
189+ } while ( iSliceIdx+1 < iSliceNum );
190+ fRmse = sqrtf(fRmse/iSliceNum);
191+ if ( iSliceNum >= 8 )
192+ {
193+ fThr += THRESHOLD_RMSE_CORE8;
194+ }
195+ else if ( iSliceNum >= 4 )
196+ {
197+ fThr += THRESHOLD_RMSE_CORE4;
198+ }
199+ else if ( iSliceNum >= 2 )
200+ {
201+ fThr += THRESHOLD_RMSE_CORE2;
202+ }
203+ else
204+ fThr = 1.0f;
205+ if ( fRmse > fThr )
206+ iNeedAdj = true;
207+#if defined(ENABLE_TRACE_MT)
208+ 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",
209+ iNeedAdj, fRmse, fThr, iSliceNum);
210+#endif//ENABLE_TRACE_MT
211+#else
212+ do{
213+ const float kfRatio = 1.0f * pSliceConsume[uiSliceIdx] / uiTotalConsume;
214+ if ( kfRatio+EPSN < fRatioLower || kfRatio > ratio_upper+EPSN )
215+ {
216+#if defined(ENABLE_TRACE_MT)
217+ 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",
218+ uiSliceIdx, kfRatio, pSliceConsume[uiSliceIdx], uiTotalConsume, uiSliceNum);
219+#endif//ENABLE_TRACE_MT
220+ iNeedAdj = true;
221+ break;
222+ }
223+ ++ uiSliceIdx;
224+ } while ( uiSliceIdx+1 < uiSliceNum );
225+#endif//USE_RMSE_SLICE_COMPLEXITY_RATIO_FOR_BALANCING
226+
227+ return iNeedAdj;
228+}
229+#endif//..
230+
231+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
232+void DynamicAdjustSlicing( sWelsEncCtx *pCtx,
233+ SDqLayer *pCurDqLayer,
234+ void *pComplexRatio,
235+ int32_t iCurDid )
236+{
237+ SSliceCtx *pSliceCtx = pCurDqLayer->pSliceEncCtx;
238+ const int32_t kiCountSliceNum = pSliceCtx->iSliceNumInFrame;
239+ const int32_t kiCountNumMb = pSliceCtx->iMbNumInFrame;
240+ int32_t iMinimalMbNum = pSliceCtx->iMbWidth; // in theory we need only 1 SMB, here let it as one SMB row required
241+ int32_t iMaximalMbNum = 0; // dynamically assign later
242+ float *pSliceComplexRatio = (float *)pComplexRatio;
243+ int32_t iMbNumLeft = kiCountNumMb;
244+ int32_t iRunLen[MAX_THREADS_NUM] = {0};
245+ int32_t iSliceIdx = 0;
246+
247+ int32_t iNumMbInEachGom;
248+ SWelsSvcRc *pWelsSvcRc = &pCtx->pWelsSvcRc[iCurDid];
249+ if(pCtx->pSvcParam->bEnableRc)
250+ {
251+ iNumMbInEachGom = pWelsSvcRc->iNumberMbGom;
252+
253+ if ( iNumMbInEachGom <= 0 )
254+ {
255+ WelsLog(pCtx, WELS_LOG_ERROR, "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d\n", iNumMbInEachGom, iCurDid, kiCountNumMb);
256+ return;
257+ }
258+
259+ // do not adjust in case no extra iNumMbInEachGom based left for slicing adjustment,
260+ // extra MB of non integrated GOM assigned at the last pSlice in default, keep up on early initial result.
261+ if ( iNumMbInEachGom * kiCountSliceNum >= kiCountNumMb )
262+ {
263+ return;
264+ }
265+ iMinimalMbNum = iNumMbInEachGom;
266+ }
267+
268+ if ( kiCountSliceNum < 2 || (kiCountSliceNum & 0x01) ) // we need suppose uiSliceNum is even for multiple threading
269+ return;
270+
271+ iMaximalMbNum = kiCountNumMb - (kiCountSliceNum - 1) * iMinimalMbNum;
272+
273+#if defined(X86_ASM)
274+ WelsEmms();
275+#endif //X86_ASM
276+
277+#if defined(ENABLE_TRACE_MT)
278+ WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iDid= %d, iCountNumMb= %d\n", iCurDid, kiCountNumMb);
279+#endif//ENABLE_TRACE_MT
280+
281+ iSliceIdx = 0;
282+ while (iSliceIdx+1 < kiCountSliceNum) {
283+ int32_t iNumMbAssigning = (int32_t)(kiCountNumMb * pSliceComplexRatio[iSliceIdx] + EPSN);
284+
285+ // GOM boundary aligned
286+ if(pCtx->pSvcParam->bEnableRc)
287+ {
288+ iNumMbAssigning=(int32_t)(1.0f * iNumMbAssigning / iNumMbInEachGom + 0.5f + EPSN) * iNumMbInEachGom;
289+ }
290+
291+ // make sure one GOM at least in each pSlice for safe
292+ if ( iNumMbAssigning < iMinimalMbNum )
293+ iNumMbAssigning = iMinimalMbNum;
294+ else if ( iNumMbAssigning > iMaximalMbNum )
295+ iNumMbAssigning = iMaximalMbNum;
296+
297+ assert( iNumMbAssigning > 0 );
298+
299+ iMbNumLeft -= iNumMbAssigning;
300+ if ( iMbNumLeft <= 0 ) // error due to we can not support slice_skip now yet, do not adjust this time
301+ {
302+ assert( 0 );
303+ return;
304+ }
305+ iRunLen[iSliceIdx] = iNumMbAssigning;
306+#if defined(ENABLE_TRACE_MT)
307+ WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), uiSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n",
308+ iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iNumMbAssigning);
309+#endif//ENABLE_TRACE_MT
310+ ++ iSliceIdx;
311+ iMaximalMbNum = iMbNumLeft - (kiCountSliceNum - iSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts
312+ }
313+ iRunLen[iSliceIdx] = iMbNumLeft;
314+#if defined(ENABLE_TRACE_MT)
315+ WelsLog(pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iSliceIdx= %d, pSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d\n",
316+ iSliceIdx, pSliceComplexRatio[iSliceIdx], pSliceCtx->pCountMbNumInSlice[iSliceIdx], iMbNumLeft);
317+#endif//ENABLE_TRACE_MT
318+
319+
320+ if ( DynamicAdjustSlicePEncCtxAll( pSliceCtx, iRunLen ) == 0 )
321+ {
322+ const int32_t kiThreadNum = pCtx->pSvcParam->iCountThreadsNum;
323+ int32_t iThreadIdx = 0;
324+ do {
325+#ifdef WIN32
326+ WelsEventSignal( &pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] );
327+#else
328+ WelsEventSignal( pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx] );
329+#endif//WIN32
330+ ++ iThreadIdx;
331+ } while(iThreadIdx < kiThreadNum);
332+
333+ WelsMultipleEventsWaitAllBlocking( kiThreadNum, &pCtx->pSliceThreading->pFinUpdateMbListEvent[0] );
334+ }
335+}
336+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
337+
338+#ifdef PACKING_ONE_SLICE_PER_LAYER
339+void ResetEnvMt( sWelsEncCtx *pCtx)
340+{
341+ const int16_t kiSliceCount = pCtx->iMaxSliceCount;
342+ int32_t iIdx = 0;
343+
344+ while ( iIdx < kiSliceCount )
345+ {
346+ SWelsSliceBs *pSliceBs = &pCtx->pSliceBs[iIdx];
347+ pSliceBs->uiBsPos = 0;
348+ ++ iIdx;
349+ }
350+}
351+#endif//PACKING_ONE_SLICE_PER_LAYER
352+
353+int32_t RequestMtResource( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pCodingParam, const int32_t iCountBsLen, const int32_t iTargetSpatialBsSize )
354+{
355+ CMemoryAlign *pMa = NULL;
356+ SWelsSvcCodingParam *pPara= NULL;
357+ SSliceThreading *pSmt = NULL;
358+ SWelsSliceBs *pSliceB = NULL;
359+ uint8_t *pBsBase = NULL;
360+ int32_t iNumSpatialLayers = 0;
361+ int32_t iThreadNum = 0;
362+ int32_t iIdx = 0;
363+ int32_t iSliceBsBufferSize= 0;
364+ int16_t iMaxSliceNum = 1;
365+
366+ if ( NULL == ppCtx || NULL == pCodingParam || NULL == *ppCtx || iCountBsLen <= 0 )
367+ return 1;
368+
369+ pMa = (*ppCtx)->pMemAlign;
370+ pPara= pCodingParam;
371+ iNumSpatialLayers = pPara->iNumDependencyLayer;
372+ iThreadNum = pPara->iCountThreadsNum;
373+ iMaxSliceNum = (*ppCtx)->iMaxSliceCount;
374+
375+ pSmt = (SSliceThreading *)pMa->WelsMalloc(sizeof(SSliceThreading), "SSliceThreading");
376+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt), FreeMemorySvc(ppCtx) )
377+ (*ppCtx)->pSliceThreading = pSmt;
378+ pSmt->pThreadPEncCtx = (SSliceThreadPrivateData *)pMa->WelsMalloc( sizeof(SSliceThreadPrivateData) * iThreadNum, "pThreadPEncCtx" );
379+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadPEncCtx), FreeMemorySvc(ppCtx) )
380+ pSmt->pThreadHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pThreadHandles" );
381+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pThreadHandles), FreeMemorySvc(ppCtx) )
382+
383+#ifdef WIN32
384+ pSmt->pSliceCodedEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pSliceCodedEvent" );
385+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceCodedEvent), FreeMemorySvc(ppCtx) )
386+ pSmt->pReadySliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pReadySliceCodingEvent" );
387+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pReadySliceCodingEvent), FreeMemorySvc(ppCtx) )
388+ pSmt->pFinSliceCodingEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinSliceCodingEvent" );
389+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinSliceCodingEvent), FreeMemorySvc(ppCtx) )
390+#endif//WIN32
391+
392+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
393+#if defined(__GNUC__)
394+ pSmt->pUpdateMbListThrdHandles = (WELS_THREAD_HANDLE *)pMa->WelsMalloc( sizeof(WELS_THREAD_HANDLE) * iThreadNum, "pUpdateMbListThrdHandles" );
395+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListThrdHandles), FreeMemorySvc(ppCtx) )
396+#endif//__GNUC__
397+#ifdef WIN32
398+ pSmt->pUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pUpdateMbListEvent" );
399+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pUpdateMbListEvent), FreeMemorySvc(ppCtx) )
400+ pSmt->pFinUpdateMbListEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pFinUpdateMbListEvent" );
401+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pFinUpdateMbListEvent), FreeMemorySvc(ppCtx) )
402+#endif//WIN32
403+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
404+
405+#ifdef WIN32
406+ pSmt->pExitEncodeEvent = (WELS_EVENT *)pMa->WelsMalloc( sizeof(WELS_EVENT) * iThreadNum, "pExitEncodeEvent" );
407+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pExitEncodeEvent), FreeMemorySvc(ppCtx) )
408+#endif//WIN32
409+
410+#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
411+ iIdx = 0;
412+ while ( iIdx < iNumSpatialLayers )
413+ {
414+ SMulSliceOption *pMso = &pPara->sDependencyLayers[iIdx].sMso;
415+ const int32_t kiSliceNum= pMso->sSliceArgument.iSliceNum;
416+ if (pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE && pPara->iMultipleThreadIdc > 1 && pPara->iMultipleThreadIdc >= kiSliceNum )
417+ {
418+ pSmt->pSliceConsumeTime[iIdx] = (uint32_t *)pMa->WelsMallocz( kiSliceNum * sizeof(uint32_t), "pSliceConsumeTime[]" );
419+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceConsumeTime[iIdx]), FreeMemorySvc(ppCtx) )
420+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
421+ pSmt->pSliceComplexRatio[iIdx] = (float *)pMa->WelsMalloc( kiSliceNum * sizeof(float), "pSliceComplexRatio[]" );
422+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pSliceComplexRatio[iIdx]), FreeMemorySvc(ppCtx) )
423+#endif//TRY_SLICING_BALANCE
424+ }
425+ else
426+ {
427+ pSmt->pSliceConsumeTime[iIdx] = NULL;
428+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
429+ pSmt->pSliceComplexRatio[iIdx] = NULL;
430+#endif//TRY_SLICING_BALANCE
431+ }
432+ ++ iIdx;
433+ }
434+ // NULL for pSliceConsumeTime[iIdx]: iIdx from iNumSpatialLayers to MAX_DEPENDENCY_LAYERS
435+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
436+
437+#ifdef MT_DEBUG
438+ // file handle for MT debug
439+ pSmt->pFSliceDiff = NULL;
440+
441+ if ( pSmt->pFSliceDiff )
442+ {
443+ fclose( pSmt->pFSliceDiff );
444+ pSmt->pFSliceDiff = NULL;
445+ }
446+#ifdef WIN32
447+ pSmt->pFSliceDiff = fopen(".\\slice_time.txt", "wt+" );
448+#else
449+ pSmt->pFSliceDiff = fopen("/tmp/slice_time.txt", "wt+" );
450+#endif//WIN32
451+#endif//MT_DEBUG
452+
453+#if defined(ENABLE_TRACE_MT)
454+ WelsLog((*ppCtx), WELS_LOG_INFO, "encpEncCtx= 0x%p\n", (void *)(*ppCtx));
455+#endif//ENABLE_TRACE_MT
456+
457+ iIdx = 0;
458+ while ( iIdx < iThreadNum )
459+ {
460+#ifdef __GNUC__ // for posix threading
461+ str_t name[SEM_NAME_MAX] = {0};
462+ int32_t used_len = 0;
463+ WELS_THREAD_ERROR_CODE err = 0;
464+#endif//__GNUC__
465+ pSmt->pThreadPEncCtx[iIdx].pWelsPEncCtx = (void *)(*ppCtx);
466+ pSmt->pThreadPEncCtx[iIdx].iSliceIndex = iIdx;
467+ pSmt->pThreadPEncCtx[iIdx].iThreadIndex = iIdx;
468+ pSmt->pThreadHandles[iIdx] = 0;
469+
470+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
471+#ifdef WIN32
472+ WelsEventInit( &pSmt->pUpdateMbListEvent[iIdx] );
473+ WelsEventInit( &pSmt->pFinUpdateMbListEvent[iIdx] );
474+#else
475+ // length of semaphore name should be system constrained at least on mac 10.7
476+ SNPRINTF( name, SEM_NAME_MAX, "ud%d%p", iIdx, (void *)(*ppCtx) );
477+ err = WelsEventOpen( &pSmt->pUpdateMbListEvent[iIdx], name );
478+#if defined(ENABLE_TRACE_MT)
479+ WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
480+#endif
481+ used_len = SNPRINTF( name, SEM_NAME_MAX, "fu%d%p", iIdx, (void *)(*ppCtx) );
482+ name[used_len] = '\0';
483+ err = WelsEventOpen( &pSmt->pFinUpdateMbListEvent[iIdx], name );
484+#if defined(ENABLE_TRACE_MT)
485+ WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pFinUpdateMbListEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
486+#endif
487+#endif//WIN32
488+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
489+
490+#ifdef WIN32
491+ WelsEventInit( &pSmt->pSliceCodedEvent[iIdx] );
492+ WelsEventInit( &pSmt->pReadySliceCodingEvent[iIdx] );
493+ WelsEventInit( &pSmt->pFinSliceCodingEvent[iIdx] );
494+ WelsEventInit( &pSmt->pExitEncodeEvent[iIdx] );
495+#else
496+ used_len = SNPRINTF( name, SEM_NAME_MAX, "sc%d%p", iIdx, (void *)(*ppCtx) );
497+ name[used_len] = '\0';
498+ err = WelsEventOpen( &pSmt->pSliceCodedEvent[iIdx], name );
499+#if defined(ENABLE_TRACE_MT)
500+ WelsLog((*ppCtx), WELS_LOG_INFO, "[MT] Open pSliceCodedEvent%d named(%s) ret%d err%d\n", iIdx, name, err, errno);
501+#endif
502+ used_len = SNPRINTF( name, SEM_NAME_MAX, "rc%d%p", iIdx, (void *)(*ppCtx) );
503+ name[used_len] = '\0';
504+ err = WelsEventOpen( &pSmt->pReadySliceCodingEvent[iIdx], name );
505+#if defined(ENABLE_TRACE_MT)
506+ 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);
507+#endif
508+#endif//WIN32
509+
510+ ++ iIdx;
511+ }
512+
513+#ifdef PACKING_ONE_SLICE_PER_LAYER
514+ pSmt->pCountBsSizeInPartition = (uint32_t *)pMa->WelsMalloc( sizeof(uint32_t) * iThreadNum, "pCountBsSizeInPartition" );
515+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSmt->pCountBsSizeInPartition), FreeMemorySvc(ppCtx) )
516+#endif//PACKING_ONE_SLICE_PER_LAYER
517+
518+ WelsMutexInit( &pSmt->mutexSliceNumUpdate );
519+
520+ (*ppCtx)->pSliceBs = (SWelsSliceBs *)pMa->WelsMalloc( sizeof(SWelsSliceBs) * iMaxSliceNum, "pSliceBs" );
521+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pSliceBs), FreeMemorySvc(ppCtx) )
522+
523+ pBsBase = (*ppCtx)->pFrameBs + iCountBsLen;
524+ pSliceB = (*ppCtx)->pSliceBs;
525+ iSliceBsBufferSize = iTargetSpatialBsSize;
526+ iIdx = 0;
527+ while ( iIdx < iMaxSliceNum )
528+ {
529+ pSliceB->pBsBuffer = (uint8_t *)pMa->WelsMalloc( iSliceBsBufferSize, "pSliceB->pBsBuffer" );
530+
531+ WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pSliceB->pBsBuffer), FreeMemorySvc(ppCtx) )
532+ pSliceB->uiSize = iSliceBsBufferSize;
533+
534+ if ( iIdx > 0 )
535+ {
536+ pSliceB->pBs = pBsBase;
537+ pSliceB->uiBsPos = 0;
538+ pBsBase += iSliceBsBufferSize;
539+ }
540+ else
541+ {
542+ pSliceB->pBs = NULL;
543+ pSliceB->uiBsPos = 0;
544+ }
545+ ++ pSliceB;
546+ ++ iIdx;
547+ }
548+
549+#if defined(ENABLE_TRACE_MT)
550+ WelsLog((*ppCtx), WELS_LOG_INFO, "RequestMtResource(), iThreadNum=%d, iCountSliceNum= %d\n", pPara->iCountThreadsNum, iMaxSliceNum);
551+#endif
552+
553+ return 0;
554+}
555+
556+void ReleaseMtResource( sWelsEncCtx **ppCtx )
557+{
558+ SWelsSliceBs *pSliceB = NULL;
559+ SWelsSvcCodingParam *pCodingParam = NULL;
560+ SSliceThreading *pSmt = NULL;
561+ CMemoryAlign *pMa = NULL;
562+ int32_t iIdx = 0;
563+ int32_t iThreadNum = 0;
564+ int16_t uiSliceNum = 0;
565+
566+ if ( NULL == ppCtx || NULL == *ppCtx )
567+ return;
568+
569+ pMa = (*ppCtx)->pMemAlign;
570+ pCodingParam = (*ppCtx)->pSvcParam;
571+ uiSliceNum = (*ppCtx)->iMaxSliceCount;
572+ iThreadNum = (*ppCtx)->pSvcParam->iCountThreadsNum;
573+ pSmt = (*ppCtx)->pSliceThreading;
574+
575+ if ( NULL == pSmt )
576+ return;
577+
578+ while ( iIdx < iThreadNum) {
579+#ifdef WIN32
580+ if ( pSmt->pThreadHandles != NULL && pSmt->pThreadHandles[iIdx] != NULL )
581+ WelsThreadDestroy( &pSmt->pThreadHandles[iIdx] );
582+
583+ if ( pSmt->pSliceCodedEvent != NULL )
584+ WelsEventDestroy( &pSmt->pSliceCodedEvent[iIdx] );
585+ if ( pSmt->pReadySliceCodingEvent != NULL )
586+ WelsEventDestroy( &pSmt->pReadySliceCodingEvent[iIdx] );
587+ if ( pSmt->pFinSliceCodingEvent != NULL )
588+ WelsEventDestroy( &pSmt->pFinSliceCodingEvent[iIdx] );
589+ if ( pSmt->pExitEncodeEvent != NULL )
590+ WelsEventDestroy( &pSmt->pExitEncodeEvent[iIdx] );
591+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
592+ if ( pSmt->pUpdateMbListEvent != NULL )
593+ WelsEventDestroy( &pSmt->pUpdateMbListEvent[iIdx] );
594+ if ( pSmt->pFinUpdateMbListEvent != NULL )
595+ WelsEventDestroy( &pSmt->pFinUpdateMbListEvent[iIdx] );
596+#endif//DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE
597+#else
598+ str_t ename[SEM_NAME_MAX] = {0};
599+ int32_t used_len = 0;
600+ // length of semaphore name should be system constrained at least on mac 10.7
601+ SNPRINTF( ename, SEM_NAME_MAX, "sc%d%p", iIdx, (void *)(*ppCtx) );
602+ WelsEventClose( pSmt->pSliceCodedEvent[iIdx], ename );
603+ used_len = SNPRINTF( ename, SEM_NAME_MAX, "rc%d%p", iIdx, (void *)(*ppCtx) );
604+ ename[used_len] = '\0';
605+ WelsEventClose( pSmt->pReadySliceCodingEvent[iIdx], ename );
606+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
607+ used_len = SNPRINTF( ename, SEM_NAME_MAX, "ud%d%p", iIdx, (void *)(*ppCtx) );
608+ ename[used_len] = '\0';
609+ WelsEventClose( pSmt->pUpdateMbListEvent[iIdx], ename );
610+ used_len = SNPRINTF( ename, SEM_NAME_MAX, "fu%d%p", iIdx, (void *)(*ppCtx) );
611+ ename[used_len] = '\0';
612+ WelsEventClose( pSmt->pFinUpdateMbListEvent[iIdx], ename );
613+#endif//DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE
614+#endif//WIN32
615+
616+ ++ iIdx;
617+ }
618+
619+#ifdef WIN32
620+ if ( pSmt->pExitEncodeEvent != NULL )
621+ {
622+ pMa->WelsFree( pSmt->pExitEncodeEvent, "pExitEncodeEvent" );
623+ pSmt->pExitEncodeEvent = NULL;
624+ }
625+ if ( pSmt->pSliceCodedEvent != NULL )
626+ {
627+ pMa->WelsFree( pSmt->pSliceCodedEvent, "pSliceCodedEvent" );
628+ pSmt->pSliceCodedEvent = NULL;
629+ }
630+ if ( pSmt->pReadySliceCodingEvent != NULL )
631+ {
632+ pMa->WelsFree( pSmt->pReadySliceCodingEvent, "pReadySliceCodingEvent" );
633+ pSmt->pReadySliceCodingEvent = NULL;
634+ }
635+ if ( pSmt->pFinSliceCodingEvent != NULL )
636+ {
637+ pMa->WelsFree( pSmt->pFinSliceCodingEvent, "pFinSliceCodingEvent" );
638+ pSmt->pFinSliceCodingEvent = NULL;
639+ }
640+#endif//WIN32
641+
642+#ifdef PACKING_ONE_SLICE_PER_LAYER
643+ if ( NULL != pSmt->pCountBsSizeInPartition )
644+ {
645+ pMa->WelsFree( pSmt->pCountBsSizeInPartition, "pCountBsSizeInPartition" );
646+ pSmt->pCountBsSizeInPartition = NULL;
647+ }
648+#endif//PACKING_ONE_SLICE_PER_LAYER
649+ WelsMutexDestroy( &pSmt->mutexSliceNumUpdate );
650+
651+ if ( pSmt->pThreadPEncCtx != NULL )
652+ {
653+ pMa->WelsFree( pSmt->pThreadPEncCtx, "pThreadPEncCtx" );
654+ pSmt->pThreadPEncCtx = NULL;
655+ }
656+ if ( pSmt->pThreadHandles != NULL )
657+ {
658+ pMa->WelsFree( pSmt->pThreadHandles, "pThreadHandles" );
659+ pSmt->pThreadHandles = NULL;
660+ }
661+
662+ pSliceB = (*ppCtx)->pSliceBs;
663+ iIdx = 0;
664+ while ( pSliceB != NULL && iIdx < uiSliceNum )
665+ {
666+ if ( pSliceB->pBsBuffer )
667+ {
668+ pMa->WelsFree( pSliceB->pBsBuffer, "pSliceB->pBsBuffer" );
669+ pSliceB->pBsBuffer = NULL;
670+ pSliceB->uiSize = 0;
671+ }
672+ ++ iIdx;
673+ ++ pSliceB;
674+ }
675+ if ( (*ppCtx)->pSliceBs != NULL )
676+ {
677+ pMa->WelsFree( (*ppCtx)->pSliceBs, "pSliceBs" );
678+ (*ppCtx)->pSliceBs = NULL;
679+ }
680+#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
681+ if ( pSmt->pSliceConsumeTime != NULL )
682+ {
683+ iIdx = 0;
684+ while (iIdx < pCodingParam->iNumDependencyLayer)
685+ {
686+ if ( pSmt->pSliceConsumeTime[iIdx] )
687+ {
688+ pMa->WelsFree( pSmt->pSliceConsumeTime[iIdx], "pSliceConsumeTime[]" );
689+ pSmt->pSliceConsumeTime[iIdx] = NULL;
690+ }
691+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
692+ if ( pSmt->pSliceComplexRatio[iIdx] != NULL )
693+ {
694+ pMa->WelsFree( pSmt->pSliceComplexRatio[iIdx], "pSliceComplexRatio[]" );
695+ pSmt->pSliceComplexRatio[iIdx] = NULL;
696+ }
697+#endif//TRY_SLICING_BALANCE
698+ ++ iIdx;
699+ }
700+ }
701+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
702+
703+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
704+
705+#ifdef WIN32
706+ if ( pSmt->pUpdateMbListEvent != NULL )
707+ {
708+ pMa->WelsFree( pSmt->pUpdateMbListEvent, "pUpdateMbListEvent" );
709+ pSmt->pUpdateMbListEvent = NULL;
710+ }
711+ if ( pSmt->pFinUpdateMbListEvent != NULL )
712+ {
713+ pMa->WelsFree( pSmt->pFinUpdateMbListEvent, "pFinUpdateMbListEvent" );
714+ pSmt->pFinUpdateMbListEvent = NULL;
715+ }
716+#else
717+ if ( pSmt->pUpdateMbListThrdHandles )
718+ {
719+ pMa->WelsFree( pSmt->pUpdateMbListThrdHandles, "pUpdateMbListThrdHandles" );
720+ pSmt->pUpdateMbListThrdHandles = NULL;
721+ }
722+#endif//WIN32
723+
724+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
725+
726+#ifdef MT_DEBUG
727+ // file handle for debug
728+ if ( pSmt->pFSliceDiff )
729+ {
730+ fclose( pSmt->pFSliceDiff );
731+ pSmt->pFSliceDiff = NULL;
732+ }
733+#endif//MT_DEBUG
734+ pMa->WelsFree((*ppCtx)->pSliceThreading, "SSliceThreading");
735+ (*ppCtx)->pSliceThreading = NULL;
736+}
737+
738+int32_t AppendSliceToFrameBs( sWelsEncCtx *pCtx, SLayerBSInfo *pLbi, const int32_t iSliceCount )
739+{
740+ SWelsSvcCodingParam *pCodingParam = pCtx->pSvcParam;
741+ SDLayerParam *pDlp = &pCodingParam->sDependencyLayers[pCtx->uiDependencyId];
742+ SWelsSliceBs *pSliceBs = NULL;
743+ const BOOL_T kbIsDynamicSlicingMode = (pDlp->sMso.uiSliceMode == SM_DYN_SLICE);
744+ int32_t iLayerSize = 0;
745+ int32_t iNalIdxBase = pLbi->iNalCount;
746+ int32_t iSliceIdx = 0;
747+
748+ if ( !kbIsDynamicSlicingMode )
749+ {
750+ pSliceBs = &pCtx->pSliceBs[0];
751+ iLayerSize = pSliceBs->uiBsPos; // assign with base pSlice first
752+ iSliceIdx = 1; // pSlice 0 bs has been written to pFrameBs yet by now, so uiSliceIdx base should be 1
753+ while (iSliceIdx < iSliceCount)
754+ {
755+ ++ pSliceBs;
756+ if ( pSliceBs != NULL && pSliceBs->uiBsPos > 0 )
757+ {
758+ int32_t iNalIdx = 0;
759+ const int32_t iCountNal = pSliceBs->iNalIndex;
760+
761+#if MT_DEBUG_BS_WR
762+ assert(pSliceBs->bSliceCodedFlag);
763+#endif//MT_DEBUG_BS_WR
764+
765+ memmove(pCtx->pFrameBs + pCtx->iPosBsBuffer, pSliceBs->pBs, pSliceBs->uiBsPos); // confirmed_safe_unsafe_usage
766+ pCtx->iPosBsBuffer += pSliceBs->uiBsPos;
767+
768+ iLayerSize += pSliceBs->uiBsPos;
769+
770+ while (iNalIdx < iCountNal)
771+ {
772+ pLbi->iNalLengthInByte[iNalIdxBase+iNalIdx] = pSliceBs->iNalLen[iNalIdx];
773+ ++ iNalIdx;
774+ }
775+ pLbi->iNalCount += iCountNal;
776+ iNalIdxBase += iCountNal;
777+ }
778+ ++ iSliceIdx;
779+ }
780+ }
781+ else // for SM_DYN_SLICE
782+ {
783+ const int32_t kiPartitionCnt = iSliceCount;
784+ int32_t iPartitionIdx = 0;
785+
786+ // due partition_0 has been written to pFrameBsBuffer
787+ // so iLayerSize need add it
788+ while ( iPartitionIdx < kiPartitionCnt )
789+ {
790+ const int32_t kiCountSlicesCoded = pCtx->pCurDqLayer->pNumSliceCodedOfPartition[iPartitionIdx];
791+ int32_t iIdx = 0;
792+
793+ iSliceIdx = iPartitionIdx;
794+ while(iIdx < kiCountSlicesCoded)
795+ {
796+ pSliceBs = &pCtx->pSliceBs[iSliceIdx];
797+ if ( pSliceBs != NULL && pSliceBs->uiBsPos > 0 )
798+ {
799+ if ( iPartitionIdx > 0 )
800+ {
801+ int32_t iNalIdx = 0;
802+ const int32_t iCountNal = pSliceBs->iNalIndex;
803+
804+ memmove(pCtx->pFrameBs + pCtx->iPosBsBuffer, pSliceBs->pBs, pSliceBs->uiBsPos); // confirmed_safe_unsafe_usage
805+ pCtx->iPosBsBuffer += pSliceBs->uiBsPos;
806+
807+ iLayerSize += pSliceBs->uiBsPos;
808+
809+ while (iNalIdx < iCountNal)
810+ {
811+ pLbi->iNalLengthInByte[iNalIdxBase+iNalIdx] = pSliceBs->iNalLen[iNalIdx];
812+ ++ iNalIdx;
813+ }
814+ pLbi->iNalCount += iCountNal;
815+ iNalIdxBase += iCountNal;
816+ }
817+ else
818+ {
819+ iLayerSize += pSliceBs->uiBsPos;
820+ }
821+ }
822+
823+ iSliceIdx += kiPartitionCnt;
824+ ++ iIdx;
825+ }
826+ ++ iPartitionIdx;
827+ }
828+ }
829+
830+ return iLayerSize;
831+}
832+
833+int32_t WriteSliceToFrameBs( sWelsEncCtx *pCtx, SLayerBSInfo *pLbi, uint8_t *pFrameBsBuffer, const int32_t iSliceIdx )
834+{
835+ SWelsSliceBs *pSliceBs = &pCtx->pSliceBs[iSliceIdx];
836+ SNalUnitHeaderExt *pNalHdrExt= &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt;
837+ uint8_t *pDst = pFrameBsBuffer;
838+ int32_t pNalLen[2];
839+ int32_t iSliceSize = 0;
840+ const int32_t kiNalCnt = pSliceBs->iNalIndex;
841+ int32_t iNalIdx = 0;
842+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
843+ const int32_t iFirstSlice = (iSliceIdx == 0);
844+ int32_t iNalBase = iFirstSlice ? 0 : pLbi->iNalCount;
845+#else
846+ int32_t iNalBase = 0;
847+#endif//!PACKING_ONE_SLICE_PER_LAYER
848+
849+ while ( iNalIdx < kiNalCnt ) {
850+ iSliceSize += WelsEncodeNalExt( &pSliceBs->sNalList[iNalIdx], pNalHdrExt, pDst, &pNalLen[iNalIdx] );
851+ pDst += pNalLen[iNalIdx];
852+ pLbi->iNalLengthInByte[iNalBase+iNalIdx] = pNalLen[iNalIdx];
853+
854+ ++ iNalIdx;
855+ }
856+
857+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
858+ pSliceBs->uiBsPos = iSliceSize;
859+ if ( iFirstSlice )
860+ {
861+ // pBsBuffer has been updated at coding_slice_0_in_encoder_mother_thread()
862+ pLbi->uiLayerType = VIDEO_CODING_LAYER;
863+ pLbi->uiSpatialId = pNalHdrExt->uiDependencyId;
864+ pLbi->uiTemporalId = pNalHdrExt->uiTemporalId;
865+ pLbi->uiQualityId = 0;
866+ pLbi->uiPriorityId = 0;
867+ pLbi->iNalCount = kiNalCnt;
868+ }
869+ else
870+ {
871+ pLbi->iNalCount += kiNalCnt;
872+ }
873+#else
874+ pLbi->uiLayerType = VIDEO_CODING_LAYER;
875+ pLbi->uiSpatialId = pNalHdrExt->uiDependencyId;
876+ pLbi->uiTemporalId = pNalHdrExt->uiTemporalId;
877+ pLbi->uiQualityId = 0;
878+ pLbi->uiPriorityId = 0;
879+ pLbi->iNalCount = kiNalCnt;
880+#endif//PACKING_ONE_SLICE_PER_LAYER
881+
882+ return iSliceSize;
883+}
884+
885+int32_t WriteSliceBs( sWelsEncCtx *pCtx, uint8_t *pSliceBsBuf, const int32_t iSliceIdx )
886+{
887+ SWelsSliceBs *pSliceBs = &pCtx->pSliceBs[iSliceIdx];
888+ SNalUnitHeaderExt *pNalHdrExt= &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt;
889+ uint8_t *pDst = pSliceBsBuf;
890+ int32_t *pNalLen = &pSliceBs->iNalLen[0];
891+ int32_t iSliceSize = 0;
892+ const int32_t kiNalCnt = pSliceBs->iNalIndex;
893+ int32_t iNalIdx = 0;
894+
895+ assert( kiNalCnt <= 2 );
896+ if ( kiNalCnt > 2 )
897+ return 0;
898+
899+ while ( iNalIdx < kiNalCnt ) {
900+ iSliceSize += WelsEncodeNalExt( &pSliceBs->sNalList[iNalIdx], pNalHdrExt, pDst, &pNalLen[iNalIdx] );
901+ pDst += pNalLen[iNalIdx];
902+
903+ ++ iNalIdx;
904+ }
905+ pSliceBs->uiBsPos = iSliceSize;
906+
907+ return iSliceSize;
908+}
909+
910+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
911+#if defined(__GNUC__)
912+WELS_THREAD_ROUTINE_TYPE UpdateMbListThreadProc( void *arg )
913+{
914+ SSliceThreadPrivateData *pPrivateData = (SSliceThreadPrivateData *)arg;
915+ sWelsEncCtx *pEncPEncCtx = NULL;
916+ SDqLayer *pCurDq = NULL;
917+ int32_t iSliceIdx = -1;
918+ int32_t iEventIdx = -1;
919+ WELS_THREAD_ERROR_CODE iWaitRet = WELS_THREAD_ERROR_GENERIAL;
920+ uint32_t uiThrdRet = 0;
921+
922+ if ( NULL == pPrivateData )
923+ WELS_THREAD_ROUTINE_RETURN(1);
924+
925+ pEncPEncCtx = (sWelsEncCtx *)pPrivateData->pWelsPEncCtx;
926+ iSliceIdx = pPrivateData->iSliceIndex;
927+ iEventIdx = pPrivateData->iThreadIndex;
928+
929+ do {
930+#if defined(ENABLE_TRACE_MT)
931+ WelsLog(pEncPEncCtx, WELS_LOG_INFO, "[MT] UpdateMbListThreadProc(), try to wait (pUpdateMbListEvent[%d])!\n", iEventIdx);
932+#endif
933+ iWaitRet = WelsEventWait( pEncPEncCtx->pSliceThreading->pUpdateMbListEvent[iEventIdx] );
934+ if ( WELS_THREAD_ERROR_WAIT_OBJECT_0 == iWaitRet )
935+ {
936+ pCurDq = pEncPEncCtx->pCurDqLayer;
937+ UpdateMbListNeighborParallel( pCurDq->pSliceEncCtx, pCurDq->sMbDataP, iSliceIdx );
938+ WelsEventSignal( pEncPEncCtx->pSliceThreading->pFinUpdateMbListEvent[iEventIdx] ); // mean finished update pMb list for this pSlice
939+ }
940+ else
941+ {
942+ WelsLog(pEncPEncCtx, WELS_LOG_WARNING, "[MT] UpdateMbListThreadProc(), waiting pUpdateMbListEvent[%d] failed(%d) and thread%d terminated!\n", iEventIdx, iWaitRet, iEventIdx);
943+ uiThrdRet = 1;
944+ break;
945+ }
946+ } while(1);
947+
948+ WELS_THREAD_ROUTINE_RETURN(uiThrdRet);
949+}
950+#endif//__GNUC__
951+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
952+
953+// thread process for coding one pSlice
954+WELS_THREAD_ROUTINE_TYPE CodingSliceThreadProc( void *arg )
955+{
956+ SSliceThreadPrivateData *pPrivateData = (SSliceThreadPrivateData *)arg;
957+ sWelsEncCtx *pEncPEncCtx = NULL;
958+ SDqLayer *pCurDq = NULL;
959+ SSlice *pSlice = NULL;
960+ SWelsSliceBs *pSliceBs = NULL;
961+#ifdef WIN32
962+ WELS_EVENT pEventsList[3];
963+ int32_t iEventCount = 0;
964+#endif
965+ WELS_THREAD_ERROR_CODE iWaitRet = WELS_THREAD_ERROR_GENERIAL;
966+ uint32_t uiThrdRet = 0;
967+ int32_t iSliceSize = 0;
968+ int32_t iSliceIdx = -1;
969+ int32_t iThreadIdx = -1;
970+ int32_t iEventIdx = -1;
971+ bool_t bNeedPrefix = false;
972+ EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0;
973+ EWelsNalRefIdc eNalRefIdc = NRI_PRI_LOWEST;
974+
975+ if ( NULL == pPrivateData )
976+ WELS_THREAD_ROUTINE_RETURN(1);
977+
978+ WelsSetThreadCancelable();
979+
980+ pEncPEncCtx = (sWelsEncCtx *)pPrivateData->pWelsPEncCtx;
981+
982+ iThreadIdx = pPrivateData->iThreadIndex;
983+ iEventIdx = iThreadIdx;
984+
985+#ifdef WIN32
986+ pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pReadySliceCodingEvent[iEventIdx];
987+ pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pExitEncodeEvent[iEventIdx];
988+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
989+ pEventsList[iEventCount++] = pEncPEncCtx->pSliceThreading->pUpdateMbListEvent[iEventIdx];
990+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
991+#endif//WIN32
992+
993+ do {
994+#ifdef WIN32
995+ iWaitRet = WelsMultipleEventsWaitSingleBlocking( iEventCount,
996+ &pEventsList[0],
997+ (uint32_t)-1 ); // blocking until at least one event is
998+#else
999+#if defined(ENABLE_TRACE_MT)
1000+ 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 );
1001+#endif
1002+ iWaitRet = WelsEventWait( pEncPEncCtx->pSliceThreading->pReadySliceCodingEvent[iEventIdx] );
1003+#endif//WIN32
1004+ if ( WELS_THREAD_ERROR_WAIT_OBJECT_0 == iWaitRet ) // start pSlice coding signal waited
1005+ {
1006+ SLayerBSInfo *pLbi = pPrivateData->pLayerBs;
1007+ const int32_t kiCurDid = pEncPEncCtx->uiDependencyId;
1008+ const int32_t kiCurTid = pEncPEncCtx->uiTemporalId;
1009+ SWelsSvcCodingParam *pCodingParam = pEncPEncCtx->pSvcParam;
1010+ SDLayerParam *pParamD = &pCodingParam->sDependencyLayers[kiCurDid];
1011+
1012+ pCurDq = pEncPEncCtx->pCurDqLayer;
1013+ eNalType = pEncPEncCtx->eNalType;
1014+ eNalRefIdc = pEncPEncCtx->eNalPriority;
1015+ bNeedPrefix = pEncPEncCtx->bNeedPrefixNalFlag;
1016+
1017+ if ( pParamD->sMso.uiSliceMode != SM_DYN_SLICE )
1018+ {
1019+ int64_t iSliceStart = 0;
1020+ bool_t bDsaFlag = false;
1021+ iSliceIdx = pPrivateData->iSliceIndex;
1022+ pSlice = &pCurDq->sLayerInfo.pSliceInLayer[iSliceIdx];
1023+ pSliceBs = &pEncPEncCtx->pSliceBs[iSliceIdx];
1024+
1025+#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
1026+ bDsaFlag = (pParamD->sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE &&
1027+ pCodingParam->iMultipleThreadIdc > 1 &&
1028+ pCodingParam->iMultipleThreadIdc >= pParamD->sMso.sSliceArgument.iSliceNum);
1029+ if ( bDsaFlag )
1030+ iSliceStart = WelsTime();
1031+#endif//DYNAMIC_SLICE_ASSIGN || MT_DEBUG
1032+
1033+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
1034+ pSliceBs->uiBsPos = 0;
1035+#endif//!PACKING_ONE_SLICE_PER_LAYER
1036+ pSliceBs->iNalIndex = 0;
1037+ assert( (void*)(&pSliceBs->sBsWrite) == (void*)pSlice->pSliceBsa );
1038+ InitBits( &pSliceBs->sBsWrite, pSliceBs->pBsBuffer, pSliceBs->uiSize );
1039+
1040+#if MT_DEBUG_BS_WR
1041+ pSliceBs->bSliceCodedFlag = FALSE;
1042+#endif//MT_DEBUG_BS_WR
1043+
1044+ if ( bNeedPrefix )
1045+ {
1046+ if ( eNalRefIdc != NRI_PRI_LOWEST )
1047+ {
1048+ WelsLoadNalForSlice( pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc );
1049+ WelsWriteSVCPrefixNal( &pSliceBs->sBsWrite, eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == eNalType) );
1050+ WelsUnloadNalForSlice( pSliceBs );
1051+ }
1052+ else // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
1053+ {
1054+ WelsLoadNalForSlice( pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc );
1055+ // No need write any syntax of prefix NAL Unit RBSP here
1056+ WelsUnloadNalForSlice( pSliceBs );
1057+ }
1058+ }
1059+
1060+ WelsLoadNalForSlice( pSliceBs, eNalType, eNalRefIdc );
1061+
1062+ WelsCodeOneSlice( pEncPEncCtx, iSliceIdx, eNalType );
1063+
1064+ WelsUnloadNalForSlice( pSliceBs );
1065+
1066+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
1067+ if ( 0 == iSliceIdx )
1068+ {
1069+ pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer;
1070+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx );
1071+ pEncPEncCtx->iPosBsBuffer += iSliceSize;
1072+ }
1073+ else
1074+ iSliceSize = WriteSliceBs( pEncPEncCtx, pSliceBs->pBs, iSliceIdx );
1075+#else// PACKING_ONE_SLICE_PER_LAYER
1076+ if ( 0 == iSliceIdx )
1077+ {
1078+ pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer;
1079+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx );
1080+ pEncPEncCtx->iPosBsBuffer += iSliceSize;
1081+ }
1082+ else
1083+ {
1084+ pLbi->pBsBuf = pSliceBs->bs + pSliceBs->uiBsPos;
1085+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbi, pLbi->pBsBuf, iSliceIdx );
1086+ pSliceBs->uiBsPos += iSliceSize;
1087+ }
1088+#endif//!PACKING_ONE_SLICE_PER_LAYER
1089+
1090+ if ( pCurDq->bDeblockingParallelFlag && pSlice->sSliceHeaderExt.sSliceHeader.uiDisableDeblockingFilterIdc != 1
1091+#if !defined(ENABLE_FRAME_DUMP)
1092+ && ( eNalRefIdc != NRI_PRI_LOWEST ) &&
1093+ ( pParamD->iHighestTemporalId == 0 || kiCurTid < pParamD->iHighestTemporalId )
1094+#endif// !ENABLE_FRAME_DUMP
1095+ )
1096+ {
1097+ DeblockingFilterSliceAvcbase( pCurDq, pEncPEncCtx->pFuncList, iSliceIdx );
1098+ }
1099+
1100+#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
1101+ if ( bDsaFlag )
1102+ {
1103+ pEncPEncCtx->pSliceThreading->pSliceConsumeTime[pEncPEncCtx->uiDependencyId][iSliceIdx] = (uint32_t)(WelsTime() - iSliceStart);
1104+#if defined(ENABLE_TRACE_MT)
1105+ 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",
1106+ pEncPEncCtx->iCodingIndex, iSliceIdx, pEncPEncCtx->pSliceThreading->pSliceConsumeTime[pEncPEncCtx->uiDependencyId][iSliceIdx], iSliceSize, pCurDq->pSliceEncCtx->pFirstMbInSlice[iSliceIdx], pCurDq->pSliceEncCtx->pCountMbNumInSlice[iSliceIdx]);
1107+#endif//ENABLE_TRACE_MT
1108+ }
1109+#endif//DYNAMIC_SLICE_ASSIGN || MT_DEBUG
1110+
1111+#if defined(SLICE_INFO_OUTPUT)
1112+ fprintf( stderr,
1113+ "@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n",
1114+ iSliceIdx,
1115+ (pEncPEncCtx->eSliceType == P_SLICE ? 'P' : 'I'),
1116+ eNalRefIdc,
1117+ iSliceSize
1118+ );
1119+#endif//SLICE_INFO_OUTPUT
1120+
1121+#if MT_DEBUG_BS_WR
1122+ pSliceBs->bSliceCodedFlag = TRUE;
1123+#endif//MT_DEBUG_BS_WR
1124+
1125+#ifdef WIN32
1126+ WelsEventSignal( &pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx] ); // mean finished coding current pSlice
1127+#else
1128+ WelsEventSignal( pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx] ); // mean finished coding current pSlice
1129+#endif//WIN32
1130+ }
1131+ else // for SM_DYN_SLICE parallelization
1132+ {
1133+#ifdef PACKING_ONE_SLICE_PER_LAYER
1134+ SLayerBSInfo *pLbiPacking = NULL;
1135+#endif//PACKING_ONE_SLICE_PER_LAYER
1136+ SSliceCtx *pSliceCtx = pCurDq->pSliceEncCtx;
1137+ const int32_t kiPartitionId = iThreadIdx;
1138+ const int32_t kiSliceIdxStep = pEncPEncCtx->iActiveThreadsNum;
1139+ const int32_t kiFirstMbInPartition = pPrivateData->iStartMbIndex; // inclusive
1140+ const int32_t kiEndMbInPartition = pPrivateData->iEndMbIndex; // exclusive
1141+ int32_t iAnyMbLeftInPartition = kiEndMbInPartition - kiFirstMbInPartition;
1142+
1143+ iSliceIdx = pPrivateData->iSliceIndex;
1144+
1145+ pSliceCtx->pFirstMbInSlice[iSliceIdx] = kiFirstMbInPartition;
1146+ pCurDq->pNumSliceCodedOfPartition[kiPartitionId] = 1; // one pSlice per partition intialized, dynamic slicing inside
1147+ pCurDq->pLastMbIdxOfPartition[kiPartitionId] = kiEndMbInPartition-1;
1148+
1149+ pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId] = 0;
1150+
1151+ while( iAnyMbLeftInPartition > 0 )
1152+ {
1153+ if ( iSliceIdx >= pSliceCtx->iMaxSliceNumConstraint )
1154+ {
1155+ // TODO: need exception handler for not large enough of MAX_SLICES_NUM related memory usage
1156+ // No idea about its solution due MAX_SLICES_NUM is fixed lenght in relevent pData structure
1157+ uiThrdRet = 1;
1158+ break;
1159+ }
1160+
1161+ pSlice = &pCurDq->sLayerInfo.pSliceInLayer[iSliceIdx];
1162+ pSliceBs = &pEncPEncCtx->pSliceBs[iSliceIdx];
1163+
1164+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
1165+ pSliceBs->uiBsPos = 0;
1166+#endif//!PACKING_ONE_SLICE_PER_LAYER
1167+ pSliceBs->iNalIndex = 0;
1168+ InitBits( &pSliceBs->sBsWrite, pSliceBs->pBsBuffer, pSliceBs->uiSize );
1169+
1170+ if ( bNeedPrefix )
1171+ {
1172+ if ( eNalRefIdc != NRI_PRI_LOWEST )
1173+ {
1174+ WelsLoadNalForSlice( pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc );
1175+ WelsWriteSVCPrefixNal( &pSliceBs->sBsWrite, eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == eNalType) );
1176+ WelsUnloadNalForSlice( pSliceBs );
1177+ }
1178+ else // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
1179+ {
1180+ WelsLoadNalForSlice( pSliceBs, NAL_UNIT_PREFIX, eNalRefIdc );
1181+ // No need write any syntax of prefix NAL Unit RBSP here
1182+ WelsUnloadNalForSlice( pSliceBs );
1183+ }
1184+ }
1185+
1186+ WelsLoadNalForSlice( pSliceBs, eNalType, eNalRefIdc );
1187+
1188+ WelsCodeOneSlice( pEncPEncCtx, iSliceIdx, eNalType );
1189+
1190+ WelsUnloadNalForSlice( pSliceBs );
1191+
1192+#if !defined(PACKING_ONE_SLICE_PER_LAYER)
1193+ if ( 0 == kiPartitionId )
1194+ {
1195+ if ( 0 == iSliceIdx )
1196+ pLbi->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer;
1197+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbi, pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer, iSliceIdx );
1198+ pEncPEncCtx->iPosBsBuffer += iSliceSize;
1199+ }
1200+ else
1201+ iSliceSize = WriteSliceBs( pEncPEncCtx, pSliceBs->pBs, iSliceIdx );
1202+#else// PACKING_ONE_SLICE_PER_LAYER
1203+ pLbiPacking = pLbi + (iSliceIdx - kiPartitionId);
1204+
1205+ if ( 0 == kiPartitionId )
1206+ {
1207+ pLbiPacking->pBsBuf = pEncPEncCtx->pFrameBs + pEncPEncCtx->iPosBsBuffer;
1208+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbiPacking, pLbiPacking->pBsBuf, iSliceIdx );
1209+ pEncPEncCtx->iPosBsBuffer += iSliceSize;
1210+ }
1211+ else
1212+ {
1213+ pLbiPacking->pBsBuf = pSliceBs->bs + pSliceBs->uiBsPos;
1214+ iSliceSize = WriteSliceToFrameBs( pEncPEncCtx, pLbiPacking, pLbiPacking->pBsBuf, iSliceIdx );
1215+ pSliceBs->uiBsPos += iSliceSize;
1216+ }
1217+ pEncPEncCtx->pSliceThreading->pCountBsSizeInPartition[kiPartitionId] += iSliceSize;
1218+#endif//!PACKING_ONE_SLICE_PER_LAYER
1219+
1220+ if ( pCurDq->bDeblockingParallelFlag && pSlice->sSliceHeaderExt.sSliceHeader.uiDisableDeblockingFilterIdc != 1
1221+#if !defined(ENABLE_FRAME_DUMP)
1222+ && ( eNalRefIdc != NRI_PRI_LOWEST ) &&
1223+ ( pParamD->iHighestTemporalId == 0 || kiCurTid < pParamD->iHighestTemporalId )
1224+#endif// !ENABLE_FRAME_DUMP
1225+ )
1226+ {
1227+ DeblockingFilterSliceAvcbase( pCurDq, pEncPEncCtx->pFuncList, iSliceIdx );
1228+ }
1229+
1230+#if defined(SLICE_INFO_OUTPUT)
1231+ fprintf( stderr,
1232+ "@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n",
1233+ iSliceIdx,
1234+ (pEncPEncCtx->eSliceType == P_SLICE ? 'P' : 'I'),
1235+ eNalRefIdc,
1236+ iSliceSize
1237+ );
1238+#endif//SLICE_INFO_OUTPUT
1239+
1240+#if defined(ENABLE_TRACE_MT)
1241+ 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",
1242+ pEncPEncCtx->iCodingIndex, kiPartitionId, iSliceIdx, iSliceSize, pCurDq->pSliceEncCtx->pCountMbNumInSlice[iSliceIdx], kiEndMbInPartition, kiPartitionId, pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId]);
1243+#endif//ENABLE_TRACE_MT
1244+
1245+ iAnyMbLeftInPartition = kiEndMbInPartition - (1 + pCurDq->pLastCodedMbIdxOfPartition[kiPartitionId]);
1246+ iSliceIdx += kiSliceIdxStep;
1247+ }
1248+
1249+ if ( uiThrdRet ) // any exception??
1250+ break;
1251+
1252+#ifdef WIN32
1253+ WelsEventSignal( &pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx] ); // mean finished coding current pSlice
1254+#else
1255+ WelsEventSignal( pEncPEncCtx->pSliceThreading->pSliceCodedEvent[iEventIdx] ); // mean finished coding current pSlice
1256+#endif//WIN32
1257+ }
1258+ }
1259+#ifdef WIN32
1260+ else if ( WELS_THREAD_ERROR_WAIT_OBJECT_0+1 == iWaitRet ) // exit thread signal
1261+ {
1262+ uiThrdRet = 0;
1263+ break;
1264+ }
1265+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
1266+ else if ( WELS_THREAD_ERROR_WAIT_OBJECT_0+2 == iWaitRet ) // update pMb list singal
1267+ {
1268+ iSliceIdx = iEventIdx; // pPrivateData->iSliceIndex; old threads can not be terminated, pPrivateData is not correct for applicable
1269+ pCurDq = pEncPEncCtx->pCurDqLayer;
1270+ UpdateMbListNeighborParallel( pCurDq->pSliceEncCtx, pCurDq->sMbDataP, iSliceIdx );
1271+ WelsEventSignal( &pEncPEncCtx->pSliceThreading->pFinUpdateMbListEvent[iEventIdx] ); // mean finished update pMb list for this pSlice
1272+ }
1273+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
1274+#endif//WIN32
1275+ else // WELS_THREAD_ERROR_WAIT_TIMEOUT, or WELS_THREAD_ERROR_WAIT_FAILED
1276+ {
1277+ WelsLog(pEncPEncCtx, WELS_LOG_WARNING, "[MT] CodingSliceThreadProc(), waiting pReadySliceCodingEvent[%d] failed(%d) and thread%d terminated!\n", iEventIdx, iWaitRet, iThreadIdx);
1278+ uiThrdRet = 1;
1279+ break;
1280+ }
1281+ } while( 1 );
1282+
1283+#ifdef WIN32
1284+ WelsEventSignal( &pEncPEncCtx->pSliceThreading->pFinSliceCodingEvent[iEventIdx] ); // notify to mother encoding threading
1285+#endif//WIN32
1286+
1287+ WELS_THREAD_ROUTINE_RETURN(uiThrdRet);
1288+}
1289+
1290+int32_t CreateSliceThreads( sWelsEncCtx *pCtx )
1291+{
1292+ const int32_t kiThreadCount = pCtx->pSvcParam->iCountThreadsNum;
1293+ int32_t iIdx = 0;
1294+#if defined(WIN32) && defined(BIND_CPU_CORES_TO_THREADS)
1295+ DWORD dwProcessAffinity;
1296+ DWORD dwSystemAffinity;
1297+ GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity);
1298+#endif//WIN32 && BIND_CPU_CORES_TO_THREADS
1299+
1300+ while ( iIdx < kiThreadCount ) {
1301+ WelsThreadCreate( &pCtx->pSliceThreading->pThreadHandles[iIdx], CodingSliceThreadProc, &pCtx->pSliceThreading->pThreadPEncCtx[iIdx], 0);
1302+#if defined(WIN32) && defined(BIND_CPU_CORES_TO_THREADS)
1303+ if ( dwProcessAffinity > 1 && pCtx->pSliceThreading->pThreadHandles[iIdx] != NULL ) // multiple cores and thread created successfully
1304+ {
1305+ DWORD dw = 0;
1306+ DWORD dwAffinityMask = 1 << iIdx;
1307+ if (dwAffinityMask & dwProcessAffinity) // check if cpu is available
1308+ {
1309+ dw = SetThreadAffinityMask( pCtx->pSliceThreading->pThreadHandles[iIdx], dwAffinityMask ); //1 << iIdx
1310+ if ( dw == 0)
1311+ {
1312+ str_t str[64] = {0};
1313+ SNPRINTF(str, 64, "SetThreadAffinityMask iIdx:%d", iIdx);
1314+ }
1315+ }
1316+ }
1317+#endif//WIN32 && BIND_CPU_CORES_TO_THREADS
1318+ // We need extra threads for update_mb_list_proc on __GNUC__ like OS (mac/linux)
1319+ // due to WelsMultipleEventsWaitSingleBlocking implememtation can not work well
1320+ // in case waiting pUpdateMbListEvent and pReadySliceCodingEvent events at the same time
1321+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
1322+#if defined(__GNUC__)
1323+ WelsThreadCreate( &pCtx->pSliceThreading->pUpdateMbListThrdHandles[iIdx], UpdateMbListThreadProc, &pCtx->pSliceThreading->pThreadPEncCtx[iIdx], 0);
1324+#endif//__GNUC__
1325+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
1326+ ++ iIdx;
1327+ }
1328+#if defined(ENABLE_TRACE_MT)
1329+ WelsLog(pCtx, WELS_LOG_INFO, "CreateSliceThreads() exit..\n");
1330+#endif
1331+ return 0;
1332+}
1333+
1334+#ifdef PACKING_ONE_SLICE_PER_LAYER
1335+void ResetCountBsSizeInPartitions( uint32_t *pCountBsSizeList, const int32_t iPartitionCnt )
1336+{
1337+ if ( pCountBsSizeList != NULL && iPartitionCnt > 0 )
1338+ {
1339+ memset(pCountBsSizeList, 0, sizeof(pCountBsSizeList[0]) * iPartitionCnt );
1340+ }
1341+}
1342+#endif//PACKING_ONE_SLICE_PER_LAYER
1343+
1344+#ifdef WIN32
1345+int32_t FiredSliceThreads( SSliceThreadPrivateData *pPriData, WELS_EVENT *pEventsList, SLayerBSInfo *pLbi, const uint32_t uiNumThreads, SSliceCtx *pSliceCtx, const BOOL_T bIsDynamicSlicingMode )
1346+#else
1347+int32_t FiredSliceThreads( SSliceThreadPrivateData *pPriData, WELS_EVENT **pEventsList, SLayerBSInfo *pLbi, const uint32_t uiNumThreads, SSliceCtx *pSliceCtx, const BOOL_T bIsDynamicSlicingMode )
1348+#endif//WIN32
1349+{
1350+ int32_t iEndMbIdx = 0;
1351+ int32_t iIdx = 0;
1352+ const int32_t kiEventCnt = uiNumThreads;
1353+
1354+ if ( pPriData == NULL || pLbi == NULL || kiEventCnt <= 0 || pEventsList == NULL )
1355+ {
1356+ 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);
1357+ return 1;
1358+ }
1359+
1360+#if defined(PACKING_ONE_SLICE_PER_LAYER)
1361+ ////////////////////////////////////////
1362+ if ( bIsDynamicSlicingMode )
1363+ {
1364+ iEndMbIdx = pSliceCtx->iMbNumInFrame;
1365+ for (iIdx = kiEventCnt-1; iIdx >= 0; --iIdx)
1366+ {
1367+ const int32_t kiFirstMbIdx = pSliceCtx->pFirstMbInSlice[iIdx];
1368+ pPriData[iIdx].iStartMbIndex = kiFirstMbIdx;
1369+ pPriData[iIdx].iEndMbIndex = iEndMbIdx;
1370+ iEndMbIdx = kiFirstMbIdx;
1371+ }
1372+ }
1373+
1374+ iIdx = 0;
1375+ while (iIdx < kiEventCnt) {
1376+ pPriData[iIdx].pLayerBs = pLbi;
1377+ pPriData[iIdx].iSliceIndex = iIdx;
1378+#ifdef WIN32
1379+ if ( pEventsList[iIdx] )
1380+ WelsEventSignal( &pEventsList[iIdx] );
1381+#else
1382+ WelsEventSignal( pEventsList[iIdx] );
1383+#endif//WIN32
1384+ ++ pLbi;
1385+ ++ iIdx;
1386+ }
1387+ ////////////////////////////////////////
1388+#else
1389+ ////////////////////////////////////////
1390+ if ( bIsDynamicSlicingMode )
1391+ {
1392+ iEndMbIdx = pSliceCtx->iMbNumInFrame;
1393+ for (iIdx = kiEventCnt-1; iIdx >= 0; --iIdx)
1394+ {
1395+ const int32_t iFirstMbIdx = pSliceCtx->pFirstMbInSlice[iIdx];
1396+ pPriData[iIdx].iStartMbIndex = iFirstMbIdx;
1397+ pPriData[iIdx].iEndMbIndex = iEndMbIdx;
1398+ iEndMbIdx = iFirstMbIdx;
1399+ }
1400+ }
1401+
1402+ iIdx = 0;
1403+ while (iIdx < kiEventCnt) {
1404+ pPriData[iIdx].pLayerBs = pLbi;
1405+ pPriData[iIdx].iSliceIndex = iIdx;
1406+#ifdef WIN32
1407+ if ( pEventsList[iIdx] )
1408+ WelsEventSignal( &pEventsList[iIdx] );
1409+#else
1410+ WelsEventSignal( pEventsList[iIdx] );
1411+#endif//WIN32
1412+ ++ iIdx;
1413+ }
1414+ ////////////////////////////////////////
1415+#endif//PACKING_ONE_SLICE_PER_LAYER
1416+
1417+ return 0;
1418+}
1419+
1420+int32_t DynamicDetectCpuCores()
1421+{
1422+ WelsLogicalProcessInfo info;
1423+ WelsQueryLogicalProcessInfo(&info);
1424+ return info.ProcessorCount;
1425+}
1426+
1427+#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN)
1428+
1429+int32_t AdjustBaseLayer( sWelsEncCtx *pCtx )
1430+{
1431+ SDqLayer *pCurDq = pCtx->ppDqLayerList[0];
1432+ int32_t iNeedAdj = 1;
1433+#ifdef MT_DEBUG
1434+ int64_t iT0 = WelsTime();
1435+#endif//MT_DEBUG
1436+#ifdef TRY_SLICING_BALANCE
1437+
1438+ pCtx->pCurDqLayer = pCurDq;
1439+
1440+#ifdef NOT_ABSOLUTE_BALANCING
1441+ // do not need adjust due to not different at both slices of consumed time
1442+ iNeedAdj = NeedDynamicAdjust( pCtx->pSliceThreading->pSliceConsumeTime[0], pCurDq->pSliceEncCtx->iSliceNumInFrame );
1443+ if ( iNeedAdj )
1444+#endif//NOT_ABSOLUTE_BALANCING
1445+ DynamicAdjustSlicing( pCtx,
1446+ pCurDq,
1447+ pCtx->pSliceThreading->pSliceComplexRatio[0],
1448+ 0 );
1449+#endif//TRY_SLICING_BALANCE
1450+#ifdef MT_DEBUG
1451+ iT0 = WelsTime() - iT0;
1452+ if ( pCtx->pSliceThreading->pFSliceDiff )
1453+ {
1454+ fprintf( pCtx->pSliceThreading->pFSliceDiff,
1455+#ifdef WIN32
1456+ "%6I64d us adjust time at base spatial layer, iNeedAdj %d, DynamicAdjustSlicing()\n",
1457+#else
1458+ "%6lld us adjust time at base spatial layer, iNeedAdj %d, DynamicAdjustSlicing()\n",
1459+#endif//WIN32
1460+ iT0, iNeedAdj );
1461+ }
1462+#endif//MT_DEBUG
1463+
1464+ return iNeedAdj;
1465+}
1466+
1467+int32_t AdjustEnhanceLayer( sWelsEncCtx *pCtx, int32_t iCurDid )
1468+{
1469+#ifdef MT_DEBUG
1470+ int64_t iT1 = WelsTime();
1471+#endif//MT_DEBUG
1472+ int32_t iNeedAdj = 1;
1473+ // uiSliceMode of referencing spatial should be SM_FIXEDSLCNUM_SLICE
1474+ // if using spatial base layer for complexity estimation
1475+ const BOOL_T kbModelingFromSpatial = (pCtx->pCurDqLayer->pRefLayer != NULL && iCurDid > 0)
1476+ && (pCtx->pSvcParam->sDependencyLayers[iCurDid-1].sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pCtx->pSvcParam->iMultipleThreadIdc >= pCtx->pSvcParam->sDependencyLayers[iCurDid-1].sMso.sSliceArgument.iSliceNum);
1477+
1478+ if ( kbModelingFromSpatial ) // using spatial base layer for complexity estimation
1479+ {
1480+#ifdef TRY_SLICING_BALANCE
1481+#ifdef NOT_ABSOLUTE_BALANCING
1482+ // do not need adjust due to not different at both slices of consumed time
1483+ iNeedAdj = NeedDynamicAdjust( pCtx->pSliceThreading->pSliceConsumeTime[iCurDid-1], pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame );
1484+ if ( iNeedAdj )
1485+#endif//NOT_ABSOLUTE_BALANCING
1486+ DynamicAdjustSlicing( pCtx,
1487+ pCtx->pCurDqLayer,
1488+ pCtx->pSliceThreading->pSliceComplexRatio[iCurDid-1],
1489+ iCurDid
1490+ );
1491+#endif//TRY_SLICING_BALANCE
1492+ }
1493+ else // use temporal layer for complexity estimation
1494+ {
1495+#ifdef TRY_SLICING_BALANCE
1496+#ifdef NOT_ABSOLUTE_BALANCING
1497+ // do not need adjust due to not different at both slices of consumed time
1498+ iNeedAdj = NeedDynamicAdjust( pCtx->pSliceThreading->pSliceConsumeTime[iCurDid], pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame );
1499+ if ( iNeedAdj )
1500+#endif//NOT_ABSOLUTE_BALANCING
1501+ DynamicAdjustSlicing( pCtx,
1502+ pCtx->pCurDqLayer,
1503+ pCtx->pSliceThreading->pSliceComplexRatio[iCurDid],
1504+ iCurDid
1505+ );
1506+#endif//TRY_SLICING_BALANCE
1507+ }
1508+
1509+#ifdef MT_DEBUG
1510+ iT1 = WelsTime() - iT1;
1511+ if ( pCtx->pSliceThreading->pFSliceDiff )
1512+ {
1513+ fprintf( pCtx->pSliceThreading->pFSliceDiff,
1514+#ifdef WIN32
1515+ "%6I64d us adjust time at spatial layer %d, iNeedAdj %d, DynamicAdjustSlicing()\n",
1516+#else
1517+ "%6lld us adjust time at spatial layer %d, iNeedAdj %d, DynamicAdjustSlicing()\n",
1518+#endif//WIN32
1519+ iT1, iCurDid, iNeedAdj );
1520+ }
1521+#endif//MT_DEBUG
1522+
1523+ return iNeedAdj;
1524+}
1525+
1526+#endif//#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN)
1527+
1528+#if defined(MT_ENABLED)
1529+
1530+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE) && defined(MT_DEBUG)
1531+void TrackSliceComplexities( sWelsEncCtx *pCtx, const int32_t iCurDid )
1532+{
1533+ const int32_t kiCountSliceNum = pCtx->pCurDqLayer->pSliceEncCtx->iSliceNumInFrame;
1534+ if ( kiCountSliceNum > 0 )
1535+ {
1536+ int32_t iSliceIdx = 0;
1537+ do {
1538+ fprintf( pCtx->pSliceThreading->pFSliceDiff, "%6.3f complexity pRatio at iDid %d pSlice %d\n", pCtx->pSliceThreading->pSliceComplexRatio[iCurDid][iSliceIdx], iCurDid, iSliceIdx );
1539+ ++ iSliceIdx;
1540+ } while(iSliceIdx < kiCountSliceNum);
1541+ }
1542+}
1543+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
1544+
1545+#if defined(DYNAMIC_SLICE_ASSIGN) && defined(MT_DEBUG)
1546+void TrackSliceConsumeTime( sWelsEncCtx *pCtx, int32_t *pDidList, const int32_t iSpatialNum )
1547+{
1548+ SWelsSvcCodingParam *pPara = NULL;
1549+ int32_t iSpatialIdx = 0;
1550+
1551+ if ( iSpatialNum > MAX_DEPENDENCY_LAYER )
1552+ return;
1553+
1554+ pPara = pCtx->pSvcParam;
1555+ while ( iSpatialIdx < iSpatialNum )
1556+ {
1557+ const int32_t kiDid = pDidList[iSpatialIdx];
1558+ SDLayerParam *pDlp = &pPara->sDependencyLayers[kiDid];
1559+ SMulSliceOption *pMso = &pDlp->sMso;
1560+ SDqLayer *pCurDq = pCtx->ppDqLayerList[kiDid];
1561+ SSliceCtx *pSliceCtx= pCurDq->pSliceEncCtx;
1562+ const uint32_t kuiCountSliceNum = pSliceCtx->iSliceNumInFrame;
1563+ if(pCtx->pSliceThreading)
1564+ {
1565+ if ( pCtx->pSliceThreading->pFSliceDiff && pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE && pPara->iMultipleThreadIdc > 1 && pPara->iMultipleThreadIdc >= kuiCountSliceNum )
1566+ {
1567+ uint32_t i = 0;
1568+ uint32_t uiMaxT = 0;
1569+ int32_t iMaxI = 0;
1570+ while (i < kuiCountSliceNum) {
1571+ if ( pCtx->pSliceThreading->pSliceConsumeTime[kiDid] != NULL )
1572+ fprintf( pCtx->pSliceThreading->pFSliceDiff, "%6d us consume_time coding_idx %d iDid %d pSlice %d\n",
1573+ pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i], pCtx->iCodingIndex, kiDid, i /*/ 1000*/);
1574+ if (pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i] > uiMaxT)
1575+ {
1576+ uiMaxT = pCtx->pSliceThreading->pSliceConsumeTime[kiDid][i];
1577+ iMaxI = i;
1578+ }
1579+ ++ i;
1580+ }
1581+ fprintf( pCtx->pSliceThreading->pFSliceDiff, "%6d us consume_time_max coding_idx %d iDid %d pSlice %d\n", uiMaxT, pCtx->iCodingIndex, kiDid, iMaxI /*/ 1000*/);
1582+ }
1583+ }
1584+ ++ iSpatialIdx;
1585+ }
1586+}
1587+#endif//#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
1588+
1589+#endif//MT_ENABLED
1590+}
1591+#endif//MT_ENABLED
1592+

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