1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 /** class CCRGB12toYUV420.cpp
19 */
20 #include "ccrgb12toyuv420.h"
21
New()22 OSCL_EXPORT_REF ColorConvertBase* CCRGB12toYUV420 :: New()
23 {
24 CCRGB12toYUV420* self = OSCL_NEW(CCRGB12toYUV420, ());
25 return OSCL_STATIC_CAST(ColorConvertBase*, self);
26 }
27
28
CCRGB12toYUV420()29 CCRGB12toYUV420::CCRGB12toYUV420()
30 {
31 }
32
33
~CCRGB12toYUV420()34 OSCL_EXPORT_REF CCRGB12toYUV420 :: ~CCRGB12toYUV420()
35 {
36 // add destructor code here
37 if (_mInitialized == true)
38 {
39 freeRGB2YUVTables();
40 }
41 }
42
43
freeRGB2YUVTables()44 void CCRGB12toYUV420::freeRGB2YUVTables()
45 {
46 if (iY_Table) oscl_free(iY_Table);
47 if (iCb_Table) oscl_free(iCb_Table);
48 if (iCr_Table) oscl_free(iCr_Table);
49
50 iY_Table = NULL;
51 iCb_Table = iCr_Table = ipCb_Table = ipCr_Table = NULL;
52
53 }
54
55
Init(int32 Src_width,int32 Src_height,int32 Src_pitch,int32 Dst_width,int32 Dst_height,int32 Dst_pitch,int32 nRotation)56 int32 CCRGB12toYUV420:: Init(int32 Src_width, int32 Src_height, int32 Src_pitch, int32 Dst_width,
57 int32 Dst_height, int32 Dst_pitch, int32 nRotation)
58 {
59 int i;
60 uint8 *pTable;
61
62 if ((Src_width != Dst_width) || (Src_height != Dst_height) || (nRotation != 0 && nRotation != CCBOTTOM_UP))
63 {
64 return 0;
65 }
66
67 iBottomUp = false;
68 if (nRotation == CCBOTTOM_UP)
69 {
70 iBottomUp = true;
71 }
72
73 if (_mInitialized == true)
74 {
75 freeRGB2YUVTables();
76 _mInitialized = false;
77 }
78
79 /* memory allocation */
80 if ((iY_Table = (uint8*)oscl_malloc(384)) == NULL)
81 return 0;
82
83 if ((iCb_Table = (uint8*)oscl_malloc(768 * 2)) == NULL)
84 return 0;
85
86 if ((iCr_Table = (uint8*)oscl_malloc(768 * 2)) == NULL)
87 return 0;
88
89 #define pv_max(a, b) ((a) >= (b) ? (a) : (b))
90 #define pv_min(a, b) ((a) <= (b) ? (a) : (b))
91
92 /* Table generation */
93 for (i = 0; i < 384; i++)
94 iY_Table[i] = (uint8) pv_max(pv_min(255, (int32)(0.7152 * i + 16 + 0.5)), 0);
95
96 pTable = iCb_Table + 384;
97 for (i = -384; i < 384; i++)
98 pTable[i] = (uint8) pv_max(pv_min(255, (int32)(0.386 * i + 128 + 0.5)), 0);
99 ipCb_Table = iCb_Table + 384;
100
101 pTable = iCr_Table + 384;
102 for (i = -384; i < 384; i++)
103 pTable[i] = (uint8) pv_max(pv_min(255, (int32)(0.454 * i + 128 + 0.5)), 0);
104 ipCr_Table = iCr_Table + 384;
105
106
107 _mSrc_width = Src_width;
108 _mSrc_height = Src_height;
109 _mSrc_pitch = Src_pitch;
110 _mDst_width = Dst_width;
111 _mDst_height = Dst_height;
112 _mDst_mheight = Dst_height;
113 _mDst_pitch = Dst_pitch;
114 _mInitialized = true;
115
116 SetMode(0);
117
118 return 1;
119 }
120
121
GetOutputBufferSize(void)122 int32 CCRGB12toYUV420::GetOutputBufferSize(void)
123 {
124 OSCL_ASSERT(_mInitialized == true);
125
126 // only return value for _mState = 0 case
127 return ((((_mSrc_width + 15) >> 4) << 4) *(((_mSrc_height + 15) >> 4) << 4) * 3 / 2);
128 }
129
130
SetMode(int32 nMode)131 int32 CCRGB12toYUV420::SetMode(int32 nMode)
132 {
133 OSCL_ASSERT(_mInitialized == true);
134
135 if (nMode == 1) // do not allow scaling nor rotation
136 {
137 _mState = 1;
138 return 0;
139 }
140 else
141 {
142 _mState = 0;
143 return 1;
144 }
145 }
146
SetYuvFullRange(bool range)147 int32 CCRGB12toYUV420::SetYuvFullRange(bool range)
148 {
149 OSCL_ASSERT(_mInitialized == true);
150 if (range == true)
151 {
152 return 0; // not supported yet
153 }
154 else
155 {
156 return 1;
157 }
158 }
159
160 extern "C"
161 {
162 int32 ccrgb12toyuv(uint8 *rgb12, uint8 *yuv[], uint32 *param, uint8 *table[]);
163 }
164
Convert(uint8 * rgb12,uint8 * yuv420)165 int32 CCRGB12toYUV420::Convert(uint8 *rgb12, uint8 *yuv420)
166 {
167 uint32 param[3];
168 uint8 *table[3];
169 int32 size16 = _mDst_pitch * _mDst_mheight;
170 uint8 *yuv[3];
171
172 OSCL_ASSERT(rgb12);
173 OSCL_ASSERT(yuv420);
174 OSCL_ASSERT(_mInitialized == true);
175
176 param[0] = (uint32) _mSrc_width;
177 param[1] = (uint32) _mSrc_height;
178 param[2] = (uint32) iBottomUp;
179
180 table[0] = iY_Table;
181 table[1] = ipCb_Table;
182 table[2] = ipCr_Table;
183
184 yuv[0] = yuv420;
185 yuv[1] = yuv420 + size16;
186 yuv[2] = yuv[1] + (size16 >> 2);
187
188 return ccrgb12toyuv(rgb12, yuv, param, table);
189
190 }
191
Convert(uint8 * rgb12,uint8 ** yuv420)192 int32 CCRGB12toYUV420::Convert(uint8 *rgb12, uint8 **yuv420)
193 {
194 uint32 param[3];
195 uint8 *table[3];
196
197 OSCL_ASSERT(rgb12);
198 OSCL_ASSERT(yuv420);
199 OSCL_ASSERT(yuv420[0]);
200 OSCL_ASSERT(yuv420[1]);
201 OSCL_ASSERT(yuv420[2]);
202 OSCL_ASSERT(_mInitialized == true);
203
204 param[0] = (uint32) _mSrc_width;
205 param[1] = (uint32) _mSrc_height;
206 param[2] = (uint32) iBottomUp;
207
208 table[0] = iY_Table;
209 table[1] = ipCb_Table;
210 table[2] = ipCr_Table;
211
212 return ccrgb12toyuv(rgb12, yuv420, param, table);
213
214 }
215
ccrgb12toyuv(uint8 * rgb12,uint8 * yuv[],uint32 * param,uint8 * table[])216 int32 ccrgb12toyuv(uint8 *rgb12, uint8 *yuv[], uint32 *param, uint8 *table[])
217 {
218 uint32 *inputRGB = NULL;
219 int i, j, ilimit, jlimit;
220 uint32 *tempY, *tempU, *tempV;
221 uint32 pixels;
222 uint32 pixels_nextRow;
223 uint32 yuv_value;
224 uint32 yuv_value1;
225 uint32 yuv_value2;
226 int R_ds; /* "_ds" is the downsample version */
227 int G_ds; /* "_ds" is the downsample version */
228 int B_ds; /* "_ds" is the downsample version */
229 int tmp;
230 uint32 temp;
231
232 int32 width = param[0];
233 int32 height = param[1];
234 int32 width_16 = ((width + 15) >> 4) << 4;
235 int32 height_16 = ((height + 15) >> 4) << 4;
236 uint32 iBottomUp = param[2];
237 uint8 *y_tab = table[0];
238 uint8 *cb_tab = table[1];
239 uint8 *cr_tab = table[2];
240 int32 size16 = height_16 * width_16;
241 int adjust = (width >> 1);
242
243 inputRGB = (uint32*) rgb12;
244
245 /* do padding at the bottom first */
246 /* do padding if input RGB size(height) is different from the output YUV size(height_16) */
247 if (height < height_16 || width < width_16)
248 { /* if padding */
249 int offset = (height < height_16) ? height : height_16;
250
251 offset = (offset * width_16);
252
253 if (width < width_16)
254 {
255 offset -= (width_16 - width);
256 }
257
258 tempY = (uint32 *)yuv[0] + (offset >> 2);
259 oscl_memset((uint8 *)tempY, 16, size16 - offset); /* pad with zeros */
260
261 tempU = (uint32 *)yuv[0] + (size16 >> 2) + (offset >> 4);
262 oscl_memset((uint8 *)tempU, 128, (size16 - offset) >> 2);
263
264 tempV = (uint32 *)yuv[0] + (size16 >> 2) + (size16 >> 4) + (offset >> 4);
265 oscl_memset((uint8 *)tempV, 128, (size16 - offset) >> 2);
266 }
267
268 /* then do padding on the top */
269 tempY = (uint32 *)yuv[0]; /* Normal order */
270 tempU = tempY + ((size16) >> 2);
271 tempV = tempU + ((size16) >> 4);
272
273 /* To center the output */
274 if (height_16 > height)
275 {
276 if (width_16 >= width)
277 {
278 i = ((height_16 - height) >> 1) * width_16 + (((width_16 - width) >> 3) << 2);
279 /* make sure that (width_16-width)>>1 is divisible by 4 */
280 j = ((height_16 - height) >> 2) * (width_16 >> 1) + (((width_16 - width) >> 4) << 2);
281 /* make sure that (width_16-width)>>2 is divisible by 4 */
282 }
283 else
284 {
285 i = ((height_16 - height) >> 1) * width_16;
286 j = ((height_16 - height) >> 2) * (width_16 >> 1);
287 inputRGB += (width - width_16) >> 2;
288 }
289 oscl_memset((uint8 *)tempY, 16, i);
290 tempY += (i >> 2);
291 oscl_memset((uint8 *)tempU, 128, j);
292 tempU += (j >> 2);
293 oscl_memset((uint8 *)tempV, 128, j);
294 tempV += (j >> 2);
295 }
296 else
297 {
298 if (width_16 >= width)
299 {
300 i = (((width_16 - width) >> 3) << 2);
301 /* make sure that (width_16-width)>>1 is divisible by 4 */
302 j = (((width_16 - width) >> 4) << 2);
303 /* make sure that (width_16-width)>>2 is divisible by 4 */
304 inputRGB += (((height - height_16) >> 1) * width) >> 1;
305
306 oscl_memset((uint8 *)tempY, 16, i);
307 tempY += (i >> 2);
308 oscl_memset((uint8 *)tempU, 128, j);
309 tempU += (j >> 2);
310 oscl_memset((uint8 *)tempV, 128, j);
311 tempV += (j >> 2);
312
313 }
314 else
315 {
316 i = 0;
317 j = 0;
318 inputRGB += (((height - height_16) >> 1) * width + ((width - width_16) >> 1)) >> 1 ;
319 }
320 }
321
322 /* ColorConv RGB12-to-YUV420 with cropping or zero-padding */
323 if (height < height_16)
324 {
325 jlimit = height;
326 }
327 else
328 {
329 jlimit = height_16;
330 }
331
332 if (width < width_16)
333 {
334 ilimit = width >> 1;
335 }
336 else
337 {
338 ilimit = width_16 >> 1;
339 }
340
341 if (iBottomUp == 1)
342 {
343 inputRGB += (jlimit - 1) * (width >> 1) ; // move to last row
344 adjust = -adjust;
345 }
346
347 width = width_16 - width;
348
349
350 for (j = 0; j < jlimit; j++)
351 {
352
353 for (i = 0; i < ilimit; i += 4)
354 {
355 pixels = inputRGB[i];
356 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
357 yuv_value = (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
358 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8));
359
360 pixels = inputRGB[i+1];
361 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
362 *tempY++ = (yuv_value |
363 (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
364 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8)) << 16);
365
366 pixels = inputRGB[i+2];
367 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
368 yuv_value = (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
369 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8));
370
371 pixels = inputRGB[i+3];
372 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
373 *tempY++ = (yuv_value |
374 (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
375 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8)) << 16);
376
377
378 /* downsampling U, V */
379
380 pixels_nextRow = inputRGB[i+3+adjust/*(width>>1)*/];
381 G_ds = pixels & 0x00F000F0;
382 G_ds += (pixels_nextRow & 0x00F000F0);
383 G_ds += (G_ds >> 16);
384
385 G_ds -= 2; /* equivalent to adding constant 2<<16 = 131072 */
386
387 pixels &= 0x0F0F0F0F;
388 pixels += (pixels_nextRow & 0x0F0F0F0F);
389
390 pixels += (pixels >> 16);
391
392 B_ds = (pixels & 0x0003F) << 4;
393
394 R_ds = (pixels & 0x03F00) >> 4;
395
396 tmp = B_ds - R_ds;
397
398 yuv_value1 = cb_tab[(((B_ds-G_ds)<<16) + 19525*tmp)>>18] << 24;
399 yuv_value2 = cr_tab[(((R_ds-G_ds)<<16) - 6640*tmp)>>18] << 24;
400
401 pixels = inputRGB[i+2];
402 pixels_nextRow = inputRGB[i+2+adjust/*(width>>1)*/];
403
404 G_ds = pixels & 0x00F000F0;
405 G_ds += (pixels_nextRow & 0x00F000F0);
406 G_ds += (G_ds >> 16);
407
408 G_ds -= 2; /* equivalent to adding constant 2<<16 = 131072 */
409
410 pixels &= 0x0F0F0F0F;
411 pixels += (pixels_nextRow & 0x0F0F0F0F);
412
413 pixels += (pixels >> 16);
414
415 B_ds = (pixels & 0x0003F) << 4;
416
417 R_ds = (pixels & 0x03F00) >> 4;
418 tmp = B_ds - R_ds;
419
420 yuv_value1 |= cb_tab[(((B_ds-G_ds)<<16) + 19525*tmp)>>18] << 16;
421 yuv_value2 |= cr_tab[(((R_ds-G_ds)<<16) - 6640*tmp)>>18] << 16;
422
423 pixels = inputRGB[i+1];
424 pixels_nextRow = inputRGB[i+1+adjust /*(width>>1)*/];
425
426 G_ds = pixels & 0x00F000F0;
427 G_ds += (pixels_nextRow & 0x00F000F0);
428 G_ds += (G_ds >> 16);
429
430 G_ds -= 2; /* equivalent to adding constant 2<<16 = 131072 */
431
432 pixels &= 0x0F0F0F0F;
433 pixels += (pixels_nextRow & 0x0F0F0F0F);
434
435 pixels += (pixels >> 16);
436
437 B_ds = (pixels & 0x0003F) << 4;
438
439 R_ds = (pixels & 0x03F00) >> 4;
440 tmp = B_ds - R_ds;
441
442
443 yuv_value1 |= cb_tab[(((B_ds-G_ds)<<16) + 19525*tmp)>>18] << 8;
444 yuv_value2 |= cr_tab[(((R_ds-G_ds)<<16) - 6640*tmp)>>18] << 8;
445
446 pixels = inputRGB[i];
447 pixels_nextRow = inputRGB[i+adjust/*(width>>1)*/];
448
449 G_ds = pixels & 0x00F000F0;
450 G_ds += (pixels_nextRow & 0x00F000F0);
451 G_ds += (G_ds >> 16);
452
453 G_ds -= 2; /* equivalent to adding constant 2<<16 = 131072 */
454
455 pixels &= 0x0F0F0F0F;
456 pixels += (pixels_nextRow & 0x0F0F0F0F);
457
458 pixels += (pixels >> 16);
459
460 B_ds = (pixels & 0x0003F) << 4;
461
462 R_ds = (pixels & 0x03F00) >> 4;
463 tmp = B_ds - R_ds;
464
465 *tempU++ = yuv_value1 | (cb_tab[(((B_ds-G_ds)<<16) + 19525*tmp)>>18]);
466 *tempV++ = yuv_value2 | (cr_tab[(((R_ds-G_ds)<<16) - 6640*tmp)>>18]);
467 }
468
469 /* do padding if input RGB size(width) is different from the output YUV size(width_16) */
470
471 if ((width > 0) && j < jlimit - 1)
472 {
473 oscl_memset((uint8 *)tempY, 16/*(*(tempY-1))>>24*/, width);
474 tempY += width >> 2;
475 }
476
477 if (j++ == (jlimit - 1))
478 {
479 break; /* dealing with a odd height */
480 }
481
482 if ((width > 0) && j < jlimit - 1)
483 {
484 oscl_memset((uint8 *)tempU, 128/*(*(tempU-1))>>24*/, width >> 1);
485 tempU += width >> 3;
486 oscl_memset((uint8 *)tempV, 128/*(*(tempV-1))>>24*/, width >> 1);
487 tempV += width >> 3;
488 }
489
490 inputRGB += adjust; /* (160/2 = 80 ) */ /*(width>>1)*/; /* move to the next row */
491
492 for (i = 0; i < ilimit; i += 4)
493 {
494 pixels = inputRGB[i];
495 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
496 yuv_value = (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
497 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8));
498
499 pixels = inputRGB[i+1];
500 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
501 *tempY++ = (yuv_value |
502 (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
503 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8)) << 16);
504
505 pixels = inputRGB[i+2];
506 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
507 yuv_value = (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
508 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8));
509
510 pixels = inputRGB[i+3];
511 temp = (827 * (pixels & 0x000F000F) + 2435 * ((pixels & 0x0F000F00) >> 8));
512 *tempY++ = (yuv_value |
513 (y_tab[((temp&0x0FFFF)>> 9) + (pixels & 0x000000F0)] |
514 (y_tab[(temp >>25) + ((pixels & 0x00F00000)>>16)] << 8)) << 16);
515
516 }
517
518 /* do padding if input RGB size(width) is different from the output YUV size(width_16) */
519 if ((width > 0) && j < jlimit - 1)
520 {
521 oscl_memset((uint8 *)tempY, 16/*(*(tempY-1))>>24*/, width);
522 tempY += width >> 2;
523 }
524
525 inputRGB += adjust; /* (160/2 = 80 ) */ /*(width>>1)*/; /* move to the next row */
526
527 } /* for(j=0; j<jlimit; j++)*/
528
529 return 1;
530 }
531