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/encoder_ext.cpp (1 of 308 files). Show all

Unified · Split

codec/encoder/core/src/encoder_ext.cpp+4250−0
@@ -0,0 +1,4250 @@
1/*!
2 * \copy
3 * Copyright (c) 2009-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 encoder_ext.c
33 *
34 * \brief core encoder for SVC
35 *
36 * \date 7/24/2009 Created
37 *
38 *************************************************************************************
39 */
40#include <string.h>
41#include <stdlib.h>
42#include <assert.h>
43
44#include "encoder.h"
45#include "extern.h"
46#include "encoder_context.h"
47#include "typedefs.h"
48#include "wels_const.h"
49#include "wels_common_basis.h"
50#include "codec_def.h"
51#include "param_svc.h"
52#include "cpu_core.h"
53#include "cpu.h"
54#include "utils.h"
55#include "svc_enc_frame.h"
56#include "svc_enc_golomb.h"
57#include "svc_enc_slice_segment.h"
58#include "au_set.h"
59#include "picture_handle.h"
60#include "codec_app_def.h"
61#include "svc_base_layer_md.h"
62#include "svc_encode_slice.h"
63#include "decode_mb_aux.h"
64#include "deblocking.h"
65#include "rc.h"
66#include "ref_list_mgr_svc.h"
67#include "md.h"
68#include "ls_defines.h"
69#include "set_mb_syn_cavlc.h"
70#include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms
71#include "array_stack_align.h"
72// for MT, 4/22/2010
73#include "slice_multi_threading.h"
74#if defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG)
75#include "measure_time.h"
76#endif//DYNAMIC_SLICE_ASSIGN
77
78namespace WelsSVCEnc {
79
80
81int32_t WelsCodeOnePicPartition( sWelsEncCtx *pCtx,
82 SLayerBSInfo *pLbi,
83 int32_t *pNalIdxInLayer,
84 int32_t* pLayerSize,
85 int32_t iFirstMbInPartition, // first mb inclusive in partition
86 int32_t iEndMbInPartition, // end mb exclusive in partition
87 int32_t iStartSliceIdx
88 );
89
90
91/*!
92 * \brief validate checking in parameter configuration
93 * \pParam pParam SWelsSvcCodingParam*
94 * \return successful - 0; otherwise none 0 for failed
95 */
96int32_t ParamValidation( SWelsSvcCodingParam *pCfg )
97{
98 float fMaxFrameRate = 0.0f;
99 const float fEpsn = 0.000001f;
100 int32_t i = 0;
101 int32_t iLastSpatialWidth = 0;
102 int32_t iLastSpatialHeight = 0;
103 float fLastFrameRateIn = 0.0f;
104 float fLastFrameRateOut = 0.0f;
105 SDLayerParam *pLastSpatialParam = NULL;
106
107 assert( pCfg != NULL );
108
109 for (i = 0; i < pCfg->iNumDependencyLayer; ++ i)
110 {
111 SDLayerParam *fDlp = &pCfg->sDependencyLayers[i];
112 if ( fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn && fDlp->fInputFrameRate <= fEpsn)
113 || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn) )
114 {
115#if defined (_DEBUG)
116 fprintf(stderr, "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..\n",
117 fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i);
118#endif
119 return 1;
120 }
121 if ( UINT_MAX == GetLogFactor(fDlp->fOutputFrameRate, fDlp->fInputFrameRate) )
122 {
123#if defined (_DEBUG)
124 fprintf(stderr, "Invalid settings in input frame rate(%.6f) and output frame rate(%.6f) of layer #%d config file: iResult of output frame rate divided by input frame rate should be power of 2(i.e,in/pOut=2^n)..\n",
125 fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i);
126#endif
127 return 1;
128 }
129 }
130
131 for (i = 0; i < pCfg->iNumDependencyLayer; ++ i)
132 {
133 SDLayerParam *fDlp = &pCfg->sDependencyLayers[i];
134 if ( fDlp->fInputFrameRate > fMaxFrameRate )
135 fMaxFrameRate = fDlp->fInputFrameRate;
136 }
137
138 if ( fMaxFrameRate > fEpsn && (fMaxFrameRate - pCfg->fMaxFrameRate > fEpsn || fMaxFrameRate - pCfg->fMaxFrameRate < -fEpsn) )
139 {
140 pCfg->fMaxFrameRate = fMaxFrameRate;
141 }
142
143 for (i = 0; i < pCfg->iNumDependencyLayer; ++ i)
144 {
145 SDLayerParam *fDlp = &pCfg->sDependencyLayers[i];
146
147 pLastSpatialParam = fDlp;
148 iLastSpatialWidth = fDlp->iFrameWidth;
149 iLastSpatialHeight = fDlp->iFrameHeight;
150 fLastFrameRateIn = fDlp->fInputFrameRate;
151 fLastFrameRateOut = fDlp->fOutputFrameRate;
152 }
153
154 return 0;
155}
156
157int32_t ParamValidationExt( void *pParam )
158{
159 SWelsSvcCodingParam *pCodingParam = (SWelsSvcCodingParam *)pParam;
160 int8_t i = 0;
161 int32_t iIdx = 0;
162
163 assert ( pCodingParam != NULL );
164 if ( NULL == pCodingParam )
165 return 1;
166
167 if ( pCodingParam->iNumDependencyLayer < 1 || pCodingParam->iNumDependencyLayer > MAX_DEPENDENCY_LAYER ){
168#if defined (_DEBUG)
169 fprintf(stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumDependencyLayer: %d!\n", pCodingParam->iNumDependencyLayer);
170#endif//#if _DEBUG
171
172 return 1;
173 }
174
175 if ( pCodingParam->iNumTemporalLayer < 1 || pCodingParam->iNumTemporalLayer > MAX_TEMPORAL_LEVEL ){
176#if defined (_DEBUG)
177 fprintf(stderr, "ParamValidationExt(), monitor invalid pCodingParam->iNumTemporalLayer: %d!\n", pCodingParam->iNumTemporalLayer);
178#endif//#if _DEBUG
179 return 1;
180 }
181
182 if ( pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE ){
183#if defined (_DEBUG)
184 fprintf(stderr, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!\n", pCodingParam->uiGopSize);
185#endif//#if _DEBUG
186 return 1;
187 }
188
189
190 if ( pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize )
191 {
192#if defined (_DEBUG)
193 fprintf(stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!\n",
194 pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);
195#endif//#if _DEBUG
196 return 1;
197 }
198
199 if ( pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize-1)) != 0 )
200 {
201#if defined (_DEBUG)
202 fprintf(stderr, "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!\n",
203 pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);
204#endif//#if _DEBUG
205 return 1;
206 }
207
208
209#ifdef MT_ENABLED
210 //about iMultipleThreadIdc, bDeblockingParallelFlag, iLoopFilterDisableIdc, & uiSliceMode
211 // (1) Single Thread
212 // if (THREAD==1)//single thread
213 // no parallel_deblocking: bDeblockingParallelFlag = 0;
214 // (2) Multi Thread: see uiSliceMode decision
215 if ( pCodingParam->iMultipleThreadIdc == 1 )
216 {
217 //now is single thread. no parallel deblocking, set flag=0
218 pCodingParam->bDeblockingParallelFlag = false;
219 }
220 else
221 {
222 pCodingParam->bDeblockingParallelFlag = true;
223 }
224#else
225 pCodingParam->bDeblockingParallelFlag = false;
226#endif//MT_ENABLED
227
228 for ( i = 0; i < pCodingParam->iNumDependencyLayer; ++ i ){
229 SDLayerParam *fDlp = &pCodingParam->sDependencyLayers[i];
230 const int32_t kiPicWidth = fDlp->iFrameWidth;
231 const int32_t kiPicHeight= fDlp->iFrameHeight;
232 int32_t iMbWidth = 0;
233 int32_t iMbHeight = 0;
234 int32_t iMbNumInFrame = 0;
235 int32_t iMaxSliceNum = MAX_SLICES_NUM;
236 if ( kiPicWidth <= 0 || kiPicHeight <= 0 ){
237#if defined (_DEBUG)
238 fprintf(stderr, "ParamValidationExt(), invalid %d x %d in dependency layer settings!\n", kiPicWidth, kiPicHeight);
239#endif//#if _DEBUG
240 return 1;
241 }
242 if ( (kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0 ){
243#if defined (_DEBUG)
244 fprintf(stderr, "ParamValidationExt(), in layer #%d iWidth x iHeight(%d x %d) both should be multiple of 16, can not support with arbitrary size currently!\n", i, kiPicWidth, kiPicHeight);
245#endif//#if _DEBUG
246 return 1;
247 }
248
249 if ( fDlp->sMso.uiSliceMode >= SM_RESERVED ){
250#if defined (_DEBUG)
251 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", fDlp->sMso.uiSliceMode );
252#endif//#if _DEBUG
253 return 1;
254 }
255
256 //check pSlice settings under multi-pSlice
257 if ( kiPicWidth<=16 && kiPicHeight<=16 ){
258 //only have one MB, set to single_slice
259 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
260 }
261 switch ( fDlp->sMso.uiSliceMode )
262 {
263 case SM_SINGLE_SLICE:
264 fDlp->sMso.sSliceArgument.iSliceNum = 1;
265 fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0;
266 fDlp->sMso.sSliceArgument.iSliceNum = 0;
267 for (iIdx=0; iIdx<MAX_SLICES_NUM;iIdx++)
268 {
269 fDlp->sMso.sSliceArgument.uiSliceMbNum[iIdx] = 0;
270 }
271 break;
272 case SM_FIXEDSLCNUM_SLICE:
273 {
274 fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0;
275
276 iMbWidth = (kiPicWidth+15)>>4;
277 iMbHeight = (kiPicHeight+15)>>4;
278 iMbNumInFrame = iMbWidth * iMbHeight;
279 iMaxSliceNum = MAX_SLICES_NUM;
280 if ( fDlp->sMso.sSliceArgument.iSliceNum <= 0
281 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum )
282 {
283#if defined (_DEBUG)
284 fprintf(stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum );
285#endif//#if _DEBUG
286 return 1;
287 }
288 if (fDlp->sMso.sSliceArgument.iSliceNum == 1)
289 {
290#if defined (_DEBUG)
291 fprintf(stderr, "ParamValidationExt(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!\n", fDlp->sMso.sSliceArgument.iSliceNum );
292#endif//#if _DEBUG
293 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
294 break;
295 }
296 if (pCodingParam->bEnableRc) // multiple slices verify with gom
297 {
298 //check uiSliceNum
299 GomValidCheckSliceNum( iMbWidth, iMbHeight, (int32_t*)&fDlp->sMso.sSliceArgument.iSliceNum );
300 assert(fDlp->sMso.sSliceArgument.iSliceNum > 1);
301 //set uiSliceMbNum with current uiSliceNum
302 GomValidCheckSliceMbNum( iMbWidth, iMbHeight, &fDlp->sMso.sSliceArgument );
303 }
304 else if ( !CheckFixedSliceNumMultiSliceSetting( iMbNumInFrame, &fDlp->sMso.sSliceArgument ) ) // verify interleave mode settings
305 {//check uiSliceMbNum with current uiSliceNum
306#if defined (_DEBUG)
307 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0] );
308#endif//#if _DEBUG
309 return 1;
310 }
311 // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting
312 if ( iMbNumInFrame <= MIN_NUM_MB_PER_SLICE )
313 {
314 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
315 fDlp->sMso.sSliceArgument.iSliceNum = 1;
316 break;
317 }
318 }
319 break;
320 case SM_RASTER_SLICE:
321 {
322 fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0;
323
324 iMbWidth = (kiPicWidth+15)>>4;
325 iMbHeight = (kiPicHeight+15)>>4;
326 iMbNumInFrame = iMbWidth * iMbHeight;
327 iMaxSliceNum = MAX_SLICES_NUM;
328 if ( fDlp->sMso.sSliceArgument.uiSliceMbNum[0] <= 0 )
329 {
330#if defined (_DEBUG)
331 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0] );
332#endif//#if _DEBUG
333 return 1;
334 }
335
336 if ( !CheckRasterMultiSliceSetting( iMbNumInFrame, &fDlp->sMso.sSliceArgument ) ) // verify interleave mode settings
337 {
338#if defined (_DEBUG)
339 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0] );
340#endif//#if _DEBUG
341 return 1;
342 }
343 if ( fDlp->sMso.sSliceArgument.iSliceNum <= 0 || fDlp->sMso.sSliceArgument.iSliceNum > iMaxSliceNum ) // verify interleave mode settings
344 {
345#if defined (_DEBUG)
346 fprintf(stderr, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!\n", fDlp->sMso.sSliceArgument.iSliceNum );
347#endif//#if _DEBUG
348 return 1;
349 }
350 if (fDlp->sMso.sSliceArgument.iSliceNum == 1)
351 {
352#if defined (_DEBUG)
353 fprintf(stderr, "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!\n" );
354#endif//#if _DEBUG
355 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
356 break;
357 }
358#ifdef MT_ENABLED
359 if (pCodingParam->bEnableRc && fDlp->sMso.sSliceArgument.iSliceNum > 1)
360 {
361#if defined (_DEBUG)
362 fprintf(stderr, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!\n" );
363#endif//#if _DEBUG
364 }
365#endif
366 // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting
367 if ( iMbNumInFrame <= MIN_NUM_MB_PER_SLICE )
368 {
369 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
370 fDlp->sMso.sSliceArgument.iSliceNum = 1;
371 break;
372 }
373 }
374 break;
375 case SM_ROWMB_SLICE:
376 {
377 fDlp->sMso.sSliceArgument.uiSliceSizeConstraint = 0;
378
379 iMbWidth = (kiPicWidth+15)>>4;
380 iMbHeight = (kiPicHeight+15)>>4;
381 iMaxSliceNum = MAX_SLICES_NUM;
382 if ( iMbHeight > iMaxSliceNum )
383 {
384#if defined (_DEBUG)
385 fprintf(stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX!\n", iMbHeight );
386#endif//#if _DEBUG
387 return 1;
388 }
389 fDlp->sMso.sSliceArgument.iSliceNum = iMbHeight;
390
391 if ( fDlp->sMso.sSliceArgument.iSliceNum <= 0 )
392 {
393#if defined (_DEBUG)
394 fprintf(stderr, "ParamValidationExt(), invalid uiSliceNum (%d) settings!\n", fDlp->sMso.sSliceArgument.iSliceNum );
395#endif//#if _DEBUG
396 return 1;
397 }
398 if ( !CheckRowMbMultiSliceSetting( iMbWidth, &fDlp->sMso.sSliceArgument ) ) // verify interleave mode settings
399 {
400#if defined (_DEBUG)
401 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceMbNum[0] );
402#endif//#if _DEBUG
403 return 1;
404 }
405 }
406 break;
407 case SM_DYN_SLICE:
408 {
409 iMbWidth = (kiPicWidth+15)>>4;
410 iMbHeight = (kiPicHeight+15)>>4;
411 if ( fDlp->sMso.sSliceArgument.uiSliceSizeConstraint <= 0 )
412 {
413#if defined (_DEBUG)
414 fprintf(stderr, "ParamValidationExt(), invalid iSliceSize (%d) settings!\n", fDlp->sMso.sSliceArgument.uiSliceSizeConstraint );
415#endif//#if _DEBUG
416 return 1;
417 }
418 // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting
419 if ( iMbWidth * iMbHeight <= MIN_NUM_MB_PER_SLICE )
420 {
421 fDlp->sMso.uiSliceMode = SM_SINGLE_SLICE;
422 fDlp->sMso.sSliceArgument.iSliceNum = 1;
423 break;
424 }
425 }
426 break;
427 default:
428 {
429
430#if defined (_DEBUG)
431 fprintf(stderr, "ParamValidationExt(), invalid uiSliceMode (%d) settings!\n", pCodingParam->sDependencyLayers[0].sMso.uiSliceMode );
432#endif//#if _DEBUG
433 return 1;
434
435 }
436 break;
437 }
438 }
439
440 return ParamValidation(pCodingParam);
441}
442
443/*!
444 * \brief acquire count number of layers and NALs based on configurable paramters dependency
445 * \pParam pCtx sWelsEncCtx*
446 * \pParam pParam SWelsSvcCodingParam*
447 * \pParam pCountLayers pointer of count number of layers indeed
448 * \pParam iCountNals pointer of count number of nals indeed
449 * \return 0 - successful; otherwise failed
450 */
451static inline int32_t AcquireLayersNals( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pParam, int32_t *pCountLayers, int32_t *pCountNals )
452{
453 int32_t iCountNumLayers = 0;
454 int32_t iCountNumNals = 0;
455 int32_t iNumDependencyLayers = 0;
456 int32_t iDIndex = 0;
457#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
458 int32_t iNumLayersPack = 0;
459#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER
460
461 if ( NULL == pParam || NULL == ppCtx || NULL == *ppCtx )
462 return 1;
463
464 iNumDependencyLayers = pParam->iNumDependencyLayer;
465
466 do {
467 SDLayerParam *pDLayer = &pParam->sDependencyLayers[iDIndex];
468// pDLayer->ptr_cfg = pParam;
469 int32_t iOrgNumNals = iCountNumNals;
470
471 //Note: Sep. 2010
472 //Review this part and suggest no change, since the memory over-use
473 //(1) counts little to the overall performance
474 //(2) should not be critial even under mobile case
475 if ( SM_DYN_SLICE == pDLayer->sMso.uiSliceMode )
476 {
477 iCountNumNals += MAX_SLICES_NUM;
478 // plus prefix NALs
479 if ( iDIndex == 0 )
480 iCountNumNals += MAX_SLICES_NUM;
481 // MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME ensured at svc_enc_slice_segment.h
482#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
483 assert(MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME);
484 // iNumLayersPack += MAX_SLICES_NUM; // do not count it for dynamic slicing mode
485#else//!MT_ENABLED || !PACKING_ONE_SLICE_PER_LAYER
486 assert(iCountNumNals - iOrgNumNals <= MAX_NAL_UNITS_IN_LAYER );
487#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER
488 }
489 else /*if ( SM_SINGLE_SLICE != pDLayer->sMso.uiSliceMode )*/
490 {
491 const int32_t kiNumOfSlice = GetInitialSliceNum( (pDLayer->iFrameWidth+0x0f)>>4,
492 (pDLayer->iFrameHeight+0x0f)>>4,
493 &pDLayer->sMso );
494
495 // NEED check iCountNals value in case multiple slices is used
496 iCountNumNals += kiNumOfSlice; // for pSlice VCL NALs
497 // plus prefix NALs
498 if ( iDIndex == 0 )
499 iCountNumNals += kiNumOfSlice;
500#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
501 assert(num_of_slice <= MAX_SLICES_NUM && MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME);
502 iNumLayersPack += num_of_slice;
503#else//!MT_ENABLED || !PACKING_ONE_SLICE_PER_LAYER
504 assert(iCountNumNals - iOrgNumNals <= MAX_NAL_UNITS_IN_LAYER );
505#endif//MT_ENALBED && PACKING_ONE_SLICE_PER_LAYER
506 if ( kiNumOfSlice > MAX_SLICES_NUM )
507 {
508 WelsLog( *ppCtx, WELS_LOG_ERROR, "AcquireLayersNals(), num_of_slice(%d) > MAX_SLICES_NUM(%d) per (iDid= %d, qid= %d) settings!\n",
509 kiNumOfSlice, MAX_SLICES_NUM, iDIndex, 0 );
510 return 1;
511 }
512 }
513#if !defined(MT_ENABLED) || !defined(PACKING_ONE_SLICE_PER_LAYER)
514 if ( iCountNumNals - iOrgNumNals > MAX_NAL_UNITS_IN_LAYER )
515 {
516 WelsLog( *ppCtx, WELS_LOG_ERROR, "AcquireLayersNals(), num_of_nals(%d) > MAX_NAL_UNITS_IN_LAYER(%d) per (iDid= %d, qid= %d) settings!\n",
517 (iCountNumNals - iOrgNumNals), MAX_NAL_UNITS_IN_LAYER, iDIndex, 0 );
518 return 1;
519 }
520#endif//!MT_ENABLED) || !PACKING_ONE_SLICE_PER_LAYER
521
522 iCountNumLayers ++;
523
524 ++ iDIndex;
525 } while(iDIndex < iNumDependencyLayers);
526
527 iCountNumNals += 1 + iNumDependencyLayers + (iCountNumLayers<<1) + iCountNumLayers; // plus iCountNumLayers for reserved application
528#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
529 iNumLayersPack += 1 + iNumDependencyLayers + (iCountNumLayers<<1);
530#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER
531
532 // to check number of layers / nals / slices dependencies, 12/8/2010
533#if !defined(MT_ENABLED)
534 if ( iCountNumLayers > MAX_LAYER_NUM_OF_FRAME )
535 {
536 WelsLog( *ppCtx, WELS_LOG_ERROR, "AcquireLayersNals(), iCountNumLayers(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!", iCountNumLayers, MAX_LAYER_NUM_OF_FRAME );
537 return 1;
538 }
539#else//MT_ENABLED
540#if defined(PACKING_ONE_SLICE_PER_LAYER)
541 if ( iNumLayersPack > MAX_LAYER_NUM_OF_FRAME )
542 {
543 WelsLog( *ppCtx, WELS_LOG_ERROR, "AcquireLayersNals(), num_layers_pack_overall(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!", iNumLayersPack, MAX_LAYER_NUM_OF_FRAME );
544 return 1;
545 }
546#else//!PACKING_ONE_SLICE_PER_LAYER
547 if ( iCountNumLayers > MAX_LAYER_NUM_OF_FRAME )
548 {
549 WelsLog( *ppCtx, WELS_LOG_ERROR, "AcquireLayersNals(), iCountNumLayers(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!", iCountNumLayers, MAX_LAYER_NUM_OF_FRAME );
550 return 1;
551 }
552#endif//PACKING_ONE_SLICE_PER_LAYER
553#endif//!MT_ENABLED
554
555 if ( NULL != pCountLayers )
556 *pCountLayers = iCountNumLayers;
557 if ( NULL != pCountNals )
558 *pCountNals = iCountNumNals;
559 return 0;
560}
561
562/*!
563 * \brief alloc spatial layers pictures (I420 based source pictures)
564 */
565int32_t AllocSpatialPictures( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pParam )
566{
567 CMemoryAlign *pMa = (*ppCtx)->pMemAlign;
568 const int32_t kiDlayerCount = pParam->iNumDependencyLayer;
569 int32_t iDlayerIndex = 0;
570
571 // spatial pictures
572 iDlayerIndex = 0;
573 do {
574 const int32_t kiPicWidth = pParam->sDependencyLayers[iDlayerIndex].iFrameWidth;
575 const int32_t kiPicHeight = pParam->sDependencyLayers[iDlayerIndex].iFrameHeight;
576 const uint8_t kuiLayerInTemporal = 2 + WELS_MAX(pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1);
577 const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum;
578 uint8_t i = 0;
579
580 do {
581 SPicture *pPic = AllocPicture( pMa, kiPicWidth, kiPicHeight, false );
582 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pPic), FreeMemorySvc(ppCtx); *ppCtx = NULL )
583 (*ppCtx)->pSpatialPic[iDlayerIndex][i] = pPic;
584 ++ i;
585 } while( i < kuiRefNumInTemporal);
586
587 (*ppCtx)->uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal;
588 (*ppCtx)->uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal;
589 ++ iDlayerIndex;
590 } while( iDlayerIndex < kiDlayerCount );
591
592 return 0;
593}
594
595void FreeSpatialPictures( sWelsEncCtx *pCtx )
596{
597 CMemoryAlign *pMa = pCtx->pMemAlign;
598 int32_t j = 0;
599 while( j < pCtx->pSvcParam->iNumDependencyLayer )
600 {
601 uint8_t i = 0;
602 uint8_t uiRefNumInTemporal = pCtx->uiSpatialPicNum[j];
603
604 while( i < uiRefNumInTemporal )
605 {
606 if ( NULL != pCtx->pSpatialPic[j][i] )
607 {
608 FreePicture( pMa, &pCtx->pSpatialPic[j][i] );
609 }
610 ++ i;
611 }
612 pCtx->uiSpatialLayersInTemporal[j] = 0;
613 ++ j;
614 }
615
616}
617
618static void InitMbInfo(sWelsEncCtx * pEnc, SMB * pList, SDqLayer * pLayer, const int32_t kiDlayerId, const int32_t kiMaxMbNum )
619{
620 int32_t iMbWidth = pLayer->iMbWidth;
621 int32_t iMbHeight = pLayer->iMbHeight;
622 int32_t iIdx;
623 int32_t iMbNum = iMbWidth * iMbHeight;
624 SSliceCtx *pSliceCtx= pLayer->pSliceEncCtx;
625 uint32_t uiNeighborAvail;
626 const int32_t kiOffset = (kiDlayerId & 0x01) * kiMaxMbNum;
627 SMVUnitXY (*pLayerMvUnitBlock4x4)[MB_BLOCK4x4_NUM] = (SMVUnitXY(*)[MB_BLOCK4x4_NUM])(&pEnc->pMvUnitBlock4x4[MB_BLOCK4x4_NUM*kiOffset]);
628 int8_t (*pLayerRefIndexBlock8x8)[MB_BLOCK8x8_NUM] = (int8_t(*)[MB_BLOCK8x8_NUM])(&pEnc->pRefIndexBlock4x4[MB_BLOCK8x8_NUM*kiOffset]);
629
630 for( iIdx = 0; iIdx<iMbNum; iIdx++ ){
631 BOOL_T bLeft;
632 BOOL_T bTop;
633 BOOL_T bLeftTop;
634 BOOL_T bRightTop;
635 int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;
636 uint8_t uiSliceIdc;
637
638 pList[iIdx].iMbX = pEnc->pStrideTab->pMbIndexX[kiDlayerId][iIdx];
639 pList[iIdx].iMbY = pEnc->pStrideTab->pMbIndexY[kiDlayerId][iIdx];
640 pList[iIdx].iMbXY = iIdx;
641
642 uiSliceIdc = WelsMbToSliceIdc(pSliceCtx, iIdx);
643 iLeftXY = iIdx - 1;
644 iTopXY = iIdx - iMbWidth;
645 iLeftTopXY = iTopXY - 1;
646 iRightTopXY = iTopXY + 1;
647
648 bLeft = (pList[iIdx].iMbX > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iLeftXY));
649 bTop = (pList[iIdx].iMbY > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iTopXY));
650 bLeftTop = (pList[iIdx].iMbX > 0) && (pList[iIdx].iMbY > 0) && (uiSliceIdc ==
651 WelsMbToSliceIdc(pSliceCtx, iLeftTopXY));
652 bRightTop = (pList[iIdx].iMbX < (iMbWidth-1)) && (pList[iIdx].iMbY > 0) && (uiSliceIdc ==
653 WelsMbToSliceIdc(pSliceCtx, iRightTopXY));
654
655 uiNeighborAvail = 0;
656 if( bLeft ){
657 uiNeighborAvail |= LEFT_MB_POS;
658 }
659 if( bTop ){
660 uiNeighborAvail |= TOP_MB_POS;
661 }
662 if( bLeftTop ){
663 uiNeighborAvail |= TOPLEFT_MB_POS;
664 }
665 if( bRightTop ){
666 uiNeighborAvail |= TOPRIGHT_MB_POS;
667 }
668 pList[iIdx].uiSliceIdc = uiSliceIdc; // merge from svc_hd_opt_b for multiple slices coding
669 pList[iIdx].uiNeighborAvail = uiNeighborAvail;
670 uiNeighborAvail = 0;
671 if(pList[iIdx].iMbX >= BASE_MV_MB_NMB)
672 uiNeighborAvail |= LEFT_MB_POS;
673 if(pList[iIdx].iMbX <= (iMbWidth-1-BASE_MV_MB_NMB))
674 uiNeighborAvail |= RIGHT_MB_POS;
675 if (pList[iIdx].iMbY >= BASE_MV_MB_NMB)
676 uiNeighborAvail |= TOP_MB_POS;
677 if(pList[iIdx].iMbY <= (iMbHeight-1-BASE_MV_MB_NMB))
678 uiNeighborAvail |= BOTTOM_MB_POS;
679
680 pList[iIdx].sMv = pLayerMvUnitBlock4x4[iIdx];
681 pList[iIdx].pRefIndex = pLayerRefIndexBlock8x8[iIdx];
682 pList[iIdx].pSadCost = &pEnc->pSadCostMb[iIdx];
683 pList[iIdx].pIntra4x4PredMode = &pEnc->pIntra4x4PredModeBlocks[iIdx*INTRA_4x4_MODE_NUM];
684 pList[iIdx].pNonZeroCount = &pEnc->pNonZeroCountBlocks[iIdx*MB_LUMA_CHROMA_BLOCK4x4_NUM];
685 }
686}
687
688
689int32_t InitMbListD( sWelsEncCtx ** ppCtx)
690{
691 int32_t iNumDlayer = (*ppCtx)->pSvcParam->iNumDependencyLayer;
692 int32_t iMbSize[MAX_DEPENDENCY_LAYER] = { 0 };
693 int32_t iOverallMbNum = 0;
694 int32_t iMbWidth = 0;
695 int32_t iMbHeight= 0;
696 int32_t i;
697
698 if ( iNumDlayer > MAX_DEPENDENCY_LAYER )
699 return 1;
700
701 for( i=0;i<iNumDlayer;i++ ){
702 iMbWidth = ((*ppCtx)->pSvcParam->sDependencyLayers[i].iFrameWidth + 15)>>4;
703 iMbHeight = ((*ppCtx)->pSvcParam->sDependencyLayers[i].iFrameHeight + 15)>>4;
704 iMbSize[i] = iMbWidth * iMbHeight;
705 iOverallMbNum += iMbSize[i];
706 }
707
708 (*ppCtx)->ppMbListD = static_cast<SMB **>((*ppCtx)->pMemAlign->WelsMalloc(iNumDlayer * sizeof(SMB *), "ppMbListD"));
709 (*ppCtx)->ppMbListD[0] = NULL;
710 WELS_VERIFY_RETURN_PROC_IF(1, (*ppCtx)->ppMbListD==NULL, FreeMemorySvc(ppCtx));
711 (*ppCtx)->ppMbListD[0] = static_cast<SMB*>((*ppCtx)->pMemAlign->WelsMallocz(iOverallMbNum * sizeof(SMB), "ppMbListD[0]"));
712 WELS_VERIFY_RETURN_PROC_IF(1, (*ppCtx)->ppMbListD[0]==NULL, FreeMemorySvc(ppCtx));
713 (*ppCtx)->ppDqLayerList[0]->sMbDataP = (*ppCtx)->ppMbListD[0];
714 InitMbInfo(*ppCtx, (*ppCtx)->ppMbListD[0], (*ppCtx)->ppDqLayerList[0], 0, iMbSize[iNumDlayer-1]);
715 for( i=1;i<iNumDlayer;i++ ){
716 (*ppCtx)->ppMbListD[i] = (*ppCtx)->ppMbListD[i-1] + iMbSize[i-1];
717 (*ppCtx)->ppDqLayerList[i]->sMbDataP = (*ppCtx)->ppMbListD[i];
718 InitMbInfo(*ppCtx, (*ppCtx)->ppMbListD[i], (*ppCtx)->ppDqLayerList[i], i, iMbSize[iNumDlayer-1]);
719 }
720
721 return 0;
722}
723
724int32_t AllocMbCacheAligned( SMbCache *pMbCache, CMemoryAlign *pMa )
725{
726 pMbCache->pCoeffLevel = (int16_t *)pMa->WelsMalloc(MB_COEFF_LIST_SIZE*sizeof(int16_t), "pMbCache->pCoeffLevel");
727 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pCoeffLevel));
728 pMbCache->pMemPredMb = (uint8_t *)pMa->WelsMalloc(2*256*sizeof(uint8_t), "pMbCache->pMemPredMb");
729 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pMemPredMb));
730 pMbCache->pSkipMb = (uint8_t *)pMa->WelsMalloc(384*sizeof(uint8_t), "pMbCache->pSkipMb");
731 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pSkipMb));
732 pMbCache->pMemPredBlk4 = (uint8_t *)pMa->WelsMalloc(2*16*sizeof(uint8_t), "pMbCache->pMemPredBlk4");
733 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pMemPredBlk4));
734 pMbCache->pBufferInterPredMe = (uint8_t *)pMa->WelsMalloc(4*640*sizeof(uint8_t), "pMbCache->pBufferInterPredMe");
735 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pBufferInterPredMe));
736 pMbCache->pPrevIntra4x4PredModeFlag = (bool_t *)pMa->WelsMalloc(16*sizeof(bool_t), "pMbCache->pPrevIntra4x4PredModeFlag");
737 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pPrevIntra4x4PredModeFlag));
738 pMbCache->pRemIntra4x4PredModeFlag = (int8_t *)pMa->WelsMalloc(16*sizeof(int8_t), "pMbCache->pRemIntra4x4PredModeFlag");
739 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pRemIntra4x4PredModeFlag));
740 pMbCache->pDct = (SDCTCoeff *)pMa->WelsMalloc(sizeof(SDCTCoeff), "pMbCache->pDct");
741 WELS_VERIFY_RETURN_IF(1, (NULL==pMbCache->pDct));
742 return 0;
743}
744
745void FreeMbCache( SMbCache *pMbCache, CMemoryAlign *pMa )
746{
747 if ( NULL != pMbCache->pCoeffLevel )
748 {
749 pMa->WelsFree( pMbCache->pCoeffLevel, "pMbCache->pCoeffLevel" );
750 pMbCache->pCoeffLevel = NULL;
751 }
752 if ( NULL != pMbCache->pMemPredMb )
753 {
754 pMa->WelsFree( pMbCache->pMemPredMb, "pMbCache->pMemPredMb" );
755 pMbCache->pMemPredMb = NULL;
756 }
757 if ( NULL != pMbCache->pSkipMb )
758 {
759 pMa->WelsFree( pMbCache->pSkipMb, "pMbCache->pSkipMb" );
760 pMbCache->pSkipMb = NULL;
761 }
762 if ( NULL != pMbCache->pMemPredBlk4 )
763 {
764 pMa->WelsFree( pMbCache->pMemPredBlk4, "pMbCache->pMemPredBlk4" );
765 pMbCache->pMemPredBlk4 = NULL;
766 }
767 if ( NULL != pMbCache->pBufferInterPredMe )
768 {
769 pMa->WelsFree( pMbCache->pBufferInterPredMe, "pMbCache->pBufferInterPredMe" );
770 pMbCache->pBufferInterPredMe = NULL;
771 }
772 if ( NULL != pMbCache->pPrevIntra4x4PredModeFlag )
773 {
774 pMa->WelsFree( pMbCache->pPrevIntra4x4PredModeFlag, "pMbCache->pPrevIntra4x4PredModeFlag" );
775 pMbCache->pPrevIntra4x4PredModeFlag = NULL;
776 }
777 if ( NULL != pMbCache->pRemIntra4x4PredModeFlag )
778 {
779 pMa->WelsFree( pMbCache->pRemIntra4x4PredModeFlag, "pMbCache->pRemIntra4x4PredModeFlag" );
780 pMbCache->pRemIntra4x4PredModeFlag = NULL;
781 }
782 if ( NULL != pMbCache->pDct )
783 {
784 pMa->WelsFree( pMbCache->pDct, "pMbCache->pDct" );
785 pMbCache->pDct = NULL;
786 }
787}
788
789
790/*!
791 * \brief initialize ppDqLayerList and slicepEncCtx_list due to count number of layers available
792 * \pParam pCtx sWelsEncCtx*
793 * \return 0 - successful; otherwise failed
794 */
795static inline int32_t InitDqLayers( sWelsEncCtx **ppCtx )
796{
797 SWelsSvcCodingParam *pParam = NULL;
798 SWelsSPS *pSps = NULL;
799 SSubsetSps *pSubsetSps = NULL;
800 SWelsPPS *pPps = NULL;
801 CMemoryAlign *pMa = NULL;
802 SStrideTables *pStrideTab = NULL;
803 int32_t iDlayerCount = 0;
804 int32_t iDlayerIndex = 0;
805 uint32_t iSpsId = 0;
806 uint32_t iPpsId = 0;
807 uint32_t iNumRef = 0;
808 int32_t iResult = 0;
809
810 if ( NULL == ppCtx || NULL == *ppCtx )
811 return 1;
812
813 pMa = (*ppCtx)->pMemAlign;
814 pParam = (*ppCtx)->pSvcParam;
815 iDlayerCount = pParam->iNumDependencyLayer;
816 iNumRef = pParam->iNumRefFrame;
817// highest_layers_in_temporal = 1 + WELS_MAX(pParam->iDecompStages, 1);
818 pStrideTab = (*ppCtx)->pStrideTab;
819
820 iDlayerIndex = 0;
821 while (iDlayerIndex < iDlayerCount)
822 {
823 SRefList *pRefList = NULL;
824 uint32_t i = 0;
825 const int32_t kiWidth = pParam->sDependencyLayers[iDlayerIndex].iFrameWidth;
826 const int32_t kiHeight = pParam->sDependencyLayers[iDlayerIndex].iFrameHeight;
827 int32_t iPicWidth = WELS_ALIGN(kiWidth, MB_WIDTH_LUMA) + (PADDING_LENGTH<<1); // with iWidth of horizon
828 int32_t iPicChromaWidth = iPicWidth >> 1;
829
830 iPicWidth = WELS_ALIGN( iPicWidth, 32 ); // 32(or 16 for chroma below) to match original imp. here instead of iCacheLineSize
831 iPicChromaWidth = WELS_ALIGN( iPicChromaWidth, 16 );
832
833 WelsGetEncBlockStrideOffset( (*ppCtx)->pStrideTab->pStrideEncBlockOffset[iDlayerIndex], iPicWidth, iPicChromaWidth);
834
835 // pRef list
836 pRefList = (SRefList *)pMa->WelsMallocz( sizeof(SRefList), "pRefList" );
837 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pRefList), FreeMemorySvc(ppCtx) )
838
839 do {
840 pRefList->pRef[i] = AllocPicture( pMa, kiWidth, kiHeight, true ); // to use actual size of current layer
841 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pRefList->pRef[i]), FreeMemorySvc(ppCtx) )
842 ++ i;
843 } while(i < 1 + iNumRef);
844
845 pRefList->pNextBuffer = pRefList->pRef[0];
846 (*ppCtx)->ppRefPicListExt[iDlayerIndex] = pRefList;
847 ++ iDlayerIndex;
848 }
849
850 // for I420 based source spatial pictures
851 if ( AllocSpatialPictures( ppCtx, pParam ) )
852 {
853 FreeMemorySvc( ppCtx );
854 return 1;
855 }
856
857 iDlayerIndex = 0;
858 while (iDlayerIndex < iDlayerCount) {
859 SDqLayer *pDqLayer = NULL;
860 SDLayerParam *pDlayer = &pParam->sDependencyLayers[iDlayerIndex];
861 const int32_t kiMbW = (pDlayer->iFrameWidth + 0x0f) >> 4;
862 const int32_t kiMbH = (pDlayer->iFrameHeight + 0x0f) >> 4;
863 int32_t iMaxSliceNum = 1;
864 const int32_t kiSliceNum = GetInitialSliceNum( kiMbW, kiMbH, &pDlayer->sMso );
865 if ( iMaxSliceNum < kiSliceNum )
866 iMaxSliceNum = kiSliceNum;
867
868 // pDq layers list
869 pDqLayer = (SDqLayer *)pMa->WelsMallocz( sizeof(SDqLayer), "pDqLayer" );
870 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pDqLayer), FreeMemorySvc(ppCtx) )
871
872 // for dynamic slicing mode
873 if ( SM_DYN_SLICE == pDlayer->sMso.uiSliceMode )
874 {
875 const int32_t iSize = pParam->iCountThreadsNum * sizeof(int32_t);
876
877 pDqLayer->pNumSliceCodedOfPartition = (int32_t *)pMa->WelsMallocz( iSize, "pNumSliceCodedOfPartition" );
878 pDqLayer->pLastCodedMbIdxOfPartition = (int32_t *)pMa->WelsMallocz( iSize, "pLastCodedMbIdxOfPartition" );
879 pDqLayer->pLastMbIdxOfPartition = (int32_t *)pMa->WelsMallocz( iSize, "pLastMbIdxOfPartition" );
880
881 WELS_VERIFY_RETURN_PROC_IF( 1,
882 (NULL == pDqLayer->pNumSliceCodedOfPartition ||
883 NULL == pDqLayer->pLastCodedMbIdxOfPartition ||
884 NULL == pDqLayer->pLastMbIdxOfPartition),
885 FreeMemorySvc(ppCtx) )
886 }
887
888 pDqLayer->iMbWidth = kiMbW;
889 pDqLayer->iMbHeight = kiMbH;
890#ifndef MT_ENABLED
891 if ( SM_DYN_SLICE == pDlayer->sMso.uiSliceMode )//wmalloc pSliceInLayer
892 {
893 SSlice *pSlice = NULL;
894 int32_t iSliceIdx = 0;
895 //wmalloc AVERSLICENUM_CONSTANT of pDqLayer->sLayerInfo.pSliceInLayer,
896 //wmalloc AVERSLICENUM_CONSTANT num of pSlice as initialization
897 //only set value for the first pSlice
898 pDqLayer->sLayerInfo.pSliceInLayer = (SSlice *)pMa->WelsMallocz( sizeof(SSlice) * iMaxSliceNum, "pSliceInLayer" );
899
900 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pDqLayer->sLayerInfo.pSliceInLayer), FreeMemorySvc(ppCtx) )
901 {
902 pSlice = &pDqLayer->sLayerInfo.pSliceInLayer[0];
903 pSlice->uiSliceIdx = 0;
904 pSlice->pSliceBsa = &(*ppCtx)->pOut->sBsWrite;
905 }
906
907 while(iSliceIdx < iMaxSliceNum)
908 {
909 pSlice = &pDqLayer->sLayerInfo.pSliceInLayer[iSliceIdx];
910 if ( AllocMbCacheAligned(&pSlice->sMbCacheInfo, pMa) )
911 {
912 FreeMemorySvc(ppCtx);
913 return 1;
914 }
915 ++ iSliceIdx;
916 }
917 }
918 else
919#endif//!MT_ENABLED
920 {
921 int32_t iSliceIdx = 0;
922 pDqLayer->sLayerInfo.pSliceInLayer = (SSlice *)pMa->WelsMallocz( sizeof(SSlice) * iMaxSliceNum, "pSliceInLayer" );
923
924 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pDqLayer->sLayerInfo.pSliceInLayer), FreeMemorySvc(ppCtx) )
925 if ( iMaxSliceNum > 1 )
926 {
927 while (iSliceIdx < iMaxSliceNum) {
928 SSlice *pSlice = &pDqLayer->sLayerInfo.pSliceInLayer[iSliceIdx];
929 pSlice->uiSliceIdx = iSliceIdx;
930#ifdef MT_ENABLED
931 if ( pParam->iMultipleThreadIdc > 1 )
932 pSlice->pSliceBsa = &(*ppCtx)->pSliceBs[iSliceIdx].sBsWrite;
933 else
934 pSlice->pSliceBsa = &(*ppCtx)->pOut->sBsWrite;
935#else
936 pSlice->pSliceBsa = &(*ppCtx)->pOut->sBsWrite;
937#endif//MT_ENABLED
938 if ( AllocMbCacheAligned(&pSlice->sMbCacheInfo, pMa) )
939 {
940 FreeMemorySvc(ppCtx);
941 return 1;
942 }
943 ++ iSliceIdx;
944 }
945 }
946 // fix issue in case single pSlice coding might be inclusive exist in variant spatial layer setting, also introducing multi-pSlice modes
947 else // only one pSlice
948 {
949 SSlice *pSlice = &pDqLayer->sLayerInfo.pSliceInLayer[0];
950 pSlice->uiSliceIdx = 0;
951 pSlice->pSliceBsa = &(*ppCtx)->pOut->sBsWrite;
952 if ( AllocMbCacheAligned(&pSlice->sMbCacheInfo, pMa) )
953 {
954 FreeMemorySvc(ppCtx);
955 return 1;
956 }
957 }
958 }
959
960 //deblocking parameters initialization
961 //target-layer deblocking
962 pDqLayer->iLoopFilterDisableIdc = pParam->iLoopFilterDisableIdc;
963 pDqLayer->iLoopFilterAlphaC0Offset = (pParam->iLoopFilterAlphaC0Offset)<<1;
964 pDqLayer->iLoopFilterBetaOffset = (pParam->iLoopFilterBetaOffset)<<1;
965 //inter-layer deblocking
966 pDqLayer->uiDisableInterLayerDeblockingFilterIdc = pParam->iInterLayerLoopFilterDisableIdc;
967 pDqLayer->iInterLayerSliceAlphaC0Offset = (pParam->iInterLayerLoopFilterAlphaC0Offset)<<1;
968 pDqLayer->iInterLayerSliceBetaOffset = (pParam->iInterLayerLoopFilterBetaOffset)<<1;
969 //parallel deblocking
970 pDqLayer->bDeblockingParallelFlag = pParam->bDeblockingParallelFlag;
971
972 //deblocking parameter adjustment
973 if ( SM_SINGLE_SLICE == pDlayer->sMso.uiSliceMode )
974 {
975 //iLoopFilterDisableIdc: will be 0 or 1 under single_slice
976 if ( 2 == pParam->iLoopFilterDisableIdc )
977 {
978 pDqLayer->iLoopFilterDisableIdc = 0;
979 }
980 //bDeblockingParallelFlag
981 pDqLayer->bDeblockingParallelFlag = false;
982 }
983 else
984 {//multi-pSlice
985#ifdef MT_ENABLED
986 if ( 0 == pDqLayer->iLoopFilterDisableIdc )
987 {
988 pDqLayer->bDeblockingParallelFlag = false;
989 }
990#endif
991 }
992
993 (*ppCtx)->ppDqLayerList[iDlayerIndex] = pDqLayer;
994
995 ++ iDlayerIndex;
996 }
997
998 // for dynamically malloc for parameter sets memory instead of maximal items for standard to reduce size, 3/18/2010
999 if ( &(*ppCtx)->pSvcParam->bMgsT0OnlyStrategy )
1000 {
1001 (*ppCtx)->pPPSArray = (SWelsPPS *)pMa->WelsMalloc( (1+iDlayerCount) * sizeof(SWelsPPS), "pPPSArray" );
1002 }
1003 else
1004 {
1005 (*ppCtx)->pPPSArray = (SWelsPPS *)pMa->WelsMalloc( iDlayerCount * sizeof(SWelsPPS), "pPPSArray" );
1006 }
1007 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pPPSArray), FreeMemorySvc(ppCtx) )
1008
1009 (*ppCtx)->pSpsArray = (SWelsSPS *)pMa->WelsMalloc( sizeof(SWelsSPS), "pSpsArray" );
1010 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc(ppCtx) )
1011 if ( iDlayerCount > 1 )
1012 {
1013 (*ppCtx)->pSubsetArray = (SSubsetSps *)pMa->WelsMalloc( (iDlayerCount-1) * sizeof(SSubsetSps), "pSubsetArray" );
1014 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc(ppCtx) )
1015 }
1016
1017 (*ppCtx)->pDqIdcMap = (SDqIdc *)pMa->WelsMallocz( iDlayerCount * sizeof(SDqIdc), "pDqIdcMap" );
1018 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pDqIdcMap), FreeMemorySvc(ppCtx) )
1019
1020 iDlayerIndex = 0;
1021 while (iDlayerIndex < iDlayerCount) {
1022 SDqIdc *pDqIdc = &(*ppCtx)->pDqIdcMap[iDlayerIndex];
1023 const bool_t bUseSubsetSps = (iDlayerIndex > BASE_DEPENDENCY_ID);
1024 SDLayerParam *pDlayerParam = &pParam->sDependencyLayers[iDlayerIndex];
1025
1026 pDqIdc->uiSpatialId = iDlayerIndex;
1027 pPps = &(*ppCtx)->pPPSArray[iPpsId];
1028 if ( !bUseSubsetSps )
1029 {
1030 pSps = &(*ppCtx)->pSpsArray[iSpsId];
1031 }
1032 else
1033 {
1034 pSubsetSps = &(*ppCtx)->pSubsetArray[iSpsId];
1035 pSps = &pSubsetSps->pSps;
1036 }
1037
1038 // Need port pSps/pPps initialization due to spatial scalability changed
1039 if ( !bUseSubsetSps )
1040 {
1041 WelsInitSps( pSps, pDlayerParam, pParam->uiIntraPeriod, pParam->iNumRefFrame, iSpsId,
1042 pParam->bEnableFrameCroppingFlag, pParam->bEnableRc );
1043
1044 if( iDlayerCount > 1 )
1045 {
1046 pSps->bConstraintSet0Flag = true;
1047 pSps->bConstraintSet1Flag = true;
1048 pSps->bConstraintSet2Flag = true;
1049 }
1050 }
1051 else
1052 {
1053 WelsInitSubsetSps( pSubsetSps, pDlayerParam, pParam->uiIntraPeriod, pParam->iNumRefFrame, iSpsId,
1054 pParam->bEnableFrameCroppingFlag, pParam->bEnableRc );
1055 }
1056
1057 // initialize pPps
1058 WelsInitPps( pPps, pSps, pSubsetSps, iPpsId, true, bUseSubsetSps );
1059
1060 // Not using FMO in SVC coding so far, come back if need FMO
1061 {
1062 iResult = InitSlicePEncCtx( &(*ppCtx)->pSliceCtxList[iDlayerIndex],
1063 (*ppCtx)->pMemAlign,
1064 false,
1065 pSps->iMbWidth,
1066 pSps->iMbHeight,
1067 &(pDlayerParam->sMso),
1068 pPps );
1069 if ( iResult )
1070 {
1071 WelsLog( *ppCtx, WELS_LOG_WARNING, "InitDqLayers(), InitSlicePEncCtx failed(%d)!", iResult );
1072 FreeMemorySvc( ppCtx );
1073 return 1;
1074 }
1075 (*ppCtx)->ppDqLayerList[iDlayerIndex]->pSliceEncCtx = &(*ppCtx)->pSliceCtxList[iDlayerIndex];
1076 }
1077 pDqIdc->iSpsId = iSpsId;
1078 pDqIdc->iPpsId = iPpsId;
1079
1080 (*ppCtx)->sPSOVector.bPpsIdMappingIntoSubsetsps[iPpsId] = bUseSubsetSps;
1081
1082 if ( bUseSubsetSps )
1083 ++ iSpsId;
1084 ++ iPpsId;
1085 ++ (*ppCtx)->iSpsNum;
1086 ++ (*ppCtx)->iPpsNum;
1087
1088 ++ iDlayerIndex;
1089 }
1090 return 0;
1091}
1092
1093int32_t AllocStrideTables( sWelsEncCtx **ppCtx, const int32_t kiNumSpatialLayers )
1094{
1095 CMemoryAlign *pMa = (*ppCtx)->pMemAlign;
1096 SWelsSvcCodingParam *pParam = (*ppCtx)->pSvcParam;
1097 SStrideTables *pPtr = NULL;
1098 int16_t *pTmpRow = NULL, *pRowX = NULL, *pRowY = NULL, *p = NULL;
1099 uint8_t *pBase = NULL;
1100 uint8_t *pBaseDec = NULL, *pBaseEnc = NULL, *pBaseMbX = NULL, *pBaseMbY = NULL;
1101 struct {
1102 int32_t iMbWidth;
1103 int32_t iCountMbNum; // count number of SMB in each spatial
1104 int32_t iSizeAllMbAlignCache; // cache line size aligned in each spatial
1105 } sMbSizeMap[MAX_DEPENDENCY_LAYER] = {0};
1106 int32_t iLineSizeY[MAX_DEPENDENCY_LAYER][2] = {0};
1107 int32_t iLineSizeUV[MAX_DEPENDENCY_LAYER][2]= {0};
1108 int32_t iMapSpatialIdx[MAX_DEPENDENCY_LAYER][2] = {0};
1109 int32_t iSizeDec = 0;
1110 int32_t iSizeEnc = 0;
1111 int32_t iCountLayersNeedCs[2] = {0};
1112 const int32_t kiUnit1Size = 24 * sizeof(int32_t);
1113 int32_t iUnit2Size = 0;
1114 int32_t iNeedAllocSize = 0;
1115 int32_t iRowSize = 0;
1116 int16_t iMaxMbWidth = 0;
1117 int16_t iMaxMbHeight = 0;
1118 int32_t i = 0;
1119 int32_t iSpatialIdx = 0;
1120 int32_t iTemporalIdx = 0;
1121 int32_t iCntTid = 0;
1122
1123 if ( kiNumSpatialLayers <= 0 || kiNumSpatialLayers > MAX_DEPENDENCY_LAYER)
1124 return 1;
1125
1126 pPtr = (SStrideTables *)pMa->WelsMalloc(sizeof(SStrideTables), "SStrideTables");
1127 if (NULL == pPtr)
1128 return 1;
1129 (*ppCtx)->pStrideTab = pPtr;
1130
1131 iCntTid = pParam->iNumTemporalLayer > 1 ? 2 : 1;
1132
1133 iSpatialIdx = 0;
1134 while (iSpatialIdx < kiNumSpatialLayers) {
1135 const int32_t kiTmpWidth = (pParam->sDependencyLayers[iSpatialIdx].iFrameWidth + 15) >> 4;
1136 const int32_t kiTmpHeight= (pParam->sDependencyLayers[iSpatialIdx].iFrameHeight + 15) >> 4;
1137 int32_t iNumMb = kiTmpWidth * kiTmpHeight;
1138
1139 sMbSizeMap[iSpatialIdx].iMbWidth = kiTmpWidth;
1140 sMbSizeMap[iSpatialIdx].iCountMbNum = iNumMb;
1141
1142 iNumMb *= sizeof(int16_t);
1143 sMbSizeMap[iSpatialIdx].iSizeAllMbAlignCache = iNumMb;
1144 iUnit2Size += iNumMb;
1145
1146 ++ iSpatialIdx;
1147 }
1148
1149 // Adaptive size_cs, size_fdec by implementation dependency
1150 iTemporalIdx= 0;
1151 while ( iTemporalIdx < iCntTid )
1152 {
1153 const bool_t kbBaseTemporalFlag = (iTemporalIdx == 0);
1154
1155 iSpatialIdx = 0;
1156 while ( iSpatialIdx < kiNumSpatialLayers )
1157 {
1158 SDLayerParam *fDlp = &pParam->sDependencyLayers[iSpatialIdx];
1159
1160 const int32_t kiWidthPad = WELS_ALIGN( fDlp->iFrameWidth, 16 ) + (PADDING_LENGTH<<1);
1161 iLineSizeY[iSpatialIdx][kbBaseTemporalFlag] = WELS_ALIGN( kiWidthPad, 32 );
1162 iLineSizeUV[iSpatialIdx][kbBaseTemporalFlag]= WELS_ALIGN( (kiWidthPad>>1), 16 );
1163
1164 iMapSpatialIdx[iCountLayersNeedCs[kbBaseTemporalFlag]][kbBaseTemporalFlag] = iSpatialIdx;
1165 ++ iCountLayersNeedCs[kbBaseTemporalFlag];
1166 ++ iSpatialIdx;
1167 }
1168 ++ iTemporalIdx;
1169 }
1170 iSizeDec= kiUnit1Size * (iCountLayersNeedCs[0] + iCountLayersNeedCs[1]);
1171 iSizeEnc= kiUnit1Size * kiNumSpatialLayers;
1172
1173 iNeedAllocSize = iSizeDec + iSizeEnc + (iUnit2Size << 1);
1174
1175 pBase = (uint8_t *)pMa->WelsMalloc( iNeedAllocSize, "pBase" );
1176 if ( NULL == pBase )
1177 {
1178 return 1;
1179 }
1180
1181 pBaseDec= pBase; // iCountLayersNeedCs
1182 pBaseEnc= pBaseDec + iSizeDec; // iNumSpatialLayers
1183 pBaseMbX = pBaseEnc + iSizeEnc; // iNumSpatialLayers
1184 pBaseMbY = pBaseMbX + iUnit2Size; // iNumSpatialLayers
1185
1186 iTemporalIdx= 0;
1187 while ( iTemporalIdx < iCntTid )
1188 {
1189 const bool_t kbBaseTemporalFlag = (iTemporalIdx == 0);
1190
1191 iSpatialIdx = 0;
1192 while ( iSpatialIdx < iCountLayersNeedCs[kbBaseTemporalFlag] )
1193 {
1194 const int32_t kiActualSpatialIdx = iMapSpatialIdx[iSpatialIdx][kbBaseTemporalFlag];
1195 const int32_t kiLumaWidth = iLineSizeY[kiActualSpatialIdx][kbBaseTemporalFlag];
1196 const int32_t kiChromaWidth = iLineSizeUV[kiActualSpatialIdx][kbBaseTemporalFlag];
1197
1198 WelsGetEncBlockStrideOffset( (int32_t *)pBaseDec, kiLumaWidth, kiChromaWidth );
1199
1200 pPtr->pStrideDecBlockOffset[kiActualSpatialIdx][kbBaseTemporalFlag] = (int32_t *)pBaseDec;
1201 pBaseDec+= kiUnit1Size;
1202
1203 ++ iSpatialIdx;
1204 }
1205 ++ iTemporalIdx;
1206 }
1207 iTemporalIdx= 0;
1208 while ( iTemporalIdx < iCntTid )
1209 {
1210 const bool_t kbBaseTemporalFlag = (iTemporalIdx == 0);
1211
1212 iSpatialIdx = 0;
1213 while (iSpatialIdx < kiNumSpatialLayers)
1214 {
1215 int32_t iMatchIndex = 0;
1216 bool_t bInMap = false;
1217 bool_t bMatchFlag = false;
1218
1219 i = 0;
1220 while ( i < iCountLayersNeedCs[kbBaseTemporalFlag] )
1221 {
1222 const int32_t kiActualIdx = iMapSpatialIdx[i][kbBaseTemporalFlag];
1223 if ( kiActualIdx == iSpatialIdx )
1224 {
1225 bInMap = true;
1226 break;
1227 }
1228 if ( !bMatchFlag )
1229 {
1230 iMatchIndex = kiActualIdx;
1231 bMatchFlag = true;
1232 }
1233 ++ i;
1234 }
1235
1236 if ( bInMap )
1237 {
1238 ++ iSpatialIdx;
1239 continue;
1240 }
1241
1242 // not in spatial map and assign match one to it
1243 pPtr->pStrideDecBlockOffset[iSpatialIdx][kbBaseTemporalFlag] = pPtr->pStrideDecBlockOffset[iMatchIndex][kbBaseTemporalFlag];
1244
1245 ++ iSpatialIdx;
1246 }
1247 ++ iTemporalIdx;
1248 }
1249
1250 iSpatialIdx = 0;
1251 while ( iSpatialIdx < kiNumSpatialLayers )
1252 {
1253 const int32_t kiAllocMbSize = sMbSizeMap[iSpatialIdx].iSizeAllMbAlignCache;
1254
1255 pPtr->pStrideEncBlockOffset[iSpatialIdx] = (int32_t *)pBaseEnc;
1256
1257 pPtr->pMbIndexX[iSpatialIdx] = (int16_t *)pBaseMbX;
1258 pPtr->pMbIndexY[iSpatialIdx] = (int16_t *)pBaseMbY;
1259
1260 pBaseEnc += kiUnit1Size;
1261 pBaseMbX += kiAllocMbSize;
1262 pBaseMbY += kiAllocMbSize;
1263
1264 ++ iSpatialIdx;
1265 }
1266
1267 while ( iSpatialIdx < MAX_DEPENDENCY_LAYER )
1268 {
1269 pPtr->pStrideDecBlockOffset[iSpatialIdx][0] = NULL;
1270 pPtr->pStrideDecBlockOffset[iSpatialIdx][1] = NULL;
1271 pPtr->pStrideEncBlockOffset[iSpatialIdx] = NULL;
1272 pPtr->pMbIndexX[iSpatialIdx] = NULL;
1273 pPtr->pMbIndexY[iSpatialIdx] = NULL;
1274
1275 ++ iSpatialIdx;
1276 }
1277
1278 // initialize pMbIndexX and pMbIndexY tables as below
1279
1280 iMaxMbWidth = sMbSizeMap[kiNumSpatialLayers-1].iMbWidth;
1281 iMaxMbWidth = WELS_ALIGN(iMaxMbWidth, 4); // 4 loops for int16_t required introduced as below
1282 iRowSize = iMaxMbWidth * sizeof(int16_t);
1283
1284 pTmpRow = (int16_t*)pMa->WelsMalloc( iRowSize, "pTmpRow" );
1285 if ( NULL == pTmpRow )
1286 {
1287 return 1;
1288 }
1289 pRowX = pTmpRow;
1290 pRowY = pRowX;
1291 // initialize pRowX & pRowY
1292 i = 0;
1293 p = pRowX;
1294 while ( i < iMaxMbWidth )
1295 {
1296 *p = i;
1297 *(p+1) = 1+i;
1298 *(p+2) = 2+i;
1299 *(p+3) = 3+i;
1300
1301 p += 4;
1302 i += 4;
1303 }
1304
1305 iSpatialIdx = kiNumSpatialLayers;
1306 while ( --iSpatialIdx >= 0 )
1307 {
1308 int16_t *pMbIndexX = pPtr->pMbIndexX[iSpatialIdx];
1309 const int32_t kiMbWidth = sMbSizeMap[iSpatialIdx].iMbWidth;
1310 const int32_t kiMbHeight = sMbSizeMap[iSpatialIdx].iCountMbNum / kiMbWidth;
1311 const int32_t kiLineSize = kiMbWidth * sizeof(int16_t);
1312
1313 i = 0;
1314 while ( i < kiMbHeight )
1315 {
1316 memcpy( pMbIndexX, pRowX, kiLineSize ); // confirmed_safe_unsafe_usage
1317
1318 pMbIndexX += kiMbWidth;
1319 ++ i;
1320 }
1321 }
1322
1323 memset(pRowY, 0, iRowSize);
1324 iMaxMbHeight = sMbSizeMap[kiNumSpatialLayers-1].iCountMbNum / sMbSizeMap[kiNumSpatialLayers-1].iMbWidth;
1325 i = 0;
1326 for (;;)
1327 {
1328 ENFORCE_STACK_ALIGN_1D(int16_t, t, 4, 16)
1329
1330 int32_t t32 = 0;
1331 int16_t j = 0;
1332
1333 for ( iSpatialIdx = kiNumSpatialLayers-1; iSpatialIdx >= 0; -- iSpatialIdx )
1334 {
1335 const int32_t kiMbWidth = sMbSizeMap[iSpatialIdx].iMbWidth;
1336 const int32_t kiMbHeight = sMbSizeMap[iSpatialIdx].iCountMbNum / kiMbWidth;
1337 const int32_t kiLineSize = kiMbWidth * sizeof(int16_t);
1338 int16_t *pMbIndexY = pPtr->pMbIndexY[iSpatialIdx] + i * kiMbWidth;
1339
1340 if ( i < kiMbHeight )
1341 {
1342 memcpy( pMbIndexY, pRowY, kiLineSize ); // confirmed_safe_unsafe_usage
1343 }
1344 }
1345 ++ i;
1346 if (i >= iMaxMbHeight)
1347 break;
1348
1349 t32 = i | (i << 16);
1350 ST32( t , t32 );
1351 ST32( t+2, t32 );
1352
1353 p = pRowY;
1354 while ( j < iMaxMbWidth )
1355 {
1356 ST64( p, LD64(t) );
1357
1358 p += 4;
1359 j += 4;
1360 }
1361 }
1362
1363 pMa->WelsFree( pTmpRow, "pTmpRow" );
1364 pTmpRow = NULL;
1365
1366 return 0;
1367}
1368
1369/*!
1370 * \brief request specific memory for SVC
1371 * \pParam pEncCtx sWelsEncCtx*
1372 * \return successful - 0; otherwise none 0 for failed
1373 */
1374int32_t RequestMemorySvc( sWelsEncCtx **ppCtx )
1375{
1376 SWelsSvcCodingParam *pParam = (*ppCtx)->pSvcParam;
1377 CMemoryAlign *pMa = (*ppCtx)->pMemAlign;
1378 SDLayerParam *pFinalSpatial = NULL;
1379 int32_t iCountBsLen = 0;
1380 int32_t iCountNals = 0;
1381 int32_t iMaxPicWidth = 0;
1382 int32_t iMaxPicHeight = 0;
1383 int32_t iCountMaxMbNum = 0;
1384 int32_t iIndex = 0;
1385 int32_t iCountLayers = 0;
1386 int32_t iResult = 0;
1387 float fCompressRatioThr = .5f;
1388 const int32_t kiNumDependencyLayers = pParam->iNumDependencyLayer;
1389 const uint32_t kuiMvdInterTableSize = ( kiNumDependencyLayers == 1 ? (1 + (648 << 1)) : (1 + (972 << 1)) );
1390 const uint32_t kuiMvdCacheAlginedSize = kuiMvdInterTableSize * sizeof(uint16_t);
1391 int32_t iVclLayersBsSizeCount = 0;
1392 int32_t iNonVclLayersBsSizeCount = 0;
1393#if defined(MT_ENABLED)
1394 int32_t iTargetSpatialBsSize = 0;
1395#endif//MT_ENABLED
1396
1397 if ( kiNumDependencyLayers < 1 || kiNumDependencyLayers > MAX_DEPENDENCY_LAYER )
1398 {
1399 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc() failed due to invalid iNumDependencyLayers(%d)!\n", kiNumDependencyLayers);
1400 FreeMemorySvc( ppCtx );
1401 return 1;
1402 }
1403
1404 if ( pParam->uiGopSize == 0 || ( pParam->uiIntraPeriod && ((pParam->uiIntraPeriod % pParam->uiGopSize) != 0)) )
1405 {
1406 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc() failed due to invalid uiIntraPeriod(%d) (=multipler of uiGopSize(%d)!",
1407 pParam->uiIntraPeriod, pParam->uiGopSize);
1408 FreeMemorySvc( ppCtx );
1409 return 1;
1410 }
1411
1412 pFinalSpatial = &pParam->sDependencyLayers[kiNumDependencyLayers - 1];
1413 iMaxPicWidth = pFinalSpatial->iFrameWidth;
1414 iMaxPicHeight = pFinalSpatial->iFrameHeight;
1415 iCountMaxMbNum= ((15+iMaxPicWidth)>>4) * ((15+iMaxPicHeight)>>4);
1416
1417 iResult = AcquireLayersNals( ppCtx, pParam, &iCountLayers, &iCountNals );
1418 if ( iResult )
1419 {
1420 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc(), AcquireLayersNals failed(%d)!", iResult);
1421 FreeMemorySvc( ppCtx );
1422 return 1;
1423 }
1424
1425 iNonVclLayersBsSizeCount = SSEI_BUFFER_SIZE + pParam->iNumDependencyLayer * SPS_BUFFER_SIZE + (1+pParam->iNumDependencyLayer) * PPS_BUFFER_SIZE;
1426
1427 int32_t iLayerBsSize = 0;
1428 iIndex = 0;
1429 while(iIndex < pParam->iNumDependencyLayer)
1430 {
1431 SDLayerParam *fDlp = &pParam->sDependencyLayers[iIndex];
1432
1433 fCompressRatioThr = COMPRESS_RATIO_DECIDED_BY_RESOLUTION(fDlp->iFrameWidth, fDlp->iFrameHeight);
1434
1435 iLayerBsSize = WELS_ROUND( ( (3 * fDlp->iFrameWidth * fDlp->iFrameHeight)>>1) * fCompressRatioThr);
1436 iLayerBsSize = WELS_ALIGN(iLayerBsSize, 4); // 4 bytes alinged
1437 iVclLayersBsSizeCount += iLayerBsSize;
1438 ++ iIndex;
1439 }
1440#if defined(MT_ENABLED)
1441 iTargetSpatialBsSize = iLayerBsSize;
1442#endif//MT_ENABLED
1443 iCountBsLen = iNonVclLayersBsSizeCount + iVclLayersBsSizeCount;
1444
1445 pParam->iNumRefFrame = WELS_CLIP3(pParam->iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM);
1446
1447 // Output
1448 (*ppCtx)->pOut = (SWelsEncoderOutput *)pMa->WelsMalloc( sizeof(SWelsEncoderOutput), "SWelsEncoderOutput" );
1449 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pOut), FreeMemorySvc(ppCtx) )
1450 (*ppCtx)->pOut->pBsBuffer = (uint8_t *)pMa->WelsMalloc( iCountBsLen, "pOut->pBsBuffer" );
1451 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pOut->pBsBuffer), FreeMemorySvc(ppCtx) )
1452 (*ppCtx)->pOut->uiSize = iCountBsLen;
1453 (*ppCtx)->pOut->sNalList = (SWelsNalRaw *)pMa->WelsMalloc( iCountNals * sizeof(SWelsNalRaw), "pOut->sNalList" );
1454 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pOut->sNalList), FreeMemorySvc(ppCtx) )
1455 (*ppCtx)->pOut->iCountNals = iCountNals;
1456 (*ppCtx)->pOut->iNalIndex = 0;
1457
1458#ifdef MT_ENABLED
1459 if ( pParam->iMultipleThreadIdc > 1 )
1460 {
1461 (*ppCtx)->pFrameBs = (uint8_t *)pMa->WelsMalloc( iCountBsLen + (iTargetSpatialBsSize * ((*ppCtx)->iMaxSliceCount-1)), "pFrameBs" );
1462 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pFrameBs), FreeMemorySvc(ppCtx) )
1463 (*ppCtx)->iFrameBsSize = iCountBsLen * (*ppCtx)->iMaxSliceCount;
1464 }
1465 else
1466#endif//MT_ENABLED
1467 {
1468 (*ppCtx)->pFrameBs = (uint8_t *)pMa->WelsMalloc( iCountBsLen, "pFrameBs" );
1469 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pFrameBs), FreeMemorySvc(ppCtx) )
1470 (*ppCtx)->iFrameBsSize = iCountBsLen;
1471 }
1472 (*ppCtx)->iPosBsBuffer = 0;
1473
1474#ifdef MT_ENABLED
1475 // for pSlice bs buffers
1476 if ( pParam->iMultipleThreadIdc > 1 && RequestMtResource( ppCtx, pParam, iCountBsLen, iTargetSpatialBsSize ) )
1477 {
1478 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc(), RequestMtResource failed!");
1479 FreeMemorySvc( ppCtx );
1480 return 1;
1481 }
1482#endif
1483
1484 (*ppCtx)->pIntra4x4PredModeBlocks = static_cast<int8_t*>
1485 (pMa->WelsMallocz( iCountMaxMbNum * INTRA_4x4_MODE_NUM, "pIntra4x4PredModeBlocks" ));
1486 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pIntra4x4PredModeBlocks), FreeMemorySvc(ppCtx) )
1487
1488 (*ppCtx)->pNonZeroCountBlocks = static_cast<int8_t*>
1489 (pMa->WelsMallocz( iCountMaxMbNum * MB_LUMA_CHROMA_BLOCK4x4_NUM, "pNonZeroCountBlocks" ));
1490 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pNonZeroCountBlocks), FreeMemorySvc(ppCtx) )
1491
1492 (*ppCtx)->pMvUnitBlock4x4 = static_cast<SMVUnitXY*>
1493 (pMa->WelsMallocz( iCountMaxMbNum * 2 * MB_BLOCK4x4_NUM * sizeof(SMVUnitXY), "pMvUnitBlock4x4" ));
1494 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pMvUnitBlock4x4), FreeMemorySvc(ppCtx) )
1495
1496 (*ppCtx)->pRefIndexBlock4x4 = static_cast<int8_t*>
1497 (pMa->WelsMallocz( iCountMaxMbNum * 2 * MB_BLOCK8x8_NUM * sizeof(int8_t), "pRefIndexBlock4x4" ));
1498 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pRefIndexBlock4x4), FreeMemorySvc(ppCtx) )
1499
1500 (*ppCtx)->pSadCostMb = static_cast<int32_t*>
1501 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(int32_t), "pSadCostMb" ));
1502 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pSadCostMb), FreeMemorySvc(ppCtx))
1503
1504 (*ppCtx)->bEncCurFrmAsIdrFlag = true; // make sure first frame is IDR
1505 (*ppCtx)->iGlobalQp = 26; // global qp in default
1506
1507 (*ppCtx)->pLtr = (SLTRState *)pMa->WelsMalloc( kiNumDependencyLayers*sizeof(SLTRState), "SLTRState" );
1508 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pLtr), FreeMemorySvc(ppCtx) )
1509 int32_t i = 0;
1510 for( i = 0; i < kiNumDependencyLayers; i++ )
1511 {
1512 ResetLtrState( &(*ppCtx)->pLtr[i] );
1513 }
1514
1515 (*ppCtx)->ppRefPicListExt = (SRefList**)pMa->WelsMalloc( kiNumDependencyLayers * sizeof(SRefList *), "ppRefPicListExt" );
1516 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->ppRefPicListExt), FreeMemorySvc(ppCtx) )
1517
1518 // pSlice context list
1519 (*ppCtx)->pSliceCtxList = (SSliceCtx *)pMa->WelsMallocz( kiNumDependencyLayers * sizeof(SSliceCtx), "pSliceCtxList" );
1520 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pSliceCtxList), FreeMemorySvc(ppCtx) )
1521
1522 (*ppCtx)->ppDqLayerList = (SDqLayer **)pMa->WelsMalloc( kiNumDependencyLayers * sizeof(SDqLayer *), "ppDqLayerList" );
1523 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->ppDqLayerList), FreeMemorySvc(ppCtx) )
1524
1525 // stride tables
1526 if ( AllocStrideTables( ppCtx, kiNumDependencyLayers ) )
1527 {
1528 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc(), AllocStrideTables failed!");
1529 FreeMemorySvc( ppCtx );
1530 return 1;
1531 }
1532
1533 //Rate control module memory allocation
1534 // only malloc once for RC pData, 12/14/2009
1535 (*ppCtx)->pWelsSvcRc = (SWelsSvcRc *)pMa->WelsMallocz( kiNumDependencyLayers * sizeof(SWelsSvcRc), "pWelsSvcRc" );
1536 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pWelsSvcRc), FreeMemorySvc(ppCtx) )
1537 //End of Rate control module memory allocation
1538
1539 //pVaa memory allocation
1540 (*ppCtx)->pVaa = (SVAAFrameInfo *)pMa->WelsMallocz( sizeof(SVAAFrameInfo), "pVaa" );
1541 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa), FreeMemorySvc(ppCtx) )
1542
1543 if((*ppCtx)->pSvcParam->bEnableAdaptiveQuant)//malloc mem
1544 {
1545 (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureUnit = static_cast<SMotionTextureUnit*>
1546 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(SMotionTextureUnit), "pVaa->sAdaptiveQuantParam.pMotionTextureUnit" ));
1547 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureUnit), FreeMemorySvc(ppCtx) )
1548 (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp = static_cast<int8_t*>
1549 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(int8_t), "pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp" ));
1550 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp), FreeMemorySvc(ppCtx) )
1551 }
1552
1553 (*ppCtx)->pVaa->pVaaBackgroundMbFlag = (int8_t *)pMa->WelsMallocz( iCountMaxMbNum * sizeof(int8_t), "pVaa->vaa_skip_mb_flag" );
1554 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->pVaaBackgroundMbFlag), FreeMemorySvc(ppCtx) )
1555
1556 (*ppCtx)->pVaa->sVaaCalcInfo.pSad8x8 = static_cast<int32_t(*)[4]>
1557 (pMa->WelsMallocz( iCountMaxMbNum * 4 * sizeof(int32_t), "pVaa->sVaaCalcInfo.sad8x8" ));
1558 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSad8x8), FreeMemorySvc(ppCtx) )
1559 (*ppCtx)->pVaa->sVaaCalcInfo.pSsd16x16 = static_cast<int32_t*>
1560 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(int32_t), "pVaa->sVaaCalcInfo.pSsd16x16" ));
1561 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSsd16x16), FreeMemorySvc(ppCtx) )
1562 (*ppCtx)->pVaa->sVaaCalcInfo.pSum16x16 = static_cast<int32_t*>
1563 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(int32_t), "pVaa->sVaaCalcInfo.pSum16x16" ));
1564 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSum16x16), FreeMemorySvc(ppCtx) )
1565 (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfSquare16x16 = static_cast<int32_t*>
1566 (pMa->WelsMallocz( iCountMaxMbNum * sizeof(int32_t), "pVaa->sVaaCalcInfo.pSumOfSquare16x16" ));
1567 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfSquare16x16), FreeMemorySvc(ppCtx) )
1568
1569 if ((*ppCtx)->pSvcParam->bEnableBackgroundDetection) //BGD control
1570 {
1571 (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfDiff8x8 = static_cast<int32_t(*)[4]>
1572 (pMa->WelsMallocz( iCountMaxMbNum * 4 * sizeof(int32_t), "pVaa->sVaaCalcInfo.sd_16x16" ));
1573 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfDiff8x8), FreeMemorySvc(ppCtx) )
1574 (*ppCtx)->pVaa->sVaaCalcInfo.pMad8x8 = static_cast<uint8_t(*)[4]>
1575 (pMa->WelsMallocz( iCountMaxMbNum * 4 * sizeof(uint8_t), "pVaa->sVaaCalcInfo.mad_16x16" ));
1576 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pMad8x8), FreeMemorySvc(ppCtx) )
1577 }
1578
1579 //End of pVaa memory allocation
1580
1581 iResult = InitDqLayers( ppCtx );
1582 if ( iResult )
1583 {
1584 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc(), InitDqLayers failed(%d)!", iResult );
1585 FreeMemorySvc( ppCtx );
1586 return iResult;
1587 }
1588
1589 if( InitMbListD( ppCtx ) )
1590 {
1591 WelsLog( *ppCtx, WELS_LOG_WARNING, "RequestMemorySvc(), InitMbListD failed!" );
1592 FreeMemorySvc( ppCtx );
1593 return 1;
1594 }
1595
1596 (*ppCtx)->pMvdCostTableInter = (uint16_t *)pMa->WelsMallocz( 52 * kuiMvdCacheAlginedSize, "pMvdCostTableInter" );
1597 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == (*ppCtx)->pMvdCostTableInter), FreeMemorySvc(ppCtx) )
1598 MvdCostInit( (*ppCtx)->pMvdCostTableInter, kuiMvdInterTableSize ); //should put to a better place?
1599
1600 if ( (*ppCtx)->ppRefPicListExt[0] != NULL && (*ppCtx)->ppRefPicListExt[0]->pRef[0] != NULL )
1601 (*ppCtx)->pDecPic = (*ppCtx)->ppRefPicListExt[0]->pRef[0];
1602 else
1603 (*ppCtx)->pDecPic = NULL; // error here
1604
1605 (*ppCtx)->pSps = &(*ppCtx)->pSpsArray[0];
1606 (*ppCtx)->pPps = &(*ppCtx)->pPPSArray[0];
1607
1608 return 0;
1609}
1610
1611
1612/*!
1613 * \brief free memory in SVC core encoder
1614 * \pParam pEncCtx sWelsEncCtx*
1615 * \return none
1616 */
1617void FreeMemorySvc( sWelsEncCtx **ppCtx )
1618{
1619 if ( NULL != *ppCtx )
1620 {
1621 sWelsEncCtx *pCtx = *ppCtx;
1622 CMemoryAlign *pMa = pCtx->pMemAlign;
1623 SWelsSvcCodingParam *pParam= pCtx->pSvcParam;
1624 int32_t ilayer = 0;
1625
1626 // SStrideTables
1627 if ( NULL != pCtx->pStrideTab )
1628 {
1629 if ( NULL != pCtx->pStrideTab->pStrideDecBlockOffset[0][1] )
1630 {
1631 pMa->WelsFree( pCtx->pStrideTab->pStrideDecBlockOffset[0][1], "pBase" );
1632 pCtx->pStrideTab->pStrideDecBlockOffset[0][1] = NULL;
1633 }
1634 pMa->WelsFree(pCtx->pStrideTab, "SStrideTables");
1635 pCtx->pStrideTab = NULL;
1636 }
1637 // pDq idc map
1638 if ( NULL != pCtx->pDqIdcMap )
1639 {
1640 pMa->WelsFree( pCtx->pDqIdcMap, "pDqIdcMap" );
1641 pCtx->pDqIdcMap = NULL;
1642 }
1643
1644 if ( NULL != pCtx->pOut )
1645 {
1646 // bs pBuffer
1647 if ( NULL != pCtx->pOut->pBsBuffer )
1648 {
1649 pMa->WelsFree( pCtx->pOut->pBsBuffer, "pOut->pBsBuffer" );
1650 pCtx->pOut->pBsBuffer = NULL;
1651 }
1652 // NALs list
1653 if ( NULL != pCtx->pOut->sNalList )
1654 {
1655 pMa->WelsFree( pCtx->pOut->sNalList, "pOut->sNalList" );
1656 pCtx->pOut->sNalList = NULL;
1657 }
1658 pMa->WelsFree( pCtx->pOut, "SWelsEncoderOutput" );
1659 pCtx->pOut = NULL;
1660 }
1661
1662#ifdef MT_ENABLED
1663 if ( pParam != NULL && pParam->iMultipleThreadIdc > 1 )
1664 ReleaseMtResource( ppCtx );
1665#endif//MT_ENABLED
1666
1667 // frame bitstream pBuffer
1668 if ( NULL != pCtx->pFrameBs )
1669 {
1670 pMa->WelsFree( pCtx->pFrameBs, "pFrameBs" );
1671 pCtx->pFrameBs = NULL;
1672 }
1673
1674 // pSpsArray
1675 if ( NULL != pCtx->pSpsArray )
1676 {
1677 pMa->WelsFree( pCtx->pSpsArray, "pSpsArray" );
1678 pCtx->pSpsArray = NULL;
1679 }
1680 // pPPSArray
1681 if ( NULL != pCtx->pPPSArray )
1682 {
1683 pMa->WelsFree( pCtx->pPPSArray, "pPPSArray" );
1684 pCtx->pPPSArray = NULL;
1685 }
1686 // subset_sps_array
1687 if ( NULL != pCtx->pSubsetArray )
1688 {
1689 pMa->WelsFree( pCtx->pSubsetArray, "pSubsetArray" );
1690 pCtx->pSubsetArray = NULL;
1691 }
1692
1693 if( NULL != pCtx->pIntra4x4PredModeBlocks ){
1694 pMa->WelsFree( pCtx->pIntra4x4PredModeBlocks, "pIntra4x4PredModeBlocks" );
1695 pCtx->pIntra4x4PredModeBlocks = NULL;
1696 }
1697
1698 if( NULL != pCtx->pNonZeroCountBlocks ){
1699 pMa->WelsFree( pCtx->pNonZeroCountBlocks, "pNonZeroCountBlocks" );
1700 pCtx->pNonZeroCountBlocks = NULL;
1701 }
1702
1703 if ( NULL != pCtx->pMvUnitBlock4x4)
1704 {
1705 pMa->WelsFree( pCtx->pMvUnitBlock4x4, "pMvUnitBlock4x4" );
1706 pCtx->pMvUnitBlock4x4 = NULL;
1707 }
1708
1709 if ( NULL != pCtx->pRefIndexBlock4x4)
1710 {
1711 pMa->WelsFree( pCtx->pRefIndexBlock4x4, "pRefIndexBlock4x4" );
1712 pCtx->pRefIndexBlock4x4 = NULL;
1713 }
1714
1715 if ( NULL != pCtx->ppMbListD )
1716 {
1717 if( NULL != pCtx->ppMbListD[0] ){
1718 pMa->WelsFree( pCtx->ppMbListD[0], "ppMbListD[0]" );
1719 (*ppCtx)->ppMbListD[0] = NULL;
1720 }
1721 pMa->WelsFree( pCtx->ppMbListD, "ppMbListD" );
1722 pCtx->ppMbListD = NULL;
1723 }
1724
1725 if ( NULL != pCtx->pSadCostMb)
1726 {
1727 pMa->WelsFree( pCtx->pSadCostMb, "pSadCostMb" );
1728 pCtx->pSadCostMb = NULL;
1729 }
1730
1731 // SLTRState
1732 if ( NULL != pCtx->pLtr )
1733 {
1734 pMa->WelsFree( pCtx->pLtr, "SLTRState" );
1735 pCtx->pLtr = NULL;
1736 }
1737
1738 // pDq layers list
1739 ilayer = 0;
1740 if ( NULL != pCtx->ppDqLayerList && pParam != NULL )
1741 {
1742 while (ilayer < pParam->iNumDependencyLayer) {
1743 SDqLayer *pDq = pCtx->ppDqLayerList[ilayer];
1744 SDLayerParam *pDlp = &pCtx->pSvcParam->sDependencyLayers[ilayer];
1745 const BOOL_T kbIsDynamicSlicing = (SM_DYN_SLICE == pDlp->sMso.uiSliceMode);
1746
1747 // pDq layers
1748 if ( NULL != pDq )
1749 {
1750 if ( NULL != pDq->sLayerInfo.pSliceInLayer )
1751 {
1752 int32_t iSliceIdx = 0;
1753 int32_t iSliceNum = GetInitialSliceNum( pDq->iMbWidth, pDq->iMbHeight, &pDlp->sMso );
1754 if (iSliceNum < 1)
1755 iSliceNum = 1;
1756 while(iSliceIdx < iSliceNum)
1757 {
1758 SSlice *pSlice = &pDq->sLayerInfo.pSliceInLayer[iSliceIdx];
1759 FreeMbCache(&pSlice->sMbCacheInfo, pMa);
1760 ++ iSliceIdx;
1761 }
1762 pMa->WelsFree( pDq->sLayerInfo.pSliceInLayer, "pSliceInLayer" );
1763 pDq->sLayerInfo.pSliceInLayer = NULL;
1764 }
1765 if ( kbIsDynamicSlicing )
1766 {
1767 pMa->WelsFree( pDq->pNumSliceCodedOfPartition, "pNumSliceCodedOfPartition" );
1768 pDq->pNumSliceCodedOfPartition = NULL;
1769 pMa->WelsFree( pDq->pLastCodedMbIdxOfPartition, "pLastCodedMbIdxOfPartition" );
1770 pDq->pLastCodedMbIdxOfPartition = NULL;
1771 pMa->WelsFree( pDq->pLastMbIdxOfPartition, "pLastMbIdxOfPartition" );
1772 pDq->pLastMbIdxOfPartition = NULL;
1773 }
1774
1775 pMa->WelsFree( pDq, "pDq" );
1776 pDq = NULL;
1777 pCtx->ppDqLayerList[ilayer] = NULL;
1778 }
1779 ++ ilayer;
1780 }
1781 pMa->WelsFree( pCtx->ppDqLayerList, "ppDqLayerList" );
1782 pCtx->ppDqLayerList = NULL;
1783 }
1784 FreeSpatialPictures( pCtx );
1785
1786 // reference picture list extension
1787 if ( NULL != pCtx->ppRefPicListExt && pParam != NULL )
1788 {
1789 ilayer = 0;
1790 while (ilayer < pParam->iNumDependencyLayer) {
1791 SRefList *pRefList = pCtx->ppRefPicListExt[ilayer];
1792 if ( NULL != pRefList )
1793 {
1794 int32_t iRef = 0;
1795 do {
1796 if ( pRefList->pRef[iRef] != NULL )
1797 {
1798 FreePicture( pMa, &pRefList->pRef[iRef] );
1799 }
1800 ++ iRef;
1801 } while(iRef < 1 + pParam->iNumRefFrame);
1802
1803 pMa->WelsFree( pCtx->ppRefPicListExt[ilayer], "ppRefPicListExt[]" );
1804 pCtx->ppRefPicListExt[ilayer] = NULL;
1805 }
1806 ++ ilayer;
1807 }
1808
1809 pMa->WelsFree( pCtx->ppRefPicListExt, "ppRefPicListExt" );
1810 pCtx->ppRefPicListExt = NULL;
1811 }
1812
1813 // pSlice context list
1814 if ( NULL != pCtx->pSliceCtxList && pParam != NULL )
1815 {
1816 ilayer = 0;
1817 while (ilayer < pParam->iNumDependencyLayer) {
1818 SSliceCtx *pSliceCtx = &pCtx->pSliceCtxList[ilayer];
1819 if ( NULL != pSliceCtx )
1820 UninitSlicePEncCtx( pSliceCtx, pMa );
1821 ++ ilayer;
1822 }
1823 pMa->WelsFree( pCtx->pSliceCtxList, "pSliceCtxList" );
1824 pCtx->pSliceCtxList = NULL;
1825 }
1826
1827 // VAA
1828 if ( NULL != pCtx->pVaa )
1829 {
1830 if(pCtx->pSvcParam->bEnableAdaptiveQuant)//free mem
1831 {
1832 pMa->WelsFree( pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureUnit, "pVaa->sAdaptiveQuantParam.pMotionTextureUnit" );
1833 pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureUnit = NULL;
1834 pMa->WelsFree( pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp, "pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp" );
1835 pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp = NULL;
1836 }
1837
1838 pMa->WelsFree( pCtx->pVaa->pVaaBackgroundMbFlag, "pVaa->pVaaBackgroundMbFlag");
1839 pCtx->pVaa->pVaaBackgroundMbFlag = NULL;
1840 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pSad8x8, "pVaa->sVaaCalcInfo.sad8x8" );
1841 pCtx->pVaa->sVaaCalcInfo.pSad8x8 = NULL;
1842 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pSsd16x16, "pVaa->sVaaCalcInfo.pSsd16x16" );
1843 pCtx->pVaa->sVaaCalcInfo.pSsd16x16 = NULL;
1844 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pSum16x16, "pVaa->sVaaCalcInfo.pSum16x16" );
1845 pCtx->pVaa->sVaaCalcInfo.pSum16x16 = NULL;
1846 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pSumOfSquare16x16, "pVaa->sVaaCalcInfo.pSumOfSquare16x16" );
1847 pCtx->pVaa->sVaaCalcInfo.pSumOfSquare16x16 = NULL;
1848
1849 if (pCtx->pSvcParam->bEnableBackgroundDetection) //BGD control
1850 {
1851 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pSumOfDiff8x8, "pVaa->sVaaCalcInfo.pSumOfDiff8x8" );
1852 pCtx->pVaa->sVaaCalcInfo.pSumOfDiff8x8 = NULL;
1853 pMa->WelsFree( pCtx->pVaa->sVaaCalcInfo.pMad8x8, "pVaa->sVaaCalcInfo.pMad8x8" );
1854 pCtx->pVaa->sVaaCalcInfo.pMad8x8 = NULL;
1855 }
1856
1857 pMa->WelsFree( pCtx->pVaa, "pVaa" );
1858 pCtx->pVaa = NULL;
1859 }
1860
1861 WelsRcFreeMemory(pCtx);
1862 // rate control module memory free
1863 if ( NULL != pCtx->pWelsSvcRc )
1864 {
1865 pMa->WelsFree( pCtx->pWelsSvcRc, "pWelsSvcRc" );
1866 pCtx->pWelsSvcRc = NULL;
1867 }
1868
1869 /* MVD cost tables for Inter */
1870 if ( NULL != pCtx->pMvdCostTableInter )
1871 {
1872 pMa->WelsFree( pCtx->pMvdCostTableInter, "pMvdCostTableInter" );
1873 pCtx->pMvdCostTableInter = NULL;
1874 }
1875
1876#ifdef ENABLE_TRACE_FILE
1877 if ( NULL != pCtx->pFileLog )
1878 {
1879 fclose( pCtx->pFileLog );
1880 pCtx->pFileLog = NULL;
1881 }
1882 pCtx->uiSizeLog = 0;
1883#endif//ENABLE_TRACE_FILE
1884
1885 FreeCodingParam( &pCtx->pSvcParam, pMa );
1886 if ( NULL != pCtx->pFuncList )
1887 {
1888 pMa->WelsFree(pCtx->pFuncList, "SWelsFuncPtrList");
1889 pCtx->pFuncList = NULL;
1890 }
1891
1892#if defined(MEMORY_MONITOR)
1893 assert(pMa->WelsGetMemoryUsage() == 0); // ensure all memory free well
1894#endif//MEMORY_MONITOR
1895
1896 if ( (*ppCtx)->pMemAlign != NULL )
1897 {
1898 WelsLog( NULL, WELS_LOG_INFO, "FreeMemorySvc(), verify memory usage (%d bytes) after free..\n", (*ppCtx)->pMemAlign->WelsGetMemoryUsage() );
1899 delete (*ppCtx)->pMemAlign;
1900 (*ppCtx)->pMemAlign = NULL;
1901 }
1902
1903 free(*ppCtx);
1904 *ppCtx = NULL;
1905 }
1906}
1907
1908int32_t InitSliceSettings( SWelsSvcCodingParam *pCodingParam, const int32_t kiCpuCores, int16_t *pMaxSliceCount )
1909{
1910 int32_t iSpatialIdx = 0, iSpatialNum = pCodingParam->iNumDependencyLayer;
1911 int16_t iMaxSliceCount = 0;
1912
1913 do {
1914 SDLayerParam *pDlp = &pCodingParam->sDependencyLayers[iSpatialIdx];
1915 SMulSliceOption *pMso = &pDlp->sMso;
1916 SSliceArgument *pSlcArg = &pMso->sSliceArgument;
1917 const int32_t kiMbWidth = (pDlp->iFrameWidth+15)>>4;
1918 const int32_t kiMbHeight = (pDlp->iFrameHeight+15)>>4;
1919 const int32_t kiMbNumInFrame = kiMbWidth * kiMbHeight;
1920#if defined(MT_ENABLED)
1921#if defined(DYNAMIC_SLICE_ASSIGN)
1922 int32_t iSliceNum = (SM_FIXEDSLCNUM_SLICE == pMso->uiSliceMode || SM_DYN_SLICE == pMso->uiSliceMode) ? kiCpuCores : pSlcArg->iSliceNum; // uiSliceNum per input has been validated at ParamValidationExt()
1923#else//!DYNAMIC_SLICE_ASSIGN
1924 int32_t iSliceNum = (SM_DYN_SLICE == pMso->uiSliceMode) ? kiCpuCores : pSlcArg->uiSliceNum; // uiSliceNum per input has been validated at ParamValidationExt()
1925#endif//DYNAMIC_SLICE_ASSIGN
1926#else//!MT_ENABLED
1927 int16_t iSliceNum = pSlcArg->iSliceNum; // uiSliceNum per input has been validated at ParamValidationExt()
1928#endif//MT_ENABLED
1929
1930 // NOTE: Per design, in case MT/DYNAMIC_SLICE_ASSIGN enabled, for SM_FIXEDSLCNUM_SLICE mode,
1931 // uiSliceNum of current spatial layer settings equals to uiCpuCores number; SM_DYN_SLICE mode,
1932 // uiSliceNum intials as uiCpuCores also, stay tuned dynamically slicing in future
1933 pSlcArg->iSliceNum = iSliceNum; // used fixed one
1934
1935 switch(pMso->uiSliceMode)
1936 {
1937 case SM_DYN_SLICE:
1938 iMaxSliceCount = AVERSLICENUM_CONSTRAINT;
1939//#ifndef MT_ENABLED
1940 break; // go through for MT_ENABLED & SM_DYN_SLICE?
1941//#endif//MT_ENABLED
1942 case SM_FIXEDSLCNUM_SLICE:
1943 if ( iSliceNum > iMaxSliceCount )
1944 iMaxSliceCount = iSliceNum;
1945 // need perform check due uiSliceNum might change, although has been initialized somewhere outside
1946 if (pCodingParam->bEnableRc)
1947 {
1948 GomValidCheckSliceMbNum( kiMbWidth, kiMbHeight, pSlcArg );
1949 }
1950 else
1951 {
1952 CheckFixedSliceNumMultiSliceSetting( kiMbNumInFrame, pSlcArg );
1953 }
1954 break;
1955 case SM_SINGLE_SLICE:
1956 if ( iSliceNum > iMaxSliceCount )
1957 iMaxSliceCount = iSliceNum;
1958 break;
1959 case SM_RASTER_SLICE:
1960 if ( iSliceNum > iMaxSliceCount )
1961 iMaxSliceCount = iSliceNum;
1962 break;
1963 case SM_ROWMB_SLICE:
1964 if ( iSliceNum > iMaxSliceCount )
1965 iMaxSliceCount = iSliceNum;
1966 break;
1967 default:
1968 break;
1969 }
1970
1971 ++ iSpatialIdx;
1972 } while(iSpatialIdx < iSpatialNum);
1973
1974#ifdef MT_ENABLED
1975 pCodingParam->iCountThreadsNum = WELS_MIN(kiCpuCores, iMaxSliceCount);
1976 pCodingParam->iMultipleThreadIdc = pCodingParam->iCountThreadsNum;
1977#else
1978 pCodingParam->iMultipleThreadIdc = 1;
1979 pCodingParam->iCountThreadsNum = 1;
1980#endif//MT_ENABLED
1981
1982#ifndef WELS_TESTBED // for product release and non-SGE testing
1983
1984 if ( kiCpuCores < 2 ) // single CPU core, make no sense for MT parallelization
1985 {
1986 pCodingParam->iMultipleThreadIdc = 1;
1987 pCodingParam->iCountThreadsNum = 1;
1988 }
1989#endif
1990
1991 *pMaxSliceCount = iMaxSliceCount;
1992
1993 return 0;
1994}
1995
1996/*!
1997 * \brief log output for cpu features/capabilities
1998 */
1999void OutputCpuFeaturesLog( uint32_t uiCpuFeatureFlags, uint32_t uiCpuCores, int32_t iCacheLineSize )
2000{
2001 // welstracer output
2002 WelsLog(NULL, WELS_LOG_INFO, "WELS CPU features/capacities (0x%x) detected: \t" \
2003 "HTT: %c, " \
2004 "MMX: %c, " \
2005 "MMXEX: %c, " \
2006 "SSE: %c, " \
2007 "SSE2: %c, " \
2008 "SSE3: %c, " \
2009 "SSSE3: %c, " \
2010 "SSE4.1: %c, " \
2011 "SSE4.2: %c, " \
2012 "AVX: %c, " \
2013 "FMA: %c, " \
2014 "X87-FPU: %c, " \
2015 "3DNOW: %c, " \
2016 "3DNOWEX: %c, " \
2017 "ALTIVEC: %c, " \
2018 "CMOV: %c, " \
2019 "MOVBE: %c, " \
2020 "AES: %c, " \
2021 "NUMBER OF LOGIC PROCESSORS ON CHIP: %d, " \
2022 "CPU CACHE LINE SIZE (BYTES): %d\n",
2023 uiCpuFeatureFlags,
2024 (uiCpuFeatureFlags & WELS_CPU_HTT) ? 'Y' : 'N',
2025 (uiCpuFeatureFlags & WELS_CPU_MMX) ? 'Y' : 'N',
2026 (uiCpuFeatureFlags & WELS_CPU_MMXEXT) ? 'Y' : 'N',
2027 (uiCpuFeatureFlags & WELS_CPU_SSE) ? 'Y' : 'N',
2028 (uiCpuFeatureFlags & WELS_CPU_SSE2) ? 'Y' : 'N',
2029 (uiCpuFeatureFlags & WELS_CPU_SSE3) ? 'Y' : 'N',
2030 (uiCpuFeatureFlags & WELS_CPU_SSSE3) ? 'Y' : 'N',
2031 (uiCpuFeatureFlags & WELS_CPU_SSE41) ? 'Y' : 'N',
2032 (uiCpuFeatureFlags & WELS_CPU_SSE42) ? 'Y' : 'N',
2033 (uiCpuFeatureFlags & WELS_CPU_AVX) ? 'Y' : 'N',
2034 (uiCpuFeatureFlags & WELS_CPU_FMA) ? 'Y' : 'N',
2035 (uiCpuFeatureFlags & WELS_CPU_FPU) ? 'Y' : 'N',
2036 (uiCpuFeatureFlags & WELS_CPU_3DNOW) ? 'Y' : 'N',
2037 (uiCpuFeatureFlags & WELS_CPU_3DNOWEXT) ? 'Y' : 'N',
2038 (uiCpuFeatureFlags & WELS_CPU_ALTIVEC) ? 'Y' : 'N',
2039 (uiCpuFeatureFlags & WELS_CPU_CMOV) ? 'Y' : 'N',
2040 (uiCpuFeatureFlags & WELS_CPU_MOVBE) ? 'Y' : 'N',
2041 (uiCpuFeatureFlags & WELS_CPU_AES) ? 'Y' : 'N',
2042 uiCpuCores,
2043 iCacheLineSize );
2044
2045#ifdef _DEBUG // output at console & _debug
2046 fprintf( stderr, "WELS CPU features/capacities (0x%x) detected: \n" \
2047 "HTT: %c, " \
2048 "MMX: %c, " \
2049 "MMXEX: %c, " \
2050 "SSE: %c, " \
2051 "SSE2: %c, " \
2052 "SSE3: %c, " \
2053 "SSSE3: %c, " \
2054 "SSE4.1: %c, " \
2055 "SSE4.2: %c, " \
2056 "AVX: %c, " \
2057 "FMA: %c, " \
2058 "X87-FPU: %c, " \
2059 "3DNOW: %c, " \
2060 "3DNOWEX: %c, " \
2061 "ALTIVEC: %c, " \
2062 "CMOV: %c, " \
2063 "MOVBE: %c, " \
2064 "AES: %c, " \
2065 "NUMBER OF LOGIC PROCESSORS ON CHIP: %d, " \
2066 "CPU CACHE LINE SIZE (BYTES): %d\n",
2067 uiCpuFeatureFlags,
2068 (uiCpuFeatureFlags & WELS_CPU_HTT) ? 'Y' : 'N',
2069 (uiCpuFeatureFlags & WELS_CPU_MMX) ? 'Y' : 'N',
2070 (uiCpuFeatureFlags & WELS_CPU_MMXEXT) ? 'Y' : 'N',
2071 (uiCpuFeatureFlags & WELS_CPU_SSE) ? 'Y' : 'N',
2072 (uiCpuFeatureFlags & WELS_CPU_SSE2) ? 'Y' : 'N',
2073 (uiCpuFeatureFlags & WELS_CPU_SSE3) ? 'Y' : 'N',
2074 (uiCpuFeatureFlags & WELS_CPU_SSSE3) ? 'Y' : 'N',
2075 (uiCpuFeatureFlags & WELS_CPU_SSE41) ? 'Y' : 'N',
2076 (uiCpuFeatureFlags & WELS_CPU_SSE42) ? 'Y' : 'N',
2077 (uiCpuFeatureFlags & WELS_CPU_AVX) ? 'Y' : 'N',
2078 (uiCpuFeatureFlags & WELS_CPU_FMA) ? 'Y' : 'N',
2079 (uiCpuFeatureFlags & WELS_CPU_FPU) ? 'Y' : 'N',
2080 (uiCpuFeatureFlags & WELS_CPU_3DNOW) ? 'Y' : 'N',
2081 (uiCpuFeatureFlags & WELS_CPU_3DNOWEXT) ? 'Y' : 'N',
2082 (uiCpuFeatureFlags & WELS_CPU_ALTIVEC) ? 'Y' : 'N',
2083 (uiCpuFeatureFlags & WELS_CPU_CMOV) ? 'Y' : 'N',
2084 (uiCpuFeatureFlags & WELS_CPU_MOVBE) ? 'Y' : 'N',
2085 (uiCpuFeatureFlags & WELS_CPU_AES) ? 'Y' : 'N',
2086 uiCpuCores,
2087 iCacheLineSize );
2088#endif//_DEBUG
2089}
2090
2091/*!
2092 * \brief initialize Wels avc encoder core library
2093 * \pParam ppCtx sWelsEncCtx**
2094 * \pParam pParam SWelsSvcCodingParam*
2095 * \return successful - 0; otherwise none 0 for failed
2096 */
2097int32_t WelsInitEncoderExt( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pCodingParam )
2098{
2099 sWelsEncCtx *pCtx = NULL;
2100 int32_t iRet = 0;
2101 uint32_t uiCpuFeatureFlags = 0; // CPU features
2102 int32_t uiCpuCores = 1; // number of logic processors on physical processor package, one logic processor means HTT not supported
2103 int32_t iCacheLineSize = 16; // on chip cache line size in byte
2104 int16_t iSliceNum = 1; // number of slices used
2105
2106 if ( NULL == ppCtx || NULL == pCodingParam )
2107 {
2108 WelsLog(NULL, WELS_LOG_ERROR, "WelsInitEncoderExt(), NULL == ppCtx(0x%p) or NULL == pCodingParam(0x%p).\n", (void *)ppCtx, (void *)pCodingParam);
2109 return 1;
2110 }
2111
2112 iRet = ParamValidationExt( pCodingParam );
2113 if ( iRet != 0 )
2114 {
2115 WelsLog(NULL, WELS_LOG_ERROR, "WelsInitEncoderExt(), ParamValidationExt failed return %d.\n", iRet);
2116 return iRet;
2117 }
2118
2119 // for cpu features detection, Only detect once??
2120#ifdef X86_ASM
2121 uiCpuFeatureFlags = WelsCPUFeatureDetect( &uiCpuCores ); // detect cpu capacity features
2122 if ( uiCpuFeatureFlags & WELS_CPU_CACHELINE_128 )
2123 iCacheLineSize = 128;
2124 else if ( uiCpuFeatureFlags & WELS_CPU_CACHELINE_64 )
2125 iCacheLineSize = 64;
2126 else if ( uiCpuFeatureFlags & WELS_CPU_CACHELINE_32 )
2127 iCacheLineSize = 32;
2128 else if ( uiCpuFeatureFlags & WELS_CPU_CACHELINE_16 )
2129 iCacheLineSize = 16;
2130 OutputCpuFeaturesLog( uiCpuFeatureFlags, uiCpuCores, iCacheLineSize );
2131#else
2132 iCacheLineSize = 16; // 16 bytes aligned in default
2133#endif//X86_ASM
2134
2135#ifndef WELS_TESTBED
2136
2137#if defined(MT_ENABLED) && defined(DYNAMIC_DETECT_CPU_CORES)
2138 if ( pCodingParam->iMultipleThreadIdc > 0 )
2139 uiCpuCores = pCodingParam->iMultipleThreadIdc;
2140 else
2141 {
2142 if ( uiCpuFeatureFlags == 0 ) // cpuid not supported, use high level system API as followed to detect number of pysical/logic processor
2143 uiCpuCores = DynamicDetectCpuCores();
2144 // So far so many cpu cores up to MAX_THREADS_NUM mean for server platforms,
2145 // for client application here it is constrained by maximal to MAX_THREADS_NUM
2146 if ( uiCpuCores > MAX_THREADS_NUM ) // MAX_THREADS_NUM
2147 uiCpuCores = MAX_THREADS_NUM; // MAX_THREADS_NUM
2148 else if ( uiCpuCores < 1 ) // just for safe
2149 uiCpuCores = 1;
2150 }
2151#endif//MT_ENABLED && DYNAMIC_DETECT_CPU_CORES
2152
2153#else//WELS_TESTBED
2154
2155 uiCpuCores = pCodingParam->iMultipleThreadIdc; // assigned uiCpuCores from iMultipleThreadIdc from SGE testing
2156
2157#endif//WELS_TESTBED
2158
2159 uiCpuCores = WELS_CLIP3(uiCpuCores, 1, MAX_THREADS_NUM);
2160
2161 if ( InitSliceSettings(pCodingParam, uiCpuCores, &iSliceNum ) )
2162 {
2163 WelsLog(NULL, WELS_LOG_ERROR, "WelsInitEncoderExt(), InitSliceSettings failed.\n");
2164 return 1;
2165 }
2166
2167 *ppCtx = NULL;
2168
2169 pCtx = static_cast<sWelsEncCtx*>(malloc( sizeof(sWelsEncCtx) ));
2170
2171 WELS_VERIFY_RETURN_IF(1, (NULL == pCtx))
2172 memset( pCtx, 0, sizeof(sWelsEncCtx) );
2173
2174 pCtx->pMemAlign = new CMemoryAlign( iCacheLineSize );
2175 WELS_VERIFY_RETURN_PROC_IF( 1, (NULL == pCtx->pMemAlign), FreeMemorySvc(&pCtx) )
2176
2177 // for logs
2178#ifdef ENABLE_TRACE_FILE
2179 if (wlog == WelsLogDefault)
2180 {
2181 str_t fname[MAX_FNAME_LEN] = {0};
2182
2183#if defined (_MSC_VER)
2184#if _MSC_VER>=1500
2185 SNPRINTF(fname, MAX_FNAME_LEN, MAX_FNAME_LEN, "%swels_svc_encoder_trace.txt", pCodingParam->sTracePath ); // confirmed_safe_unsafe_usage
2186#else
2187 SNPRINTF(fname, MAX_FNAME_LEN, "%swels_svc_encoder_trace.txt", pCodingParam->sTracePath ); // confirmed_safe_unsafe_usage
2188#endif//_MSC_VER>=1500
2189#else
2190 //GNUC/
2191 SNPRINTF(fname, MAX_FNAME_LEN, "%swels_svc_encoder_trace.txt", pCodingParam->sTracePath ); // confirmed_safe_unsafe_usage
2192#endif//_MSC_VER
2193
2194
2195#if defined(__GNUC__)
2196 pCtx->pFileLog = FOPEN(fname, "wt+");
2197#else//WIN32
2198#if defined(WIN32) && defined(_MSC_VER)
2199#if _MSC_VER >= 1500
2200 FOPEN(&pCtx->pFileLog,fname, "wt+");
2201#else
2202 pCtx->pFileLog = FOPEN(fname, "wt+");
2203#endif//_MSC_VER>=1500
2204#endif//WIN32 && _MSC_VER
2205#endif//__GNUC__
2206 pCtx->uiSizeLog = 0;
2207 }
2208#endif//ENABLE_TRACE_FILE
2209
2210 pCodingParam->DetermineTemporalSettings();
2211 iRet = AllocCodingParam( &pCtx->pSvcParam, pCtx->pMemAlign, pCodingParam->iNumDependencyLayer );
2212 if ( iRet != 0 )
2213 {
2214 FreeMemorySvc( &pCtx );
2215 return iRet;
2216 }
2217 memcpy( pCtx->pSvcParam, pCodingParam, sizeof(SWelsSvcCodingParam) ); // confirmed_safe_unsafe_usage
2218
2219 pCtx->pFuncList = (SWelsFuncPtrList *)pCtx->pMemAlign->WelsMalloc(sizeof(SWelsFuncPtrList), "SWelsFuncPtrList");
2220 if ( NULL == pCtx->pFuncList )
2221 {
2222 FreeMemorySvc( &pCtx );
2223 return 1;
2224 }
2225 InitFunctionPointers( pCtx->pFuncList, pCtx->pSvcParam, uiCpuFeatureFlags );
2226
2227 pCtx->iActiveThreadsNum = pCodingParam->iCountThreadsNum;
2228 pCtx->iMaxSliceCount = iSliceNum;
2229 iRet = RequestMemorySvc( &pCtx );
2230 if ( iRet != 0 )
2231 {
2232 WelsLog(pCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), RequestMemorySvc failed return %d.\n", iRet);
2233 FreeMemorySvc( &pCtx );
2234 return iRet;
2235 }
2236
2237#ifdef MT_ENABLED
2238 if ( pCodingParam->iMultipleThreadIdc > 1 )
2239 iRet = CreateSliceThreads( pCtx);
2240#endif
2241
2242 WelsRcInitModule( pCtx, pCtx->pSvcParam->bEnableRc ? WELS_RC_GOM : WELS_RC_DISABLE);
2243
2244 pCtx->pVpp = new CWelsPreProcess((void *)pCtx);
2245 if ( pCtx->pVpp == NULL )
2246 {
2247 WelsLog(pCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), pOut of memory in case new CWelsPreProcess().\n");
2248 FreeMemorySvc( &pCtx );
2249 return iRet;
2250 }
2251
2252#if defined(MEMORY_MONITOR)
2253 WelsLog(pCtx, WELS_LOG_INFO, "WelsInitEncoderExt() exit, overall memory usage: %lu bytes\n", sizeof(sWelsEncCtx) /* requested size from malloc() or new operator */
2254 + pCtx->pMemAlign->WelsGetMemoryUsage() /* requested size from CMemoryAlign::WelsMalloc() */
2255 );
2256#endif//MEMORY_MONITOR
2257
2258 *ppCtx = pCtx;
2259
2260 WelsLog(pCtx, WELS_LOG_DEBUG, "WelsInitEncoderExt(), pCtx= 0x%p.\n", (void *)pCtx);
2261
2262 return 0;
2263}
2264/*
2265 *
2266 * status information output
2267 */
2268#if defined(STAT_OUTPUT)
2269void StatOverallEncodingExt(sWelsEncCtx *pCtx)
2270{
2271 int8_t i = 0;
2272 int8_t j = 0;
2273 for (i = 0;i<pCtx->pSvcParam->iNumDependencyLayer;i++)
2274 {
2275 fprintf( stdout,"\nDependency layer : %d\n",i);
2276 fprintf( stdout,"Quality layer : %d\n",j);
2277 {
2278 const int32_t iCount = pCtx->sStatData[i][j].sSliceData.iSliceCount[I_SLICE] +
2279 pCtx->sStatData[i][j].sSliceData.iSliceCount[P_SLICE] +
2280 pCtx->sStatData[i][j].sSliceData.iSliceCount[B_SLICE];
2281#if defined(MB_TYPES_CHECK)
2282 if (iCount > 0){
2283 int32_t iCountNumIMb = pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra4x4] + pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra16x16]+ pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][7];
2284 int32_t iCountNumPMb = pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra4x4] +
2285 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra16x16] +
2286 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][7] +
2287 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] +
2288 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] +
2289 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] +
2290 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] +
2291 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10] +
2292 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][PSkip];
2293 int32_t count_p_mbL0 = pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] +
2294 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] +
2295 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] +
2296 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] +
2297 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10];
2298
2299 int32_t iMbCount = iCountNumIMb + iCountNumPMb;
2300 if ( iMbCount > 0 ){
2301 fprintf( stderr,
2302 "SVC: overall Slices MBs: %d Avg\nI4x4: %.3f%% I16x16: %.3f%% IBL: %.3f%%\nP16x16: %.3f%% P16x8: %.3f%% P8x16: %.3f%% P8x8: %.3f%% SUBP8x8: %.3f%% PSKIP: %.3f%%\nILP(All): %.3f%% ILP(PL0): %.3f%% BLSKIP(PL0): %.3f%% RP(PL0): %.3f%%\n",
2303 iMbCount,
2304 (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra4x4] + pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra4x4]) / iMbCount),
2305 (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra16x16] + pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra16x16]) / iMbCount),
2306 (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][7] + pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][7]) / iMbCount),
2307 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] / iMbCount ),
2308 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] / iMbCount ),
2309 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] / iMbCount ),
2310 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] / iMbCount),
2311 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10] / iMbCount),
2312 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][PSkip] / iMbCount),
2313 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][11] / iMbCount),
2314 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][11] / count_p_mbL0),
2315 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][8] / count_p_mbL0),
2316 (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][9] / count_p_mbL0)
2317 );
2318 }
2319 }
2320#endif //#if defined(MB_TYPES_CHECK)
2321
2322 if (iCount > 0){
2323 fprintf( stdout, "SVC: overall PSNR Y: %2.3f U: %2.3f V: %2.3f kb/s: %.1f fps: %.3f\n\n",
2324 (pCtx->sStatData[i][j].sQualityStat.rYPsnr[I_SLICE]+pCtx->sStatData[i][j].sQualityStat.rYPsnr[P_SLICE]+pCtx->sStatData[i][j].sQualityStat.rYPsnr[B_SLICE]) / (float)(iCount),
2325 (pCtx->sStatData[i][j].sQualityStat.rUPsnr[I_SLICE]+pCtx->sStatData[i][j].sQualityStat.rUPsnr[P_SLICE]+pCtx->sStatData[i][j].sQualityStat.rUPsnr[B_SLICE]) / (float)(iCount),
2326 (pCtx->sStatData[i][j].sQualityStat.rVPsnr[I_SLICE]+pCtx->sStatData[i][j].sQualityStat.rVPsnr[P_SLICE]+pCtx->sStatData[i][j].sQualityStat.rVPsnr[B_SLICE]) / (float)(iCount),
2327 1.0f * pCtx->pSvcParam->sDependencyLayers[i].fOutputFrameRate *(pCtx->sStatData[i][j].sSliceData.iSliceSize[I_SLICE] +pCtx->sStatData[i][j].sSliceData.iSliceSize[P_SLICE] +pCtx->sStatData[i][j].sSliceData.iSliceSize[B_SLICE] ) / (float)(iCount+pCtx->pWelsSvcRc[i].iSkipFrameNum)/1000,
2328 1.0f * pCtx->pSvcParam->sDependencyLayers[i].fOutputFrameRate );
2329
2330 }
2331
2332 }
2333
2334 }
2335}
2336#endif
2337/*!
2338 * \brief uninitialize Wels encoder core library
2339 * \pParam pEncCtx sWelsEncCtx*
2340 * \return none
2341 */
2342void WelsUninitEncoderExt( sWelsEncCtx **ppCtx )
2343{
2344 if ( NULL == ppCtx || NULL == *ppCtx )
2345 return;
2346
2347 WelsLog( *ppCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), pCtx= %p, iThreadCount= %d, iMultipleThreadIdc= %d.\n", (void *)(*ppCtx), (*ppCtx)->pSvcParam->iCountThreadsNum, (*ppCtx)->pSvcParam->iMultipleThreadIdc );
2348
2349#if defined(STAT_OUTPUT)
2350 StatOverallEncodingExt( *ppCtx );
2351#endif
2352
2353#if defined(MT_ENABLED)
2354 if ( (*ppCtx)->pSvcParam->iMultipleThreadIdc > 1 && (*ppCtx)->pSliceThreading != NULL )
2355 {
2356 const int32_t iThreadCount = (*ppCtx)->pSvcParam->iCountThreadsNum;
2357 int32_t iThreadIdx = 0;
2358
2359#if defined(WIN32)
2360 if ( (*ppCtx)->pSliceThreading->pExitEncodeEvent != NULL )
2361 {
2362 do {
2363 if ( (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] != NULL ) // iThreadIdx is already created successfully
2364 WelsEventSignal( &(*ppCtx)->pSliceThreading->pExitEncodeEvent[iThreadIdx] );
2365 ++ iThreadIdx;
2366 } while(iThreadIdx < iThreadCount);
2367
2368 WelsMultipleEventsWaitAllBlocking( iThreadCount, &(*ppCtx)->pSliceThreading->pFinSliceCodingEvent[0] );
2369
2370 }
2371#elif defined(__GNUC__)
2372 while ( iThreadIdx < iThreadCount )
2373 {
2374 int res = 0;
2375 if ( (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] )
2376 {
2377 res = WelsThreadCancel( (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] );
2378 WelsLog( *ppCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), WelsThreadCancel(pThreadHandles%d) return %d..\n", iThreadIdx, res);
2379 res = WelsThreadJoin( (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] ); // waiting thread exit
2380 WelsLog( *ppCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), pthread_join(pThreadHandles%d) return %d..\n", iThreadIdx, res);
2381 (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] = 0;
2382 }
2383#if defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
2384 if ( (*ppCtx)->pSliceThreading->pUpdateMbListThrdHandles[iThreadIdx] )
2385 {
2386 res = WelsThreadCancel( (*ppCtx)->pSliceThreading->pUpdateMbListThrdHandles[iThreadIdx] );
2387 WelsLog( *ppCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), WelsThreadCancel(pUpdateMbListThrdHandles%d) return %d..\n", iThreadIdx, res);
2388 res = WelsThreadJoin( (*ppCtx)->pSliceThreading->pUpdateMbListThrdHandles[iThreadIdx] ); // waiting thread exit
2389 WelsLog( *ppCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), pthread_join(pUpdateMbListThrdHandles%d) return %d..\n", iThreadIdx, res);
2390 (*ppCtx)->pSliceThreading->pUpdateMbListThrdHandles[iThreadIdx] = 0;
2391 }
2392#endif//DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE
2393 ++ iThreadIdx;
2394 }
2395#endif//WIN32
2396 }
2397#endif//MT_ENABLED
2398
2399 if ((*ppCtx)->pVpp)
2400 {
2401 delete (*ppCtx)->pVpp;
2402 (*ppCtx)->pVpp = NULL;
2403 }
2404 FreeMemorySvc( ppCtx );
2405 *ppCtx = NULL;
2406}
2407
2408/*!
2409 * \brief get temporal level due to configuration and coding context
2410 */
2411static inline int32_t GetTemporalLevel( SDLayerParam *fDlp, const int32_t kiFrameNum, const int32_t kiGopSize )
2412{
2413 const int32_t kiCodingIdx = kiFrameNum & (kiGopSize-1);
2414
2415 return fDlp->uiCodingIdx2TemporalId[kiCodingIdx];
2416}
2417
2418void DynslcUpdateMbNeighbourInfoListForAllSlices( SSliceCtx *pSliceCtx, SMB *pMbList )
2419{
2420 const int32_t kiMbWidth = pSliceCtx->iMbWidth;
2421 const int32_t kiEndMbInSlice = pSliceCtx->iMbNumInFrame - 1;
2422 int32_t iIdx = 0;
2423
2424 do {
2425 SMB *pMb = &pMbList[iIdx];
2426 uint32_t uiNeighborAvailFlag = 0;
2427 const int32_t kiMbXY = pMb->iMbXY;
2428 const int32_t kiMbX = pMb->iMbX;
2429 const int32_t kiMbY = pMb->iMbY;
2430 BOOL_T bLeft;
2431 BOOL_T bTop;
2432 BOOL_T bLeftTop;
2433 BOOL_T bRightTop;
2434 int32_t uiSliceIdc;
2435 int32_t iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;
2436
2437 uiSliceIdc = WelsMbToSliceIdc(pSliceCtx, kiMbXY);
2438 pMb->uiSliceIdc = uiSliceIdc;
2439 iLeftXY = kiMbXY - 1;
2440 iTopXY = kiMbXY - kiMbWidth;
2441 iLeftTopXY = iTopXY - 1;
2442 iRightTopXY = iTopXY + 1;
2443
2444 bLeft = (kiMbX > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iLeftXY));
2445 bTop = (kiMbY > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iTopXY));
2446 bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iLeftTopXY));
2447 bRightTop = (kiMbX < (kiMbWidth-1)) && (kiMbY > 0) && (uiSliceIdc == WelsMbToSliceIdc(pSliceCtx, iRightTopXY));
2448
2449 if( bLeft ){
2450 uiNeighborAvailFlag |= LEFT_MB_POS;
2451 }
2452 if( bTop ){
2453 uiNeighborAvailFlag |= TOP_MB_POS;
2454 }
2455 if( bLeftTop ){
2456 uiNeighborAvailFlag |= TOPLEFT_MB_POS;
2457 }
2458 if( bRightTop ){
2459 uiNeighborAvailFlag |= TOPRIGHT_MB_POS;
2460 }
2461 pMb->uiNeighborAvail = (uint8_t)uiNeighborAvailFlag;
2462
2463 ++ iIdx;
2464 } while(iIdx <= kiEndMbInSlice);
2465}
2466
2467/*
2468 * TUNE back if number of picture partition decision algorithm based on past if available
2469 */
2470int32_t PicPartitionNumDecision( sWelsEncCtx *pCtx )
2471{
2472 int32_t iPartitionNum = 1;
2473#ifdef MT_ENABLED
2474 if ( pCtx->pSvcParam->iMultipleThreadIdc > 1 )
2475 {
2476 iPartitionNum = pCtx->pSvcParam->iCountThreadsNum;
2477#if !defined(FIXED_PARTITION_ASSIGN)
2478 if ( P_SLICE == pCtx->eSliceType )
2479 iPartitionNum = 1;
2480#endif//!FIXED_PARTITION_ASSIGN
2481 }
2482 return iPartitionNum;
2483#else
2484 return iPartitionNum;
2485#endif//MT_ENABLED
2486}
2487
2488#if defined(MT_ENABLED)
2489void WelsInitCurrentQBLayerMltslc( sWelsEncCtx *pCtx )
2490{
2491 //pData init
2492 SDqLayer* pCurDq = pCtx->pCurDqLayer;
2493 SSliceCtx* pSliceCtx = (pCurDq->pSliceEncCtx);
2494
2495 //mb_neighbor
2496 DynslcUpdateMbNeighbourInfoListForAllSlices( pSliceCtx, pCurDq->sMbDataP );
2497}
2498
2499void UpdateSlicepEncCtxWithPartition( SSliceCtx *pSliceCtx, int32_t iPartitionNum )
2500{
2501 const int32_t kiMbNumInFrame = pSliceCtx->iMbNumInFrame;
2502 int32_t iCountMbNumPerPartition = kiMbNumInFrame;
2503 int32_t iAssignableMbLeft = kiMbNumInFrame;
2504 int32_t iFirstMbIdx = 0;
2505 int32_t i/*, j*/;
2506
2507 if ( iPartitionNum <= 0 )
2508 iPartitionNum = 1;
2509 else if ( iPartitionNum > AVERSLICENUM_CONSTRAINT )
2510 iPartitionNum = AVERSLICENUM_CONSTRAINT; // AVERSLICENUM_CONSTRAINT might be variable, however not fixed by MACRO
2511 iCountMbNumPerPartition /= iPartitionNum;
2512 pSliceCtx->iSliceNumInFrame = iPartitionNum;
2513 i = 0;
2514 while( i < iPartitionNum )
2515 {
2516 if ( i + 1 == iPartitionNum )
2517 {
2518 pSliceCtx->pCountMbNumInSlice[i] = iAssignableMbLeft;
2519 }
2520 else
2521 {
2522 pSliceCtx->pCountMbNumInSlice[i] = iCountMbNumPerPartition;
2523 }
2524 pSliceCtx->pFirstMbInSlice[i] = iFirstMbIdx;
2525
2526 memset( pSliceCtx->pOverallMbMap+iFirstMbIdx, (uint8_t)i, pSliceCtx->pCountMbNumInSlice[i]*sizeof(uint8_t) );
2527
2528 // for next partition(or pSlice)
2529 iFirstMbIdx += pSliceCtx->pCountMbNumInSlice[i];
2530 iAssignableMbLeft -= pSliceCtx->pCountMbNumInSlice[i];
2531 ++ i;
2532 }
2533}
2534
2535void WelsInitCurrentDlayerMltslc( sWelsEncCtx *pCtx, int32_t iPartitionNum )
2536{
2537 SDqLayer* pCurDq = pCtx->pCurDqLayer;
2538 SSliceCtx* pSliceCtx = pCurDq->pSliceEncCtx;
2539
2540 UpdateSlicepEncCtxWithPartition( pSliceCtx, iPartitionNum );
2541
2542 if ( I_SLICE == pCtx->eSliceType )//check if uiSliceSizeConstraint too small
2543 {
2544#define byte_complexIMBat26 (60)
2545 uint8_t iCurDid = pCtx->uiDependencyId;
2546 uint32_t uiFrmByte = 0;
2547
2548 if ( pCtx->pSvcParam->bEnableRc )
2549 {//RC case
2550 uiFrmByte = (
2551 ( (uint32_t)(pCtx->pSvcParam->sDependencyLayers[iCurDid].iSpatialBitrate)
2552 /(uint32_t)(pCtx->pSvcParam->sDependencyLayers[iCurDid].fInputFrameRate) ) >> 3 );
2553 }
2554 else
2555 {//fixed QP case
2556 const int32_t iTtlMbNumInFrame = pSliceCtx->iMbNumInFrame;
2557 int32_t iQDeltaTo26 = ( 26 - pCtx->pSvcParam->sDependencyLayers[iCurDid].iDLayerQp );
2558
2559 uiFrmByte = (iTtlMbNumInFrame * byte_complexIMBat26);
2560 if ( iQDeltaTo26 > 0 )
2561 {
2562 //smaller QP than 26
2563 uiFrmByte = (uint32_t)( uiFrmByte * ( (float)iQDeltaTo26 / 4 ) );
2564 }
2565 else if ( iQDeltaTo26 < 0 )
2566 {
2567 //larger QP than 26
2568 iQDeltaTo26 = ( (-iQDeltaTo26) >> 2 ); //delta mod 4
2569 uiFrmByte = ( uiFrmByte >> (iQDeltaTo26) ); //if delta 4, byte /2
2570 }
2571 }
2572
2573 //MINPACKETSIZE_CONSTRAINT
2574 if ( pSliceCtx->uiSliceSizeConstraint
2575 <
2576 (uint32_t)( uiFrmByte//suppose 16 byte per mb at average
2577 / ( pSliceCtx->iMaxSliceNumConstraint ) )
2578 )
2579 {
2580
2581 WelsLog( pCtx,
2582 WELS_LOG_WARNING,
2583 "Set-SliceConstraint(%d) too small for current resolution (MB# %d) under QP/BR!\n",
2584 pSliceCtx->uiSliceSizeConstraint,
2585 pSliceCtx->iMbNumInFrame
2586 );
2587 }
2588 }
2589
2590 WelsInitCurrentQBLayerMltslc( pCtx );
2591}
2592#else
2593void WelsInitCurrentQBLayerMltslc( sWelsEncCtx *pCtx )
2594{
2595 //pData init
2596 SDqLayer* pCurDq = pCtx->pCurDqLayer;
2597 SSliceCtx* pSliceCtx = (pCurDq->pSliceEncCtx);
2598 SSlice * pSlice = &pCurDq->sLayerInfo.pSliceInLayer[0];
2599 int32_t iTtlMbNumInFrame = pSliceCtx->iMbNumInFrame;
2600
2601 //pSliceCtx
2602 memset( pSliceCtx->pOverallMbMap, 0, iTtlMbNumInFrame * sizeof(uint8_t) );
2603 memset( pSliceCtx->pCountMbNumInSlice, 0, pSliceCtx->iSliceNumInFrame * sizeof(int32_t) );
2604 memset( pSliceCtx->pFirstMbInSlice, 0, pSliceCtx->iSliceNumInFrame * sizeof(int16_t) );
2605 pSliceCtx->iSliceNumInFrame = 1;//
2606 pSliceCtx->pCountMbNumInSlice[0] = iTtlMbNumInFrame;
2607
2608 //mb_neighbor
2609 DynslcUpdateMbNeighbourInfoListForAllSlices( pSliceCtx, pCurDq->sMbDataP );
2610
2611 //pSlice init
2612 pSlice->uiSliceIdx = 0;
2613 pSlice->pSliceBsa = &pCtx->pOut->sBsWrite;
2614 pSlice->bDynamicSlicingSliceSizeCtrlFlag = false;
2615 pSlice->uiAssumeLog2BytePerMb = ( pCtx->eSliceType == P_SLICE ) ? 0 : 1;
2616}
2617
2618void WelsInitCurrentDlayerMltslc( sWelsEncCtx *pCtx, int32_t iPartitionNum )
2619{
2620 SDqLayer* pCurDq = pCtx->pCurDqLayer;
2621 SSliceCtx* pSliceCtx = ( pCurDq->pSliceEncCtx );
2622 int32_t iTtlMbNumInFrame = pCurDq->iMbHeight*pCurDq->iMbWidth;
2623
2624 pSliceCtx->iMbNumInFrame
2625 = pSliceCtx->pCountMbNumInSlice[0] = iTtlMbNumInFrame;
2626
2627 if ( I_SLICE == pCtx->eSliceType )//check if uiSliceSizeConstraint too small
2628 {
2629#define byte_complexIMBat26 (60)
2630 uint8_t iCurDid = pCtx->uiDependencyId;
2631 uint32_t uiFrmByte = 0;
2632
2633 if ( pCtx->pSvcParam->bEnableRc )
2634 {//RC case
2635 uiFrmByte = (
2636 ( (uint32_t)(pCtx->pSvcParam->sDependencyLayers[iCurDid].iSpatialBitrate)
2637 /(uint32_t)(pCtx->pSvcParam->sDependencyLayers[iCurDid].fInputFrameRate) ) >> 3 );
2638 }
2639 else
2640 {//fixed QP case
2641 int32_t iQDeltaTo26 = ( 26 - pCtx->pSvcParam->sDependencyLayers[iCurDid].iDLayerQp );
2642
2643 uiFrmByte = (iTtlMbNumInFrame * byte_complexIMBat26);
2644 if ( iQDeltaTo26 > 0 )
2645 {
2646 //smaller QP than 26
2647 uiFrmByte = (uint32_t)( uiFrmByte * ( (float)iQDeltaTo26 / 4 ) );
2648 }
2649 else if ( iQDeltaTo26 < 0 )
2650 {
2651 //larger QP than 26
2652 iQDeltaTo26 = ( (-iQDeltaTo26) >> 2 ); //delta mod 4
2653 uiFrmByte = ( uiFrmByte >> (iQDeltaTo26) ); //if delta 4, byte /2
2654 }
2655 }
2656
2657 //MINPACKETSIZE_CONSTRAINT
2658 if ( pSliceCtx->uiSliceSizeConstraint
2659 <
2660 (uint32_t)( uiFrmByte//suppose 16 byte per mb at average
2661 / ( pSliceCtx->iMaxSliceNumConstraint ) )
2662 )
2663 {
2664
2665 WelsLog( pCtx,
2666 WELS_LOG_WARNING,
2667 "Set-SliceConstraint(%d) too small for current resolution (MB# %d) under QP/BR!\n",
2668 pSliceCtx->uiSliceSizeConstraint,
2669 pSliceCtx->iMbNumInFrame
2670 );
2671 }
2672 }
2673
2674 WelsInitCurrentQBLayerMltslc( pCtx );
2675}
2676#endif
2677
2678/*!
2679 * \brief initialize current layer
2680 */
2681void WelsInitCurrentLayer( sWelsEncCtx *pCtx,
2682 const int32_t kiWidth,
2683 const int32_t kiHeight )
2684{
2685 SWelsSvcCodingParam *pParam = pCtx->pSvcParam;
2686 SPicture *pEncPic = pCtx->pEncPic;
2687 SPicture *pDecPic = pCtx->pDecPic;
2688 SDqLayer *pCurDq = pCtx->pCurDqLayer;
2689 SSlice *pBaseSlice = &pCurDq->sLayerInfo.pSliceInLayer[0];
2690 SSlice *pSlice = NULL;
2691 const uint8_t kiCurDid = pCtx->uiDependencyId;
2692 const bool_t kbUseSubsetSpsFlag= (kiCurDid > BASE_DEPENDENCY_ID);
2693 SDLayerParam *fDlp = &pParam->sDependencyLayers[kiCurDid];
2694 SNalUnitHeaderExt *pNalHdExt = &pCurDq->sLayerInfo.sNalHeaderExt;
2695 SNalUnitHeader *pNalHd = &pNalHdExt->sNalHeader;
2696 SDqIdc *pDqIdc = &pCtx->pDqIdcMap[kiCurDid];
2697 int32_t iIdx = 0;
2698 int32_t iSliceCount = 0;
2699
2700 if ( NULL == pCurDq )
2701 return;
2702
2703 pCurDq->pDecPic = pDecPic;
2704
2705 if ( fDlp->sMso.uiSliceMode == SM_DYN_SLICE ) // need get extra slices for update
2706 iSliceCount = GetInitialSliceNum( pCurDq->iMbWidth, pCurDq->iMbHeight, &fDlp->sMso );
2707 else
2708 iSliceCount = GetCurrentSliceNum( pCurDq->pSliceEncCtx );
2709 assert( iSliceCount > 0 );
2710
2711 pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId = pDqIdc->iPpsId;
2712 pCurDq->sLayerInfo.pPpsP =
2713 pBaseSlice->sSliceHeaderExt.sSliceHeader.pPps = &pCtx->pPPSArray[pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId];
2714 pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId = pDqIdc->iSpsId;
2715 if ( kbUseSubsetSpsFlag )
2716 {
2717 pCurDq->sLayerInfo.pSubsetSpsP = &pCtx->pSubsetArray[pDqIdc->iSpsId];
2718 pCurDq->sLayerInfo.pSpsP =
2719 pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps = &pCurDq->sLayerInfo.pSubsetSpsP->pSps;
2720 }
2721 else
2722 {
2723 pCurDq->sLayerInfo.pSubsetSpsP = NULL;
2724 pCurDq->sLayerInfo.pSpsP =
2725 pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps = &pCtx->pSpsArray[pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId];
2726 }
2727
2728 pSlice = pBaseSlice;
2729 iIdx = 1;
2730 while ( iIdx < iSliceCount ) {
2731 ++ pSlice;
2732 pSlice->sSliceHeaderExt.sSliceHeader.iPpsId = pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId;
2733 pSlice->sSliceHeaderExt.sSliceHeader.pPps = pBaseSlice->sSliceHeaderExt.sSliceHeader.pPps;
2734 pSlice->sSliceHeaderExt.sSliceHeader.iSpsId = pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId;
2735 pSlice->sSliceHeaderExt.sSliceHeader.pSps = pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps;
2736 ++ iIdx;
2737 }
2738
2739 memset( pNalHdExt, 0, sizeof(SNalUnitHeaderExt) );
2740 pNalHd->uiNalRefIdc = pCtx->eNalPriority;
2741 pNalHd->eNalUnitType = pCtx->eNalType;
2742
2743 pNalHdExt->uiDependencyId = kiCurDid;
2744 pNalHdExt->bDiscardableFlag = (pCtx->bNeedPrefixNalFlag) ? (pNalHd->uiNalRefIdc == NRI_PRI_LOWEST) : false;
2745 pNalHdExt->bIdrFlag = (pCtx->iFrameNum == 0) && ((pCtx->eNalType == NAL_UNIT_CODED_SLICE_IDR) || (pCtx->eSliceType == I_SLICE));
2746 pNalHdExt->uiTemporalId = pCtx->uiTemporalId;
2747
2748 pBaseSlice->bSliceHeaderExtFlag = (NAL_UNIT_CODED_SLICE_EXT == pNalHd->eNalUnitType);
2749
2750 pSlice = pBaseSlice;
2751 iIdx = 1;
2752 while (iIdx < iSliceCount) {
2753 ++ pSlice;
2754 pSlice->bSliceHeaderExtFlag = pBaseSlice->bSliceHeaderExtFlag;
2755 ++ iIdx;
2756 }
2757
2758 // pEncPic pData
2759 pCurDq->pEncData[0] = pEncPic->pData[0];
2760 pCurDq->pEncData[1] = pEncPic->pData[1];
2761 pCurDq->pEncData[2] = pEncPic->pData[2];
2762 pCurDq->iEncStride[0] = pEncPic->iLineSize[0];
2763 pCurDq->iEncStride[1] = pEncPic->iLineSize[1];
2764 pCurDq->iEncStride[2] = pEncPic->iLineSize[2];
2765 // cs pData
2766 pCurDq->pCsData[0] = pDecPic->pData[0];
2767 pCurDq->pCsData[1] = pDecPic->pData[1];
2768 pCurDq->pCsData[2] = pDecPic->pData[2];
2769 pCurDq->iCsStride[0] = pDecPic->iLineSize[0];
2770 pCurDq->iCsStride[1] = pDecPic->iLineSize[1];
2771 pCurDq->iCsStride[2] = pDecPic->iLineSize[2];
2772
2773 if ( pCurDq->pRefLayer != NULL )
2774 {
2775 pCurDq->bBaseLayerAvailableFlag = true;
2776 }
2777 else
2778 {
2779 pCurDq->bBaseLayerAvailableFlag = false;
2780 }
2781}
2782
2783void PreprocessSliceCoding( sWelsEncCtx *pCtx )
2784{
2785 SDqLayer *pCurLayer = pCtx->pCurDqLayer;
2786 const bool_t kbBaseAvail = pCurLayer->bBaseLayerAvailableFlag;
2787
2788 /* function pointers conditional assignment under sWelsEncCtx, layer_mb_enc_rec (in stack) is exclusive */
2789
2790 if ( P_SLICE == pCtx->eSliceType )
2791 {
2792 if ( kbBaseAvail )
2793 {
2794 if ( pCtx->pSvcParam->iNumDependencyLayer == (pCurLayer->sLayerInfo.sNalHeaderExt.uiDependencyId + 1) ) //
2795 {
2796 pCtx->pFuncList->pfMotionSearch = WelsMotionEstimateSearchSad;
2797 pCtx->pFuncList->pfFirstIntraMode = WelsMdFirstIntraMode;
2798 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartitionVaa;
2799 pCtx->pFuncList->pfInterFineMd = WelsMdInterFinePartitionVaa;
2800 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Sad;
2801 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Sad;
2802 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSad;
2803 }
2804 else
2805 {
2806 pCtx->pFuncList->pfMotionSearch = WelsMotionEstimateSearchSatd;
2807 pCtx->pFuncList->pfFirstIntraMode = WelsMdFirstIntraMode;
2808 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartition;
2809 pCtx->pFuncList->pfInterFineMd = WelsMdInterFinePartition;
2810 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2811 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Satd;
2812 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Satd;
2813 pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3Satd;
2814 }
2815 pCtx->pFuncList->sSampleDealingFuncs.pfMeCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2816 }
2817 else
2818 {
2819 //case 3: pBase layer MD + encoding
2820 if ( pCurLayer->sLayerInfo.sNalHeaderExt.uiDependencyId+1 == pCtx->pSvcParam->iNumDependencyLayer )
2821 {
2822 pCtx->pFuncList->pfMotionSearch = WelsMotionEstimateSearchSad;
2823 pCtx->pFuncList->pfFirstIntraMode = WelsMdFirstIntraMode;
2824 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartitionVaa;
2825 pCtx->pFuncList->pfInterFineMd = WelsMdInterFinePartitionVaa;
2826 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSad;
2827 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Sad;
2828 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Sad;
2829 }
2830 else
2831 {
2832 pCtx->pFuncList->pfMotionSearch = WelsMotionEstimateSearchSatd;
2833 pCtx->pFuncList->pfFirstIntraMode = WelsMdFirstIntraMode;
2834 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartition;
2835 pCtx->pFuncList->pfInterFineMd = WelsMdInterFinePartition;
2836 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2837 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Satd;
2838 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Satd;
2839 pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3Satd;
2840 }
2841 pCtx->pFuncList->sSampleDealingFuncs.pfMeCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2842 }
2843 }
2844 else if ( I_SLICE == pCtx->eSliceType )
2845 {
2846 if ( pCurLayer->sLayerInfo.sNalHeaderExt.uiDependencyId+1 == pCtx->pSvcParam->iNumDependencyLayer )
2847 {
2848 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSad;
2849 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Sad;
2850 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Sad;
2851 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartitionVaa;
2852 }
2853 else
2854 {
2855 pCtx->pFuncList->sSampleDealingFuncs.pfMdCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2856 pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Satd;
2857 pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Satd;
2858 pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3 = pCtx->pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3Satd;
2859 pCtx->pFuncList->pfIntraFineMd = WelsMdIntraFinePartition;
2860 }
2861 }
2862}
2863
2864/*!
2865 * \brief swap pDq layers between current pDq layer and reference pDq layer
2866 */
2867
2868static inline void WelsSwapDqLayers( sWelsEncCtx *pCtx )
2869{
2870 // swap and assign reference
2871 const int32_t kiDid = pCtx->uiDependencyId;
2872 const int32_t kiNextDqIdx = 1 + kiDid;
2873
2874 SDqLayer *pTmpLayer = pCtx->ppDqLayerList[kiNextDqIdx];
2875 SDqLayer *pRefLayer = pCtx->pCurDqLayer;
2876 pCtx->pCurDqLayer = pTmpLayer;
2877 pCtx->pCurDqLayer->pRefLayer = pRefLayer;
2878}
2879
2880/*!
2881 * \brief prefetch reference picture after WelsBuildRefList
2882 */
2883static inline void PrefetchReferencePicture( sWelsEncCtx *pCtx, const EFrameType keFrameType )
2884{
2885 SSlice *pSliceBase = &pCtx->pCurDqLayer->sLayerInfo.pSliceInLayer[0];
2886 const int32_t kiSliceCount = GetCurrentSliceNum( pCtx->pCurDqLayer->pSliceEncCtx );
2887 int32_t iIdx = 0;
2888 uint8_t uiRefIdx = -1;
2889
2890 assert( kiSliceCount > 0 );
2891 if ( keFrameType != WELS_FRAME_TYPE_IDR )
2892 {
2893 assert( pCtx->iNumRef0 > 0 );
2894 pCtx->pRefPic = pCtx->pRefList0[0]; // always get item 0 due to reordering done
2895 pCtx->pCurDqLayer->pRefPic = pCtx->pRefPic;
2896 uiRefIdx = 0; // reordered reference iIndex
2897 }
2898 else // safe for IDR coding
2899 {
2900 pCtx->pRefPic = NULL;
2901 pCtx->pCurDqLayer->pRefPic = NULL;
2902 }
2903
2904 iIdx = 0;
2905 while (iIdx < kiSliceCount) {
2906 pSliceBase->sSliceHeaderExt.sSliceHeader.uiRefIndex = uiRefIdx;
2907 ++ pSliceBase;
2908 ++ iIdx;
2909 }
2910}
2911
2912
2913void ParasetIdAdditionIdAdjust( SParaSetOffsetVariable *sParaSetOffsetVariable, const int32_t kiCurEncoderParaSetId, const uint32_t kuiMaxIdInBs )//paraset_type = 0: SPS; =1: PPS
2914{
2915 //SPS_ID in avc_sps and pSubsetSps will be different using this
2916 //SPS_ID case example:
2917 //1st enter: next_spsid_in_bs == 0; spsid == 0; delta==0; //actual spsid_in_bs == 0
2918 //1st finish: next_spsid_in_bs == 1;
2919 //2nd enter: next_spsid_in_bs == 1; spsid == 0; delta==1; //actual spsid_in_bs == 1
2920 //2nd finish: next_spsid_in_bs == 2;
2921 //31st enter: next_spsid_in_bs == 31; spsid == 0~2; delta==31~29; //actual spsid_in_bs == 31
2922 //31st finish: next_spsid_in_bs == 0;
2923 //31st enter: next_spsid_in_bs == 0; spsid == 0~2; delta==-2~0; //actual spsid_in_bs == 0
2924 //31st finish: next_spsid_in_bs == 1;
2925
2926 const int32_t kiEncId = kiCurEncoderParaSetId;
2927 const uint32_t kuiPrevIdInBs = sParaSetOffsetVariable->iParaSetIdDelta[kiEncId] + kiEncId;//mark current_id
2928 const bool_t *kpUsedIdPointer = &sParaSetOffsetVariable->bUsedParaSetIdInBs[0];
2929 uint32_t uiNextIdInBs = sParaSetOffsetVariable->uiNextParaSetIdToUseInBs;
2930
2931#if _DEBUG
2932 if ( 0 != sParaSetOffsetVariable->iParaSetIdDelta[kiEncId] )
2933 assert ( sParaSetOffsetVariable->bUsedParaSetIdInBs[kuiPrevIdInBs] ); //sure the prev-used one was marked activated correctly
2934#endif
2935 //update current layer's pCodingParam
2936 sParaSetOffsetVariable->iParaSetIdDelta[kiEncId] = uiNextIdInBs - kiEncId; //for current parameter set, change its id_delta
2937 //write pso pData for next update:
2938 sParaSetOffsetVariable->bUsedParaSetIdInBs[kuiPrevIdInBs] = false; //
2939 sParaSetOffsetVariable->bUsedParaSetIdInBs[uiNextIdInBs] = true; // update current used_id
2940
2941 //prepare for next update:
2942 // find the next avaibable iId
2943 do
2944 {
2945 ++uiNextIdInBs;
2946 if (uiNextIdInBs >= kuiMaxIdInBs )
2947 {
2948 uiNextIdInBs = 0;//ensure the SPS_ID wound not exceed MAX_SPS_COUNT
2949 }
2950 }while ( kpUsedIdPointer[uiNextIdInBs] );
2951
2952 // update next_id
2953 sParaSetOffsetVariable->uiNextParaSetIdToUseInBs = uiNextIdInBs;
2954
2955#if _DEBUG
2956 assert ( !sParaSetOffsetVariable->bUsedParaSetIdInBs[uiNextIdInBs] ); //sure the next-to-use one is marked activated correctly
2957#endif
2958
2959}
2960
2961/*!
2962 * \brief write all parameter sets introduced in SVC extension
2963 * \return size in bytes of bitstream wrote
2964 */
2965int32_t WelsWriteParameterSets( sWelsEncCtx *pCtx, int32_t *pNalLen, int32_t *pNumNal )
2966{
2967 int32_t iSize = 0;
2968 int32_t iNal = 0;
2969 int32_t iIdx = 0;
2970 int32_t iId = 0;
2971 int32_t iCountNal = 0;
2972
2973 if ( NULL == pCtx || NULL == pNalLen || NULL == pNumNal )
2974 return 0;
2975
2976 /* write all SPS */
2977 iIdx = 0;
2978 while (iIdx < pCtx->iSpsNum) {
2979 SDqIdc *pDqIdc = &pCtx->pDqIdcMap[iIdx];
2980 const int32_t kiDid = pDqIdc->uiSpatialId;
2981 const bool_t kbUsingSubsetSps = (kiDid > BASE_DEPENDENCY_ID);
2982
2983 iNal = pCtx->pOut->iNalIndex;
2984
2985 if ( pCtx->pSvcParam->bEnableSpsPpsIdAddition )
2986 {
2987#if _DEBUG
2988 pCtx->sPSOVector.bEnableSpsPpsIdAddition = 1;
2989 assert(kiDid < MAX_DEPENDENCY_LAYER);
2990 assert(iIdx < MAX_DQ_LAYER_NUM);
2991#endif
2992
2993 ParasetIdAdditionIdAdjust( &(pCtx->sPSOVector.sParaSetOffsetVariable[kbUsingSubsetSps ? PARA_SET_TYPE_SUBSETSPS : PARA_SET_TYPE_AVCSPS]),
2994 (kbUsingSubsetSps)?(pCtx->pSubsetArray[iIdx - 1].pSps.uiSpsId):(pCtx->pSpsArray[0].uiSpsId ),
2995 MAX_SPS_COUNT );
2996 }
2997 else
2998 {
2999 memset(&(pCtx->sPSOVector), 0, sizeof(pCtx->sPSOVector) );
3000 }
3001
3002 if ( kbUsingSubsetSps ){
3003 iId = iIdx - 1;
3004
3005 /* generate Subset SPS */
3006 WelsLoadNal( pCtx->pOut, NAL_UNIT_SUBSET_SPS, NRI_PRI_HIGHEST );
3007
3008 WelsWriteSubsetSpsSyntax( &pCtx->pSubsetArray[iId], &pCtx->pOut->sBsWrite, &(pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_SUBSETSPS].iParaSetIdDelta[0]) );
3009 WelsUnloadNal( pCtx->pOut );
3010 }
3011 else{
3012 iId = 0;
3013
3014 /* generate sequence parameters set */
3015 WelsLoadNal( pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST );
3016 WelsWriteSpsNal( &pCtx->pSpsArray[0], &pCtx->pOut->sBsWrite, &(pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS].iParaSetIdDelta[0]) );
3017 WelsUnloadNal( pCtx->pOut );
3018 }
3019
3020 pNalLen[iCountNal] = WelsEncodeNal( &pCtx->pOut->sNalList[iNal], pCtx->pFrameBs + pCtx->iPosBsBuffer, &pNalLen[iCountNal] );
3021
3022 pCtx->iPosBsBuffer += pNalLen[iCountNal];
3023 iSize += pNalLen[iCountNal];
3024
3025 ++ iIdx;
3026 ++ iCountNal;
3027 }
3028
3029 /* write all PPS */
3030 iIdx = 0;
3031 while (iIdx < pCtx->iPpsNum) {
3032 if ( pCtx->pSvcParam->bEnableSpsPpsIdAddition )
3033 {
3034 //para_set_type = 2: PPS, use MAX_PPS_COUNT
3035 ParasetIdAdditionIdAdjust( &pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_PPS], pCtx->pPPSArray[iIdx].iPpsId, MAX_PPS_COUNT );
3036 }
3037
3038 iNal = pCtx->pOut->iNalIndex;
3039 /* generate picture parameter set */
3040 WelsLoadNal( pCtx->pOut, NAL_UNIT_PPS, NRI_PRI_HIGHEST );
3041 WelsWritePpsSyntax( &pCtx->pPPSArray[iIdx], &pCtx->pOut->sBsWrite, &(pCtx->sPSOVector) );
3042 WelsUnloadNal( pCtx->pOut );
3043
3044 pNalLen[iCountNal] = WelsEncodeNal( &pCtx->pOut->sNalList[iNal], pCtx->pFrameBs + pCtx->iPosBsBuffer, &pNalLen[iCountNal] );
3045
3046 pCtx->iPosBsBuffer += pNalLen[iCountNal];
3047 iSize += pNalLen[iCountNal];
3048
3049 ++ iIdx;
3050 ++ iCountNal;
3051 }
3052
3053 *pNumNal = iCountNal;
3054
3055 return iSize;
3056}
3057
3058static inline int32_t AddPrefixNal( sWelsEncCtx *pCtx,
3059 SLayerBSInfo *pLayerBsInfo,
3060 int32_t *pNalLen,
3061 int32_t *pNalIdxInLayer,
3062 const EWelsNalUnitType keNalType,
3063 const EWelsNalRefIdc keNalRefIdc )
3064{
3065 int32_t iPayloadSize = 0;
3066
3067 if ( keNalRefIdc != NRI_PRI_LOWEST )
3068 {
3069 WelsLoadNal( pCtx->pOut, NAL_UNIT_PREFIX, keNalRefIdc );
3070
3071 WelsWriteSVCPrefixNal( &pCtx->pOut->sBsWrite, keNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == keNalType) );
3072
3073 WelsUnloadNal( pCtx->pOut );
3074
3075 iPayloadSize = WelsEncodeNalExt( &pCtx->pOut->sNalList[pCtx->pOut->iNalIndex-1],
3076 &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3077 pCtx->pFrameBs + pCtx->iPosBsBuffer,
3078 &pNalLen[*pNalIdxInLayer] );
3079
3080 pCtx->iPosBsBuffer += iPayloadSize;
3081 pLayerBsInfo->iNalLengthInByte[*pNalIdxInLayer] = iPayloadSize;
3082
3083 (*pNalIdxInLayer) ++;
3084 }
3085 else // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
3086 {
3087 WelsLoadNal( pCtx->pOut, NAL_UNIT_PREFIX, keNalRefIdc );
3088 // No need write any syntax of prefix NAL Unit RBSP here
3089 WelsUnloadNal( pCtx->pOut );
3090
3091 iPayloadSize = WelsEncodeNalExt( &pCtx->pOut->sNalList[pCtx->pOut->iNalIndex-1],
3092 &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3093 pCtx->pFrameBs + pCtx->iPosBsBuffer,
3094 &pNalLen[*pNalIdxInLayer] );
3095
3096 pCtx->iPosBsBuffer += iPayloadSize;
3097 pLayerBsInfo->iNalLengthInByte[*pNalIdxInLayer] = iPayloadSize;
3098
3099 (*pNalIdxInLayer) ++;
3100 }
3101
3102 return iPayloadSize;
3103}
3104
3105int32_t WritePadding(sWelsEncCtx *pCtx, int32_t iLen)
3106{
3107 int32_t i=0;
3108 int32_t iNal = 0;
3109 SBitStringAux *pBs = NULL;
3110 int32_t iNalLen;
3111 int32_t iSize=0;
3112
3113 iNal = pCtx->pOut->iNalIndex;
3114 pBs = &pCtx->pOut->sBsWrite; // SBitStringAux instance for non VCL NALs decoding
3115
3116 if((pBs->pBufEnd - pBs->pBufPtr) < iLen || iNal >= pCtx->pOut->iCountNals)
3117 {
3118#if GOM_TRACE_FLAG
3119 WelsLog( pCtx, WELS_LOG_ERROR,"[RC] paddingcal pBuffer overflow, bufferlen=%d, paddinglen=%d, iNalIdx= %d, iCountNals= %d\n",
3120 (pBs->pBufEnd-pBs->pBufPtr), iLen, iNal, pCtx->pOut->iCountNals);
3121#endif
3122 return 0;
3123 }
3124
3125 WelsLoadNal( pCtx->pOut, NAL_UNIT_FILLER_DATA, NRI_PRI_LOWEST );
3126
3127 for(i=0;i<iLen;i++)
3128 {
3129 BsWriteBits( pBs, 8, 0xff);
3130 }
3131
3132 BsRbspTrailingBits( pBs );
3133
3134 BsFlush( pBs );
3135
3136 WelsUnloadNal( pCtx->pOut );
3137 iNalLen = WelsEncodeNal( &pCtx->pOut->sNalList[iNal], pCtx->pFrameBs + pCtx->iPosBsBuffer, &iNalLen );
3138
3139 pCtx->iPosBsBuffer += iNalLen;
3140 iSize += iNalLen;
3141
3142 return iSize;
3143}
3144
3145/*
3146 * post process of dynamic slicing bs writing in case PACKING_ONE_SLICE_PER_LAYER
3147 * include: count bs size of over all the slices in layer,
3148 * return: count number of slices in layer
3149 */
3150#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
3151int32_t PostProcDynamicSlicingBsWriting( sWelsEncCtx *pCtx, SLayerBSInfo *pLayerBsInfo, int32_t *pLayerSize, const int32_t kiPartitionCnt )
3152{
3153 SDqLayer *pCurDq = pCtx->pCurDqLayer;
3154 int32_t iPartitionIdx = 0;
3155 int32_t iCheckingIdx = 0;
3156 int32_t iSwappingIdx = -1;
3157 int32_t iSliceCount = 0;
3158 int32_t iLayerSize = 0;
3159
3160 // count number of slices in layer and layer size
3161 while(iPartitionIdx < kiPartitionCnt)
3162 {
3163 const int32_t coded_slice_cnt = pCurDq->pNumSliceCodedOfPartition[iPartitionIdx];
3164 iLayerSize += pCtx->pSliceThreading->pCountBsSizeInPartition[iPartitionIdx];
3165 iSliceCount += coded_slice_cnt;
3166 ++ iPartitionIdx;
3167 }
3168 *pLayerSize = iLayerSize;
3169
3170 // reordering pLayerBs pointers, but do not ensure raster scan order of picture
3171 // just maintain discontinuous items,i.e,
3172 // input:
3173 // partition 1: uiSliceIdx: 0 2 4 6
3174 // partition 2: uiSliceIdx: 1 3 5 7 9 11 13
3175 // output:
3176 // uiSliceIdx: 0 1 2 3 4 5 6 7 8 9 10
3177 iCheckingIdx = 0;
3178 while(true)
3179 {
3180 bool_t bMatchFlag = false;
3181 iPartitionIdx = 0;
3182 while(iPartitionIdx < kiPartitionCnt)
3183 {
3184 const int32_t coded_slice_cnt = pCurDq->pNumSliceCodedOfPartition[iPartitionIdx];
3185 // iCheckingIdx need convert to iIndex of iPartitionIdx based to avoid linear searching
3186 // belong this partition and not exceed the number of slices coded in partition
3187 if ( iPartitionIdx == (iCheckingIdx % kiPartitionCnt)
3188 && iCheckingIdx / kiPartitionCnt < coded_slice_cnt )
3189 {
3190 if ( iSwappingIdx >= 0 )
3191 {
3192 // memory swapping
3193 memmove(pLayerBsInfo+iSwappingIdx, LayerBsInfo+iCheckingIdx, sizeof(SLayerBSInfo)); // confirmed_safe_unsafe_usage
3194 ++ iSwappingIdx; // record iSwappingIdx
3195 }
3196 ++ iCheckingIdx;
3197 bMatchFlag = true;
3198 break;
3199 }
3200 ++ iPartitionIdx;
3201 }
3202 if ( !bMatchFlag )
3203 {
3204 if ( iSwappingIdx < 0 )
3205 iSwappingIdx = iCheckingIdx;
3206 ++ iCheckingIdx;
3207 }
3208 if ( iSwappingIdx >= iSliceCount )
3209 break;
3210 }
3211
3212 return iSliceCount;
3213}
3214#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER
3215
3216/*
3217 * Force coding IDR as follows
3218 */
3219int32_t ForceCodingIDR( sWelsEncCtx *pCtx )
3220{
3221 if ( NULL == pCtx )
3222 return 1;
3223
3224 pCtx->bEncCurFrmAsIdrFlag = true;
3225 pCtx->iCodingIndex = 0;
3226
3227 return 0;
3228}
3229
3230/*!
3231 * \brief core svc encoding process
3232 *
3233 * \pParam pCtx sWelsEncCtx*, encoder context
3234 * \pParam pDst FrameBSInfo*
3235 * \pParam pSrc SSourcePicture* for need_ds = true or SSourcePicture** for need_ds = false
3236 * \pParam iConfiguredLayerNum =1 in case need_ds = true or >1 in case need_ds = false
3237 * \pParam need_ds Indicate whether need down sampling desired
3238 * [NO in picture list case, YES in console aplication based]
3239 * \return EFrameType (WELS_FRAME_TYPE_IDR/WELS_FRAME_TYPE_I/WELS_FRAME_TYPE_P)
3240 */
3241int32_t WelsEncoderEncodeExt( sWelsEncCtx *pCtx, void *pDst, const SSourcePicture **ppSrcList, const int32_t iConfiguredLayerNum )
3242{
3243 SFrameBSInfo *pFbi = (SFrameBSInfo *)pDst;
3244 SLayerBSInfo *pLayerBsInfo = &pFbi->sLayerInfo[0];
3245 SWelsSvcCodingParam *pSvcParam = pCtx->pSvcParam;
3246 SSpatialPicIndex *pSpatialIndexMap= &pCtx->sSpatialIndexMap[0];
3247#if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3248 SPicture *fsnr = NULL;
3249#endif//ENABLE_FRAME_DUMP || ENABLE_PSNR_CALC
3250 SPicture *pEncPic = NULL; // to be decided later
3251#if defined(MT_ENABLED) && (defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG))
3252 int32_t did_list[MAX_DEPENDENCY_LAYER] = {0};
3253#endif//MT_ENABLED && DYNAMIC_SLICE_ASSIGN
3254 int32_t iLayerNum = 0;
3255 int32_t iLayerSize = 0;
3256 int32_t iSpatialNum = 0; // available count number of spatial layers due to frame size changed in this given frame
3257 int32_t iSpatialIdx = 0; // iIndex of spatial layers due to frame size changed in this given frame
3258 int32_t iFrameSize = 0;
3259 int32_t iNalLen[128] = {0};
3260 int32_t iNalIdxInLayer = 0;
3261 int32_t iCountNal = 0;
3262 EFrameType eFrameType = WELS_FRAME_TYPE_AUTO;
3263 int32_t iCurWidth = 0;
3264 int32_t iCurHeight = 0;
3265 EWelsNalUnitType eNalType = NAL_UNIT_UNSPEC_0;
3266 EWelsNalRefIdc eNalRefIdc = NRI_PRI_LOWEST;
3267 int8_t iCurDid = 0;
3268 int8_t iCurTid = 0;
3269 bool_t bAvcBased = false;
3270#if defined(ENABLE_PSNR_CALC)
3271 real32_t snr_y = .0f, snr_u = .0f, snr_v = .0f;
3272#endif//ENABLE_PSNR_CALC
3273
3274#if defined(_DEBUG)
3275 int32_t i = 0, j = 0, k = 0;
3276#endif//_DEBUG
3277
3278 pFbi->iLayerNum = 0; // for initialization
3279
3280 // perform csc/denoise/downsample/padding, generate spatial layers
3281 iSpatialNum = pCtx->pVpp->WelsPreprocessStep1(pCtx, ppSrcList, iConfiguredLayerNum);
3282 if ( iSpatialNum < 1 ) // skip due to temporal layer settings (different frame rate)
3283 {
3284 ++ pCtx->iCodingIndex;
3285 return WELS_FRAME_TYPE_SKIP;
3286 }
3287
3288 eFrameType = DecideFrameType( pCtx, iSpatialNum );
3289 if (eFrameType == WELS_FRAME_TYPE_SKIP)
3290 return eFrameType;
3291
3292 InitFrameCoding( pCtx, eFrameType );
3293
3294 iCurTid = GetTemporalLevel( &pSvcParam->sDependencyLayers[pSpatialIndexMap->iDid], pCtx->iCodingIndex, pSvcParam->uiGopSize );
3295 pCtx->uiTemporalId = iCurTid;
3296
3297 pLayerBsInfo->pBsBuf = pCtx->pFrameBs ;
3298
3299 if ( eFrameType == WELS_FRAME_TYPE_IDR )
3300 {
3301 ++ pCtx->sPSOVector.uiIdrPicId;
3302 //if ( pSvcParam->bEnableSSEI )
3303
3304 // write parameter sets bitstream here
3305 WelsWriteParameterSets( pCtx, &iNalLen[0], &iCountNal );
3306
3307 pLayerBsInfo->uiPriorityId = 0;
3308 pLayerBsInfo->uiSpatialId = 0;
3309 pLayerBsInfo->uiTemporalId = 0;
3310 pLayerBsInfo->uiQualityId = 0;
3311 pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER;
3312 pLayerBsInfo->iNalCount = iCountNal;
3313 for (int32_t iNalIndex = 0; iNalIndex < iCountNal; ++ iNalIndex)
3314 {
3315 pLayerBsInfo->iNalLengthInByte[iNalIndex] = iNalLen[iNalIndex];
3316 }
3317
3318 ++ pLayerBsInfo;
3319 pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3320 ++ iLayerNum;
3321 }
3322
3323 pCtx->pCurDqLayer = pCtx->ppDqLayerList[pSpatialIndexMap->iDid];
3324 pCtx->pCurDqLayer->pRefLayer = NULL;
3325
3326 while ( iSpatialIdx < iSpatialNum )
3327 {
3328 const int32_t d_idx = (pSpatialIndexMap+iSpatialIdx)->iDid; // get iDid
3329 SDLayerParam *param_d = &pSvcParam->sDependencyLayers[d_idx];
3330
3331 pCtx->uiDependencyId = iCurDid = (int8_t)d_idx;
3332 pCtx->pVpp->WelsPreprocessStep3(pCtx, d_idx);
3333
3334 pCtx->pEncPic = pEncPic = (pSpatialIndexMap+iSpatialIdx)->pSrc;
3335 pCtx->pEncPic->iPictureType = pCtx->eSliceType;
3336 pCtx->pEncPic->iFramePoc = pCtx->iPOC;
3337
3338 iCurWidth = param_d->iFrameWidth;
3339 iCurHeight = param_d->iFrameHeight;
3340
3341#if defined(MT_ENABLED) && (defined(DYNAMIC_SLICE_ASSIGN) || defined(MT_DEBUG))
3342 did_list[iSpatialIdx] = iCurDid;
3343#endif//MT_ENABLED && DYNAMIC_SLICE_ASSIGN
3344
3345 // Encoding this picture might mulitiple sQualityStat layers potentially be encoded as followed
3346
3347 switch ( param_d->sMso.uiSliceMode )
3348 {
3349 case SM_FIXEDSLCNUM_SLICE:
3350 {
3351#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN)
3352 if ( (iCurDid > 0) && (pSvcParam->iMultipleThreadIdc > 1) &&
3353 (pSvcParam->sDependencyLayers[iCurDid].sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pSvcParam->iMultipleThreadIdc >= pSvcParam->sDependencyLayers[iCurDid].sMso.sSliceArgument.iSliceNum )
3354 )
3355 AdjustEnhanceLayer( pCtx, iCurDid );
3356#endif//MT_ENABLED && DYNAMIC_SLICE_ASSIGN
3357 break;
3358 }
3359 case SM_DYN_SLICE:
3360 {
3361 int32_t iPicIPartitionNum = PicPartitionNumDecision( pCtx );
3362 // MT compatibility
3363 pCtx->iActiveThreadsNum = iPicIPartitionNum; // we try to active number of threads, equal to number of picture partitions
3364 WelsInitCurrentDlayerMltslc( pCtx, iPicIPartitionNum );
3365 break;
3366 }
3367 default:
3368 {
3369 break;
3370 }
3371 }
3372
3373 /* coding each spatial layer, only one sQualityStat layer within spatial support */
3374 int32_t iSliceCount = 1;
3375 if ( iLayerNum >= MAX_LAYER_NUM_OF_FRAME ) // check available layer_bs_info writing as follows
3376 {
3377 WelsLog( pCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) overflow(max:%d)!", iLayerNum, MAX_LAYER_NUM_OF_FRAME);
3378 return -1;
3379 }
3380
3381 iNalIdxInLayer = 0;
3382 bAvcBased = (iCurDid == BASE_DEPENDENCY_ID);
3383 pCtx->bNeedPrefixNalFlag = (bAvcBased &&
3384 (pSvcParam->bPrefixNalAddingCtrl ||
3385 (pSvcParam->iNumDependencyLayer > 1) ));
3386
3387 if ( eFrameType == WELS_FRAME_TYPE_P )
3388 {
3389 eNalType = bAvcBased ? NAL_UNIT_CODED_SLICE : NAL_UNIT_CODED_SLICE_EXT;
3390 }
3391 else if ( eFrameType == WELS_FRAME_TYPE_IDR )
3392 {
3393 eNalType = bAvcBased ? NAL_UNIT_CODED_SLICE_IDR : NAL_UNIT_CODED_SLICE_EXT;
3394 }
3395 if ( iCurTid == 0 || pCtx->eSliceType == I_SLICE )
3396 eNalRefIdc = NRI_PRI_HIGHEST;
3397 else if ( iCurTid == pSvcParam->iDecompStages )
3398 eNalRefIdc = NRI_PRI_LOWEST;
3399 else if ( 1 + iCurTid == pSvcParam->iDecompStages )
3400 eNalRefIdc = NRI_PRI_LOW;
3401 else // more details for other temporal layers?
3402 eNalRefIdc = NRI_PRI_HIGHEST;
3403 pCtx->eNalType = eNalType;
3404 pCtx->eNalPriority = eNalRefIdc;
3405
3406 pCtx->pDecPic = pCtx->ppRefPicListExt[iCurDid]->pNextBuffer;
3407#if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3408 fsnr = pCtx->pDecPic;
3409#endif//#if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3410 pCtx->pDecPic->iPictureType = pCtx->eSliceType;
3411 pCtx->pDecPic->iFramePoc = pCtx->iPOC;
3412
3413 WelsInitCurrentLayer( pCtx, iCurWidth, iCurHeight );
3414
3415 WelsMarkPic(pCtx);
3416 if ( !WelsBuildRefList( pCtx, pCtx->iPOC ) )
3417 {
3418 // Force coding IDR as followed
3419 ForceCodingIDR( pCtx );
3420 WelsLog(pCtx, WELS_LOG_WARNING, "WelsEncoderEncodeExt(), WelsBuildRefList failed for P frames, pCtx->iNumRef0= %d.\n", pCtx->iNumRef0);
3421 return -1;
3422 }
3423#ifdef LONG_TERM_REF_DUMP
3424 dump_ref(pCtx);
3425#endif
3426 WelsUpdateRefSyntax(pCtx, pCtx->iPOC, eFrameType); //get reordering syntax used for writing slice header and transmit to encoder.
3427 PrefetchReferencePicture( pCtx, eFrameType ); // update reference picture for current pDq layer
3428
3429 pCtx->pFuncList->pfRc.pfWelsRcPictureInit(pCtx);
3430 PreprocessSliceCoding( pCtx ); // MUST be called after pfWelsRcPictureInit() and WelsInitCurrentLayer()
3431
3432 iLayerSize = 0;
3433 if ( SM_SINGLE_SLICE == param_d->sMso.uiSliceMode ) // only one slice within a sQualityStat layer
3434 {
3435 int32_t iSliceSize = 0;
3436
3437 if ( pCtx->bNeedPrefixNalFlag )
3438 {
3439 iLayerSize += AddPrefixNal( pCtx, pLayerBsInfo, &iNalLen[0], &iNalIdxInLayer, eNalType, eNalRefIdc );
3440 }
3441
3442 WelsLoadNal( pCtx->pOut, eNalType, eNalRefIdc );
3443
3444 WelsCodeOneSlice( pCtx, 0, eNalType );
3445
3446 WelsUnloadNal( pCtx->pOut );
3447
3448 iSliceSize = WelsEncodeNalExt( &pCtx->pOut->sNalList[pCtx->pOut->iNalIndex-1],
3449 &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3450 pCtx->pFrameBs + pCtx->iPosBsBuffer,
3451 &iNalLen[iNalIdxInLayer] );
3452 iLayerSize += iSliceSize;
3453 pCtx->iPosBsBuffer += iSliceSize;
3454 pLayerBsInfo->uiLayerType = VIDEO_CODING_LAYER;
3455 pLayerBsInfo->uiSpatialId = iCurDid;
3456 pLayerBsInfo->uiTemporalId = iCurTid;
3457 pLayerBsInfo->uiQualityId = 0;
3458 pLayerBsInfo->uiPriorityId = 0;
3459 pLayerBsInfo->iNalLengthInByte[iNalIdxInLayer] = iSliceSize;
3460 pLayerBsInfo->iNalCount = ++ iNalIdxInLayer;
3461 }
3462 // for dynamic slicing single threading..
3463#ifndef MT_ENABLED
3464 else if ( SM_DYN_SLICE == param_d->sMso.uiSliceMode )
3465#else // MT_ENABLED
3466 else if ( (SM_DYN_SLICE == param_d->sMso.uiSliceMode) && (pSvcParam->iMultipleThreadIdc <= 1) )
3467#endif//MT_ENABLED
3468 {
3469 const int32_t kiLastMbInFrame = pCtx->pCurDqLayer->pSliceEncCtx->iMbNumInFrame;
3470 WelsCodeOnePicPartition( pCtx, pLayerBsInfo, &iNalIdxInLayer, &iLayerSize, 0, kiLastMbInFrame, 0 );
3471 }
3472 else
3473 {//other multi-slice uiSliceMode
3474#if defined(MT_ENABLED)
3475 int err = 0;
3476 // THREAD_FULLY_FIRE_MODE/THREAD_PICK_UP_MODE for any mode of non-SM_DYN_SLICE
3477 if ( (SM_DYN_SLICE != param_d->sMso.uiSliceMode) && (pSvcParam->iMultipleThreadIdc > 1) )
3478 {
3479 iSliceCount = GetCurrentSliceNum( pCtx->pCurDqLayer->pSliceEncCtx );
3480 if ( iLayerNum +
3481#if defined(PACKING_ONE_SLICE_PER_LAYER)
3482 iSliceCount
3483#else
3484 1
3485#endif//PACKING_ONE_SLICE_PER_LAYER
3486 >= MAX_LAYER_NUM_OF_FRAME ) // check available layer_bs_info for further writing as followed
3487 {
3488 WelsLog( pCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) overflow(max:%d) at iDid= %d uiSliceMode= %d, iSliceCount= %d!",
3489 iLayerNum, MAX_LAYER_NUM_OF_FRAME, iCurDid, param_d->sMso.uiSliceMode, iSliceCount );
3490 return -1;
3491 }
3492 if ( iSliceCount <= 1 )
3493 {
3494 WelsLog( pCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iSliceCount(%d) from GetCurrentSliceNum() is untrusted due stack/heap crupted!\n", iSliceCount );
3495 return -1;
3496 }
3497
3498 if ( pSvcParam->iCountThreadsNum >= iSliceCount ) //THREAD_FULLY_FIRE_MODE
3499 {
3500#if defined(PACKING_ONE_SLICE_PER_LAYER)
3501 int32_t iSliceIdx = 1;
3502 int32_t iOrgSlicePos[MAX_SLICES_NUM] = {0};
3503 iOrgSlicePos[0] = pCtx->iPosBsBuffer;
3504 while (uiSliceIdx < iSliceCount)
3505 {
3506 iOrgSlicePos[uiSliceIdx] = pCtx->pSliceBs[uiSliceIdx].uiBsPos;
3507 ++ uiSliceIdx;
3508 }
3509#elif defined(MT_DEBUG)
3510 int64_t t_bs_append = 0;
3511#endif//PACKING_ONE_SLICE_PER_LAYER
3512
3513 pCtx->iActiveThreadsNum = iSliceCount;
3514 // to fire slice coding threads
3515 err = FiredSliceThreads( &pCtx->pSliceThreading->pThreadPEncCtx[0], &pCtx->pSliceThreading->pReadySliceCodingEvent[0], pLayerBsInfo, iSliceCount, pCtx->pCurDqLayer->pSliceEncCtx, FALSE );
3516 if ( err )
3517 {
3518 WelsLog( pCtx, WELS_LOG_ERROR, "[MT] WelsEncoderEncodeExt(), FiredSliceThreads return(%d) failed and exit encoding frame, iCountThreadsNum= %d, iSliceCount= %d, uiSliceMode= %d, iMultipleThreadIdc= %d!!\n",
3519 err, pSvcParam->iCountThreadsNum, iSliceCount, param_d->sMso.uiSliceMode, pSvcParam->iMultipleThreadIdc );
3520 return -1;
3521 }
3522
3523 WelsMultipleEventsWaitAllBlocking( iSliceCount, &pCtx->pSliceThreading->pSliceCodedEvent[0] );
3524
3525
3526 // all slices are finished coding here
3527 // append exclusive slice 0 bs to pFrameBs
3528#if defined(PACKING_ONE_SLICE_PER_LAYER)
3529 iLayerSize = pCtx->iPosBsBuffer - iOrgSlicePos[0];
3530 uiSliceIdx = 1;
3531 while (uiSliceIdx < iSliceCount)
3532 {
3533 iLayerSize += pCtx->pSliceBs[uiSliceIdx].uiBsPos - iOrgSlicePos[uiSliceIdx];
3534 ++ uiSliceIdx;
3535 }
3536 iLayerNum += iSliceCount; // each slice stickly output as layer info for performance improvement directly
3537 pLayerBsInfo += iSliceCount;
3538#else
3539#if defined(MT_DEBUG)
3540 t_bs_append = WelsTime();
3541#endif//MT_DEBUG
3542 iLayerSize = AppendSliceToFrameBs( pCtx, pLayerBsInfo, iSliceCount );
3543#if defined(MT_DEBUG)
3544 t_bs_append = WelsTime() - t_bs_append;
3545 if ( pCtx->pSliceThreading->pFSliceDiff )
3546 {
3547 fprintf(pCtx->pSliceThreading->pFSliceDiff,
3548#if defined(WIN32)
3549 "%6I64d us consumed at AppendSliceToFrameBs() for coding_idx: %d iDid: %d qid: %d\n",
3550#else
3551 "%6lld us consumed at AppendSliceToFrameBs() for coding_idx: %d iDid: %d qid: %d\n",
3552#endif//WIN32
3553 t_bs_append, pCtx->iCodingIndex, iCurDid, 0 );
3554 }
3555#endif//MT_DEBUG
3556#endif//PACKING_ONE_SLICE_PER_LAYER
3557 }
3558 else //THREAD_PICK_UP_MODE
3559 {
3560 int32_t iNumThreadsRunning = 0;
3561 int32_t iNumThreadsScheduled = 0;
3562 int32_t iIndexOfSliceToBeCoded = 0;
3563#if defined(PACKING_ONE_SLICE_PER_LAYER)
3564 int32_t iSliceIdx = 1;
3565 int32_t iOrgSlicePos[MAX_SLICES_NUM] = {0};
3566 iOrgSlicePos[0] = pCtx->iPosBsBuffer;
3567 while (uiSliceIdx < iSliceCount)
3568 {
3569 iOrgSlicePos[uiSliceIdx] = pCtx->pSliceBs[uiSliceIdx].uiBsPos;
3570 ++ uiSliceIdx;
3571 }
3572#endif//PACKING_ONE_SLICE_PER_LAYER
3573
3574 pCtx->iActiveThreadsNum = pSvcParam->iCountThreadsNum;
3575 iNumThreadsScheduled = pCtx->iActiveThreadsNum;
3576 iNumThreadsRunning = iNumThreadsScheduled;
3577 // to fire slice coding threads
3578 err = FiredSliceThreads( &pCtx->pSliceThreading->pThreadPEncCtx[0], &pCtx->pSliceThreading->pReadySliceCodingEvent[0], pLayerBsInfo, iNumThreadsRunning, pCtx->pCurDqLayer->pSliceEncCtx, FALSE );
3579 if ( err )
3580 {
3581 WelsLog( pCtx, WELS_LOG_ERROR, "[MT] WelsEncoderEncodeExt(), FiredSliceThreads return(%d) failed and exit encoding frame, iCountThreadsNum= %d, iSliceCount= %d, uiSliceMode= %d, iMultipleThreadIdc= %d!!\n",
3582 err, pSvcParam->iCountThreadsNum, iSliceCount, param_d->sMso.uiSliceMode, pSvcParam->iMultipleThreadIdc );
3583 return -1;
3584 }
3585
3586 iIndexOfSliceToBeCoded = iNumThreadsRunning;
3587 while (1)
3588 {
3589 if ( iIndexOfSliceToBeCoded >= iSliceCount && iNumThreadsRunning <= 0 )
3590 break;
3591#ifdef WIN32
3592 WELS_THREAD_ERROR_CODE lwait = 0;
3593 int32_t iEventId = -1;
3594
3595 lwait = WelsMultipleEventsWaitSingleBlocking( iNumThreadsScheduled,
3596 &pCtx->pSliceThreading->pSliceCodedEvent[0],
3597 2 ); // 2 ms for one tick
3598 iEventId = (int32_t)(lwait - WELS_THREAD_ERROR_WAIT_OBJECT_0);
3599 if ( iEventId >= 0 && iEventId < iNumThreadsScheduled )
3600 {
3601 if ( iIndexOfSliceToBeCoded < iSliceCount )
3602 {
3603 // pick up succeeding slice for threading
3604 // thread_id equal to iEventId per implementation here
3605 pCtx->pSliceThreading->pThreadPEncCtx[iEventId].iSliceIndex = iIndexOfSliceToBeCoded;
3606#ifdef PACKING_ONE_SLICE_PER_LAYER
3607 pCtx->pSliceThreading->pThreadPEncCtx[iEventId].pLayerBs = pLayerBsInfo+iIndexOfSliceToBeCoded;
3608#endif//PACKING_ONE_SLICE_PER_LAYER
3609 WelsEventSignal( &pCtx->pSliceThreading->pReadySliceCodingEvent[iEventId] );
3610
3611 ++ iIndexOfSliceToBeCoded;
3612 }
3613 else // no other slices left for coding
3614 {
3615 -- iNumThreadsRunning;
3616 }
3617 }
3618 else
3619 {
3620 WelsSleep(1);
3621 }
3622#else//__GNUC__
3623 // TODO for pthread platforms
3624 // alternate implementation using blocking due non-blocking with timeout mode not support at wels thread lib, tune back if available
3625 WelsMultipleEventsWaitAllBlocking( iNumThreadsRunning, &pCtx->pSliceThreading->pSliceCodedEvent[0] );
3626 if ( iIndexOfSliceToBeCoded < iSliceCount )
3627 {
3628 int32_t iThreadIdx = 0;
3629 // pick up succeeding slices for threading if left
3630 while ( iThreadIdx < iNumThreadsScheduled )
3631 {
3632 if ( iIndexOfSliceToBeCoded >= iSliceCount )
3633 break;
3634 pCtx->pSliceThreading->pThreadPEncCtx[iThreadIdx].iSliceIndex = iIndexOfSliceToBeCoded;
3635#ifdef PACKING_ONE_SLICE_PER_LAYER
3636 pCtx->pSliceThreading->pThreadPEncCtx[iThreadIdx].pLayerBs = pLayerBsInfo+iIndexOfSliceToBeCoded;
3637#endif//PACKING_ONE_SLICE_PER_LAYER
3638 WelsEventSignal( pCtx->pSliceThreading->pReadySliceCodingEvent[iThreadIdx] );
3639
3640 ++ iIndexOfSliceToBeCoded;
3641 ++ iThreadIdx;
3642 }
3643 // update iNumThreadsRunning
3644 iNumThreadsRunning = iThreadIdx;
3645 }
3646 else
3647 {
3648 iNumThreadsRunning = 0;
3649 }
3650#endif//WIN32
3651 }//while(1)
3652
3653// all slices are finished coding here
3654 // append exclusive slice 0 bs to pFrameBs
3655#if defined(PACKING_ONE_SLICE_PER_LAYER)
3656 iLayerSize = pCtx->iPosBsBuffer - iOrgSlicePos[0];
3657 uiSliceIdx = 1;
3658 while (uiSliceIdx < iSliceCount)
3659 {
3660 iLayerSize += pCtx->pSliceBs[uiSliceIdx].uiBsPos - iOrgSlicePos[uiSliceIdx];
3661 ++ uiSliceIdx;
3662 }
3663 iLayerNum += iSliceCount; // each slice stickly output as layer info for performance improvement directly
3664 pLayerBsInfo += iSliceCount;
3665#else
3666 iLayerSize = AppendSliceToFrameBs( pCtx, pLayerBsInfo, iSliceCount );
3667#endif//PACKING_ONE_SLICE_PER_LAYER
3668 }
3669 }
3670 // THREAD_FULLY_FIRE_MODE && SM_DYN_SLICE
3671 else if ( (SM_DYN_SLICE == param_d->sMso.uiSliceMode) && (pSvcParam->iMultipleThreadIdc > 1) )
3672 {
3673 const int32_t kiPartitionCnt = pCtx->iActiveThreadsNum; //pSvcParam->iCountThreadsNum;
3674#if defined(PACKING_ONE_SLICE_PER_LAYER)
3675 ResetCountBsSizeInPartitions( pCtx->pSliceThreading->pCountBsSizeInPartition, kiPartitionCnt );
3676 pCtx->pCurDqLayer->pSliceEncCtx->iMaxSliceNumConstraint = WELS_MIN ( MAX_SLICES_NUM, DynamicMaxSliceNumConstraint( MAX_LAYER_NUM_OF_FRAME, iLayerNum, 1 + /*( num_qlayer - 1) +*/ ( ( (iCurDid==0) && ( pSvcParam->uiGopSize>1 ) ) ? 1: 0 ) ) );
3677#endif//PACKING_ONE_SLICE_PER_LAYER
3678
3679 // to fire slice coding threads
3680 err = FiredSliceThreads( &pCtx->pSliceThreading->pThreadPEncCtx[0], &pCtx->pSliceThreading->pReadySliceCodingEvent[0], pLayerBsInfo, kiPartitionCnt, pCtx->pCurDqLayer->pSliceEncCtx, TRUE );
3681 if ( err )
3682 {
3683 WelsLog( pCtx, WELS_LOG_ERROR, "[MT] WelsEncoderEncodeExt(), FiredSliceThreads return(%d) failed and exit encoding frame, iCountThreadsNum= %d, iSliceCount= %d, uiSliceMode= %d, iMultipleThreadIdc= %d!!\n",
3684 err, pSvcParam->iCountThreadsNum, iSliceCount, param_d->sMso.uiSliceMode, pSvcParam->iMultipleThreadIdc );
3685 return -1;
3686 }
3687
3688 WelsMultipleEventsWaitAllBlocking( kiPartitionCnt, &pCtx->pSliceThreading->pSliceCodedEvent[0] );
3689
3690#if defined(PACKING_ONE_SLICE_PER_LAYER)
3691 iSliceCount = PostProcDynamicSlicingBsWriting( pCtx, pLayerBsInfo, &iLayerSize, kiPartitionCnt );
3692 assert(iLayerNum + iSliceCount < MAX_LAYER_NUM_OF_FRAME);
3693 pLayerBsInfo += iSliceCount;
3694 iLayerNum += iSliceCount;
3695#else
3696 iLayerSize = AppendSliceToFrameBs( pCtx, pLayerBsInfo, kiPartitionCnt );
3697#endif//PACKING_ONE_SLICE_PER_LAYER
3698 }
3699 else // for non-dynamic-slicing mode single threading branch..
3700#endif//MT_ENABLED
3701 {
3702 const bool_t bNeedPrefix = pCtx->bNeedPrefixNalFlag;
3703 int32_t iSliceIdx = 0;
3704
3705 iSliceCount = GetCurrentSliceNum( pCtx->pCurDqLayer->pSliceEncCtx );
3706 while (iSliceIdx < iSliceCount)
3707 {
3708 int32_t iSliceSize = 0;
3709
3710 if ( bNeedPrefix )
3711 {
3712 iLayerSize += AddPrefixNal( pCtx, pLayerBsInfo, &iNalLen[0], &iNalIdxInLayer, eNalType, eNalRefIdc );
3713 }
3714
3715 WelsLoadNal( pCtx->pOut, eNalType, eNalRefIdc );
3716 WelsCodeOneSlice( pCtx, iSliceIdx, eNalType );
3717 WelsUnloadNal( pCtx->pOut );
3718
3719 iSliceSize = WelsEncodeNalExt( &pCtx->pOut->sNalList[pCtx->pOut->iNalIndex-1],
3720 &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3721 pCtx->pFrameBs + pCtx->iPosBsBuffer,
3722 &iNalLen[iNalIdxInLayer] );
3723 pCtx->iPosBsBuffer += iSliceSize;
3724 iLayerSize += iSliceSize;
3725 pLayerBsInfo->iNalLengthInByte[iNalIdxInLayer] = iSliceSize;
3726
3727#if defined(SLICE_INFO_OUTPUT)
3728 fprintf( stderr,
3729 "@slice=%-6d sliceType:%c idc:%d size:%-6d\n",
3730 iSliceIdx,
3731 (pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
3732 eNalRefIdc,
3733 iSliceSize );
3734#endif//SLICE_INFO_OUTPUT
3735 ++ iNalIdxInLayer;
3736 ++ iSliceIdx;
3737 }
3738
3739 pLayerBsInfo->uiLayerType = VIDEO_CODING_LAYER;
3740 pLayerBsInfo->uiSpatialId = iCurDid;
3741 pLayerBsInfo->uiTemporalId = iCurTid;
3742 pLayerBsInfo->uiQualityId = 0;
3743 pLayerBsInfo->uiPriorityId = 0;
3744 pLayerBsInfo->iNalCount = iNalIdxInLayer;
3745 }
3746 }
3747
3748 // deblocking filter
3749 if (
3750#if defined(MT_ENABLED)
3751 (!pCtx->pCurDqLayer->bDeblockingParallelFlag) &&
3752#endif//MT_ENABLED
3753#if !defined(ENABLE_FRAME_DUMP)
3754 ( (eNalRefIdc != NRI_PRI_LOWEST) && (param_d->iHighestTemporalId == 0 || iCurTid < param_d->iHighestTemporalId) ) &&
3755#endif//!ENABLE_FRAME_DUMP
3756 true
3757 )
3758 {
3759 PerformDeblockingFilter( pCtx );
3760 }
3761
3762 // reference picture list update
3763 if ( eNalRefIdc != NRI_PRI_LOWEST )
3764 {
3765 if ( !WelsUpdateRefList( pCtx ) )
3766 {
3767 // Force coding IDR as followed
3768 ForceCodingIDR( pCtx );
3769 WelsLog(pCtx, WELS_LOG_WARNING, "WelsEncoderEncodeExt(), WelsUpdateRefList failed.\n");
3770 return -1;
3771 }
3772 }
3773
3774 iFrameSize += iLayerSize;
3775
3776 pCtx->pFuncList->pfRc.pfWelsRcPictureInfoUpdate(pCtx, iLayerSize);
3777
3778#ifdef ENABLE_FRAME_DUMP
3779 // Dump reconstruction picture for each sQualityStat layer
3780 if ( iCurDid+1 < pSvcParam->iNumDependencyLayer )
3781 DumpDependencyRec( fsnr, &param_d->sRecFileName[0], iCurDid );
3782#endif//ENABLE_FRAME_DUMP
3783
3784#if defined(ENABLE_PSNR_CALC)
3785 snr_y = WelsCalcPsnr( fsnr->pData[0],
3786 fsnr->iLineSize[0],
3787 pEncPic->pData[0],
3788 pEncPic->iLineSize[0],
3789 iCurWidth,
3790 iCurHeight );
3791 snr_u = WelsCalcPsnr( fsnr->pData[1],
3792 fsnr->iLineSize[1],
3793 pEncPic->pData[1],
3794 pEncPic->iLineSize[1],
3795 (iCurWidth>>1),
3796 (iCurHeight>>1) );
3797 snr_v = WelsCalcPsnr( fsnr->pData[2],
3798 fsnr->iLineSize[2],
3799 pEncPic->pData[2],
3800 pEncPic->iLineSize[2],
3801 (iCurWidth>>1),
3802 (iCurHeight>>1) );
3803#endif//ENABLE_PSNR_CALC
3804
3805#if defined(LAYER_INFO_OUTPUT)
3806 fprintf( stderr, "%2s %5d: %-5d %2s T%1d D%1d Q%-2d QP%3d Y%2.2f U%2.2f V%2.2f %8d bits\n",
3807 (iSpatialIdx == 0) ? "#AU" : " ",
3808 pCtx->iPOC,
3809 pCtx->iFrameNum,
3810 (uiFrameType == WELS_FRAME_TYPE_I || uiFrameType == WELS_FRAME_TYPE_IDR) ? "I": "P",
3811 iCurTid,
3812 iCurDid,
3813 0,
3814 pCtx->pWelsSvcRc[pCtx->uiDependencyId].iAverageFrameQp,
3815 snr_y,
3816 snr_u,
3817 snr_v,
3818 (iLayerSize<<3) );
3819#endif//LAYER_INFO_OUTPUT
3820
3821#if defined(STAT_OUTPUT)
3822
3823#if defined(ENABLE_PSNR_CALC)
3824 {
3825 pCtx->sStatData[iCurDid][0].sQualityStat.rYPsnr[pCtx->eSliceType] += snr_y;
3826 pCtx->sStatData[iCurDid][0].sQualityStat.rUPsnr[pCtx->eSliceType] += snr_u;
3827 pCtx->sStatData[iCurDid][0].sQualityStat.rVPsnr[pCtx->eSliceType] += snr_v;
3828 }
3829#endif//ENABLE_PSNR_CALC
3830
3831#if defined(MB_TYPES_CHECK) //091025, frame output
3832 if (pCtx->eSliceType == P_SLICE)
3833 {
3834 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Intra4x4] += pCtx->sPerInfo.iMbCount[P_SLICE][Intra4x4];
3835 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Intra16x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Intra16x16];
3836 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter16x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter16x16];
3837 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter16x8] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter16x8];
3838 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter8x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter8x16];
3839 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter8x8] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter8x8];
3840 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][PSkip] += pCtx->sPerInfo.iMbCount[P_SLICE][PSkip];
3841 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][8] += pCtx->sPerInfo.iMbCount[P_SLICE][8];
3842 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][9] += pCtx->sPerInfo.iMbCount[P_SLICE][9];
3843 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][10] += pCtx->sPerInfo.iMbCount[P_SLICE][10];
3844 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][11] += pCtx->sPerInfo.iMbCount[P_SLICE][11];
3845 }
3846 else if (pCtx->eSliceType == I_SLICE)
3847 {
3848 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][Intra4x4] += pCtx->sPerInfo.iMbCount[I_SLICE][Intra4x4];
3849 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][Intra16x16] += pCtx->sPerInfo.iMbCount[I_SLICE][Intra16x16];
3850 pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][7] += pCtx->sPerInfo.iMbCount[I_SLICE][7];
3851 }
3852
3853 memset(pCtx->sPerInfo.iMbCount[P_SLICE], 0, 18*sizeof( int32_t ));
3854 memset(pCtx->sPerInfo.iMbCount[I_SLICE], 0, 18*sizeof( int32_t ));
3855
3856#endif//MB_TYPES_CHECK
3857 {
3858 //no pCtx->pSvcParam->bMgsT0OnlyStrategy
3859 ++ pCtx->sStatData[iCurDid][0].sSliceData.iSliceCount[pCtx->eSliceType]; // for multiple slices coding
3860 pCtx->sStatData[iCurDid][0].sSliceData.iSliceSize[pCtx->eSliceType] += (iLayerSize<<3); // bits
3861 }
3862#endif//STAT_OUTPUT
3863
3864#if defined(MT_ENABLED) && defined(PACKING_ONE_SLICE_PER_LAYER)
3865 if ( pSvcParam->iMultipleThreadIdc <= 1 || SM_SINGLE_SLICE == param_d->sMso.uiSliceMode ) // sigle thread actually used
3866#else
3867 if ( 1 )
3868#endif//MT_ENABLED && PACKING_ONE_SLICE_PER_LAYER
3869 {
3870 ++ iLayerNum;
3871 ++ pLayerBsInfo;
3872 }
3873
3874
3875 pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3876
3877 if( pSvcParam->iPaddingFlag && pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize > 0 )
3878 {
3879 const int32_t kiPaddingNalSize = WritePadding(pCtx, pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize);
3880
3881#if GOM_TRACE_FLAG
3882 WelsLog( pCtx, WELS_LOG_INFO,"[RC] encoding_qp%d Padding: %d\n",pCtx->uiDependencyId, pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize);
3883#endif
3884 if ( kiPaddingNalSize <= 0 )
3885 return -1;
3886
3887 pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingBitrateStat += pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize;
3888
3889 pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize=0;
3890
3891 pLayerBsInfo->uiPriorityId = 0;
3892 pLayerBsInfo->uiSpatialId = 0;
3893 pLayerBsInfo->uiTemporalId = 0;
3894 pLayerBsInfo->uiQualityId = 0;
3895 pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER;
3896 pLayerBsInfo->iNalCount = 1;
3897 pLayerBsInfo->iNalLengthInByte[0] = kiPaddingNalSize;
3898 ++ pLayerBsInfo;
3899 pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3900 ++ iLayerNum;
3901 }
3902
3903#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN) && defined(TRY_SLICING_BALANCE)
3904 if ( param_d->sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pSvcParam->iMultipleThreadIdc > 1 &&
3905 pSvcParam->iMultipleThreadIdc >= param_d->sMso.sSliceArgument.iSliceNum )
3906 {
3907 CalcSliceComplexRatio( pCtx->pSliceThreading->pSliceComplexRatio[iCurDid], pCtx->pCurDqLayer->pSliceEncCtx, pCtx->pSliceThreading->pSliceConsumeTime[iCurDid] );
3908#if defined(MT_DEBUG)
3909 TrackSliceComplexities( pCtx, iCurDid );
3910#endif//#if defined(MT_DEBUG)
3911 }
3912#endif//MT_ENABLED && DYNAMIC_SLICE_ASSIGN && TRY_SLICING_BALANCE
3913
3914 ++ iSpatialIdx;
3915
3916 if ( iCurDid+1 < pSvcParam->iNumDependencyLayer )
3917 {
3918 WelsSwapDqLayers( pCtx );
3919 }
3920
3921 if ( pSvcParam->bEnableLongTermReference && (pCtx->pLtr[pCtx->uiDependencyId].bLTRMarkingFlag && (pCtx->pLtr[pCtx->uiDependencyId].iLTRMarkMode == LTR_DELAY_MARK)))
3922 {
3923 pCtx->bLongTermRefFlag[d_idx][0] = true;
3924 }
3925
3926 if ( iCurTid < pCtx->uiSpatialLayersInTemporal[d_idx] - 1 || pSvcParam->iDecompStages == 0 )
3927 {
3928 if ( (iCurTid >= MAX_TEMPORAL_LEVEL)||(pCtx->uiSpatialLayersInTemporal[d_idx]-1>= MAX_TEMPORAL_LEVEL))
3929 {
3930 ForceCodingIDR( pCtx ); // some logic error
3931 return -1;
3932 }
3933
3934 if ( pSvcParam->bEnableLongTermReference && pCtx->bLongTermRefFlag[d_idx][iCurTid] )
3935 {
3936 SPicture *tmp = pCtx->pSpatialPic[d_idx][pCtx->uiSpatialLayersInTemporal[d_idx]+pCtx->pVaa->uiMarkLongTermPicIdx];
3937 pCtx->pSpatialPic[d_idx][pCtx->uiSpatialLayersInTemporal[d_idx]+pCtx->pVaa->uiMarkLongTermPicIdx] = pCtx->pSpatialPic[d_idx][iCurTid];
3938 pCtx->pSpatialPic[d_idx][iCurTid] = pCtx->pSpatialPic[d_idx][pCtx->uiSpatialLayersInTemporal[d_idx]-1];
3939 pCtx->pSpatialPic[d_idx][pCtx->uiSpatialLayersInTemporal[d_idx]-1] = tmp;
3940 pCtx->bLongTermRefFlag[d_idx][iCurTid] = false;
3941 }
3942 else
3943 {
3944 WelsExchangeSpatialPictures( &pCtx->pSpatialPic[d_idx][pCtx->uiSpatialLayersInTemporal[d_idx]-1], &pCtx->pSpatialPic[d_idx][iCurTid] );
3945 }
3946 }
3947
3948 if ( pSvcParam->bEnableLongTermReference && ((pCtx->pLtr[pCtx->uiDependencyId].bLTRMarkingFlag && (pCtx->pLtr[pCtx->uiDependencyId].iLTRMarkMode == LTR_DIRECT_MARK)) || eFrameType == WELS_FRAME_TYPE_IDR))
3949 {
3950 pCtx->bLongTermRefFlag[d_idx][iCurTid] = true;
3951 }
3952 }
3953
3954#if defined(MT_ENABLED) && defined(MT_DEBUG)
3955 TrackSliceConsumeTime( pCtx, did_list, iSpatialNum );
3956#endif//MT_ENABLED && MT_DEBUG
3957
3958#if defined(MT_ENABLED) && defined(DYNAMIC_SLICE_ASSIGN)
3959 if ( pSvcParam->iMultipleThreadIdc > 1 && did_list[0] == BASE_DEPENDENCY_ID
3960 && pSvcParam->sDependencyLayers[0].sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pSvcParam->iMultipleThreadIdc >= pSvcParam->sDependencyLayers[0].sMso.sSliceArgument.iSliceNum
3961 && pSvcParam->sDependencyLayers[did_list[iSpatialNum-1]].sMso.uiSliceMode == SM_FIXEDSLCNUM_SLICE && pSvcParam->iMultipleThreadIdc >= pSvcParam->sDependencyLayers[did_list[iSpatialNum-1]].sMso.sSliceArgument.iSliceNum )
3962 {
3963 AdjustBaseLayer( pCtx );
3964 }
3965#endif//DYNAMIC_SLICE_ASSIGN
3966
3967#ifdef ENABLE_FRAME_DUMP
3968 DumpRecFrame( fsnr, &pSvcParam->sDependencyLayers[pSvcParam->iNumDependencyLayer-1].sRecFileName[0] ); // pDecPic: final reconstruction output
3969#endif//ENABLE_FRAME_DUMP
3970
3971 ++ pCtx->iCodingIndex;
3972 pCtx->eLastNalPriority = eNalRefIdc;
3973 pFbi->iLayerNum = iLayerNum;
3974
3975#if defined(X86_ASM)
3976 WelsEmms();
3977#endif //X86_ASM
3978
3979 return eFrameType;
3980}
3981
3982/*!
3983 * \brief Wels SVC encoder parameters adjustment
3984 * SVC adjustment results in new requirement in memory blocks adjustment
3985 */
3986int32_t WelsEncoderParamAdjust( sWelsEncCtx **ppCtx, SWelsSvcCodingParam *pNewParam )
3987{
3988 SWelsSvcCodingParam *pOldParam = NULL;
3989 int32_t iReturn = 0;
3990 int8_t iIndexD= 0;
3991 bool_t bNeedReset = false;
3992
3993 if ( NULL == ppCtx || NULL == *ppCtx || NULL == pNewParam ) return 1;
3994
3995 /* Check validation in new parameters */
3996 iReturn = ParamValidationExt( pNewParam );
3997 if ( iReturn != 0 ) return iReturn;
3998
3999 pOldParam = (*ppCtx)->pSvcParam;
4000
4001 /* Decide whether need reset for IDR frame based on adjusting prarameters changed */
4002 /* Temporal levels, spatial settings and/ or quality settings changed need update parameter sets related. */
4003 bNeedReset = (pOldParam == NULL ) ||
4004 (pOldParam->iNumTemporalLayer != pNewParam->iNumTemporalLayer) ||
4005 (pOldParam->uiGopSize != pNewParam->uiGopSize) ||
4006 (pOldParam->iNumDependencyLayer != pNewParam->iNumDependencyLayer) ||
4007 (pOldParam->iDecompStages != pNewParam->iDecompStages) ||
4008 (pOldParam->iActualPicWidth != pNewParam->iActualPicWidth || pOldParam->iActualPicHeight != pNewParam->iActualPicHeight) ||
4009 (pOldParam->SUsedPicRect.iWidth != pNewParam->SUsedPicRect.iWidth || pOldParam->SUsedPicRect.iHeight != pNewParam->SUsedPicRect.iHeight) ||
4010 (pOldParam->bEnableLongTermReference != pNewParam->bEnableLongTermReference);
4011 if ( !bNeedReset ){ // Check its picture resolutions/quality settings respectively in each dependency layer
4012 iIndexD = 0;
4013 assert( pOldParam->iNumDependencyLayer == pNewParam->iNumDependencyLayer );
4014 do
4015 {
4016 const SDLayerParam *kpOldDlp = &pOldParam->sDependencyLayers[iIndexD];
4017 const SDLayerParam *kpNewDlp = &pNewParam->sDependencyLayers[iIndexD];
4018 float fT1 = .0f;
4019 float fT2 = .0f;
4020
4021 // check frame size settings
4022 if ( kpOldDlp->iFrameWidth != kpNewDlp->iFrameWidth ||
4023 kpOldDlp->iFrameHeight != kpNewDlp->iFrameHeight ||
4024 kpOldDlp->iActualWidth != kpNewDlp->iActualWidth ||
4025 kpOldDlp->iActualHeight != kpNewDlp->iActualHeight ){
4026 bNeedReset = true;
4027 break;
4028 }
4029
4030 if ( kpOldDlp->sMso.uiSliceMode != kpNewDlp->sMso.uiSliceMode ||
4031 kpOldDlp->sMso.sSliceArgument.iSliceNum != kpNewDlp->sMso.sSliceArgument.iSliceNum )
4032 {
4033 bNeedReset = true;
4034 break;
4035 }
4036
4037 // check frame rate
4038 // we can not check whether corresponding fFrameRate is equal or not,
4039 // only need to check d_max/d_min and max_fr/d_max whether it is equal or not
4040 if ( kpNewDlp->fInputFrameRate > EPSN && kpOldDlp->fInputFrameRate > EPSN )
4041 fT1 = kpNewDlp->fOutputFrameRate/kpNewDlp->fInputFrameRate - kpOldDlp->fOutputFrameRate/kpOldDlp->fInputFrameRate;
4042 if ( kpNewDlp->fOutputFrameRate > EPSN && kpOldDlp->fOutputFrameRate > EPSN )
4043 fT2 = pNewParam->fMaxFrameRate/kpNewDlp->fOutputFrameRate - pOldParam->fMaxFrameRate/kpOldDlp->fOutputFrameRate;
4044 if ( fT1 > EPSN || fT1 < -EPSN || fT2 > EPSN || fT2 < -EPSN )
4045 {
4046 bNeedReset = true;
4047 break;
4048 }
4049
4050 if ( kpOldDlp->iHighestTemporalId != kpNewDlp->iHighestTemporalId )
4051 {
4052 bNeedReset = true;
4053 break;
4054 }
4055
4056 ++ iIndexD;
4057 } while (iIndexD < pOldParam->iNumDependencyLayer);
4058 }
4059
4060 if ( bNeedReset ){
4061 SParaSetOffsetVariable sTmpPsoVariable[PARA_SET_TYPE];
4062 uint16_t uiTmpIdrPicId;//this is for LTR!
4063 memcpy( sTmpPsoVariable, (*ppCtx)->sPSOVector.sParaSetOffsetVariable, (PARA_SET_TYPE)*sizeof(SParaSetOffsetVariable) );// confirmed_safe_unsafe_usage
4064 uiTmpIdrPicId = (*ppCtx)->sPSOVector.uiIdrPicId;
4065
4066 WelsUninitEncoderExt( ppCtx );
4067
4068 /* Update new parameters */
4069 if ( WelsInitEncoderExt( ppCtx, pNewParam ) )
4070 return 1;
4071
4072 // reset the scaled spatial picture size
4073 (*ppCtx)->pVpp->WelsPreprocessReset(*ppCtx);
4074 //if WelsInitEncoderExt succeed
4075
4076 //for FLEXIBLE_PARASET_ID
4077 memcpy( (*ppCtx)->sPSOVector.sParaSetOffsetVariable, sTmpPsoVariable, (PARA_SET_TYPE)*sizeof(SParaSetOffsetVariable) );// confirmed_safe_unsafe_usage
4078 (*ppCtx)->sPSOVector.uiIdrPicId = uiTmpIdrPicId;
4079 }
4080 else{
4081 /* maybe adjustment introduced in bitrate or little settings adjustment and so on.. */
4082 pNewParam->iNumRefFrame = WELS_CLIP3(pNewParam->iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM);
4083 pNewParam->iLoopFilterDisableIdc = WELS_CLIP3(pNewParam->iLoopFilterDisableIdc, 0, 6);
4084 pNewParam->iLoopFilterAlphaC0Offset = WELS_CLIP3(pNewParam->iLoopFilterAlphaC0Offset, -6, 6);
4085 pNewParam->iLoopFilterBetaOffset = WELS_CLIP3(pNewParam->iLoopFilterBetaOffset, -6, 6);
4086 pNewParam->iInterLayerLoopFilterDisableIdc = WELS_CLIP3(pNewParam->iInterLayerLoopFilterDisableIdc, 0, 6);
4087 pNewParam->iInterLayerLoopFilterAlphaC0Offset = WELS_CLIP3(pNewParam->iInterLayerLoopFilterAlphaC0Offset, -6, 6);
4088 pNewParam->iInterLayerLoopFilterBetaOffset = WELS_CLIP3(pNewParam->iInterLayerLoopFilterBetaOffset, -6, 6);
4089 pNewParam->fMaxFrameRate = WELS_CLIP3(pNewParam->fMaxFrameRate, MIN_FRAME_RATE, MAX_FRAME_RATE);
4090
4091 // we can not use direct struct based memcpy due some fields need keep unchanged as before
4092 pOldParam->fMaxFrameRate = pNewParam->fMaxFrameRate; // maximal frame rate [Hz / fps]
4093 pOldParam->iInputCsp = pNewParam->iInputCsp; // color space of input sequence
4094 pOldParam->uiIntraPeriod = pNewParam->uiIntraPeriod; // intra period (multiple of GOP size as desired)
4095 pOldParam->bEnableSpsPpsIdAddition = pNewParam->bEnableSpsPpsIdAddition;
4096 pOldParam->bPrefixNalAddingCtrl = pNewParam->bPrefixNalAddingCtrl;
4097 pOldParam->iNumRefFrame = pNewParam->iNumRefFrame; // number of reference frame used
4098
4099 /* denoise control */
4100 pOldParam->bEnableDenoise = pNewParam->bEnableDenoise;
4101
4102 /* background detection control */
4103 pOldParam->bEnableBackgroundDetection = pNewParam->bEnableBackgroundDetection;
4104
4105 /* adaptive quantization control */
4106 pOldParam->bEnableAdaptiveQuant = pNewParam->bEnableAdaptiveQuant;
4107
4108 /* int32_t term reference control */
4109 pOldParam->bEnableLongTermReference = pNewParam->bEnableLongTermReference;
4110 pOldParam->uiLtrMarkPeriod = pNewParam->uiLtrMarkPeriod;
4111
4112 // keep below values unchanged as before
4113 pOldParam->bEnableSSEI = pNewParam->bEnableSSEI;
4114 pOldParam->bEnableFrameCroppingFlag = pNewParam->bEnableFrameCroppingFlag; // enable frame cropping flag
4115
4116 /* Motion search */
4117
4118 /* Deblocking loop filter */
4119 pOldParam->iLoopFilterDisableIdc = pNewParam->iLoopFilterDisableIdc; // 0: on, 1: off, 2: on except for slice boundaries
4120 pOldParam->iLoopFilterAlphaC0Offset = pNewParam->iLoopFilterAlphaC0Offset;// AlphaOffset: valid range [-6, 6], default 0
4121 pOldParam->iLoopFilterBetaOffset = pNewParam->iLoopFilterBetaOffset; // BetaOffset: valid range [-6, 6], default 0
4122 pOldParam->iInterLayerLoopFilterDisableIdc = pNewParam->iInterLayerLoopFilterDisableIdc; // Employed based upon inter-layer, same comment as above
4123 pOldParam->iInterLayerLoopFilterAlphaC0Offset = pNewParam->iInterLayerLoopFilterAlphaC0Offset; // InterLayerLoopFilterAlphaC0Offset
4124 pOldParam->iInterLayerLoopFilterBetaOffset = pNewParam->iInterLayerLoopFilterBetaOffset; // InterLayerLoopFilterBetaOffset
4125
4126 /* Rate Control */
4127 pOldParam->bEnableRc = pNewParam->bEnableRc;
4128 pOldParam->iRCMode = pNewParam->iRCMode;
4129 pOldParam->iTargetBitrate = pNewParam->iTargetBitrate; // overall target bitrate introduced in RC module
4130 pOldParam->iPaddingFlag = pNewParam->iPaddingFlag;
4131
4132 /* Layer definition */
4133 pOldParam->bPrefixNalAddingCtrl = pNewParam->bPrefixNalAddingCtrl;
4134
4135 // d
4136 iIndexD = 0;
4137 do
4138 {
4139 SDLayerParam *pOldDlp = &pOldParam->sDependencyLayers[iIndexD];
4140 SDLayerParam *pNewDlp = &pNewParam->sDependencyLayers[iIndexD];
4141
4142 pOldDlp->fInputFrameRate = pNewDlp->fInputFrameRate; // input frame rate
4143 pOldDlp->fOutputFrameRate = pNewDlp->fOutputFrameRate; // output frame rate
4144 pOldDlp->iSpatialBitrate = pNewDlp->iSpatialBitrate;
4145
4146 pOldDlp->uiProfileIdc = pNewDlp->uiProfileIdc; // value of profile IDC (0 for auto-detection)
4147
4148 /* Derived variants below */
4149 pOldDlp->iTemporalResolution = pNewDlp->iTemporalResolution;
4150 pOldDlp->iDecompositionStages = pNewDlp->iDecompositionStages;
4151
4152 memcpy(pOldDlp->uiCodingIdx2TemporalId, pNewDlp->uiCodingIdx2TemporalId, sizeof(pOldDlp->uiCodingIdx2TemporalId)); // confirmed_safe_unsafe_usage
4153
4154 ++ iIndexD;
4155 } while (iIndexD < pOldParam->iNumDependencyLayer);
4156 }
4157
4158 /* Any else initialization/reset for rate control here? */
4159
4160 return 0;
4161}
4162
4163
4164int32_t WelsCodeOnePicPartition( sWelsEncCtx *pCtx,
4165 SLayerBSInfo *pLayerBsInfo,
4166 int32_t *pNalIdxInLayer,
4167 int32_t* pLayerSize,
4168 int32_t iFirstMbInPartition, // first mb inclusive in partition
4169 int32_t iEndMbInPartition, // end mb exclusive in partition
4170 int32_t iStartSliceIdx
4171 )
4172{
4173
4174 SDqLayer * pCurLayer = pCtx->pCurDqLayer;
4175 SSliceCtx * pSliceCtx = pCurLayer->pSliceEncCtx;
4176 int32_t iNalLen[MAX_NAL_UNITS_IN_LAYER] = {0};
4177 int32_t iNalIdxInLayer = *pNalIdxInLayer;
4178 int32_t iSliceIdx = iStartSliceIdx;
4179 const int32_t kiSliceStep = pCtx->iActiveThreadsNum;
4180 const int32_t kiPartitionId = iStartSliceIdx % kiSliceStep;
4181 int32_t iPartitionBsSize = 0;
4182 int32_t iAnyMbLeftInPartition= iEndMbInPartition - iFirstMbInPartition;
4183 const EWelsNalUnitType keNalType = pCtx->eNalType;
4184 const EWelsNalRefIdc keNalRefIdc = pCtx->eNalPriority;
4185 const bool_t kbNeedPrefix = pCtx->bNeedPrefixNalFlag;
4186
4187 //init
4188 {
4189 pSliceCtx->pFirstMbInSlice[iSliceIdx] = iFirstMbInPartition;
4190 pCurLayer->pNumSliceCodedOfPartition[kiPartitionId] = 1; // one slice per partition intialized, dynamic slicing inside
4191 pCurLayer->pLastMbIdxOfPartition[kiPartitionId] = iEndMbInPartition-1;
4192 }
4193 pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId] = 0;
4194
4195 while ( iAnyMbLeftInPartition > 0 )
4196 {
4197 int32_t iSliceSize = 0;
4198
4199 if ( iSliceIdx >= pSliceCtx->iMaxSliceNumConstraint ) // insufficient memory in pSliceInLayer[]
4200 {
4201 // TODO: need exception handler for not large enough of MAX_SLICES_NUM related memory usage
4202 // No idea about its solution due MAX_SLICES_NUM is fixed lenght in relevent pData structure
4203 return 1;
4204 }
4205
4206 if ( kbNeedPrefix )
4207 {
4208 iPartitionBsSize += AddPrefixNal( pCtx, pLayerBsInfo, &iNalLen[0], &iNalIdxInLayer, keNalType, keNalRefIdc );
4209 }
4210
4211 WelsLoadNal( pCtx->pOut, keNalType, keNalRefIdc );
4212 WelsCodeOneSlice( pCtx, iSliceIdx, keNalType );
4213 WelsUnloadNal( pCtx->pOut );
4214
4215 iSliceSize = WelsEncodeNalExt( &pCtx->pOut->sNalList[pCtx->pOut->iNalIndex-1],
4216 &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
4217 pCtx->pFrameBs + pCtx->iPosBsBuffer,
4218 &iNalLen[iNalIdxInLayer] );
4219 pCtx->iPosBsBuffer += iSliceSize;
4220 iPartitionBsSize += iSliceSize;
4221 pLayerBsInfo->iNalLengthInByte[iNalIdxInLayer] = iSliceSize;
4222
4223#if defined(SLICE_INFO_OUTPUT)
4224 fprintf( stderr,
4225 "@slice=%-6d sliceType:%c idc:%d size:%-6d\n",
4226 iSliceIdx,
4227 (pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
4228 eNalRefIdc,
4229 iSliceSize );
4230#endif//SLICE_INFO_OUTPUT
4231
4232 ++ iNalIdxInLayer;
4233 iSliceIdx += kiSliceStep; //if uiSliceIdx is not continuous
4234 iAnyMbLeftInPartition = iEndMbInPartition - (1 + pCurLayer->pLastCodedMbIdxOfPartition[kiPartitionId]);
4235 }
4236
4237 *pLayerSize = iPartitionBsSize;
4238 *pNalIdxInLayer = iNalIdxInLayer;
4239
4240 // slice based packing???
4241 pLayerBsInfo->uiLayerType = VIDEO_CODING_LAYER;
4242 pLayerBsInfo->uiSpatialId = pCtx->uiDependencyId;
4243 pLayerBsInfo->uiTemporalId = pCtx->uiTemporalId;
4244 pLayerBsInfo->uiQualityId = 0;
4245 pLayerBsInfo->uiPriorityId = 0;
4246 pLayerBsInfo->iNalCount = iNalIdxInLayer;
4247
4248 return 0;
4249}
4250} // namespace WelsSVCEnc

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