Coverage Report

Created: 2026-08-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libhevc/decoder/ihevcd_fmt_conv.c
Line
Count
Source
1
/******************************************************************************
2
*
3
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
4
*
5
* Licensed under the Apache License, Version 2.0 (the "License");
6
* you may not use this file except in compliance with the License.
7
* You may obtain a copy of the License at:
8
*
9
* http://www.apache.org/licenses/LICENSE-2.0
10
*
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
16
*
17
******************************************************************************/
18
/**
19
*******************************************************************************
20
* @file
21
*  ihevcd_fmt_conv.c
22
*
23
* @brief
24
*  Contains functions for format conversion or frame copy of output buffer
25
*
26
* @author
27
*  Harish
28
*
29
* @par List of Functions:
30
*
31
* @remarks
32
*  None
33
*
34
*******************************************************************************
35
*/
36
/*****************************************************************************/
37
/* File Includes                                                             */
38
/*****************************************************************************/
39
#include <stdio.h>
40
#include <stddef.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <assert.h>
44
45
#include "ihevc_typedefs.h"
46
#include "iv.h"
47
#include "ivd.h"
48
#include "ihevcd_cxa.h"
49
#include "ithread.h"
50
51
#include "ihevc_defs.h"
52
#include "ihevc_debug.h"
53
#include "ihevc_structs.h"
54
#include "ihevc_macros.h"
55
#include "ihevc_platform_macros.h"
56
#include "ihevc_cabac_tables.h"
57
#include "ihevc_disp_mgr.h"
58
59
#include "ihevcd_defs.h"
60
#include "ihevcd_function_selector.h"
61
#include "ihevcd_structs.h"
62
#include "ihevcd_error.h"
63
#include "ihevcd_nal.h"
64
#include "ihevcd_bitstream.h"
65
#include "ihevcd_fmt_conv.h"
66
#include "ihevcd_profile.h"
67
68
/* SIMD variants of format conversion modules do not support width less than 32 */
69
0
#define MIN_FMT_CONV_SIMD_WIDTH 32
70
/**
71
*******************************************************************************
72
*
73
* @brief Function used from copying a 420SP buffer
74
*
75
* @par   Description
76
* Function used from copying a 420SP buffer
77
*
78
* @param[in] pu1_y_src
79
*   Input Y pointer
80
*
81
* @param[in] pu1_uv_src
82
*   Input UV pointer (UV is interleaved either in UV or VU format)
83
*
84
* @param[in] pu1_y_dst
85
*   Output Y pointer
86
*
87
* @param[in] pu1_uv_dst
88
*   Output UV pointer (UV is interleaved in the same format as that of input)
89
*
90
* @param[in] wd
91
*   Width
92
*
93
* @param[in] ht
94
*   Height
95
*
96
* @param[in] src_y_strd
97
*   Input Y Stride
98
*
99
* @param[in] src_uv_strd
100
*   Input UV stride
101
*
102
* @param[in] dst_y_strd
103
*   Output Y stride
104
*
105
* @param[in] dst_uv_strd
106
*   Output UV stride
107
*
108
* @returns None
109
*
110
* @remarks In case there is a need to perform partial frame copy then
111
* by passion appropriate source and destination pointers and appropriate
112
* values for wd and ht it can be done
113
*
114
*******************************************************************************
115
*/
116
117
void ihevcd_fmt_conv_420sp_to_420sp(UWORD8 *pu1_y_src,
118
                                    UWORD8 *pu1_uv_src,
119
                                    UWORD8 *pu1_y_dst,
120
                                    UWORD8 *pu1_uv_dst,
121
                                    WORD32 wd,
122
                                    WORD32 ht,
123
                                    WORD32 src_y_strd,
124
                                    WORD32 src_uv_strd,
125
                                    WORD32 dst_y_strd,
126
                                    WORD32 dst_uv_strd)
127
0
{
128
0
    UWORD8 *pu1_src, *pu1_dst;
129
0
    WORD32 num_rows, num_cols, src_strd, dst_strd;
130
0
    WORD32 i;
131
132
    /* copy luma */
133
0
    pu1_src = (UWORD8 *)pu1_y_src;
134
0
    pu1_dst = (UWORD8 *)pu1_y_dst;
135
136
0
    num_rows = ht;
137
0
    num_cols = wd;
138
139
0
    src_strd = src_y_strd;
140
0
    dst_strd = dst_y_strd;
141
142
0
    for(i = 0; i < num_rows; i++)
143
0
    {
144
0
        memcpy(pu1_dst, pu1_src, num_cols);
145
0
        pu1_dst += dst_strd;
146
0
        pu1_src += src_strd;
147
0
    }
148
149
    /* copy U and V */
150
0
    pu1_src = (UWORD8 *)pu1_uv_src;
151
0
    pu1_dst = (UWORD8 *)pu1_uv_dst;
152
153
0
    num_rows = ht >> 1;
154
0
    num_cols = wd;
155
156
0
    src_strd = src_uv_strd;
157
0
    dst_strd = dst_uv_strd;
158
159
0
    for(i = 0; i < num_rows; i++)
160
0
    {
161
0
        memcpy(pu1_dst, pu1_src, num_cols);
162
0
        pu1_dst += dst_strd;
163
0
        pu1_src += src_strd;
164
0
    }
165
0
    return;
166
0
}
167
168
169
/**
170
*******************************************************************************
171
*
172
* @brief Function used from copying a 400 buffer
173
*
174
* @par   Description
175
* Function used from copying a 400 buffer
176
*
177
* @param[in] pu1_y_src
178
*   Input Y pointer
179
*
180
* @param[in] pu1_y_dst
181
*   Output Y pointer
182
*
183
* @param[in] wd
184
*   Width
185
*
186
* @param[in] ht
187
*   Height
188
*
189
* @param[in] src_y_strd
190
*   Input Y Stride
191
*
192
* @param[in] dst_y_strd
193
*   Output Y stride
194
*
195
* @returns None
196
*
197
* @remarks In case there is a need to perform partial frame copy then
198
* by passion appropriate source and destination pointers and appropriate
199
* values for wd and ht it can be done
200
*
201
*******************************************************************************
202
*/
203
204
void ihevcd_fmt_conv_luma_copy(UWORD8 *pu1_y_src,
205
                               UWORD8 *pu1_y_dst,
206
                               WORD32 wd,
207
                               WORD32 ht,
208
                               WORD32 src_y_strd,
209
                               WORD32 dst_y_strd)
210
0
{
211
0
    UWORD8 *pu1_src, *pu1_dst;
212
0
    WORD32 num_rows, num_cols, src_strd, dst_strd;
213
0
    WORD32 i;
214
215
    /* copy luma */
216
0
    pu1_src = (UWORD8 *)pu1_y_src;
217
0
    pu1_dst = (UWORD8 *)pu1_y_dst;
218
219
0
    num_rows = ht;
220
0
    num_cols = wd;
221
222
0
    src_strd = src_y_strd;
223
0
    dst_strd = dst_y_strd;
224
225
0
    for(i = 0; i < num_rows; i++)
226
0
    {
227
0
        memcpy(pu1_dst, pu1_src, num_cols);
228
0
        pu1_dst += dst_strd;
229
0
        pu1_src += src_strd;
230
0
    }
231
0
    return;
232
0
}
233
234
/**
235
*******************************************************************************
236
*
237
* @brief Function to convert a YUV 4:0:0 buffer to YUV 4:2:0 buffer
238
*
239
* @par   Description
240
* This function handles the format conversion from a 4:0:0 input buffer to a
241
* 4:2:0 output buffer. It copies the Luma (Y) plane directly and synthesizes
242
* the Chroma (U and V) planes by initializing them to a neutral gray value (128).
243
*
244
* @param[in] pu1_y_src
245
*   Input Y pointer
246
*
247
* @param[out] pu1_y_dst_tmp
248
*   Output Y pointer
249
*
250
* @param[out] pu1_u_dst_tmp
251
*   Output Chroma U pointer
252
*
253
* @param[out] pu1_v_dst_tmp
254
*   Output Chroma V pointer
255
*
256
* @param[in] ps_codec
257
*   Pointer to the codec structure
258
*
259
* @param[in] num_rows
260
*   Number of rows (height) to process.
261
*
262
* @returns None
263
*
264
* @remarks The Chroma (U and V) planes are initialized to 128, which represents
265
* a neutral gray in 8-bit YUV, effectively 'zeroing out' the color information
266
* present in the 4:0:0 (grayscale) source. The Luma plane is copied using
267
* ihevcd_fmt_conv_400_to_400.
268
*
269
*******************************************************************************
270
*/
271
void ihevcd_fmt_conv_400_to_420p(UWORD8 *pu1_y_src,
272
                                 UWORD8 *pu1_y_dst,
273
                                 UWORD8 *pu1_u_dst,
274
                                 UWORD8 *pu1_v_dst,
275
                                 WORD32 wd,
276
                                 WORD32 ht,
277
                                 WORD32 src_y_strd,
278
                                 WORD32 dst_y_strd,
279
                                 WORD32 dst_uv_strd)
280
0
{
281
0
    ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
282
0
    for(int i = 0; i < ALIGN2(ht) / 2; i++)
283
0
    {
284
0
        memset(pu1_u_dst, 128, ALIGN2(wd) / 2);
285
0
        memset(pu1_v_dst, 128, ALIGN2(wd) / 2);
286
0
        pu1_u_dst += dst_uv_strd;
287
0
        pu1_v_dst += dst_uv_strd;
288
0
    }
289
0
    return;
290
0
}
291
292
/**
293
*******************************************************************************
294
*
295
* @brief Function used from copying a 420SP buffer
296
*
297
* @par   Description
298
* Function used from copying a 420SP buffer
299
*
300
* @param[in] pu1_y_src
301
*   Input Y pointer
302
*
303
* @param[in] pu1_uv_src
304
*   Input UV pointer (UV is interleaved either in UV or VU format)
305
*
306
* @param[in] pu1_y_dst
307
*   Output Y pointer
308
*
309
* @param[in] pu1_uv_dst
310
*   Output UV pointer (UV is interleaved in the same format as that of input)
311
*
312
* @param[in] wd
313
*   Width
314
*
315
* @param[in] ht
316
*   Height
317
*
318
* @param[in] src_y_strd
319
*   Input Y Stride
320
*
321
* @param[in] src_uv_strd
322
*   Input UV stride
323
*
324
* @param[in] dst_y_strd
325
*   Output Y stride
326
*
327
* @param[in] dst_uv_strd
328
*   Output UV stride
329
*
330
* @returns None
331
*
332
* @remarks In case there is a need to perform partial frame copy then
333
* by passion appropriate source and destination pointers and appropriate
334
* values for wd and ht it can be done
335
*
336
*******************************************************************************
337
*/
338
void ihevcd_fmt_conv_420sp_to_420sp_swap_uv(UWORD8 *pu1_y_src,
339
                                            UWORD8 *pu1_uv_src,
340
                                            UWORD8 *pu1_y_dst,
341
                                            UWORD8 *pu1_uv_dst,
342
                                            WORD32 wd,
343
                                            WORD32 ht,
344
                                            WORD32 src_y_strd,
345
                                            WORD32 src_uv_strd,
346
                                            WORD32 dst_y_strd,
347
                                            WORD32 dst_uv_strd)
348
0
{
349
0
    UWORD8 *pu1_src, *pu1_dst;
350
0
    WORD32 num_rows, num_cols, src_strd, dst_strd;
351
0
    WORD32 i;
352
353
    /* copy luma */
354
0
    pu1_src = (UWORD8 *)pu1_y_src;
355
0
    pu1_dst = (UWORD8 *)pu1_y_dst;
356
357
0
    num_rows = ht;
358
0
    num_cols = wd;
359
360
0
    src_strd = src_y_strd;
361
0
    dst_strd = dst_y_strd;
362
363
0
    for(i = 0; i < num_rows; i++)
364
0
    {
365
0
        memcpy(pu1_dst, pu1_src, num_cols);
366
0
        pu1_dst += dst_strd;
367
0
        pu1_src += src_strd;
368
0
    }
369
370
    /* copy U and V */
371
0
    pu1_src = (UWORD8 *)pu1_uv_src;
372
0
    pu1_dst = (UWORD8 *)pu1_uv_dst;
373
374
0
    num_rows = ht >> 1;
375
0
    num_cols = wd;
376
377
0
    src_strd = src_uv_strd;
378
0
    dst_strd = dst_uv_strd;
379
380
0
    for(i = 0; i < num_rows; i++)
381
0
    {
382
0
        WORD32 j;
383
0
        for(j = 0; j < num_cols; j += 2)
384
0
        {
385
0
            pu1_dst[j + 0] = pu1_src[j + 1];
386
0
            pu1_dst[j + 1] = pu1_src[j + 0];
387
0
        }
388
0
        pu1_dst += dst_strd;
389
0
        pu1_src += src_strd;
390
0
    }
391
0
    return;
392
0
}
393
/**
394
*******************************************************************************
395
*
396
* @brief Function used from copying a 420SP buffer
397
*
398
* @par   Description
399
* Function used from copying a 420SP buffer
400
*
401
* @param[in] pu1_y_src
402
*   Input Y pointer
403
*
404
* @param[in] pu1_uv_src
405
*   Input UV pointer (UV is interleaved either in UV or VU format)
406
*
407
* @param[in] pu1_y_dst
408
*   Output Y pointer
409
*
410
* @param[in] pu1_u_dst
411
*   Output U pointer
412
*
413
* @param[in] pu1_v_dst
414
*   Output V pointer
415
*
416
* @param[in] wd
417
*   Width
418
*
419
* @param[in] ht
420
*   Height
421
*
422
* @param[in] src_y_strd
423
*   Input Y Stride
424
*
425
* @param[in] src_uv_strd
426
*   Input UV stride
427
*
428
* @param[in] dst_y_strd
429
*   Output Y stride
430
*
431
* @param[in] dst_uv_strd
432
*   Output UV stride
433
*
434
* @param[in] is_u_first
435
*   Flag to indicate if U is the first byte in input chroma part
436
*
437
* @returns none
438
*
439
* @remarks In case there is a need to perform partial frame copy then
440
* by passion appropriate source and destination pointers and appropriate
441
* values for wd and ht it can be done
442
*
443
*******************************************************************************
444
*/
445
446
447
void ihevcd_fmt_conv_420sp_to_420p(UWORD8 *pu1_y_src,
448
                                   UWORD8 *pu1_uv_src,
449
                                   UWORD8 *pu1_y_dst,
450
                                   UWORD8 *pu1_u_dst,
451
                                   UWORD8 *pu1_v_dst,
452
                                   WORD32 wd,
453
                                   WORD32 ht,
454
                                   WORD32 src_y_strd,
455
                                   WORD32 src_uv_strd,
456
                                   WORD32 dst_y_strd,
457
                                   WORD32 dst_uv_strd,
458
                                   WORD32 is_u_first,
459
                                   WORD32 disable_luma_copy)
460
0
{
461
0
    UWORD8 *pu1_src, *pu1_dst;
462
0
    UWORD8 *pu1_u_src, *pu1_v_src;
463
0
    WORD32 num_rows, num_cols, src_strd, dst_strd;
464
0
    WORD32 i, j;
465
466
0
    if(0 == disable_luma_copy)
467
0
    {
468
        /* copy luma */
469
0
        pu1_src = (UWORD8 *)pu1_y_src;
470
0
        pu1_dst = (UWORD8 *)pu1_y_dst;
471
472
0
        num_rows = ht;
473
0
        num_cols = wd;
474
475
0
        src_strd = src_y_strd;
476
0
        dst_strd = dst_y_strd;
477
478
0
        for(i = 0; i < num_rows; i++)
479
0
        {
480
0
            memcpy(pu1_dst, pu1_src, num_cols);
481
0
            pu1_dst += dst_strd;
482
0
            pu1_src += src_strd;
483
0
        }
484
0
    }
485
    /* de-interleave U and V and copy to destination */
486
0
    if(is_u_first)
487
0
    {
488
0
        pu1_u_src = (UWORD8 *)pu1_uv_src;
489
0
        pu1_v_src = (UWORD8 *)pu1_uv_src + 1;
490
0
    }
491
0
    else
492
0
    {
493
0
        pu1_u_src = (UWORD8 *)pu1_uv_src + 1;
494
0
        pu1_v_src = (UWORD8 *)pu1_uv_src;
495
0
    }
496
497
498
0
    num_rows = ht >> 1;
499
0
    num_cols = wd >> 1;
500
501
0
    src_strd = src_uv_strd;
502
0
    dst_strd = dst_uv_strd;
503
504
0
    for(i = 0; i < num_rows; i++)
505
0
    {
506
0
        for(j = 0; j < num_cols; j++)
507
0
        {
508
0
            pu1_u_dst[j] = pu1_u_src[j * 2];
509
0
            pu1_v_dst[j] = pu1_v_src[j * 2];
510
0
        }
511
512
0
        pu1_u_dst += dst_strd;
513
0
        pu1_v_dst += dst_strd;
514
0
        pu1_u_src += src_strd;
515
0
        pu1_v_src += src_strd;
516
0
    }
517
0
    return;
518
0
}
519
520
/**
521
*******************************************************************************
522
*
523
* @brief Function to convert a YUV 4:4:4 sp buffer to YUV 4:4:4 planar buffer
524
*
525
* @par   Description
526
* This function handles the format conversion from a 4:4:4 semi planar input buffer
527
* to a 4:4:4 planar output buffer.
528
*
529
* @param[in] pu1_y_src
530
*   Input Y pointer
531
*
532
* @param[in] pu1_uv_src
533
*   Input UV pointer (UV is interleaved)
534
*
535
* @param[in] pu1_y_dst
536
*   Output Y pointer
537
*
538
* @param[in] pu1_u_dst
539
*   Output U pointer
540
*
541
* @param[in] pu1_v_dst
542
*   Output V pointer
543
*
544
* @param[in] wd
545
*   Width
546
*
547
* @param[in] ht
548
*   Height
549
*
550
* @param[in] src_y_strd
551
*   Input Y Stride
552
*
553
* @param[in] src_uv_strd
554
*   Input UV stride
555
*
556
* @param[in] dst_y_strd
557
*   Output Y stride
558
*
559
* @param[in] dst_uv_strd
560
*   Output U or V stride
561
*
562
* @returns none
563
*
564
* @remarks none
565
*
566
*******************************************************************************
567
*/
568
void ihevcd_fmt_conv_444sp_to_444p(UWORD8 *pu1_y_src,
569
                                   UWORD8 *pu1_uv_src,
570
                                   UWORD8 *pu1_y_dst,
571
                                   UWORD8 *pu1_u_dst,
572
                                   UWORD8 *pu1_v_dst,
573
                                   WORD32 wd,
574
                                   WORD32 ht,
575
                                   WORD32 src_y_strd,
576
                                   WORD32 src_uv_strd,
577
                                   WORD32 dst_y_strd,
578
                                   WORD32 dst_uv_strd)
579
0
{
580
0
    ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
581
582
    /* de-interleave U and V and copy to destination */
583
0
    UWORD8 *pu1_u_src = (UWORD8*)pu1_uv_src;
584
0
    UWORD8 *pu1_v_src = (UWORD8*)pu1_uv_src + 1;
585
586
0
    for(WORD32 i = 0; i < ht; i++)
587
0
    {
588
0
        for(WORD32 j = 0; j < wd; j++)
589
0
        {
590
0
            pu1_u_dst[j] = pu1_u_src[j * 2];
591
0
            pu1_v_dst[j] = pu1_v_src[j * 2];
592
0
        }
593
0
        pu1_u_dst += dst_uv_strd;
594
0
        pu1_v_dst += dst_uv_strd;
595
0
        pu1_u_src += src_uv_strd;
596
0
        pu1_v_src += src_uv_strd;
597
0
    }
598
0
    return;
599
0
}
600
601
void ihevcd_fmt_conv_444sp_to_420p(UWORD8 *pu1_y_src,
602
                                   UWORD8 *pu1_uv_src,
603
                                   UWORD8 *pu1_y_dst,
604
                                   UWORD8 *pu1_u_dst,
605
                                   UWORD8 *pu1_v_dst,
606
                                   WORD32 wd,
607
                                   WORD32 ht,
608
                                   WORD32 src_y_strd,
609
                                   WORD32 src_uv_strd,
610
                                   WORD32 dst_y_strd,
611
                                   WORD32 dst_uv_strd)
612
0
{
613
0
    ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
614
615
0
    for(WORD32 i = 0; i < ht; i += 2)
616
0
    {
617
0
        for(WORD32 j = 0; j < wd; j += 2)
618
0
        {
619
0
            WORD32 cb_sum = pu1_uv_src[j * 2];
620
0
            WORD32 cr_sum = pu1_uv_src[j * 2 + 1];
621
0
            WORD32 count = 1;
622
623
0
            if((j + 1) < wd)
624
0
            {
625
0
                cb_sum += pu1_uv_src[(j + 1) * 2];
626
0
                cr_sum += pu1_uv_src[(j + 1) * 2 + 1];
627
0
                count++;
628
0
            }
629
0
            if((i + 1) < ht)
630
0
            {
631
0
                cb_sum += pu1_uv_src[j * 2 + src_uv_strd];
632
0
                cr_sum += pu1_uv_src[j * 2 + src_uv_strd + 1];
633
0
                count++;
634
0
            }
635
0
            if((j + 1) < wd && (i + 1) < ht)
636
0
            {
637
0
                cb_sum += pu1_uv_src[(j + 1) * 2 + src_uv_strd];
638
0
                cr_sum += pu1_uv_src[(j + 1) * 2 + src_uv_strd + 1];
639
0
                count++;
640
0
            }
641
0
            pu1_u_dst[j / 2] = (cb_sum + (count >> 1)) / count;
642
0
            pu1_v_dst[j / 2] = (cr_sum + (count >> 1)) / count;
643
0
        }
644
0
        pu1_u_dst += dst_uv_strd;
645
0
        pu1_v_dst += dst_uv_strd;
646
0
        pu1_uv_src += (src_uv_strd * 2);
647
0
    }
648
0
    return;
649
0
}
650
651
void ihevcd_fmt_conv_422sp_to_422p(UWORD8 *pu1_y_src,
652
                                   UWORD8 *pu1_uv_src,
653
                                   UWORD8 *pu1_y_dst,
654
                                   UWORD8 *pu1_u_dst,
655
                                   UWORD8 *pu1_v_dst,
656
                                   WORD32 wd,
657
                                   WORD32 ht,
658
                                   WORD32 src_y_strd,
659
                                   WORD32 src_uv_strd,
660
                                   WORD32 dst_y_strd,
661
                                   WORD32 dst_uv_strd)
662
0
{
663
0
    UWORD8 *pu1_u_src, *pu1_v_src;
664
0
    WORD32 i, j;
665
666
0
    ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
667
668
0
    pu1_u_src = (UWORD8 *)pu1_uv_src;
669
0
    pu1_v_src = (UWORD8 *)pu1_uv_src + 1;
670
671
0
    for(i = 0; i < ht; i++)
672
0
    {
673
0
        for(j = 0; j < (wd >> 1); j++)
674
0
        {
675
0
            pu1_u_dst[j] = pu1_u_src[j * 2];
676
0
            pu1_v_dst[j] = pu1_v_src[j * 2];
677
0
        }
678
679
0
        pu1_u_dst += dst_uv_strd;
680
0
        pu1_v_dst += dst_uv_strd;
681
0
        pu1_u_src += src_uv_strd;
682
0
        pu1_v_src += src_uv_strd;
683
0
    }
684
0
    return;
685
0
}
686
687
void ihevcd_fmt_conv_422sp_to_420p(UWORD8 *pu1_y_src,
688
                                   UWORD8 *pu1_uv_src,
689
                                   UWORD8 *pu1_y_dst,
690
                                   UWORD8 *pu1_u_dst,
691
                                   UWORD8 *pu1_v_dst,
692
                                   WORD32 wd,
693
                                   WORD32 ht,
694
                                   WORD32 src_y_strd,
695
                                   WORD32 src_uv_strd,
696
                                   WORD32 dst_y_strd,
697
                                   WORD32 dst_uv_strd)
698
0
{
699
0
    ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
700
701
0
    for(WORD32 i = 0; i < ht; i += 2)
702
0
    {
703
0
        for(WORD32 j = 0; j < wd; j += 2)
704
0
        {
705
0
            WORD32 cb_sum = pu1_uv_src[j];
706
0
            WORD32 cr_sum = pu1_uv_src[j + 1];
707
708
0
            if((i + 1) < ht)
709
0
            {
710
0
                cb_sum += pu1_uv_src[j + src_uv_strd] + 1;
711
0
                cr_sum += pu1_uv_src[j + 1 + src_uv_strd] + 1;
712
713
0
                cb_sum >>= 1;
714
0
                cr_sum >>= 1;
715
0
            }
716
0
            pu1_u_dst[j / 2] = cb_sum;
717
0
            pu1_v_dst[j / 2] = cr_sum;
718
0
        }
719
0
        pu1_u_dst += dst_uv_strd;
720
0
        pu1_v_dst += dst_uv_strd;
721
0
        pu1_uv_src += (src_uv_strd * 2);
722
0
    }
723
0
    return;
724
0
}
725
726
727
/**
728
*******************************************************************************
729
*
730
* @brief Function used from format conversion or frame copy
731
*
732
* @par   Description
733
* Function used from copying or converting a reference frame to display buffer
734
* in non shared mode
735
*
736
* @param[in] pu1_y_dst
737
*   Output Y pointer
738
*
739
* @param[in] pu1_u_dst
740
*   Output U/UV pointer ( UV is interleaved in the same format as that of input)
741
*
742
* @param[in] pu1_v_dst
743
*   Output V pointer ( used in 420P output case)
744
*
745
* @param[in] blocking
746
*   To indicate whether format conversion should wait till frame is reconstructed
747
*   and then return after complete copy is done. To be set to 1 when called at the
748
*   end of frame processing and set to 0 when called between frame processing modules
749
*   in order to utilize available MCPS
750
*
751
* @returns Error from IHEVCD_ERROR_T
752
*
753
*******************************************************************************
754
*/
755
IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
756
                               process_ctxt_t *ps_proc,
757
                               UWORD8 *pu1_y_dst,
758
                               UWORD8 *pu1_u_dst,
759
                               UWORD8 *pu1_v_dst,
760
                               WORD32 cur_row,
761
                               WORD32 num_rows)
762
0
{
763
0
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
764
0
    pic_buf_t *ps_disp_pic;
765
0
    UWORD8 *pu1_y_src, *pu1_uv_src;
766
0
    UWORD8 *pu1_y_dst_tmp, *pu1_uv_dst_tmp;
767
0
    UWORD8 *pu1_u_dst_tmp, *pu1_v_dst_tmp;
768
0
    WORD32 is_u_first;
769
0
    UWORD8 *pu1_luma;
770
0
    UWORD8 *pu1_chroma;
771
0
    sps_t *ps_sps;
772
0
    WORD32 disable_luma_copy;
773
0
    WORD32 crop_unit_x, crop_unit_y;
774
0
    WORD32 h_samp_factor, v_samp_factor;
775
0
    WORD32 src_chroma_pixel_strd = 2;
776
0
    WORD32 src_chroma_row_stride;
777
778
0
    if(0 == num_rows)
779
0
        return ret;
780
781
    /* In case processing is disabled, then no need to format convert/copy */
782
0
    PROFILE_DISABLE_FMT_CONV();
783
0
    ps_sps = ps_proc->ps_sps;
784
785
0
    h_samp_factor = (CHROMA_FMT_IDC_YUV444 == ps_sps->i1_chroma_format_idc) ? 1 : 2;
786
0
    v_samp_factor = (CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc) ? 2 : 1;
787
788
0
    crop_unit_x = 1;
789
0
    crop_unit_y = 1;
790
791
0
    if(CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc)
792
0
    {
793
0
        crop_unit_x = 2;
794
0
        crop_unit_y = 2;
795
0
    }
796
0
    else if(CHROMA_FMT_IDC_YUV422 == ps_sps->i1_chroma_format_idc)
797
0
    {
798
0
        crop_unit_x = 2;
799
0
        crop_unit_y = 1;
800
0
    }
801
802
0
    ps_disp_pic = ps_codec->ps_disp_buf;
803
0
    pu1_luma = ps_disp_pic->pu1_luma;
804
0
    if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
805
0
    {
806
0
        pu1_chroma = ps_disp_pic->pu1_chroma;
807
0
    }
808
809
810
    /* Take care of cropping */
811
0
    pu1_luma    += ps_codec->i4_strd * ps_sps->i2_pic_crop_top_offset * crop_unit_y + ps_sps->i2_pic_crop_left_offset * crop_unit_x;
812
813
0
    src_chroma_row_stride = (ps_codec->i4_strd * src_chroma_pixel_strd / h_samp_factor);
814
0
    if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
815
0
    {
816
0
        pu1_chroma += (ps_sps->i2_pic_crop_top_offset * src_chroma_row_stride)
817
0
                        + ps_sps->i2_pic_crop_left_offset * src_chroma_pixel_strd;
818
0
    }
819
0
    is_u_first = (IV_YUV_420SP_UV == ps_codec->e_ref_chroma_fmt) ? 1 : 0;
820
821
    /* In case of 420P output luma copy is disabled for shared mode */
822
0
    disable_luma_copy = 0;
823
0
    if(1 == ps_codec->i4_share_disp_buf)
824
0
    {
825
0
        disable_luma_copy = 1;
826
0
    }
827
828
829
830
0
    {
831
0
        pu1_y_src   = pu1_luma + cur_row * ps_codec->i4_strd;
832
0
        if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
833
0
        {
834
0
            pu1_uv_src = pu1_chroma + ((cur_row / v_samp_factor) * src_chroma_row_stride);
835
0
        }
836
837
        /* In case of shared mode, with 420P output, get chroma destination */
838
0
        if((1 == ps_codec->i4_share_disp_buf) && (IV_YUV_420P == ps_codec->e_chroma_fmt))
839
0
        {
840
0
            WORD32 i;
841
0
            for(i = 0; i < ps_codec->i4_share_disp_buf_cnt; i++)
842
0
            {
843
0
                WORD32 diff = ps_disp_pic->pu1_luma - ps_codec->s_disp_buffer[i].pu1_bufs[0];
844
0
                if(diff == (ps_codec->i4_strd * PAD_TOP + PAD_LEFT))
845
0
                {
846
0
                    pu1_u_dst = ps_codec->s_disp_buffer[i].pu1_bufs[1];
847
0
                    pu1_u_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
848
849
0
                    pu1_v_dst = ps_codec->s_disp_buffer[i].pu1_bufs[2];
850
0
                    pu1_v_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
851
0
                    break;
852
0
                }
853
0
            }
854
0
        }
855
0
        pu1_y_dst_tmp  = pu1_y_dst  + cur_row * ps_codec->i4_disp_strd;
856
0
        if(IV_YUV_444P == ps_codec->e_chroma_fmt)
857
0
        {
858
0
            pu1_u_dst_tmp = pu1_u_dst + cur_row * ps_codec->i4_disp_strd;
859
0
            pu1_v_dst_tmp = pu1_v_dst + cur_row * ps_codec->i4_disp_strd;
860
0
        }
861
0
        else if(IV_YUV_422P == ps_codec->e_chroma_fmt)
862
0
        {
863
0
            pu1_u_dst_tmp = pu1_u_dst + cur_row * ((ps_codec->i4_disp_strd + 1) / 2);
864
0
            pu1_v_dst_tmp = pu1_v_dst + cur_row * ((ps_codec->i4_disp_strd + 1) / 2);
865
0
        }
866
0
        else if(IV_YUV_420P == ps_codec->e_chroma_fmt)
867
0
        {
868
0
            pu1_u_dst_tmp = pu1_u_dst + ((cur_row + 1) / 2) * ((ps_codec->i4_disp_strd + 1) / 2);
869
0
            pu1_v_dst_tmp = pu1_v_dst + ((cur_row + 1) / 2) * ((ps_codec->i4_disp_strd + 1) / 2);
870
0
        }
871
0
        else if(IV_YUV_420SP_UV == ps_codec->e_chroma_fmt
872
0
                        || IV_YUV_420SP_VU == ps_codec->e_chroma_fmt)
873
0
        {
874
0
            pu1_uv_dst_tmp = pu1_u_dst + ((cur_row + 1) / 2) * ALIGN2(ps_codec->i4_disp_strd);
875
0
        }
876
877
        /* In case of multi threaded implementation, format conversion might be called
878
         * before reconstruction is completed. If the frame being converted/copied
879
         * is same as the frame being reconstructed,
880
         * Check how many rows can be format converted
881
         * Convert those many rows and then check for remaining rows and so on
882
         */
883
884
0
        if((0 == ps_codec->i4_flush_mode) && (ps_codec->i4_disp_buf_id == ps_proc->i4_cur_pic_buf_id) && (1 < ps_codec->i4_num_cores))
885
0
        {
886
0
            WORD32 idx;
887
0
            UWORD8 *pu1_buf;
888
0
            WORD32 status;
889
0
            WORD32 last_row = cur_row + num_rows;
890
0
            WORD32 last_ctb_y;
891
0
            UWORD32 ctb_in_row;
892
893
0
            while(1)
894
0
            {
895
0
                last_row = cur_row + MAX(num_rows, (1 << ps_sps->i1_log2_ctb_size)) +
896
0
                                ps_sps->i2_pic_crop_top_offset * crop_unit_y;
897
0
                last_ctb_y = (last_row >> ps_sps->i1_log2_ctb_size) - 1;
898
                /* Since deblocking works with a shift of -4, -4 ,wait till next CTB row is processed */
899
0
                last_ctb_y++;
900
                /* In case of a  conformance window, an extra wait of one row might be needed */
901
0
                last_ctb_y++;
902
0
                last_ctb_y = MIN(last_ctb_y, (ps_sps->i2_pic_ht_in_ctb - 1));
903
904
0
                idx = (last_ctb_y * ps_sps->i2_pic_wd_in_ctb);
905
906
                /*Check if the row below is completely processed before proceeding with format conversion*/
907
0
                status = 1;
908
0
                for(ctb_in_row = 0; (WORD32)ctb_in_row < ps_sps->i2_pic_wd_in_ctb; ctb_in_row++)
909
0
                {
910
0
                    pu1_buf = (ps_codec->pu1_proc_map + idx + ctb_in_row);
911
0
                    status &= *pu1_buf;
912
0
                }
913
914
0
                if(status)
915
0
                {
916
0
                    break;
917
0
                }
918
0
                else
919
0
                {
920
0
                    ithread_yield();
921
0
                }
922
0
            }
923
0
        }
924
925
0
        if((IV_YUV_420SP_UV == ps_codec->e_chroma_fmt) || (IV_YUV_420SP_VU == ps_codec->e_chroma_fmt))
926
0
        {
927
0
            if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV420)
928
0
            {
929
0
                ihevcd_fmt_conv_420sp_to_420sp_ft *fmt_conv_fptr;
930
0
                if(ps_codec->i4_disp_wd >= MIN_FMT_CONV_SIMD_WIDTH)
931
0
                {
932
0
                    fmt_conv_fptr = ps_codec->s_func_selector.ihevcd_fmt_conv_420sp_to_420sp_fptr;
933
0
                }
934
0
                else
935
0
                {
936
0
                    fmt_conv_fptr = ihevcd_fmt_conv_420sp_to_420sp;
937
0
                }
938
0
                fmt_conv_fptr(pu1_y_src, pu1_uv_src,
939
0
                              pu1_y_dst_tmp, pu1_uv_dst_tmp,
940
0
                              ps_codec->i4_disp_wd, num_rows,
941
0
                              ps_codec->i4_strd, ps_codec->i4_strd,
942
0
                              ps_codec->i4_disp_strd, ps_codec->i4_disp_strd);
943
0
            }
944
0
        }
945
0
        else if(IV_GRAY == ps_codec->e_chroma_fmt)
946
0
        {
947
0
            ihevcd_fmt_conv_luma_copy(pu1_y_src,
948
0
                                       pu1_y_dst_tmp,
949
0
                                       ps_codec->i4_disp_wd, num_rows,
950
0
                                       ps_codec->i4_strd,
951
0
                                       ps_codec->i4_disp_strd);
952
0
        }
953
0
        else if(IV_YUV_444P == ps_codec->e_chroma_fmt)
954
0
        {
955
0
            if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV444)
956
0
            {
957
0
                ps_codec->s_func_selector.ihevcd_fmt_conv_444sp_to_444p_fptr(
958
0
                                pu1_y_src, pu1_uv_src,
959
0
                                pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
960
0
                                ps_codec->i4_disp_wd, num_rows,
961
0
                                ps_codec->i4_strd, src_chroma_row_stride,
962
0
                                ps_codec->i4_disp_strd, ps_codec->i4_disp_strd);
963
0
            }
964
0
        }
965
0
        else if(IV_YUV_422P == ps_codec->e_chroma_fmt)
966
0
        {
967
0
            if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV422)
968
0
            {
969
0
                ihevcd_fmt_conv_422sp_to_422p(pu1_y_src, pu1_uv_src,
970
0
                                              pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
971
0
                                              ps_codec->i4_disp_wd, num_rows,
972
0
                                              ps_codec->i4_strd, ps_codec->i4_strd,
973
0
                                              ps_codec->i4_disp_strd,
974
0
                                              ((ps_codec->i4_disp_strd + 1) / 2));
975
0
            }
976
0
        }
977
0
        else if(IV_YUV_420P == ps_codec->e_chroma_fmt)
978
0
        {
979
0
            if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_MONOCHROME)
980
0
            {
981
0
                ihevcd_fmt_conv_400_to_420p(pu1_y_src,
982
0
                                            pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
983
0
                                            ps_codec->i4_disp_wd, num_rows,
984
0
                                            ps_codec->i4_strd,
985
0
                                            ps_codec->i4_disp_strd,
986
0
                                            ((ps_codec->i4_disp_strd + 1) / 2));
987
0
            }
988
0
            else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV420)
989
0
            {
990
0
                ihevcd_fmt_conv_420sp_to_420p_ft *fmt_conv_fptr;
991
0
                if(ps_codec->i4_disp_wd >= MIN_FMT_CONV_SIMD_WIDTH)
992
0
                {
993
0
                    fmt_conv_fptr = ps_codec->s_func_selector.ihevcd_fmt_conv_420sp_to_420p_fptr;
994
0
                }
995
0
                else
996
0
                {
997
0
                    fmt_conv_fptr = ihevcd_fmt_conv_420sp_to_420p;
998
0
                }
999
1000
0
                if(0 == disable_luma_copy)
1001
0
                {
1002
                    // copy luma
1003
0
                    WORD32 i;
1004
0
                    WORD32 num_cols = ps_codec->i4_disp_wd;
1005
1006
0
                    for(i = 0; i < num_rows; i++)
1007
0
                    {
1008
0
                        memcpy(pu1_y_dst_tmp, pu1_y_src, num_cols);
1009
0
                        pu1_y_dst_tmp += ps_codec->i4_disp_strd;
1010
0
                        pu1_y_src += ps_codec->i4_strd;
1011
0
                    }
1012
1013
0
                    disable_luma_copy = 1;
1014
0
                }
1015
0
                fmt_conv_fptr(pu1_y_src, pu1_uv_src,
1016
0
                              pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
1017
0
                              ps_codec->i4_disp_wd, num_rows,
1018
0
                              ps_codec->i4_strd, ps_codec->i4_strd,
1019
0
                              ps_codec->i4_disp_strd, (ps_codec->i4_disp_strd / 2),
1020
0
                              is_u_first,
1021
0
                              disable_luma_copy);
1022
0
            }
1023
0
            else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV444)
1024
0
            {
1025
0
                ihevcd_fmt_conv_444sp_to_420p(pu1_y_src, pu1_uv_src,
1026
0
                                              pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
1027
0
                                              ps_codec->i4_disp_wd, num_rows,
1028
0
                                              ps_codec->i4_strd, src_chroma_row_stride,
1029
0
                                              ps_codec->i4_disp_strd,
1030
0
                                              ((ps_codec->i4_disp_strd + 1) / 2));
1031
0
            }
1032
0
            else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV422)
1033
0
            {
1034
0
                ihevcd_fmt_conv_422sp_to_420p(pu1_y_src, pu1_uv_src,
1035
0
                                              pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
1036
0
                                              ps_codec->i4_disp_wd, num_rows,
1037
0
                                              ps_codec->i4_strd, src_chroma_row_stride,
1038
0
                                              ps_codec->i4_disp_strd,
1039
0
                                              ((ps_codec->i4_disp_strd + 1) / 2));
1040
0
            }
1041
0
        }
1042
0
    }
1043
0
    return (ret);
1044
0
}
1045