1 /*
2  * Copyright (C) 2009 The Android Open Source Project
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 express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ColorConverter"
19 #include <utils/Log.h>
20 
21 #include <media/stagefright/foundation/ADebug.h>
22 #include <media/stagefright/foundation/ALooper.h>
23 #include <media/stagefright/ColorConverter.h>
24 #include <media/stagefright/MediaErrors.h>
25 
26 #include "libyuv/convert_from.h"
27 #include "libyuv/video_common.h"
28 #include <functional>
29 #include <sys/time.h>
30 
31 #define USE_LIBYUV
32 #define PERF_PROFILING 0
33 
34 
35 #if defined(__aarch64__) || defined(__ARM_NEON__)
36 #define USE_NEON_Y410 1
37 #else
38 #define USE_NEON_Y410 0
39 #endif
40 
41 #if USE_NEON_Y410
42 #include <arm_neon.h>
43 #endif
44 
45 namespace android {
46 
ColorConverter(OMX_COLOR_FORMATTYPE from,OMX_COLOR_FORMATTYPE to)47 ColorConverter::ColorConverter(
48         OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
49     : mSrcFormat(from),
50       mDstFormat(to),
51       mClip(NULL) {
52 }
53 
~ColorConverter()54 ColorConverter::~ColorConverter() {
55     delete[] mClip;
56     mClip = NULL;
57 }
58 
isValid() const59 bool ColorConverter::isValid() const {
60     switch (mSrcFormat) {
61         case OMX_COLOR_FormatYUV420Planar16:
62             if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
63                 return true;
64             }
65             // fall-thru
66         case OMX_COLOR_FormatYUV420Planar:
67             return mDstFormat == OMX_COLOR_Format16bitRGB565
68                     || mDstFormat == OMX_COLOR_Format32BitRGBA8888
69                     || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
70 
71         case OMX_COLOR_FormatCbYCrY:
72         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
73         case OMX_COLOR_FormatYUV420SemiPlanar:
74         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
75             return mDstFormat == OMX_COLOR_Format16bitRGB565;
76 
77         default:
78             return false;
79     }
80 }
81 
isDstRGB() const82 bool ColorConverter::isDstRGB() const {
83     return mDstFormat == OMX_COLOR_Format16bitRGB565
84             || mDstFormat == OMX_COLOR_Format32BitRGBA8888
85             || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
86 }
87 
BitmapParams(void * bits,size_t width,size_t height,size_t cropLeft,size_t cropTop,size_t cropRight,size_t cropBottom,OMX_COLOR_FORMATTYPE colorFromat)88 ColorConverter::BitmapParams::BitmapParams(
89         void *bits,
90         size_t width, size_t height,
91         size_t cropLeft, size_t cropTop,
92         size_t cropRight, size_t cropBottom,
93         OMX_COLOR_FORMATTYPE colorFromat)
94     : mBits(bits),
95       mColorFormat(colorFromat),
96       mWidth(width),
97       mHeight(height),
98       mCropLeft(cropLeft),
99       mCropTop(cropTop),
100       mCropRight(cropRight),
101       mCropBottom(cropBottom) {
102     switch(mColorFormat) {
103     case OMX_COLOR_Format16bitRGB565:
104         mBpp = 2;
105         mStride = 2 * mWidth;
106         break;
107 
108     case OMX_COLOR_Format32bitBGRA8888:
109     case OMX_COLOR_Format32BitRGBA8888:
110     case OMX_COLOR_FormatYUV444Y410:
111         mBpp = 4;
112         mStride = 4 * mWidth;
113         break;
114 
115     case OMX_COLOR_FormatYUV420Planar16:
116         mBpp = 2;
117         mStride = 2 * mWidth;
118         break;
119 
120     case OMX_COLOR_FormatYUV420Planar:
121     case OMX_COLOR_FormatCbYCrY:
122     case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
123     case OMX_COLOR_FormatYUV420SemiPlanar:
124     case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
125         mBpp = 1;
126         mStride = mWidth;
127         break;
128 
129     default:
130         ALOGE("Unsupported color format %d", mColorFormat);
131         mBpp = 1;
132         mStride = mWidth;
133         break;
134     }
135 }
136 
cropWidth() const137 size_t ColorConverter::BitmapParams::cropWidth() const {
138     return mCropRight - mCropLeft + 1;
139 }
140 
cropHeight() const141 size_t ColorConverter::BitmapParams::cropHeight() const {
142     return mCropBottom - mCropTop + 1;
143 }
144 
convert(const void * srcBits,size_t srcWidth,size_t srcHeight,size_t srcCropLeft,size_t srcCropTop,size_t srcCropRight,size_t srcCropBottom,void * dstBits,size_t dstWidth,size_t dstHeight,size_t dstCropLeft,size_t dstCropTop,size_t dstCropRight,size_t dstCropBottom)145 status_t ColorConverter::convert(
146         const void *srcBits,
147         size_t srcWidth, size_t srcHeight,
148         size_t srcCropLeft, size_t srcCropTop,
149         size_t srcCropRight, size_t srcCropBottom,
150         void *dstBits,
151         size_t dstWidth, size_t dstHeight,
152         size_t dstCropLeft, size_t dstCropTop,
153         size_t dstCropRight, size_t dstCropBottom) {
154     BitmapParams src(
155             const_cast<void *>(srcBits),
156             srcWidth, srcHeight,
157             srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat);
158 
159     BitmapParams dst(
160             dstBits,
161             dstWidth, dstHeight,
162             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
163 
164     if (!((src.mCropLeft & 1) == 0
165         && src.cropWidth() == dst.cropWidth()
166         && src.cropHeight() == dst.cropHeight())) {
167         return ERROR_UNSUPPORTED;
168     }
169 
170     status_t err;
171 
172     switch (mSrcFormat) {
173         case OMX_COLOR_FormatYUV420Planar:
174 #ifdef USE_LIBYUV
175             err = convertYUV420PlanarUseLibYUV(src, dst);
176 #else
177             err = convertYUV420Planar(src, dst);
178 #endif
179             break;
180 
181         case OMX_COLOR_FormatYUV420Planar16:
182         {
183 #if PERF_PROFILING
184             int64_t startTimeUs = ALooper::GetNowUs();
185 #endif
186             err = convertYUV420Planar16(src, dst);
187 #if PERF_PROFILING
188             int64_t endTimeUs = ALooper::GetNowUs();
189             ALOGD("convertYUV420Planar16 took %lld us", (long long) (endTimeUs - startTimeUs));
190 #endif
191             break;
192         }
193 
194         case OMX_COLOR_FormatCbYCrY:
195             err = convertCbYCrY(src, dst);
196             break;
197 
198         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
199             err = convertQCOMYUV420SemiPlanar(src, dst);
200             break;
201 
202         case OMX_COLOR_FormatYUV420SemiPlanar:
203             err = convertYUV420SemiPlanar(src, dst);
204             break;
205 
206         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
207             err = convertTIYUV420PackedSemiPlanar(src, dst);
208             break;
209 
210         default:
211         {
212             CHECK(!"Should not be here. Unknown color conversion.");
213             break;
214         }
215     }
216 
217     return err;
218 }
219 
convertCbYCrY(const BitmapParams & src,const BitmapParams & dst)220 status_t ColorConverter::convertCbYCrY(
221         const BitmapParams &src, const BitmapParams &dst) {
222     // XXX Untested
223 
224     uint8_t *kAdjustedClip = initClip();
225 
226     uint16_t *dst_ptr = (uint16_t *)dst.mBits
227         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
228 
229     const uint8_t *src_ptr = (const uint8_t *)src.mBits
230         + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
231 
232     for (size_t y = 0; y < src.cropHeight(); ++y) {
233         for (size_t x = 0; x < src.cropWidth(); x += 2) {
234             signed y1 = (signed)src_ptr[2 * x + 1] - 16;
235             signed y2 = (signed)src_ptr[2 * x + 3] - 16;
236             signed u = (signed)src_ptr[2 * x] - 128;
237             signed v = (signed)src_ptr[2 * x + 2] - 128;
238 
239             signed u_b = u * 517;
240             signed u_g = -u * 100;
241             signed v_g = -v * 208;
242             signed v_r = v * 409;
243 
244             signed tmp1 = y1 * 298;
245             signed b1 = (tmp1 + u_b) / 256;
246             signed g1 = (tmp1 + v_g + u_g) / 256;
247             signed r1 = (tmp1 + v_r) / 256;
248 
249             signed tmp2 = y2 * 298;
250             signed b2 = (tmp2 + u_b) / 256;
251             signed g2 = (tmp2 + v_g + u_g) / 256;
252             signed r2 = (tmp2 + v_r) / 256;
253 
254             uint32_t rgb1 =
255                 ((kAdjustedClip[r1] >> 3) << 11)
256                 | ((kAdjustedClip[g1] >> 2) << 5)
257                 | (kAdjustedClip[b1] >> 3);
258 
259             uint32_t rgb2 =
260                 ((kAdjustedClip[r2] >> 3) << 11)
261                 | ((kAdjustedClip[g2] >> 2) << 5)
262                 | (kAdjustedClip[b2] >> 3);
263 
264             if (x + 1 < src.cropWidth()) {
265                 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
266             } else {
267                 dst_ptr[x] = rgb1;
268             }
269         }
270 
271         src_ptr += src.mWidth * 2;
272         dst_ptr += dst.mWidth;
273     }
274 
275     return OK;
276 }
277 
convertYUV420PlanarUseLibYUV(const BitmapParams & src,const BitmapParams & dst)278 status_t ColorConverter::convertYUV420PlanarUseLibYUV(
279         const BitmapParams &src, const BitmapParams &dst) {
280     uint8_t *dst_ptr = (uint8_t *)dst.mBits
281         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
282 
283     const uint8_t *src_y =
284         (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
285 
286     const uint8_t *src_u =
287         (const uint8_t *)src.mBits + src.mStride * src.mHeight
288         + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2);
289 
290     const uint8_t *src_v =
291         src_u + (src.mStride / 2) * (src.mHeight / 2);
292 
293     switch (mDstFormat) {
294     case OMX_COLOR_Format16bitRGB565:
295         libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
296                 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
297         break;
298 
299     case OMX_COLOR_Format32BitRGBA8888:
300         libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
301                 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR);
302         break;
303 
304     case OMX_COLOR_Format32bitBGRA8888:
305         libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
306                 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB);
307         break;
308 
309     default:
310         return ERROR_UNSUPPORTED;
311     }
312 
313     return OK;
314 }
315 
316 std::function<void (void *, void *, void *, size_t,
317                     signed *, signed *, signed *, signed *)>
getReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat)318 getReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat) {
319     switch(srcFormat) {
320     case OMX_COLOR_FormatYUV420Planar:
321         return [](void *src_y, void *src_u, void *src_v, size_t x,
322                   signed *y1, signed *y2, signed *u, signed *v) {
323             *y1 = ((uint8_t*)src_y)[x] - 16;
324             *y2 = ((uint8_t*)src_y)[x + 1] - 16;
325             *u = ((uint8_t*)src_u)[x / 2] - 128;
326             *v = ((uint8_t*)src_v)[x / 2] - 128;
327         };
328     case OMX_COLOR_FormatYUV420Planar16:
329         return [](void *src_y, void *src_u, void *src_v, size_t x,
330                 signed *y1, signed *y2, signed *u, signed *v) {
331             *y1 = (signed)(((uint16_t*)src_y)[x] >> 2) - 16;
332             *y2 = (signed)(((uint16_t*)src_y)[x + 1] >> 2) - 16;
333             *u = (signed)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
334             *v = (signed)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
335         };
336     default:
337         TRESPASS();
338     }
339     return nullptr;
340 }
341 
342 std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat,uint8_t * kAdjustedClip)343 getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) {
344     switch (dstFormat) {
345     case OMX_COLOR_Format16bitRGB565:
346     {
347         return [kAdjustedClip](void *dst_ptr, bool uncropped,
348                                signed r1, signed g1, signed b1,
349                                signed r2, signed g2, signed b2) {
350             uint32_t rgb1 =
351                 ((kAdjustedClip[r1] >> 3) << 11)
352                 | ((kAdjustedClip[g1] >> 2) << 5)
353                 | (kAdjustedClip[b1] >> 3);
354 
355             if (uncropped) {
356                 uint32_t rgb2 =
357                     ((kAdjustedClip[r2] >> 3) << 11)
358                     | ((kAdjustedClip[g2] >> 2) << 5)
359                     | (kAdjustedClip[b2] >> 3);
360 
361                 *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
362             } else {
363                 *(uint16_t *)dst_ptr = rgb1;
364             }
365         };
366     }
367     case OMX_COLOR_Format32BitRGBA8888:
368     {
369         return [kAdjustedClip](void *dst_ptr, bool uncropped,
370                                signed r1, signed g1, signed b1,
371                                signed r2, signed g2, signed b2) {
372             ((uint32_t *)dst_ptr)[0] =
373                     (kAdjustedClip[r1])
374                     | (kAdjustedClip[g1] << 8)
375                     | (kAdjustedClip[b1] << 16)
376                     | (0xFF << 24);
377 
378             if (uncropped) {
379                 ((uint32_t *)dst_ptr)[1] =
380                         (kAdjustedClip[r2])
381                         | (kAdjustedClip[g2] << 8)
382                         | (kAdjustedClip[b2] << 16)
383                         | (0xFF << 24);
384             }
385         };
386     }
387     case OMX_COLOR_Format32bitBGRA8888:
388     {
389         return [kAdjustedClip](void *dst_ptr, bool uncropped,
390                                signed r1, signed g1, signed b1,
391                                signed r2, signed g2, signed b2) {
392             ((uint32_t *)dst_ptr)[0] =
393                     (kAdjustedClip[b1])
394                     | (kAdjustedClip[g1] << 8)
395                     | (kAdjustedClip[r1] << 16)
396                     | (0xFF << 24);
397 
398             if (uncropped) {
399                 ((uint32_t *)dst_ptr)[1] =
400                         (kAdjustedClip[b2])
401                         | (kAdjustedClip[g2] << 8)
402                         | (kAdjustedClip[r2] << 16)
403                         | (0xFF << 24);
404             }
405         };
406     }
407     default:
408         TRESPASS();
409     }
410     return nullptr;
411 }
412 
convertYUV420Planar(const BitmapParams & src,const BitmapParams & dst)413 status_t ColorConverter::convertYUV420Planar(
414         const BitmapParams &src, const BitmapParams &dst) {
415     uint8_t *kAdjustedClip = initClip();
416 
417     auto readFromSrc = getReadFromSrc(mSrcFormat);
418     auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip);
419 
420     uint8_t *dst_ptr = (uint8_t *)dst.mBits
421             + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
422 
423     uint8_t *src_y = (uint8_t *)src.mBits
424             + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
425 
426     uint8_t *src_u = (uint8_t *)src.mBits + src.mStride * src.mHeight
427             + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2 * src.mBpp;
428 
429     uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
430 
431     for (size_t y = 0; y < src.cropHeight(); ++y) {
432         for (size_t x = 0; x < src.cropWidth(); x += 2) {
433             // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
434             // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
435             // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
436 
437             // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
438             // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
439             // R = .................. + 409/256 * (V - 128)
440 
441             // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
442             // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
443             // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
444 
445             // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
446             // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
447             // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
448 
449             // clip range -278 .. 535
450 
451             signed y1, y2, u, v;
452             readFromSrc(src_y, src_u, src_v, x, &y1, &y2, &u, &v);
453 
454             signed u_b = u * 517;
455             signed u_g = -u * 100;
456             signed v_g = -v * 208;
457             signed v_r = v * 409;
458 
459             signed tmp1 = y1 * 298;
460             signed b1 = (tmp1 + u_b) / 256;
461             signed g1 = (tmp1 + v_g + u_g) / 256;
462             signed r1 = (tmp1 + v_r) / 256;
463 
464             signed tmp2 = y2 * 298;
465             signed b2 = (tmp2 + u_b) / 256;
466             signed g2 = (tmp2 + v_g + u_g) / 256;
467             signed r2 = (tmp2 + v_r) / 256;
468 
469             bool uncropped = x + 1 < src.cropWidth();
470             writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
471         }
472 
473         src_y += src.mStride;
474 
475         if (y & 1) {
476             src_u += src.mStride / 2;
477             src_v += src.mStride / 2;
478         }
479 
480         dst_ptr += dst.mStride;
481     }
482 
483     return OK;
484 }
485 
convertYUV420Planar16(const BitmapParams & src,const BitmapParams & dst)486 status_t ColorConverter::convertYUV420Planar16(
487         const BitmapParams &src, const BitmapParams &dst) {
488     if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
489         return convertYUV420Planar16ToY410(src, dst);
490     }
491 
492     return convertYUV420Planar(src, dst);
493 }
494 
495 /*
496  * Pack 10-bit YUV into RGBA_1010102.
497  *
498  * Media sends 10-bit YUV in a RGBA_1010102 format buffer. SF will handle
499  * the conversion to RGB using RenderEngine fallback.
500  *
501  * We do not perform a YUV->RGB conversion here, however the conversion with
502  * BT2020 to Full range is below for reference:
503  *
504  *   B = 1.168  *(Y - 64) + 2.148  *(U - 512)
505  *   G = 1.168  *(Y - 64) - 0.652  *(V - 512) - 0.188  *(U - 512)
506  *   R = 1.168  *(Y - 64) + 1.683  *(V - 512)
507  *
508  *   B = 1196/1024  *(Y - 64) + 2200/1024  *(U - 512)
509  *   G = .................... -  668/1024  *(V - 512) - 192/1024  *(U - 512)
510  *   R = .................... + 1723/1024  *(V - 512)
511  *
512  *   min_B = (1196  *(- 64) + 2200  *(- 512)) / 1024 = -1175
513  *   min_G = (1196  *(- 64) - 668  *(1023 - 512) - 192  *(1023 - 512)) / 1024 = -504
514  *   min_R = (1196  *(- 64) + 1723  *(- 512)) / 1024 = -937
515  *
516  *   max_B = (1196  *(1023 - 64) + 2200  *(1023 - 512)) / 1024 = 2218
517  *   max_G = (1196  *(1023 - 64) - 668  *(- 512) - 192  *(- 512)) / 1024 = 1551
518  *   max_R = (1196  *(1023 - 64) + 1723  *(1023 - 512)) / 1024 = 1980
519  *
520  *   clip range -1175 .. 2218
521  *
522  */
523 
524 #if !USE_NEON_Y410
525 
convertYUV420Planar16ToY410(const BitmapParams & src,const BitmapParams & dst)526 status_t ColorConverter::convertYUV420Planar16ToY410(
527         const BitmapParams &src, const BitmapParams &dst) {
528     uint8_t *dst_ptr = (uint8_t *)dst.mBits
529         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
530 
531     const uint8_t *src_y =
532         (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
533 
534     const uint8_t *src_u =
535         (const uint8_t *)src.mBits + src.mStride * src.mHeight
536         + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
537 
538     const uint8_t *src_v =
539         src_u + (src.mStride / 2) * (src.mHeight / 2);
540 
541     // Converting two lines at a time, slightly faster
542     for (size_t y = 0; y < src.cropHeight(); y += 2) {
543         uint32_t *dst_top = (uint32_t *) dst_ptr;
544         uint32_t *dst_bot = (uint32_t *) (dst_ptr + dst.mStride);
545         uint16_t *ptr_ytop = (uint16_t*) src_y;
546         uint16_t *ptr_ybot = (uint16_t*) (src_y + src.mStride);
547         uint16_t *ptr_u = (uint16_t*) src_u;
548         uint16_t *ptr_v = (uint16_t*) src_v;
549 
550         uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
551         size_t x = 0;
552         for (; x < src.cropWidth() - 3; x += 4) {
553             u01 = *((uint32_t*)ptr_u); ptr_u += 2;
554             v01 = *((uint32_t*)ptr_v); ptr_v += 2;
555 
556             y01 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
557             y23 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
558             y45 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
559             y67 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
560 
561             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
562             uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
563 
564             *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
565             *dst_top++ = ((y01 >> 16) << 10) | uv0;
566             *dst_top++ = ((y23 & 0x3FF) << 10) | uv1;
567             *dst_top++ = ((y23 >> 16) << 10) | uv1;
568 
569             *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
570             *dst_bot++ = ((y45 >> 16) << 10) | uv0;
571             *dst_bot++ = ((y67 & 0x3FF) << 10) | uv1;
572             *dst_bot++ = ((y67 >> 16) << 10) | uv1;
573         }
574 
575         // There should be at most 2 more pixels to process. Note that we don't
576         // need to consider odd case as the buffer is always aligned to even.
577         if (x < src.cropWidth()) {
578             u01 = *ptr_u;
579             v01 = *ptr_v;
580             y01 = *((uint32_t*)ptr_ytop);
581             y45 = *((uint32_t*)ptr_ybot);
582             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
583             *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
584             *dst_top++ = ((y01 >> 16) << 10) | uv0;
585             *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
586             *dst_bot++ = ((y45 >> 16) << 10) | uv0;
587         }
588 
589         src_y += src.mStride * 2;
590         src_u += src.mStride / 2;
591         src_v += src.mStride / 2;
592         dst_ptr += dst.mStride * 2;
593     }
594 
595     return OK;
596 }
597 
598 #else
599 
convertYUV420Planar16ToY410(const BitmapParams & src,const BitmapParams & dst)600 status_t ColorConverter::convertYUV420Planar16ToY410(
601         const BitmapParams &src, const BitmapParams &dst) {
602     uint8_t *out = (uint8_t *)dst.mBits
603         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
604 
605     const uint8_t *src_y =
606         (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
607 
608     const uint8_t *src_u =
609         (const uint8_t *)src.mBits + src.mStride * src.mHeight
610         + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
611 
612     const uint8_t *src_v =
613         src_u + (src.mStride / 2) * (src.mHeight / 2);
614 
615     for (size_t y = 0; y < src.cropHeight(); y++) {
616         uint16_t *ptr_y = (uint16_t*) src_y;
617         uint16_t *ptr_u = (uint16_t*) src_u;
618         uint16_t *ptr_v = (uint16_t*) src_v;
619         uint32_t *ptr_out = (uint32_t *) out;
620 
621         // Process 16-pixel at a time.
622         uint32_t *ptr_limit = ptr_out + (src.cropWidth() & ~15);
623         while (ptr_out < ptr_limit) {
624             uint16x4_t u0123 = vld1_u16(ptr_u); ptr_u += 4;
625             uint16x4_t u4567 = vld1_u16(ptr_u); ptr_u += 4;
626             uint16x4_t v0123 = vld1_u16(ptr_v); ptr_v += 4;
627             uint16x4_t v4567 = vld1_u16(ptr_v); ptr_v += 4;
628             uint16x4_t y0123 = vld1_u16(ptr_y); ptr_y += 4;
629             uint16x4_t y4567 = vld1_u16(ptr_y); ptr_y += 4;
630             uint16x4_t y89ab = vld1_u16(ptr_y); ptr_y += 4;
631             uint16x4_t ycdef = vld1_u16(ptr_y); ptr_y += 4;
632 
633             uint32x2_t uvtempl;
634             uint32x4_t uvtempq;
635 
636             uvtempq = vaddw_u16(vshll_n_u16(v0123, 20), u0123);
637 
638             uvtempl = vget_low_u32(uvtempq);
639             uint32x4_t uv0011 = vreinterpretq_u32_u64(
640                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
641 
642             uvtempl = vget_high_u32(uvtempq);
643             uint32x4_t uv2233 = vreinterpretq_u32_u64(
644                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
645 
646             uvtempq = vaddw_u16(vshll_n_u16(v4567, 20), u4567);
647 
648             uvtempl = vget_low_u32(uvtempq);
649             uint32x4_t uv4455 = vreinterpretq_u32_u64(
650                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
651 
652             uvtempl = vget_high_u32(uvtempq);
653             uint32x4_t uv6677 = vreinterpretq_u32_u64(
654                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
655 
656             uint32x4_t dsttemp;
657 
658             dsttemp = vorrq_u32(uv0011, vshll_n_u16(y0123, 10));
659             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
660 
661             dsttemp = vorrq_u32(uv2233, vshll_n_u16(y4567, 10));
662             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
663 
664             dsttemp = vorrq_u32(uv4455, vshll_n_u16(y89ab, 10));
665             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
666 
667             dsttemp = vorrq_u32(uv6677, vshll_n_u16(ycdef, 10));
668             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
669         }
670 
671         src_y += src.mStride;
672         if (y & 1) {
673             src_u += src.mStride / 2;
674             src_v += src.mStride / 2;
675         }
676         out += dst.mStride;
677     }
678 
679     // Process the left-overs out-of-loop, 2-pixel at a time. Note that we don't
680     // need to consider odd case as the buffer is always aligned to even.
681     if (src.cropWidth() & 15) {
682         size_t xstart = (src.cropWidth() & ~15);
683 
684         uint8_t *out = (uint8_t *)dst.mBits + dst.mCropTop * dst.mStride
685                 + (dst.mCropLeft + xstart) * dst.mBpp;
686 
687         const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mStride
688                 + (src.mCropLeft + xstart) * src.mBpp;
689 
690         const uint8_t *src_u = (const uint8_t *)src.mBits + src.mStride * src.mHeight
691             + (src.mCropTop / 2) * (src.mStride / 2)
692             + ((src.mCropLeft + xstart) / 2) * src.mBpp;
693 
694         const uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
695 
696         for (size_t y = 0; y < src.cropHeight(); y++) {
697             uint16_t *ptr_y = (uint16_t*) src_y;
698             uint16_t *ptr_u = (uint16_t*) src_u;
699             uint16_t *ptr_v = (uint16_t*) src_v;
700             uint32_t *ptr_out = (uint32_t *) out;
701             for (size_t x = xstart; x < src.cropWidth(); x += 2) {
702                 uint16_t u = *ptr_u++;
703                 uint16_t v = *ptr_v++;
704                 uint32_t y01 = *((uint32_t*)ptr_y); ptr_y += 2;
705                 uint32_t uv = u | (((uint32_t)v) << 20);
706                 *ptr_out++ = ((y01 & 0x3FF) << 10) | uv;
707                 *ptr_out++ = ((y01 >> 16) << 10) | uv;
708             }
709             src_y += src.mStride;
710             if (y & 1) {
711                 src_u += src.mStride / 2;
712                 src_v += src.mStride / 2;
713             }
714             out += dst.mStride;
715         }
716     }
717 
718     return OK;
719 }
720 
721 #endif // USE_NEON_Y410
722 
convertQCOMYUV420SemiPlanar(const BitmapParams & src,const BitmapParams & dst)723 status_t ColorConverter::convertQCOMYUV420SemiPlanar(
724         const BitmapParams &src, const BitmapParams &dst) {
725     uint8_t *kAdjustedClip = initClip();
726 
727     uint16_t *dst_ptr = (uint16_t *)dst.mBits
728         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
729 
730     const uint8_t *src_y =
731         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
732 
733     const uint8_t *src_u =
734         (const uint8_t *)src_y + src.mWidth * src.mHeight
735         + src.mCropTop * src.mWidth + src.mCropLeft;
736 
737     for (size_t y = 0; y < src.cropHeight(); ++y) {
738         for (size_t x = 0; x < src.cropWidth(); x += 2) {
739             signed y1 = (signed)src_y[x] - 16;
740             signed y2 = (signed)src_y[x + 1] - 16;
741 
742             signed u = (signed)src_u[x & ~1] - 128;
743             signed v = (signed)src_u[(x & ~1) + 1] - 128;
744 
745             signed u_b = u * 517;
746             signed u_g = -u * 100;
747             signed v_g = -v * 208;
748             signed v_r = v * 409;
749 
750             signed tmp1 = y1 * 298;
751             signed b1 = (tmp1 + u_b) / 256;
752             signed g1 = (tmp1 + v_g + u_g) / 256;
753             signed r1 = (tmp1 + v_r) / 256;
754 
755             signed tmp2 = y2 * 298;
756             signed b2 = (tmp2 + u_b) / 256;
757             signed g2 = (tmp2 + v_g + u_g) / 256;
758             signed r2 = (tmp2 + v_r) / 256;
759 
760             uint32_t rgb1 =
761                 ((kAdjustedClip[b1] >> 3) << 11)
762                 | ((kAdjustedClip[g1] >> 2) << 5)
763                 | (kAdjustedClip[r1] >> 3);
764 
765             uint32_t rgb2 =
766                 ((kAdjustedClip[b2] >> 3) << 11)
767                 | ((kAdjustedClip[g2] >> 2) << 5)
768                 | (kAdjustedClip[r2] >> 3);
769 
770             if (x + 1 < src.cropWidth()) {
771                 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
772             } else {
773                 dst_ptr[x] = rgb1;
774             }
775         }
776 
777         src_y += src.mWidth;
778 
779         if (y & 1) {
780             src_u += src.mWidth;
781         }
782 
783         dst_ptr += dst.mWidth;
784     }
785 
786     return OK;
787 }
788 
convertYUV420SemiPlanar(const BitmapParams & src,const BitmapParams & dst)789 status_t ColorConverter::convertYUV420SemiPlanar(
790         const BitmapParams &src, const BitmapParams &dst) {
791     // XXX Untested
792 
793     uint8_t *kAdjustedClip = initClip();
794 
795     uint16_t *dst_ptr = (uint16_t *)dst.mBits
796         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
797 
798     const uint8_t *src_y =
799         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
800 
801     const uint8_t *src_u =
802         (const uint8_t *)src_y + src.mWidth * src.mHeight
803         + src.mCropTop * src.mWidth + src.mCropLeft;
804 
805     for (size_t y = 0; y < src.cropHeight(); ++y) {
806         for (size_t x = 0; x < src.cropWidth(); x += 2) {
807             signed y1 = (signed)src_y[x] - 16;
808             signed y2 = (signed)src_y[x + 1] - 16;
809 
810             signed v = (signed)src_u[x & ~1] - 128;
811             signed u = (signed)src_u[(x & ~1) + 1] - 128;
812 
813             signed u_b = u * 517;
814             signed u_g = -u * 100;
815             signed v_g = -v * 208;
816             signed v_r = v * 409;
817 
818             signed tmp1 = y1 * 298;
819             signed b1 = (tmp1 + u_b) / 256;
820             signed g1 = (tmp1 + v_g + u_g) / 256;
821             signed r1 = (tmp1 + v_r) / 256;
822 
823             signed tmp2 = y2 * 298;
824             signed b2 = (tmp2 + u_b) / 256;
825             signed g2 = (tmp2 + v_g + u_g) / 256;
826             signed r2 = (tmp2 + v_r) / 256;
827 
828             uint32_t rgb1 =
829                 ((kAdjustedClip[b1] >> 3) << 11)
830                 | ((kAdjustedClip[g1] >> 2) << 5)
831                 | (kAdjustedClip[r1] >> 3);
832 
833             uint32_t rgb2 =
834                 ((kAdjustedClip[b2] >> 3) << 11)
835                 | ((kAdjustedClip[g2] >> 2) << 5)
836                 | (kAdjustedClip[r2] >> 3);
837 
838             if (x + 1 < src.cropWidth()) {
839                 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
840             } else {
841                 dst_ptr[x] = rgb1;
842             }
843         }
844 
845         src_y += src.mWidth;
846 
847         if (y & 1) {
848             src_u += src.mWidth;
849         }
850 
851         dst_ptr += dst.mWidth;
852     }
853 
854     return OK;
855 }
856 
convertTIYUV420PackedSemiPlanar(const BitmapParams & src,const BitmapParams & dst)857 status_t ColorConverter::convertTIYUV420PackedSemiPlanar(
858         const BitmapParams &src, const BitmapParams &dst) {
859     uint8_t *kAdjustedClip = initClip();
860 
861     uint16_t *dst_ptr = (uint16_t *)dst.mBits
862         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
863 
864     const uint8_t *src_y =
865         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
866 
867     const uint8_t *src_u =
868         (const uint8_t *)src_y + src.mWidth * (src.mHeight - src.mCropTop / 2);
869 
870     for (size_t y = 0; y < src.cropHeight(); ++y) {
871         for (size_t x = 0; x < src.cropWidth(); x += 2) {
872             signed y1 = (signed)src_y[x] - 16;
873             signed y2 = (signed)src_y[x + 1] - 16;
874 
875             signed u = (signed)src_u[x & ~1] - 128;
876             signed v = (signed)src_u[(x & ~1) + 1] - 128;
877 
878             signed u_b = u * 517;
879             signed u_g = -u * 100;
880             signed v_g = -v * 208;
881             signed v_r = v * 409;
882 
883             signed tmp1 = y1 * 298;
884             signed b1 = (tmp1 + u_b) / 256;
885             signed g1 = (tmp1 + v_g + u_g) / 256;
886             signed r1 = (tmp1 + v_r) / 256;
887 
888             signed tmp2 = y2 * 298;
889             signed b2 = (tmp2 + u_b) / 256;
890             signed g2 = (tmp2 + v_g + u_g) / 256;
891             signed r2 = (tmp2 + v_r) / 256;
892 
893             uint32_t rgb1 =
894                 ((kAdjustedClip[r1] >> 3) << 11)
895                 | ((kAdjustedClip[g1] >> 2) << 5)
896                 | (kAdjustedClip[b1] >> 3);
897 
898             uint32_t rgb2 =
899                 ((kAdjustedClip[r2] >> 3) << 11)
900                 | ((kAdjustedClip[g2] >> 2) << 5)
901                 | (kAdjustedClip[b2] >> 3);
902 
903             if (x + 1 < src.cropWidth()) {
904                 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
905             } else {
906                 dst_ptr[x] = rgb1;
907             }
908         }
909 
910         src_y += src.mWidth;
911 
912         if (y & 1) {
913             src_u += src.mWidth;
914         }
915 
916         dst_ptr += dst.mWidth;
917     }
918 
919     return OK;
920 }
921 
initClip()922 uint8_t *ColorConverter::initClip() {
923     static const signed kClipMin = -278;
924     static const signed kClipMax = 535;
925 
926     if (mClip == NULL) {
927         mClip = new uint8_t[kClipMax - kClipMin + 1];
928 
929         for (signed i = kClipMin; i <= kClipMax; ++i) {
930             mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
931         }
932     }
933 
934     return &mClip[-kClipMin];
935 }
936 
937 }  // namespace android
938