1/*
2 *
3 * Copyright 2012 Samsung Electronics S.LSI Co. LTD
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 * @file    swconvertor.c
20 *
21 * @brief   SEC_OMX specific define. It support MFC 6.x tiled.
22 *
23 * @author  ShinWon Lee (shinwon.lee@samsung.com)
24 *
25 * @version 1.0
26 *
27 * @history
28 *   2012.02.01 : Create
29 */
30
31#include "stdio.h"
32#include "stdlib.h"
33#include "swconverter.h"
34
35/* 2D Configurable tiled memory access (TM)
36 * Return the linear address from tiled position (x, y) */
37unsigned int Tile2D_To_Linear(
38    unsigned int width,
39    unsigned int height,
40    unsigned int xpos,
41    unsigned int ypos,
42    int crFlag)
43{
44    int  tileNumX;
45    int  tileX, tileY;
46    int  tileAddr;
47    int  offset;
48    int  addr;
49
50    width = ((width + 15) / 16) * 16;
51    tileNumX = width / 16;
52
53    /* crFlag - 0: Y plane, 1: CbCr plane */
54    if (crFlag == 0) {
55        tileX = xpos / 16;
56        tileY = ypos / 16;
57        tileAddr = tileY * tileNumX + tileX;
58        offset = (ypos & 15) * 16 + (xpos & 15);
59        addr = (tileAddr << 8) | offset;
60    } else {
61        tileX = xpos / 16;
62        tileY = ypos / 8;
63        tileAddr = tileY * tileNumX + tileX;
64        offset = (ypos & 7) * 16 + (xpos & 15);
65        addr = (tileAddr << 7) | offset;
66    }
67
68    return addr;
69}
70
71/*
72 * De-interleaves src to dest1, dest2
73 *
74 * @param dest1
75 *   Address of de-interleaved data[out]
76 *
77 * @param dest2
78 *   Address of de-interleaved data[out]
79 *
80 * @param src
81 *   Address of interleaved data[in]
82 *
83 * @param src_size
84 *   Size of interleaved data[in]
85 */
86void csc_deinterleave_memcpy(
87    unsigned char *dest1,
88    unsigned char *dest2,
89    unsigned char *src,
90    unsigned int src_size)
91{
92    unsigned int i = 0;
93    for(i=0; i<src_size/2; i++) {
94        dest1[i] = src[i*2];
95        dest2[i] = src[i*2+1];
96    }
97}
98
99/*
100 * Interleaves src1, src2 to dest
101 *
102 * @param dest
103 *   Address of interleaved data[out]
104 *
105 * @param src1
106 *   Address of de-interleaved data[in]
107 *
108 * @param src2
109 *   Address of de-interleaved data[in]
110 *
111 * @param src_size
112 *   Size of de-interleaved data[in]
113 */
114void csc_interleave_memcpy(
115    unsigned char *dest,
116    unsigned char *src1,
117    unsigned char *src2,
118    unsigned int src_size)
119{
120    unsigned int i = 0;
121    for(i=0; i<src_size; i++) {
122        dest[i*2] = src1[i];
123        dest[i*2+1] = src2[i];
124    }
125}
126
127/*
128 * Converts tiled data to linear for mfc 6.x tiled
129 * 1. y of nv12t to y of yuv420p
130 * 2. y of nv12t to y of yuv420s
131 *
132 * @param dst
133 *   y address of yuv420[out]
134 *
135 * @param src
136 *   y address of nv12t[in]
137 *
138 * @param yuv420_width
139 *   real width of yuv420[in]
140 *   it should be even
141 *
142 * @param yuv420_height
143 *   real height of yuv420[in]
144 *   it should be even.
145 *
146 */
147void csc_tiled_to_linear_y(
148    unsigned char *y_dst,
149    unsigned char *y_src,
150    unsigned int width,
151    unsigned int height)
152{
153    unsigned int i, j, k;
154    unsigned int aligned_width, aligned_height;
155    unsigned int tiled_width;
156    unsigned int src_offset, dst_offset;
157
158    aligned_height = height & (~0xF);
159    aligned_width = width & (~0xF);
160    tiled_width = ((width + 15) >> 4) << 4;
161
162    for (i = 0; i < aligned_height; i = i + 16) {
163        for (j = 0; j<aligned_width; j = j + 16) {
164            src_offset = (tiled_width * i) + (j << 4);
165            dst_offset = width * i + j;
166            for (k = 0; k < 8; k++) {
167                memcpy(y_dst + dst_offset, y_src + src_offset, 16);
168                src_offset += 16;
169                dst_offset += width;
170                memcpy(y_dst + dst_offset, y_src + src_offset, 16);
171                src_offset += 16;
172                dst_offset += width;
173            }
174        }
175        if (aligned_width != width) {
176            src_offset = (tiled_width * i) + (j << 4);
177            dst_offset = width * i + j;
178            for (k = 0; k < 8; k++) {
179                memcpy(y_dst + dst_offset, y_src + src_offset, width - j);
180                src_offset += 16;
181                dst_offset += width;
182                memcpy(y_dst + dst_offset, y_src + src_offset, width - j);
183                src_offset += 16;
184                dst_offset += width;
185            }
186        }
187    }
188
189    if (aligned_height != height) {
190        for (j = 0; j<aligned_width; j = j + 16) {
191            src_offset = (tiled_width * i) + (j << 4);
192            dst_offset = width * i + j;
193            for (k = 0; k < height - aligned_height; k = k + 2) {
194                memcpy(y_dst + dst_offset, y_src + src_offset, 16);
195                src_offset += 16;
196                dst_offset += width;
197                memcpy(y_dst + dst_offset, y_src + src_offset, 16);
198                src_offset += 16;
199                dst_offset += width;
200            }
201        }
202        if (aligned_width != width) {
203            src_offset = (tiled_width * i) + (j << 4);
204            dst_offset = width * i + j;
205            for (k = 0; k < height - aligned_height; k = k + 2) {
206                memcpy(y_dst + dst_offset, y_src + src_offset, width - j);
207                src_offset += 16;
208                dst_offset += width;
209                memcpy(y_dst + dst_offset, y_src + src_offset, width - j);
210                src_offset += 16;
211                dst_offset += width;
212            }
213        }
214    }
215}
216
217/*
218 * Converts tiled data to linear for mfc 6.x tiled
219 * 1. uv of nv12t to uv of yuv420s
220 *
221 * @param dst
222 *   uv address of yuv420s[out]
223 *
224 * @param src
225 *   uv address of nv12t[in]
226 *
227 * @param yuv420_width
228 *   real width of yuv420s[in]
229 *
230 * @param yuv420_height
231 *   real height of yuv420s[in]
232 *
233 */
234void csc_tiled_to_linear_uv(
235    unsigned char *uv_dst,
236    unsigned char *uv_src,
237    unsigned int width,
238    unsigned int height)
239{
240    unsigned int i, j, k;
241    unsigned int aligned_width, aligned_height;
242    unsigned int tiled_width;
243    unsigned int src_offset, dst_offset;
244
245    aligned_height = height & (~0x7);
246    aligned_width = width & (~0xF);
247    tiled_width = ((width + 15) >> 4) << 4;
248
249    for (i = 0; i < aligned_height; i = i + 8) {
250        for (j = 0; j<aligned_width; j = j + 16) {
251            src_offset = (tiled_width * i) + (j << 3);
252            dst_offset = width * i + j;
253            for (k = 0; k < 4; k++) {
254                memcpy(uv_dst + dst_offset, uv_src + src_offset, 16);
255                src_offset += 16;
256                dst_offset += width;
257                memcpy(uv_dst + dst_offset, uv_src + src_offset, 16);
258                src_offset += 16;
259                dst_offset += width;
260            }
261        }
262        if (aligned_width != width) {
263            src_offset = (tiled_width * i) + (j << 3);
264            dst_offset = width * i + j;
265            for (k = 0; k < 4; k++) {
266                memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j);
267                src_offset += 16;
268                dst_offset += width;
269                memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j);
270                src_offset += 16;
271                dst_offset += width;
272            }
273        }
274    }
275
276    if (aligned_height != height) {
277        for (j = 0; j<aligned_width; j = j + 16) {
278            src_offset = (tiled_width * i) + (j << 3);
279            dst_offset = width * i + j;
280            for (k = 0; k < height - aligned_height; k = k + 1) {
281                memcpy(uv_dst + dst_offset, uv_src + src_offset, 16);
282                src_offset += 16;
283                dst_offset += width;
284            }
285        }
286        if (aligned_width != width) {
287            src_offset = (tiled_width * i) + (j << 3);
288            dst_offset = width * i + j;
289            for (k = 0; k < height - aligned_height; k = k + 1) {
290                memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j);
291                src_offset += 16;
292                dst_offset += width;
293            }
294        }
295    }
296}
297
298/*
299 * Converts tiled data to linear for mfc 6.x tiled
300 * 1. uv of nt12t to uv of yuv420p
301 *
302 * @param u_dst
303 *   u address of yuv420p[out]
304 *
305 * @param v_dst
306 *   v address of yuv420p[out]
307 *
308 * @param uv_src
309 *   uv address of nt12t[in]
310 *
311 * @param yuv420_width
312 *   real width of yuv420p[in]
313 *
314 * @param yuv420_height
315 *   real height of yuv420p[in]
316 */
317void csc_tiled_to_linear_uv_deinterleave(
318    unsigned char *u_dst,
319    unsigned char *v_dst,
320    unsigned char *uv_src,
321    unsigned int width,
322    unsigned int height)
323{
324    unsigned int i, j, k;
325    unsigned int aligned_width, aligned_height;
326    unsigned int tiled_width;
327    unsigned int src_offset, dst_offset;
328
329    aligned_height = height & (~0x7);
330    aligned_width = width & (~0xF);
331    tiled_width = ((width + 15) >> 4) << 4;
332
333    for (i = 0; i < aligned_height; i = i + 8) {
334        for (j = 0; j<aligned_width; j = j + 16) {
335            src_offset = (tiled_width * i) + (j << 3);
336            dst_offset = (width >> 1) * i + (j >> 1);
337            for (k = 0; k < 4; k++) {
338                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
339                                        uv_src + src_offset, 16);
340                src_offset += 16;
341                dst_offset += width >> 1;
342                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
343                                        uv_src + src_offset, 16);
344                src_offset += 16;
345                dst_offset += width >> 1;
346            }
347        }
348        if (aligned_width != width) {
349            src_offset = (tiled_width * i) + (j << 3);
350            dst_offset = (width >> 1) * i + (j >> 1);
351            for (k = 0; k < 4; k++) {
352                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
353                                        uv_src + src_offset, width - j);
354                src_offset += 16;
355                dst_offset += width >> 1;
356                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
357                                        uv_src + src_offset, width - j);
358                src_offset += 16;
359                dst_offset += width >> 1;
360            }
361        }
362    }
363    if (aligned_height != height) {
364        for (j = 0; j<aligned_width; j = j + 16) {
365            src_offset = (tiled_width * i) + (j << 3);
366            dst_offset = (width >> 1) * i + (j >> 1);
367            for (k = 0; k < height - aligned_height; k = k + 1) {
368                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
369                                        uv_src + src_offset, 16);
370                src_offset += 16;
371                dst_offset += width >> 1;
372            }
373        }
374        if (aligned_width != width) {
375            src_offset = (tiled_width * i) + (j << 3);
376            dst_offset = (width >> 1) * i + (j >> 1);
377            for (k = 0; k < height - aligned_height; k = k + 1) {
378                csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset,
379                                        uv_src + src_offset, width - j);
380                src_offset += 16;
381                dst_offset += width >> 1;
382            }
383        }
384    }
385}
386
387/*
388 * Converts linear data to tiled
389 * It supports mfc 6.x tiled
390 * 1. y of yuv420 to y of nv12t
391 *
392 * @param dst
393 *   y address of nv12t[out]
394 *
395 * @param src
396 *   y address of yuv420[in]
397 *
398 * @param yuv420_width
399 *   real width of yuv420[in]
400 *   it should be even
401 *
402 * @param yuv420_height
403 *   real height of yuv420[in]
404 *   it should be even.
405 *
406 */
407void csc_linear_to_tiled_y(
408    unsigned char *y_dst,
409    unsigned char *y_src,
410    unsigned int width,
411    unsigned int height)
412{
413
414}
415
416/*
417 * Converts and interleaves linear data to tiled
418 * It supports mfc 6.x tiled
419 * 1. uv of nv12t to uv of yuv420
420 *
421 * @param dst
422 *   uv address of nv12t[out]
423 *
424 * @param src
425 *   u address of yuv420[in]
426 *
427 * @param src
428 *   v address of yuv420[in]
429 *
430 * @param yuv420_width
431 *   real width of yuv420[in]
432 *
433 * @param yuv420_height
434 *   real height of yuv420[in]
435 *
436 */
437void csc_linear_to_tiled_uv(
438    unsigned char *uv_dst,
439    unsigned char *u_src,
440    unsigned char *v_src,
441    unsigned int width,
442    unsigned int height)
443{
444
445}
446
447void Tile2D_To_YUV420(unsigned char *Y_plane, unsigned char *Cb_plane, unsigned char *Cr_plane,
448                        unsigned int y_addr, unsigned int c_addr, unsigned int width, unsigned int height)
449{
450    int x, y, j, k, l;
451    int out_of_width, actual_width;
452    unsigned int base_addr, data;
453
454    // y: 0, 16, 32, ...
455    for (y = 0; y < height; y += 16) {
456        // x: 0, 16, 32, ...
457        for (x = 0; x < width; x += 16) {
458            out_of_width = (x + 16) > width ? 1 : 0;
459            base_addr = y_addr + Tile2D_To_Linear(width, height, x, y, 0);
460
461            for (k = 0; (k < 16) && ((y + k) < height); k++) {
462                actual_width = out_of_width ? ((width%4)?((width%16) / 4 + 1) : ((width%16) / 4)) : 4;
463                for (l = 0; l < actual_width; l++) {
464                    data = *((unsigned int*)(base_addr + 16*k + l*4));
465                    for (j = 0; (j < 4) && (x + l*4 + j) < width; j++) {
466                        Y_plane[(y+k)*width + x + l*4 +j] = (data>>(8*j))&0xff;
467                    }
468                }
469            }
470        }
471    }
472
473    for (y = 0; y < height/2; y += 8) {
474        for (x = 0; x < width; x += 16) {
475            out_of_width = (x + 16) > width ? 1 : 0;
476            base_addr = c_addr + Tile2D_To_Linear(width, height/2, x, y, 1);
477            for (k = 0; (k < 8) && ((y+k) < height/2); k++) {
478                actual_width = out_of_width ? ((width%4) ? ((width%16) / 4 + 1) : ((width%16) / 4)) : 4;
479                for (l = 0; l < actual_width; l++) {
480                    data = *((unsigned int*)(base_addr + 16*k + l*4));
481                    for (j = 0; (j < 2) && (x/2 + l*2 +j) < width/2; j++) {
482                        Cb_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>> (8*2*j))&0xff;
483                        Cr_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>>(8*2*j+8))&0xff;
484                    }
485                }
486            }
487        }
488    }
489}
490
491/*
492 * Converts RGB565 to YUV420P
493 *
494 * @param y_dst
495 *   Y plane address of YUV420P[out]
496 *
497 * @param u_dst
498 *   U plane address of YUV420P[out]
499 *
500 * @param v_dst
501 *   V plane address of YUV420P[out]
502 *
503 * @param rgb_src
504 *   Address of RGB565[in]
505 *
506 * @param width
507 *   Width of RGB565[in]
508 *
509 * @param height
510 *   Height of RGB565[in]
511 */
512void csc_RGB565_to_YUV420P(
513    unsigned char *y_dst,
514    unsigned char *u_dst,
515    unsigned char *v_dst,
516    unsigned char *rgb_src,
517    int width,
518    int height)
519{
520    unsigned int i, j;
521    unsigned int tmp;
522
523    unsigned int R, G, B;
524    unsigned int Y, U, V;
525
526    unsigned int offset1 = width * height;
527    unsigned int offset2 = width/2 * height/2;
528
529    unsigned short int *pSrc = (unsigned short int *)rgb_src;
530
531    unsigned char *pDstY = (unsigned char *)y_dst;
532    unsigned char *pDstU = (unsigned char *)u_dst;
533    unsigned char *pDstV = (unsigned char *)v_dst;
534
535    unsigned int yIndex = 0;
536    unsigned int uIndex = 0;
537    unsigned int vIndex = 0;
538
539    for (j = 0; j < height; j++) {
540        for (i = 0; i < width; i++) {
541            tmp = pSrc[j * width + i];
542
543            R = (tmp & 0x0000F800) >> 8;
544            G = (tmp & 0x000007E0) >> 3;
545            B = (tmp & 0x0000001F);
546            B = B << 3;
547
548            Y = ((66 * R) + (129 * G) + (25 * B) + 128);
549            Y = Y >> 8;
550            Y += 16;
551
552            pDstY[yIndex++] = (unsigned char)Y;
553
554            if ((j % 2) == 0 && (i % 2) == 0) {
555                U = ((-38 * R) - (74 * G) + (112 * B) + 128);
556                U = U >> 8;
557                U += 128;
558                V = ((112 * R) - (94 * G) - (18 * B) + 128);
559                V = V >> 8;
560                V += 128;
561
562                pDstU[uIndex++] = (unsigned char)U;
563                pDstV[vIndex++] = (unsigned char)V;
564            }
565        }
566    }
567}
568
569/*
570 * Converts RGB565 to YUV420SP
571 *
572 * @param y_dst
573 *   Y plane address of YUV420SP[out]
574 *
575 * @param uv_dst
576 *   UV plane address of YUV420SP[out]
577 *
578 * @param rgb_src
579 *   Address of RGB565[in]
580 *
581 * @param width
582 *   Width of RGB565[in]
583 *
584 * @param height
585 *   Height of RGB565[in]
586 */
587void csc_RGB565_to_YUV420SP(
588    unsigned char *y_dst,
589    unsigned char *uv_dst,
590    unsigned char *rgb_src,
591    int width,
592    int height)
593{
594    unsigned int i, j;
595    unsigned int tmp;
596
597    unsigned int R, G, B;
598    unsigned int Y, U, V;
599
600    unsigned int offset = width * height;
601
602    unsigned short int *pSrc = (unsigned short int *)rgb_src;
603
604    unsigned char *pDstY = (unsigned char *)y_dst;
605    unsigned char *pDstUV = (unsigned char *)uv_dst;
606
607    unsigned int yIndex = 0;
608    unsigned int uvIndex = 0;
609
610    for (j = 0; j < height; j++) {
611        for (i = 0; i < width; i++) {
612            tmp = pSrc[j * width + i];
613
614            R = (tmp & 0x0000F800) >> 11;
615            R = R * 8;
616            G = (tmp & 0x000007E0) >> 5;
617            G = G * 4;
618            B = (tmp & 0x0000001F);
619            B = B * 8;
620
621            Y = ((66 * R) + (129 * G) + (25 * B) + 128);
622            Y = Y >> 8;
623            Y += 16;
624
625            pDstY[yIndex++] = (unsigned char)Y;
626
627            if ((j % 2) == 0 && (i % 2) == 0) {
628                U = ((-38 * R) - (74 * G) + (112 * B) + 128);
629                U = U >> 8;
630                U += 128;
631                V = ((112 * R) - (94 * G) - (18 * B) + 128);
632                V = V >> 8;
633                V += 128;
634
635                pDstUV[uvIndex++] = (unsigned char)U;
636                pDstUV[uvIndex++] = (unsigned char)V;
637            }
638        }
639    }
640}
641
642/*
643 * Converts RGB8888 to YUV420P
644 *
645 * @param y_dst
646 *   Y plane address of YUV420P[out]
647 *
648 * @param u_dst
649 *   U plane address of YUV420P[out]
650 *
651 * @param v_dst
652 *   V plane address of YUV420P[out]
653 *
654 * @param rgb_src
655 *   Address of ARGB8888[in]
656 *
657 * @param width
658 *   Width of ARGB8888[in]
659 *
660 * @param height
661 *   Height of ARGB8888[in]
662 */
663void csc_ARGB8888_to_YUV420P(
664    unsigned char *y_dst,
665    unsigned char *u_dst,
666    unsigned char *v_dst,
667    unsigned char *rgb_src,
668    unsigned int width,
669    unsigned int height)
670{
671    unsigned int i, j;
672    unsigned int tmp;
673
674    unsigned int R, G, B;
675    unsigned int Y, U, V;
676
677    unsigned int offset1 = width * height;
678    unsigned int offset2 = width/2 * height/2;
679
680    unsigned int *pSrc = (unsigned int *)rgb_src;
681
682    unsigned char *pDstY = (unsigned char *)y_dst;
683    unsigned char *pDstU = (unsigned char *)u_dst;
684    unsigned char *pDstV = (unsigned char *)v_dst;
685
686    unsigned int yIndex = 0;
687    unsigned int uIndex = 0;
688    unsigned int vIndex = 0;
689
690    for (j = 0; j < height; j++) {
691        for (i = 0; i < width; i++) {
692            tmp = pSrc[j * width + i];
693
694            R = (tmp & 0x00FF0000) >> 16;
695            G = (tmp & 0x0000FF00) >> 8;
696            B = (tmp & 0x000000FF);
697
698            Y = ((66 * R) + (129 * G) + (25 * B) + 128);
699            Y = Y >> 8;
700            Y += 16;
701
702            pDstY[yIndex++] = (unsigned char)Y;
703
704            if ((j % 2) == 0 && (i % 2) == 0) {
705                U = ((-38 * R) - (74 * G) + (112 * B) + 128);
706                U = U >> 8;
707                U += 128;
708                V = ((112 * R) - (94 * G) - (18 * B) + 128);
709                V = V >> 8;
710                V += 128;
711
712                pDstU[uIndex++] = (unsigned char)U;
713                pDstV[vIndex++] = (unsigned char)V;
714            }
715        }
716    }
717}
718
719
720/*
721 * Converts ARGB8888 to YUV420S
722 *
723 * @param y_dst
724 *   Y plane address of YUV420S[out]
725 *
726 * @param uv_dst
727 *   UV plane address of YUV420S[out]
728 *
729 * @param rgb_src
730 *   Address of ARGB8888[in]
731 *
732 * @param width
733 *   Width of ARGB8888[in]
734 *
735 * @param height
736 *   Height of ARGB8888[in]
737 */
738void csc_ARGB8888_to_YUV420SP(
739    unsigned char *y_dst,
740    unsigned char *uv_dst,
741    unsigned char *rgb_src,
742    unsigned int width,
743    unsigned int height)
744{
745    unsigned int i, j;
746    unsigned int tmp;
747
748    unsigned int R, G, B;
749    unsigned int Y, U, V;
750
751    unsigned int offset = width * height;
752
753    unsigned int *pSrc = (unsigned int *)rgb_src;
754
755    unsigned char *pDstY = (unsigned char *)y_dst;
756    unsigned char *pDstUV = (unsigned char *)uv_dst;
757
758    unsigned int yIndex = 0;
759    unsigned int uvIndex = 0;
760
761    for (j = 0; j < height; j++) {
762        for (i = 0; i < width; i++) {
763            tmp = pSrc[j * width + i];
764
765            R = (tmp & 0x00FF0000) >> 16;
766            G = (tmp & 0x0000FF00) >> 8;
767            B = (tmp & 0x000000FF);
768
769            Y = ((66 * R) + (129 * G) + (25 * B) + 128);
770            Y = Y >> 8;
771            Y += 16;
772
773            pDstY[yIndex++] = (unsigned char)Y;
774
775            if ((j % 2) == 0 && (i % 2) == 0) {
776                U = ((-38 * R) - (74 * G) + (112 * B) + 128);
777                U = U >> 8;
778                U += 128;
779                V = ((112 * R) - (94 * G) - (18 * B) + 128);
780                V = V >> 8;
781                V += 128;
782
783                pDstUV[uvIndex++] = (unsigned char)U;
784                pDstUV[uvIndex++] = (unsigned char)V;
785            }
786        }
787    }
788}