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