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
69namespace WelsSVCEnc {
70void 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
120void 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)
151int32_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)
232void 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
339void 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
353int32_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
556void 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
738int32_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
833int32_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
885int32_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__)
912WELS_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
954WELS_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
1290int32_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
1335void 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
1345int32_t FiredSliceThreads( SSliceThreadPrivateData *pPriData, WELS_EVENT *pEventsList, SLayerBSInfo *pLbi, const uint32_t uiNumThreads, SSliceCtx *pSliceCtx, const BOOL_T bIsDynamicSlicingMode )
1346#else
1347int32_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
1420int32_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
1429int32_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
1467int32_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)
1531void 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)
1546void 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