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/MediaCodecConstants.h>
27 #include <media/stagefright/MediaErrors.h>
28 
29 #include "libyuv/convert_from.h"
30 #include "libyuv/convert_argb.h"
31 #include "libyuv/planar_functions.h"
32 #include "libyuv/video_common.h"
33 #include <functional>
34 #include <sys/time.h>
35 
36 #define PERF_PROFILING 0
37 
38 #if defined(__aarch64__) || defined(__ARM_NEON__)
39 #define USE_NEON_Y410 1
40 #else
41 #define USE_NEON_Y410 0
42 #endif
43 
44 #if USE_NEON_Y410
45 #include <arm_neon.h>
46 #endif
47 
48 namespace android {
49 typedef const struct libyuv::YuvConstants LibyuvConstants;
50 
51 struct LibyuvConstPair {
52     const LibyuvConstants *yuv;
53     const LibyuvConstants *yvu;
54 };
55 
56 // Function to resolve YUV Matrices defined in libyuv
getLibYUVMatrix(const ColorConverter::ColorSpace & colorSpace,bool is10Bit)57 static LibyuvConstPair getLibYUVMatrix(
58         const ColorConverter::ColorSpace &colorSpace, bool is10Bit) {
59     LibyuvConstPair matrix = {nullptr, nullptr};
60     const bool isFullRange = (colorSpace.mRange == ColorUtils::kColorRangeFull);
61     if (colorSpace.isI601()) {
62         matrix.yuv = &libyuv::kYuvI601Constants;
63         matrix.yvu = &libyuv::kYvuI601Constants;
64     } else if (colorSpace.isJ601()) {
65         matrix.yuv = &libyuv::kYuvJPEGConstants;
66         matrix.yvu = &libyuv::kYvuJPEGConstants;
67     } else if (colorSpace.isH709()) {
68         matrix.yuv = &libyuv::kYuvH709Constants;
69         matrix.yvu = &libyuv::kYvuH709Constants;
70     } else if (colorSpace.isF709()) {
71         matrix.yuv = &libyuv::kYuvF709Constants;
72         matrix.yvu = &libyuv::kYvuF709Constants;
73     } else if (colorSpace.isBt2020()) {
74         matrix.yuv = &libyuv::kYuv2020Constants;
75         matrix.yvu = &libyuv::kYvu2020Constants;
76     } else if (colorSpace.isBtV2020()) {
77         matrix.yuv = &libyuv::kYuvV2020Constants;
78         matrix.yvu = &libyuv::kYvuV2020Constants;
79     } else {
80         // unspecified
81         if (isFullRange) {
82             matrix.yuv = is10Bit ? &libyuv::kYuvV2020Constants : &libyuv::kYuvJPEGConstants;
83             matrix.yvu = is10Bit ? &libyuv::kYvuV2020Constants : &libyuv::kYvuJPEGConstants;
84         } else {
85             matrix.yuv = is10Bit ? &libyuv::kYuv2020Constants : &libyuv::kYuvI601Constants;
86             matrix.yvu = is10Bit ? &libyuv::kYvu2020Constants : &libyuv::kYvuI601Constants;
87         }
88     }
89     return matrix;
90 }
91 
isRGB(OMX_COLOR_FORMATTYPE colorFormat)92 static bool isRGB(OMX_COLOR_FORMATTYPE colorFormat) {
93     return colorFormat == OMX_COLOR_Format16bitRGB565
94             || colorFormat == OMX_COLOR_Format32BitRGBA8888
95             || colorFormat == OMX_COLOR_Format32bitBGRA8888
96             || colorFormat == COLOR_Format32bitABGR2101010;
97 }
98 
99 // check for limited Range
isLimitedRange() const100 bool ColorConverter::ColorSpace::isLimitedRange() const {
101     return mRange == ColorUtils::kColorRangeLimited;
102 }
103 
104 // BT.2020 limited range YUV to RGB
isBt2020() const105 bool ColorConverter::ColorSpace::isBt2020() const {
106     return (mStandard == ColorUtils::kColorStandardBT2020
107             && mRange == ColorUtils::kColorRangeLimited);
108 }
109 
110 // BT.2020 full range YUV to RGB
isBtV2020() const111 bool ColorConverter::ColorSpace::isBtV2020() const {
112     return (mStandard == ColorUtils::kColorStandardBT2020
113             && mRange == ColorUtils::kColorRangeFull);
114 }
115 
116 // BT.709 full range YUV to RGB
isF709() const117 bool ColorConverter::ColorSpace::isF709() const {
118     return (mStandard == ColorUtils::kColorStandardBT709
119             && mRange == ColorUtils::kColorRangeFull);
120 }
121 
122 // BT.709 limited range YUV to RGB
isH709() const123 bool ColorConverter::ColorSpace::isH709() const {
124     return (mStandard == ColorUtils::kColorStandardBT709)
125             && (mRange == ColorUtils::kColorRangeLimited);
126 }
127 
128 // BT.601 limited range YUV to RGB
129 // the matrix coefficients are the same for both 601.625 and 601.525 standards
isI601() const130 bool ColorConverter::ColorSpace::isI601() const {
131     return ((mStandard == ColorUtils::kColorStandardBT601_625)
132             || (mStandard == ColorUtils::kColorStandardBT601_525))
133             && (mRange == ColorUtils::kColorRangeLimited);
134 }
135 
136 // BT.601 full range YUV to RGB
isJ601() const137 bool ColorConverter::ColorSpace::isJ601() const {
138     return ((mStandard == ColorUtils::kColorStandardBT601_625)
139             || (mStandard == ColorUtils::kColorStandardBT601_525))
140             && (mRange == ColorUtils::kColorRangeFull);
141 }
142 
143 // Utility functions for MediaImage2
CreateYUV420PlanarMediaImage2(uint32_t width,uint32_t height,uint32_t stride,uint32_t vstride,uint32_t bitDepth)144 static MediaImage2 CreateYUV420PlanarMediaImage2(
145         uint32_t width, uint32_t height, uint32_t stride,
146         uint32_t vstride, uint32_t bitDepth) {
147     const uint32_t componentBytes = (bitDepth + 7) / 8;
148     return MediaImage2 {
149         .mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV,
150         .mNumPlanes = 3,
151         .mWidth = width,
152         .mHeight = height,
153         .mBitDepth = bitDepth,
154         .mBitDepthAllocated = componentBytes * 8,
155         .mPlane = {
156             {
157                 .mOffset = 0,
158                 .mColInc = static_cast<int32_t>(componentBytes),
159                 .mRowInc = static_cast<int32_t>(stride),
160                 .mHorizSubsampling = 1,
161                 .mVertSubsampling = 1,
162             },
163             {
164                 .mOffset = stride * vstride,
165                 .mColInc = static_cast<int32_t>(componentBytes),
166                 .mRowInc = static_cast<int32_t>(stride / 2),
167                 .mHorizSubsampling = 2,
168                 .mVertSubsampling = 2,
169             },
170             {
171                 .mOffset = stride * vstride * 5 / 4,
172                 .mColInc = static_cast<int32_t>(componentBytes),
173                 .mRowInc = static_cast<int32_t>(stride / 2),
174                 .mHorizSubsampling = 2,
175                 .mVertSubsampling = 2,
176             }
177         },
178     };
179 }
180 
CreateYUV420SemiPlanarMediaImage2(uint32_t width,uint32_t height,uint32_t stride,uint32_t vstride,uint32_t bitDepth,bool uv=true)181 static MediaImage2 CreateYUV420SemiPlanarMediaImage2(
182         uint32_t width, uint32_t height, uint32_t stride,
183         uint32_t vstride, uint32_t bitDepth, bool uv = true /*nv12 or not*/) {
184     const uint32_t componentBytes = (bitDepth + 7) / 8;
185     return MediaImage2 {
186         .mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV,
187         .mNumPlanes = 3,
188         .mWidth = width,
189         .mHeight = height,
190         .mBitDepth = bitDepth,
191         .mBitDepthAllocated = componentBytes * 8,
192         .mPlane = {
193             {
194                 .mOffset = 0,
195                 .mColInc = static_cast<int32_t>(componentBytes),
196                 .mRowInc = static_cast<int32_t>(stride),
197                 .mHorizSubsampling = 1,
198                 .mVertSubsampling = 1,
199             },
200             {
201                 .mOffset = stride * vstride + (uv ? 0 : componentBytes),
202                 .mColInc = static_cast<int32_t>(2 * componentBytes),
203                 .mRowInc = static_cast<int32_t>(stride),
204                 .mHorizSubsampling = 2,
205                 .mVertSubsampling = 2,
206             },
207             {
208                 .mOffset = stride * vstride + (uv ? componentBytes : 0),
209                 .mColInc = static_cast<int32_t>(2 * componentBytes),
210                 .mRowInc = static_cast<int32_t>(stride),
211                 .mHorizSubsampling = 2,
212                 .mVertSubsampling = 2,
213             }
214         },
215     };
216 }
217 
Image(const MediaImage2 & img)218 ColorConverter::Image::Image(const MediaImage2& img)
219     :mImage(img),
220     mLayout(ImageLayoutUnknown),
221     mSampling(ImageSamplingUnknown) {
222     const MediaImage2::PlaneInfo &yPlane =
223             img.mPlane[MediaImage2::PlaneIndex::Y];
224     const MediaImage2::PlaneInfo &uPlane =
225             img.mPlane[MediaImage2::PlaneIndex::U];
226     const MediaImage2::PlaneInfo &vPlane =
227             img.mPlane[MediaImage2::PlaneIndex::V];
228 
229     if (mImage.mNumPlanes != 3) {
230         ALOGE("Conversion error: MediaImage2 mNumPlanes != 3");
231         mLayout = ImageLayoutUnknown;
232         mSampling = ImageSamplingUnknown;
233         mBitDepth = ImageBitDepthInvalid;
234         return;
235     }
236 
237     if (mImage.mBitDepth == 8
238             && yPlane.mColInc == 1
239             && uPlane.mColInc == 1
240             && vPlane.mColInc == 1
241             && yPlane.mVertSubsampling == 1
242             && uPlane.mVertSubsampling == 2
243             && vPlane.mVertSubsampling == 2) {
244         mLayout = ImageLayout420Planar;
245         mSampling = ImageSamplingYUV420;
246     } else if (mImage.mBitDepth == 8
247             && yPlane.mColInc == 1
248             && uPlane.mColInc == 2
249             && vPlane.mColInc == 2
250             && yPlane.mVertSubsampling == 1
251             && uPlane.mVertSubsampling == 2
252             && vPlane.mVertSubsampling == 2
253             && ((vPlane.mOffset == uPlane.mOffset + 1) ||
254             (uPlane.mOffset == vPlane.mOffset + 1))) {
255         mLayout = ImageLayout420SemiPlanar;
256         mSampling = ImageSamplingYUV420;
257     }
258 
259     mBitDepth = ImageBitDepthInvalid;
260     switch (img.mBitDepth) {
261         case 8:
262             mBitDepth = ImageBitDepth8;
263             break;
264 
265         case 10:
266         case 12:
267         case 16:
268         default:
269             // TODO: Implement 10b, 12b and 16b using MediaImage2
270             mBitDepth = ImageBitDepthInvalid;
271     }
272 
273 }
274 
getYUVPlaneOffsetAndStride(const BitmapParams & src,uint32_t * y_offset,uint32_t * u_offset,uint32_t * v_offset,size_t * y_stride,size_t * u_stride,size_t * v_stride) const275 status_t ColorConverter::Image::getYUVPlaneOffsetAndStride(
276         const BitmapParams &src,
277         uint32_t *y_offset,
278         uint32_t *u_offset,
279         uint32_t *v_offset,
280         size_t *y_stride,
281         size_t *u_stride,
282         size_t *v_stride) const {
283 
284     if (y_offset == nullptr || u_offset == nullptr || v_offset == nullptr
285             || y_stride == nullptr || u_stride == nullptr || v_stride == nullptr) {
286         return ERROR_UNSUPPORTED;
287     }
288 
289     if (mImage.mNumPlanes != 3) {
290         return ERROR_UNSUPPORTED;
291     }
292 
293     const MediaImage2::PlaneInfo &yPlane = mImage.mPlane[MediaImage2::PlaneIndex::Y];
294     *y_offset = yPlane.mOffset
295             + src.mCropTop * yPlane.mRowInc
296             + src.mCropLeft * yPlane.mColInc;
297 
298     const MediaImage2::PlaneInfo &uPlane = mImage.mPlane[MediaImage2::PlaneIndex::U];
299     *u_offset = uPlane.mOffset
300             + (src.mCropTop / uPlane.mVertSubsampling) * uPlane.mRowInc
301             + (src.mCropLeft / uPlane.mHorizSubsampling) * uPlane.mColInc;
302 
303     const MediaImage2::PlaneInfo &vPlane = mImage.mPlane[MediaImage2::PlaneIndex::V];
304     *v_offset = vPlane.mOffset
305             + (src.mCropTop / vPlane.mVertSubsampling) * vPlane.mRowInc
306             + (src.mCropLeft / vPlane.mHorizSubsampling) * vPlane.mColInc;
307 
308     *y_stride = yPlane.mRowInc;
309     *u_stride = uPlane.mRowInc;
310     *v_stride = vPlane.mRowInc;
311 
312     return OK;
313 }
314 
isNV21() const315 bool ColorConverter::Image::isNV21() const {
316     if (getLayout() == ImageLayout420SemiPlanar) {
317         const MediaImage2::PlaneInfo &uPlane = mImage.mPlane[MediaImage2::PlaneIndex::U];
318         const MediaImage2::PlaneInfo &vPlane = mImage.mPlane[MediaImage2::PlaneIndex::V];
319 
320         int componentBytes = (mImage.mBitDepthAllocated) / 8;
321 
322         return (((vPlane.mOffset + componentBytes) == uPlane.mOffset));
323     }
324     return false;
325 }
326 
327 /**
328  * This class approximates the standard YUV to RGB conversions by factoring the matrix
329  * coefficients to 1/256th-s (as dividing by 256 is easy to do with right shift). The chosen value
330  * of 256 is somewhat arbitrary and was not dependent on the bit-depth, but it does limit the
331  * precision of the matrix coefficients (KR & KB).
332  *
333  * The maximum color error after clipping from using 256 is a distance of:
334  *   0.4 (8-bit) / 1.4 (10-bit) for greens in BT.601
335  *   0.5 (8-bit) / 1.9 (10-bit) for cyans in BT.709, and
336  *   0.3 (8-bit) / 1.3 (10-bit) for violets in BT.2020 (it is 0.4 for 10-bit BT.2020 limited)
337  *
338  * Note for reference: libyuv is using a divisor of 64 instead of 256 to ensure no overflow in
339  * 16-bit math. The maximum color error for libyuv is 3.5 / 14.
340  *
341  * The clamping is done using a lookup vector where negative indices are mapped to 0
342  * and indices > 255 are mapped to 255. (For 10-bit these are clamped to 0 to 1023)
343  *
344  * The matrices are assumed to be of the following format (note the sign on the 2nd row):
345  *
346  * [ R ]     [ _y     0    _r_v ]   [ Y -  C16 ]
347  * [ G ]  =  [ _y  -_g_u  -_g_v ] * [ U - C128 ]
348  * [ B ]     [ _y   _b_u     0  ]   [ V - C128 ]
349  *
350  * C16 is 1 << (bitdepth - 4) for limited range, and 0 for full range
351  * C128 is 1 << (bitdepth - 1)
352  * C255 is (1 << bitdepth) - 1
353  *
354  * The min and max values from these equations determine the clip range needed for clamping:
355  *
356  * min = - (_y * C16 + max((_g_u + _g_v) * (C255-C128), max(_r_v, _b_u) * C128)) / 256
357  * max = (_y * (C255 - C16) + max((_g_u + _g_v) * C128, max(_r_v, _b_u) * (C255-C128)) + 128) / 256
358  */
359 
360 struct ColorConverter::Coeffs {
361     int32_t _y;
362     int32_t _r_v;
363     int32_t _g_u;
364     int32_t _g_v;
365     int32_t _b_u;
366     int32_t _c16;  // 16 for limited range matrix, 0 for full rance
367 };
368 
369 /*
370 
371 Color conversion rules are dictated by ISO (e.g. ISO:IEC 23008:2)
372 
373 Limited range means Y is in [16, 235], U and V are in [16, 224] corresponding to [-0.5 to 0.5].
374 
375 Full range means Y is in [0, 255], U and V are in [0.5, 255.5] corresponding to [-0.5 to .5].
376 
377 RGB is always in full range ([0, 255])
378 
379 The color primaries determine the KR and KB values:
380 
381 
382 For full range (assuming 8-bits) ISO defines:
383 
384 (   Y   )   (  KR      1-KR-KB       KB  )
385 (       )   (                            )   (R)
386 (       )   (-KR/2   -(1-KR-KB)/2        )   ( )
387 (U - 128) = (-----   ------------    0.5 ) * (G)
388 (       )   ((1-KB)     (1-KB)           )   ( )
389 (       )   (                            )   (B)
390 (       )   (        -(1-KR-KB)/2  -KB/2 )
391 (V - 128)   ( 0.5    ------------  ----- )
392             (           (1-KR)     (1-KR))
393 
394 (the math is rounded, 128 is (1 << (bitdepth - 1)) )
395 
396 From this
397 
398 (R)      ( 1       0        2*(1-KR)   )   (   Y   )
399 ( )      (                             )   (       )
400 ( )      (    2*KB*(KB-1)  2*KR*(KR-1) )   (       )
401 (G)  =   ( 1  -----------  ----------- ) * (U - 128)
402 ( )      (      1-KR-KB      1-KR-KB   )   (       )
403 ( )      (                             )   (       )
404 (B)      ( 1   2*(1-KB)         0      )   (V - 128)
405 
406 For limited range, this becomes
407 
408 (R)      ( 1       0        2*(1-KR)   )   (255/219  0  0)   (Y -  16)
409 ( )      (                             )   (             )   (       )
410 ( )      (    2*KB*(KB-1)  2*KR*(KR-1) )   (             )   (       )
411 (G)  =   ( 1  -----------  ----------- ) * (0  255/224  0) * (U - 128)
412 ( )      (      1-KR-KB      1-KR-KB   )   (             )   (       )
413 ( )      (                             )   (             )   (       )
414 (B)      ( 1   2*(1-KB)         0      )   (0  0  255/224)   (V - 128)
415 
416 ( For non-8-bit, 16 is (1 << (bitdepth - 4)), 128 is (1 << (bitdepth - 1)),
417   255 is ((1 << bitdepth) - 1), 219 is (219 << (bitdepth - 8)) and
418   224 is (224 << (bitdepth - 8)), so the matrix coefficients slightly change. )
419 
420 */
421 
422 namespace {
423 
424 /**
425  * BT.601:  K_R = 0.299;  K_B = 0.114
426  *
427  * clip range 8-bit: [-277, 535], 10-bit: [-1111, 2155]
428  */
429 const struct ColorConverter::Coeffs BT601_FULL      = { 256, 359,  88, 183, 454, 0 };
430 const struct ColorConverter::Coeffs BT601_LIMITED   = { 298, 409, 100, 208, 516, 16 };
431 const struct ColorConverter::Coeffs BT601_LTD_10BIT = { 299, 410, 101, 209, 518, 16 };
432 
433 /**
434  * BT.709:  K_R = 0.2126; K_B = 0.0722
435  *
436  * clip range 8-bit: [-289, 547], 10-bit: [-1159, 2202]
437  */
438 const struct ColorConverter::Coeffs BT709_FULL      = { 256, 403,  48, 120, 475, 0 };
439 const struct ColorConverter::Coeffs BT709_LIMITED   = { 298, 459,  55, 136, 541, 16 };
440 const struct ColorConverter::Coeffs BT709_LTD_10BIT = { 299, 460,  55, 137, 542, 16 };
441 
442 /**
443  * BT.2020:  K_R = 0.2627; K_B = 0.0593
444  *
445  * clip range 8-bit: [-294, 552], 10-bit: [-1175, 2218]
446  *
447  * This is the largest clip range.
448  */
449 const struct ColorConverter::Coeffs BT2020_FULL      = { 256, 377,  42, 146, 482, 0 };
450 const struct ColorConverter::Coeffs BT2020_LIMITED   = { 298, 430,  48, 167, 548, 16 };
451 const struct ColorConverter::Coeffs BT2020_LTD_10BIT = { 299, 431,  48, 167, 550, 16 };
452 
453 constexpr int CLIP_RANGE_MIN_8BIT = -294;
454 constexpr int CLIP_RANGE_MAX_8BIT = 552;
455 
456 constexpr int CLIP_RANGE_MIN_10BIT = -1175;
457 constexpr int CLIP_RANGE_MAX_10BIT = 2218;
458 
459 }
460 
ColorConverter(OMX_COLOR_FORMATTYPE from,OMX_COLOR_FORMATTYPE to)461 ColorConverter::ColorConverter(
462         OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
463     : mSrcFormat(from),
464       mDstFormat(to),
465       mSrcColorSpace({0, 0, 0}),
466       mClip(NULL),
467       mClip10Bit(NULL) {
468 }
469 
~ColorConverter()470 ColorConverter::~ColorConverter() {
471     delete[] mClip;
472     mClip = NULL;
473     delete[] mClip10Bit;
474     mClip10Bit = NULL;
475 }
476 
477 // Set MediaImage2 Flexible formats
setSrcMediaImage2(MediaImage2 img)478 void ColorConverter::setSrcMediaImage2(MediaImage2 img) {
479     mSrcImage = Image(img);
480  }
481 
isValidForMediaImage2() const482 bool ColorConverter::isValidForMediaImage2() const {
483 
484     if (!mSrcImage
485             || mSrcImage->getMediaImage2().mType != MediaImage2::MEDIA_IMAGE_TYPE_YUV) {
486         // TODO: support Yonly or RGB etc?
487         return false;
488     }
489     // try to identify the src format
490 
491     BitDepth_t srcBitDepth = mSrcImage->getBitDepth();
492 
493     //TODO: support 12b and 16b ?
494     if (srcBitDepth == ImageBitDepthInvalid) {
495         return false;
496     }
497 
498     return ((srcBitDepth == ImageBitDepth8  &&
499             (mDstFormat == OMX_COLOR_Format16bitRGB565
500             || mDstFormat == OMX_COLOR_Format32BitRGBA8888
501             || mDstFormat == OMX_COLOR_Format32bitBGRA8888))
502 
503             || (srcBitDepth == ImageBitDepth10
504             && (mDstFormat == COLOR_Format32bitABGR2101010)));
505 }
506 
isValid() const507 bool ColorConverter::isValid() const {
508     switch ((int32_t)mSrcFormat) {
509         case COLOR_FormatYUV420Flexible:
510             return isValidForMediaImage2();
511             break;
512 
513         case OMX_COLOR_FormatYUV420Planar16:
514             if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
515                 return true;
516             }
517             FALLTHROUGH_INTENDED;
518         case OMX_COLOR_FormatYUV420Planar:
519             return mDstFormat == OMX_COLOR_Format16bitRGB565
520                     || mDstFormat == OMX_COLOR_Format32BitRGBA8888
521                     || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
522 
523         case OMX_COLOR_FormatCbYCrY:
524             return mDstFormat == OMX_COLOR_Format16bitRGB565;
525 
526         case OMX_COLOR_FormatYUV420SemiPlanar:
527         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
528         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
529             if (mSrcImage) {
530                 return isValidForMediaImage2();
531             }
532             return mDstFormat == OMX_COLOR_Format16bitRGB565
533                     || mDstFormat == OMX_COLOR_Format32BitRGBA8888
534                     || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
535 
536         case COLOR_FormatYUVP010:
537             return mDstFormat == COLOR_Format32bitABGR2101010;
538 
539         default:
540             //TODO: Should this be enabled for MediaImage2?
541             return false;
542     }
543 }
544 
isDstRGB() const545 bool ColorConverter::isDstRGB() const {
546     return isRGB(mDstFormat);
547 }
548 
setSrcColorSpace(uint32_t standard,uint32_t range,uint32_t transfer)549 void ColorConverter::setSrcColorSpace(
550         uint32_t standard, uint32_t range, uint32_t transfer) {
551     if (isRGB(mSrcFormat)) {
552         ALOGW("Can't set color space on RGB source");
553         return;
554     }
555     mSrcColorSpace.mStandard = standard;
556     mSrcColorSpace.mRange = range;
557     mSrcColorSpace.mTransfer = transfer;
558 }
559 
560 /*
561  * If stride is non-zero, client's stride will be used. For planar
562  * or semi-planar YUV formats, stride must be even numbers.
563  * If stride is zero, it will be calculated based on width and bpp
564  * of the format, assuming no padding on the right edge.
565  */
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)566 ColorConverter::BitmapParams::BitmapParams(
567         void *bits,
568         size_t width, size_t height, size_t stride,
569         size_t cropLeft, size_t cropTop,
570         size_t cropRight, size_t cropBottom,
571         OMX_COLOR_FORMATTYPE colorFromat)
572     : mBits(bits),
573       mColorFormat(colorFromat),
574       mWidth(width),
575       mHeight(height),
576       mCropLeft(cropLeft),
577       mCropTop(cropTop),
578       mCropRight(cropRight),
579       mCropBottom(cropBottom) {
580     switch((int32_t)mColorFormat) {
581     case OMX_COLOR_Format16bitRGB565:
582     case OMX_COLOR_FormatYUV420Planar16:
583     case COLOR_FormatYUVP010:
584     case OMX_COLOR_FormatCbYCrY:
585         mBpp = 2;
586         mStride = 2 * mWidth;
587         break;
588 
589     case OMX_COLOR_Format32bitBGRA8888:
590     case OMX_COLOR_Format32BitRGBA8888:
591     case COLOR_Format32bitABGR2101010:
592     case OMX_COLOR_FormatYUV444Y410:
593         mBpp = 4;
594         mStride = 4 * mWidth;
595         break;
596 
597     case OMX_COLOR_FormatYUV420Planar:
598     case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
599     case OMX_COLOR_FormatYUV420SemiPlanar:
600     case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
601         mBpp = 1;
602         mStride = mWidth;
603         break;
604 
605     case COLOR_FormatYUV420Flexible:
606         // MediaImage2 should be used.
607         mBpp = 1;
608         mStride = mWidth;
609 
610         break;
611 
612     default:
613         ALOGE("Unsupported color format %d", mColorFormat);
614         mBpp = 1;
615         mStride = mWidth;
616         break;
617     }
618     // use client's stride if it's specified.
619     if (stride != 0) {
620         mStride = stride;
621     }
622 }
623 
cropWidth() const624 size_t ColorConverter::BitmapParams::cropWidth() const {
625     return mCropRight - mCropLeft + 1;
626 }
627 
cropHeight() const628 size_t ColorConverter::BitmapParams::cropHeight() const {
629     return mCropBottom - mCropTop + 1;
630 }
631 
isValid() const632 bool ColorConverter::BitmapParams::isValid() const {
633     if (!((mStride & 1) == 0  // stride must be even
634         && mStride >= mBpp * cropWidth())) {
635             return false;
636     }
637     return true;
638 }
639 
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)640 status_t ColorConverter::convert(
641         const void *srcBits,
642         size_t srcWidth, size_t srcHeight, size_t srcStride,
643         size_t srcCropLeft, size_t srcCropTop,
644         size_t srcCropRight, size_t srcCropBottom,
645         void *dstBits,
646         size_t dstWidth, size_t dstHeight, size_t dstStride,
647         size_t dstCropLeft, size_t dstCropTop,
648         size_t dstCropRight, size_t dstCropBottom) {
649     BitmapParams src(
650             const_cast<void *>(srcBits),
651             srcWidth, srcHeight, srcStride,
652             srcCropLeft, srcCropTop, srcCropRight, srcCropBottom,
653             mSrcFormat);
654 
655     BitmapParams dst(
656             dstBits,
657             dstWidth, dstHeight, dstStride,
658             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
659 
660     if (!(src.isValid()
661             && dst.isValid()
662             && (src.mCropLeft & 1) == 0
663             && src.cropWidth() == dst.cropWidth()
664             && src.cropHeight() == dst.cropHeight())) {
665         return ERROR_UNSUPPORTED;
666     }
667 #if PERF_PROFILING
668     int64_t startTimeUs = ALooper::GetNowUs();
669 #endif
670     status_t err;
671     switch ((int32_t)mSrcFormat) {
672         case COLOR_FormatYUV420Flexible:
673             err = convertYUVMediaImage(src, dst);
674             break;
675 
676         case OMX_COLOR_FormatYUV420Planar:
677             if (!mSrcImage) {
678                 mSrcImage = Image(CreateYUV420PlanarMediaImage2(
679                         srcWidth, srcHeight, srcStride, srcHeight, 8 /*bitDepth*/));
680             }
681             err = convertYUVMediaImage(src, dst);
682 
683             break;
684 
685         case OMX_COLOR_FormatYUV420Planar16:
686             err = convertYUV420Planar16(src, dst);
687             break;
688 
689         case COLOR_FormatYUVP010:
690             err = convertYUVP010(src, dst);
691 
692             break;
693 
694         case OMX_COLOR_FormatCbYCrY:
695             err = convertCbYCrY(src, dst);
696             break;
697 
698         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
699             if (!mSrcImage) {
700                 mSrcImage = Image(CreateYUV420SemiPlanarMediaImage2(
701                     srcWidth, srcHeight, srcStride, srcHeight, 8 /*bitDepth*/, false));
702             }
703             err = convertYUVMediaImage(src, dst);
704 
705             break;
706 
707         case OMX_COLOR_FormatYUV420SemiPlanar:
708         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
709             if (!mSrcImage) {
710                 mSrcImage = Image(CreateYUV420SemiPlanarMediaImage2(
711                     srcWidth, srcHeight, srcStride, srcHeight, 8 /*bitDepth*/));
712             }
713             err = convertYUVMediaImage(src, dst);
714 
715             break;
716 
717         default:
718 
719             CHECK(!"Should not be here. Unknown color conversion.");
720             break;
721     }
722 
723 #if PERF_PROFILING
724     int64_t endTimeUs = ALooper::GetNowUs();
725     ALOGD("%s image took %lld us", asString_ColorFormat(mSrcFormat,"Unknown"),
726             (long long) (endTimeUs - startTimeUs));
727 #endif
728 
729     return err;
730 }
731 
getMatrix() const732 const struct ColorConverter::Coeffs *ColorConverter::getMatrix() const {
733     const bool isFullRange = mSrcColorSpace.mRange == ColorUtils::kColorRangeFull;
734     const bool is10Bit = (mSrcFormat == COLOR_FormatYUVP010
735             || mSrcFormat == OMX_COLOR_FormatYUV420Planar16);
736 
737     ColorAspects::Primaries primaries;
738     ColorAspects::MatrixCoeffs matrix;
739     if (ColorUtils::unwrapColorAspectsFromColorStandard(
740             mSrcColorSpace.mStandard, &primaries, &matrix) != OK) {
741         matrix = ColorAspects::MatrixUnspecified;
742     }
743 
744     switch (matrix) {
745     case ColorAspects::MatrixBT601_6:
746     case ColorAspects::MatrixBT470_6M:   // use 601 matrix as that is the closest for now
747     case ColorAspects::MatrixSMPTE240M:  // use 601 matrix as that is the closest for now
748         return (isFullRange ? &BT601_FULL :
749                 is10Bit ? &BT601_LTD_10BIT : &BT601_LIMITED);
750 
751     case ColorAspects::MatrixBT709_5:
752         return (isFullRange ? &BT709_FULL :
753                 is10Bit ? &BT709_LTD_10BIT : &BT709_LIMITED);
754 
755     case ColorAspects::MatrixBT2020:
756     case ColorAspects::MatrixBT2020Constant: // use 2020 matrix as that is the closest for now
757         return (isFullRange ? &BT2020_FULL :
758                 is10Bit ? &BT2020_LTD_10BIT : &BT2020_LIMITED);
759 
760     default:
761         // use BT.2020 for 10-bit and 601 for 8-bit by default
762         if (is10Bit) {
763             return isFullRange ? &BT2020_FULL : &BT2020_LTD_10BIT;
764         } else {
765             return isFullRange ? &BT601_FULL : &BT601_LIMITED;
766         }
767     }
768 }
769 
770 // Interleaved YUV 422 CbYCrY to RGB565
convertCbYCrY(const BitmapParams & src,const BitmapParams & dst)771 status_t ColorConverter::convertCbYCrY(
772         const BitmapParams &src, const BitmapParams &dst) {
773     // XXX Untested
774 
775     const struct Coeffs *matrix = getMatrix();
776     if (!matrix) {
777         return ERROR_UNSUPPORTED;
778     }
779 
780     signed _b_u = matrix->_b_u;
781     signed _neg_g_u = -matrix->_g_u;
782     signed _neg_g_v = -matrix->_g_v;
783     signed _r_v = matrix->_r_v;
784     signed _y = matrix->_y;
785     signed _c16 = matrix->_c16;
786 
787     uint8_t *kAdjustedClip = initClip();
788 
789     uint16_t *dst_ptr = (uint16_t *)dst.mBits
790         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
791 
792     const uint8_t *src_ptr = (const uint8_t *)src.mBits
793         + (src.mCropTop * src.mWidth + src.mCropLeft) * 2;
794 
795     for (size_t y = 0; y < src.cropHeight(); ++y) {
796         for (size_t x = 0; x < src.cropWidth() - 1; x += 2) {
797             signed y1 = (signed)src_ptr[2 * x + 1] - _c16;
798             signed y2 = (signed)src_ptr[2 * x + 3] - _c16;
799             signed u = (signed)src_ptr[2 * x] - 128;
800             signed v = (signed)src_ptr[2 * x + 2] - 128;
801 
802             signed u_b = u * _b_u;
803             signed u_g = u * _neg_g_u;
804             signed v_g = v * _neg_g_v;
805             signed v_r = v * _r_v;
806 
807             signed tmp1 = y1 * _y + 128;
808             signed b1 = (tmp1 + u_b) / 256;
809             signed g1 = (tmp1 + v_g + u_g) / 256;
810             signed r1 = (tmp1 + v_r) / 256;
811 
812             signed tmp2 = y2 * _y + 128;
813             signed b2 = (tmp2 + u_b) / 256;
814             signed g2 = (tmp2 + v_g + u_g) / 256;
815             signed r2 = (tmp2 + v_r) / 256;
816 
817             uint32_t rgb1 =
818                 ((kAdjustedClip[r1] >> 3) << 11)
819                 | ((kAdjustedClip[g1] >> 2) << 5)
820                 | (kAdjustedClip[b1] >> 3);
821 
822             uint32_t rgb2 =
823                 ((kAdjustedClip[r2] >> 3) << 11)
824                 | ((kAdjustedClip[g2] >> 2) << 5)
825                 | (kAdjustedClip[b2] >> 3);
826 
827             if (x + 1 < src.cropWidth()) {
828                 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
829             } else {
830                 dst_ptr[x] = rgb1;
831             }
832         }
833 
834         src_ptr += src.mWidth * 2;
835         dst_ptr += dst.mWidth;
836     }
837 
838     return OK;
839 }
840 
getSrcYUVPlaneOffsetAndStride(const BitmapParams & src,uint32_t * y_offset,uint32_t * u_offset,uint32_t * v_offset,size_t * y_stride,size_t * u_stride,size_t * v_stride) const841 status_t ColorConverter::getSrcYUVPlaneOffsetAndStride(
842         const BitmapParams &src,
843         uint32_t *y_offset, uint32_t *u_offset, uint32_t *v_offset,
844         size_t *y_stride, size_t *u_stride, size_t *v_stride) const {
845     if (y_offset == nullptr || u_offset == nullptr || v_offset == nullptr
846             || y_stride == nullptr || u_stride == nullptr || v_stride == nullptr) {
847         ALOGE("nullptrs given for yuv source offset / stride");
848         return ERROR_MALFORMED;
849     }
850 
851     if (mSrcImage) {
852         // if we have MediaImage2; get the info from MediaImage2
853         return mSrcImage->getYUVPlaneOffsetAndStride(src, y_offset, u_offset, v_offset,
854                 y_stride, u_stride, v_stride);
855     }
856     return ERROR_UNSUPPORTED;
857 }
858 /*
859     libyuv supports the following color spaces:
860 
861     I601:  BT.601 limited range
862     J601:  BT.601 full range (jpeg)
863     H709:  BT.709 limited range
864     F709:  BT.709 Full range
865     2020:  BT.2020 limited range
866     V2020: BT.2020 Full range
867 
868 */
869 
convertYUV420PlanarUseLibYUV(const BitmapParams & src,const BitmapParams & dst)870 status_t ColorConverter::convertYUV420PlanarUseLibYUV(
871         const BitmapParams &src, const BitmapParams &dst) {
872     LibyuvConstPair yuvConstants =
873             getLibYUVMatrix(mSrcColorSpace, false);
874 
875     uint32_t y_offset = 0, u_offset = 0, v_offset = 0;
876     size_t src_stride_y =0, src_stride_u = 0, src_stride_v = 0;
877     if (getSrcYUVPlaneOffsetAndStride(src, &y_offset, &u_offset, &v_offset,
878                           &src_stride_y, &src_stride_u, &src_stride_v) != OK) {
879         return ERROR_UNSUPPORTED;
880     }
881 
882     uint8_t *dst_ptr = (uint8_t *)dst.mBits
883         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
884 
885     const uint8_t *src_y = (const uint8_t *)src.mBits + y_offset;
886 
887     const uint8_t *src_u = (const uint8_t *)src.mBits + u_offset;
888 
889     const uint8_t *src_v = (const uint8_t *)src.mBits + v_offset;
890 
891     switch (mDstFormat) {
892     case OMX_COLOR_Format16bitRGB565:
893     {
894         libyuv::I420ToRGB565Matrix(src_y,
895                 src_stride_y,
896                 src_u,
897                 src_stride_u,
898                 src_v,
899                 src_stride_v,
900                 dst_ptr,
901                 dst.mStride,
902                 yuvConstants.yuv,
903                 src.cropWidth(),
904                 src.cropHeight());
905 
906         break;
907     }
908 
909     case OMX_COLOR_Format32bitBGRA8888:
910     {
911         libyuv::I420ToARGBMatrix(src_y,
912                 src_stride_y,
913                 src_u,
914                 src_stride_u,
915                 src_v,
916                 src_stride_v,
917                 (uint8_t*)dst_ptr,
918                 dst.mStride,
919                 yuvConstants.yuv,
920                 src.cropWidth(),
921                 src.cropHeight());
922         break;
923     }
924 
925     case OMX_COLOR_Format32BitRGBA8888:
926     {
927         libyuv::I420ToARGBMatrix(src_y,
928                 src_stride_y,
929                 src_v,
930                 src_stride_v,
931                 src_u,
932                 src_stride_u,
933                 (uint8_t*)dst_ptr,
934                 dst.mStride,
935                 yuvConstants.yvu,
936                 src.cropWidth(),
937                 src.cropHeight());
938         break;
939     }
940 
941     default:
942         return ERROR_UNSUPPORTED;
943     }
944 
945     return OK;
946 }
947 
convertYUV420SemiPlanarUseLibYUV(const BitmapParams & src,const BitmapParams & dst)948 status_t ColorConverter::convertYUV420SemiPlanarUseLibYUV(
949         const BitmapParams &src, const BitmapParams &dst) {
950     LibyuvConstPair yuvConstants =
951             getLibYUVMatrix(mSrcColorSpace, false);
952 
953     uint32_t y_offset = 0, u_offset = 0, v_offset = 0;
954     size_t src_stride_y =0, src_stride_u = 0, src_stride_v = 0;
955     if (getSrcYUVPlaneOffsetAndStride(src, &y_offset, &u_offset, &v_offset,
956                           &src_stride_y, &src_stride_u, &src_stride_v) != OK) {
957         return ERROR_UNSUPPORTED;
958     }
959     (void)v_offset;
960     uint8_t *dst_ptr = (uint8_t *)dst.mBits
961         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
962 
963     const uint8_t *src_y = (const uint8_t *)src.mBits + y_offset;
964 
965     const uint8_t *src_u = (const uint8_t *)src.mBits + u_offset;
966 
967     const uint8_t *src_v = (const uint8_t *)src.mBits + v_offset;
968 
969     bool isNV21 = (u_offset == (v_offset + 1)) ? true : false;
970 
971     // libyuv function signature for semiplanar formats;
972     std::function<int(const uint8_t*, int,
973             const uint8_t*, int, uint8_t *, int,
974             LibyuvConstants *, int, int)> libyuvFunc;
975 
976     switch (mDstFormat) {
977     case OMX_COLOR_Format16bitRGB565:
978     {
979         // Note: We don't seem to have similar function for NV21
980         libyuv::NV12ToRGB565Matrix(src_y,
981                 src_stride_y,
982                 src_u,
983                 src_stride_u,
984                 (uint8_t*)dst_ptr,
985                 dst.mStride,
986                 yuvConstants.yuv,
987                 src.cropWidth(),
988                 src.cropHeight());
989         break;
990     }
991     case OMX_COLOR_Format32bitBGRA8888:
992     {
993         if (src_stride_u != src_stride_v) {
994             return ERROR_UNSUPPORTED;
995         }
996 
997         libyuvFunc = isNV21 ? libyuv:: NV21ToARGBMatrix : libyuv:: NV12ToARGBMatrix;
998 
999         libyuvFunc(src_y,
1000                 src_stride_y,
1001                 isNV21 ? src_v: src_u,
1002                 // src_stride_v should be equal to src_stride_u
1003                 // but this is done like this for readability
1004                 isNV21 ? src_stride_v : src_stride_u,
1005                 (uint8_t*)dst_ptr,
1006                 dst.mStride,
1007                 yuvConstants.yuv,
1008                 src.cropWidth(),
1009                 src.cropHeight());
1010         break;
1011     }
1012 
1013     case OMX_COLOR_Format32BitRGBA8888:
1014     {
1015 
1016         if (src_stride_u != src_stride_v) {
1017             return ERROR_UNSUPPORTED;
1018         }
1019 
1020         libyuvFunc = isNV21 ? libyuv::NV12ToARGBMatrix : libyuv::NV21ToARGBMatrix;
1021 
1022         libyuvFunc(src_y,
1023                 src_stride_y,
1024                 isNV21 ? src_v : src_u,
1025                 // src_stride_v should be equal to src_stride_u
1026                 isNV21 ? src_stride_v : src_stride_u,
1027                 (uint8_t*)dst_ptr,
1028                 dst.mStride,
1029                 yuvConstants.yvu,
1030                 src.cropWidth(),
1031                 src.cropHeight());
1032         break;
1033     }
1034 
1035     default:
1036         return ERROR_UNSUPPORTED;
1037    }
1038 
1039    return OK;
1040 }
1041 
1042 std::function<void (void *, void *, void *, size_t,
1043         signed *, signed *, signed *, signed *)>
getReadFromChromaHorizSubsampled2Image8b(std::optional<MediaImage2> image,OMX_COLOR_FORMATTYPE srcFormat)1044 getReadFromChromaHorizSubsampled2Image8b(std::optional<MediaImage2> image,
1045         OMX_COLOR_FORMATTYPE srcFormat) {
1046     // this function is for reading src only
1047     // when both chromas are horizontally subsampled by 2
1048     // this returns 2 luma for one chroma.
1049     if (image) {
1050         uint32_t uColInc =
1051                 image->mPlane[MediaImage2::PlaneIndex::U].mColInc;
1052         uint32_t vColInc =
1053                 image->mPlane[MediaImage2::PlaneIndex::V].mColInc;
1054         uint32_t uHorizSubsampling =
1055                 image->mPlane[MediaImage2::PlaneIndex::U].mHorizSubsampling;
1056          uint32_t vHorizSubsampling =
1057                 image->mPlane[MediaImage2::PlaneIndex::V].mHorizSubsampling;
1058 
1059         if (!(uHorizSubsampling == 2 && vHorizSubsampling == 2)) {
1060             return nullptr;
1061         }
1062 
1063         if (image->mBitDepthAllocated == 8) {
1064 
1065             return [uColInc, vColInc, uHorizSubsampling, vHorizSubsampling]
1066                     (void *src_y, void *src_u, void *src_v, size_t x,
1067                     signed *y1, signed *y2, signed *u, signed *v) {
1068                 *y1 = ((uint8_t *)src_y)[x];
1069                 *y2 = ((uint8_t *)src_y)[x + 1];
1070                 *u  = ((uint8_t *)src_u)[(x / uHorizSubsampling) * uColInc] - 128;
1071                 *v  = ((uint8_t *)src_v)[(x / vHorizSubsampling) * vColInc] - 128;
1072             };
1073         }
1074     }
1075     if (srcFormat == OMX_COLOR_FormatYUV420Planar16) {
1076         // OMX_COLOR_FormatYUV420Planar16
1077         return [](void *src_y, void *src_u, void *src_v, size_t x,
1078                 signed *y1, signed *y2, signed *u, signed *v) {
1079             *y1 = (uint8_t)(((uint16_t*)src_y)[x] >> 2);
1080             *y2 = (uint8_t)(((uint16_t*)src_y)[x + 1] >> 2);
1081             *u = (uint8_t)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
1082             *v = (uint8_t)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
1083         };
1084     }
1085     return nullptr;
1086 }
1087 
1088 std::function<void (void *, void *, void *, size_t,
1089         signed *, signed *, signed *)>
getReadFromImage(std::optional<MediaImage2> image,OMX_COLOR_FORMATTYPE & srcFormat)1090 getReadFromImage(std::optional<MediaImage2> image, OMX_COLOR_FORMATTYPE &srcFormat) {
1091     (void)srcFormat;
1092     if (image) {
1093         uint32_t uColInc =
1094                 image->mPlane[MediaImage2::PlaneIndex::U].mColInc;
1095         uint32_t vColInc =
1096                 image->mPlane[MediaImage2::PlaneIndex::V].mColInc;
1097         uint32_t uHorizSubsampling =
1098                 image->mPlane[MediaImage2::PlaneIndex::U].mHorizSubsampling;
1099          uint32_t vHorizSubsampling =
1100                 image->mPlane[MediaImage2::PlaneIndex::V].mHorizSubsampling;
1101 
1102         if (image->mBitDepthAllocated == 8) {
1103 
1104             return [uColInc, vColInc, uHorizSubsampling, vHorizSubsampling]
1105                     (void *src_y, void *src_u, void *src_v, size_t x,
1106                     signed *y1, signed *u, signed *v) {
1107                 *y1 = ((uint8_t *)src_y)[x];
1108                 *u  = ((uint8_t *)src_u)[(x / uHorizSubsampling) * uColInc] - 128;
1109                 *v  = ((uint8_t *)src_v)[(x / vHorizSubsampling) * vColInc] - 128;
1110             };
1111         }
1112     }
1113     return nullptr;
1114 }
1115 
1116 // TRICKY: this method only supports RGBA_1010102 output for 10-bit sources, and all other outputs
1117 // for 8-bit sources as the type of kAdjustedClip is hardcoded based on output, not input.
1118 std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat,void * kAdjustedClip)1119 getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, void *kAdjustedClip) {
1120     switch ((int)dstFormat) {
1121     case OMX_COLOR_Format16bitRGB565:
1122     {
1123         return [kAdjustedClip](void *dst_ptr, bool uncropped,
1124                                signed r1, signed g1, signed b1,
1125                                signed r2, signed g2, signed b2) {
1126             uint32_t rgb1 =
1127                 ((((uint8_t *)kAdjustedClip)[r1] >> 3) << 11)
1128                 | ((((uint8_t *)kAdjustedClip)[g1] >> 2) << 5)
1129                 | (((uint8_t *)kAdjustedClip)[b1] >> 3);
1130 
1131             if (uncropped) {
1132                 uint32_t rgb2 =
1133                     ((((uint8_t *)kAdjustedClip)[r2] >> 3) << 11)
1134                     | ((((uint8_t *)kAdjustedClip)[g2] >> 2) << 5)
1135                     | (((uint8_t *)kAdjustedClip)[b2] >> 3);
1136 
1137                 *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
1138             } else {
1139                 *(uint16_t *)dst_ptr = rgb1;
1140             }
1141         };
1142     }
1143     case OMX_COLOR_Format32BitRGBA8888:
1144     {
1145         return [kAdjustedClip](void *dst_ptr, bool uncropped,
1146                                signed r1, signed g1, signed b1,
1147                                signed r2, signed g2, signed b2) {
1148             ((uint32_t *)dst_ptr)[0] =
1149                     (((uint8_t *)kAdjustedClip)[r1])
1150                     | (((uint8_t *)kAdjustedClip)[g1] << 8)
1151                     | (((uint8_t *)kAdjustedClip)[b1] << 16)
1152                     | (0xFF << 24);
1153 
1154             if (uncropped) {
1155                 ((uint32_t *)dst_ptr)[1] =
1156                         (((uint8_t *)kAdjustedClip)[r2])
1157                         | (((uint8_t *)kAdjustedClip)[g2] << 8)
1158                         | (((uint8_t *)kAdjustedClip)[b2] << 16)
1159                         | (0xFF << 24);
1160             }
1161         };
1162     }
1163     case OMX_COLOR_Format32bitBGRA8888:
1164     {
1165         return [kAdjustedClip](void *dst_ptr, bool uncropped,
1166                                signed r1, signed g1, signed b1,
1167                                signed r2, signed g2, signed b2) {
1168             ((uint32_t *)dst_ptr)[0] =
1169                     (((uint8_t *)kAdjustedClip)[b1])
1170                     | (((uint8_t *)kAdjustedClip)[g1] << 8)
1171                     | (((uint8_t *)kAdjustedClip)[r1] << 16)
1172                     | (0xFF << 24);
1173 
1174             if (uncropped) {
1175                 ((uint32_t *)dst_ptr)[1] =
1176                         (((uint8_t *)kAdjustedClip)[b2])
1177                         | (((uint8_t *)kAdjustedClip)[g2] << 8)
1178                         | (((uint8_t *)kAdjustedClip)[r2] << 16)
1179                         | (0xFF << 24);
1180             }
1181         };
1182     }
1183     case COLOR_Format32bitABGR2101010:
1184     {
1185         return [kAdjustedClip](void *dst_ptr, bool uncropped,
1186                                signed r1, signed g1, signed b1,
1187                                signed r2, signed g2, signed b2) {
1188             ((uint32_t *)dst_ptr)[0] =
1189                     (((uint16_t *)kAdjustedClip)[r1])
1190                     | (((uint16_t *)kAdjustedClip)[g1] << 10)
1191                     | (((uint16_t *)kAdjustedClip)[b1] << 20)
1192                     | (3 << 30);
1193 
1194             if (uncropped) {
1195                 ((uint32_t *)dst_ptr)[1] =
1196                         (((uint16_t *)kAdjustedClip)[r2])
1197                         | (((uint16_t *)kAdjustedClip)[g2] << 10)
1198                         | (((uint16_t *)kAdjustedClip)[b2] << 20)
1199                         | (3 << 30);
1200             }
1201         };
1202     }
1203 
1204     default:
1205         TRESPASS();
1206     }
1207     return nullptr;
1208 }
1209 
convertYUVMediaImage(const BitmapParams & src,const BitmapParams & dst)1210 status_t ColorConverter::convertYUVMediaImage(
1211         const BitmapParams &src, const BitmapParams &dst) {
1212     // first see if we can do this as a 420Planar or 420SemiPlanar 8b
1213 
1214     if(!mSrcImage ||
1215             mSrcImage->getMediaImage2().mType != MediaImage2::MEDIA_IMAGE_TYPE_YUV
1216             || mSrcImage->getMediaImage2().mNumPlanes != 3) {
1217         ALOGE("Cannot convert without MediaImage2 or MediaImage is not Valid YUV");
1218         return ERROR_UNSUPPORTED;
1219     }
1220     if (mSrcImage->getBitDepth() == ImageBitDepth8
1221             && mSrcImage->getSampling() == ImageSamplingYUV420) {
1222         Layout_t layout = mSrcImage->getLayout();
1223         switch (layout) {
1224             case Layout_t::ImageLayout420Planar:
1225             {
1226                 return convertYUV420PlanarUseLibYUV(src, dst);
1227                 break;
1228             }
1229 
1230             case Layout_t::ImageLayout420SemiPlanar:
1231             {
1232                 // Note: libyuv doesn't support NV21 -> RGB565
1233                 if (!(mSrcImage->isNV21() && mDstFormat == OMX_COLOR_Format16bitRGB565)) {
1234                     status_t ret = convertYUV420SemiPlanarUseLibYUV(src, dst);
1235                     // This function may fail if some specific conditions are not
1236                     // met for semiPlanar formats like strideU != strideV.
1237                     // if failed, this will fail before attempting conversion, so
1238                     // no additional memcpy will be involved here.
1239                     // Upon failure, this will fall into pixel based processing below.
1240                     if (ret == OK) {
1241                         return ret;
1242                     }
1243                 }
1244                 break;
1245             }
1246             default:
1247                 // we will handle this case below.
1248                 break;
1249         }
1250     }
1251     const struct Coeffs *matrix = getMatrix();
1252     if (!matrix) {
1253         return ERROR_UNSUPPORTED;
1254     }
1255 
1256     signed _b_u = matrix->_b_u;
1257     signed _neg_g_u = -matrix->_g_u;
1258     signed _neg_g_v = -matrix->_g_v;
1259     signed _r_v = matrix->_r_v;
1260     signed _y = matrix->_y;
1261     signed _c16 = matrix->_c16;
1262 
1263     uint8_t *dst_ptr = (uint8_t *)dst.mBits
1264             + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
1265 
1266 
1267     uint32_t y_offset = 0, u_offset = 0, v_offset = 0;
1268     size_t src_stride_y =0, src_stride_u = 0, src_stride_v = 0;
1269     if (getSrcYUVPlaneOffsetAndStride(src, &y_offset, &u_offset, &v_offset,
1270             &src_stride_y, &src_stride_u, &src_stride_v) != OK) {
1271         return ERROR_UNSUPPORTED;
1272     }
1273     uint32_t uVertSubsampling =
1274             mSrcImage->getMediaImage2().mPlane[MediaImage2::PlaneIndex::U].mVertSubsampling;
1275     uint32_t vVertSubsampling =
1276             mSrcImage->getMediaImage2().mPlane[MediaImage2::PlaneIndex::V].mVertSubsampling;
1277 
1278     //TODO: optimize for chroma sampling, reading and writing multiple pixels
1279     //      within the same loop
1280 
1281     void *kAdjustedClip = nullptr;
1282     if (mSrcImage->getBitDepth() != ImageBitDepth8) {
1283         ALOGE("BitDepth != 8 for MediaImage2");
1284         return ERROR_UNSUPPORTED;
1285     }
1286     kAdjustedClip = initClip();
1287 
1288     auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip);
1289     uint8_t *src_y = (uint8_t *)src.mBits + y_offset;
1290     uint8_t *src_u = (uint8_t *)src.mBits + u_offset;
1291     uint8_t *src_v = (uint8_t *)src.mBits + v_offset;
1292 
1293     switch (mSrcImage->getSampling()) {
1294 
1295         case ImageSamplingYUV420:
1296         {
1297             // get read function that can read
1298             // chroma sampling 2 with image
1299             auto readFromSrcImage = getReadFromChromaHorizSubsampled2Image8b(
1300                     mSrcImage->getMediaImage2(), mSrcFormat);
1301             if (readFromSrcImage == nullptr) {
1302                 ALOGE("Cannot get a read function for this MediaImage2");
1303                 return ERROR_UNSUPPORTED;
1304             }
1305             for (size_t y = 0; y < src.cropHeight(); ++y) {
1306                 for (size_t x = 0; x < src.cropWidth(); x += 2) {
1307                     signed y1, y2, u, v;
1308                     readFromSrcImage(src_y, src_u, src_v, x, &y1, &y2, &u, &v);
1309 
1310                     signed u_b = u * _b_u;
1311                     signed u_g = u * _neg_g_u;
1312                     signed v_g = v * _neg_g_v;
1313                     signed v_r = v * _r_v;
1314 
1315                     y1 = y1 - _c16;
1316                     signed tmp1 = y1 * _y + 128;
1317                     signed b1 = (tmp1 + u_b) / 256;
1318                     signed g1 = (tmp1 + v_g + u_g) / 256;
1319                     signed r1 = (tmp1 + v_r) / 256;
1320 
1321                     y2 = y2 - _c16;
1322                     signed tmp2 = y2 * _y + 128;
1323                     signed b2 = (tmp2 + u_b) / 256;
1324                     signed g2 = (tmp2 + v_g + u_g) / 256;
1325                     signed r2 = (tmp2 + v_r) / 256;
1326 
1327                     bool uncropped = x + 1 < src.cropWidth();
1328                     writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
1329                 }
1330                 src_y += src_stride_y;
1331                 src_u += (((y + 1) % uVertSubsampling) == 0) ? src_stride_u : 0;
1332                 src_v += (((y + 1) % vVertSubsampling) == 0) ? src_stride_v : 0;
1333 
1334                 dst_ptr += dst.mStride;
1335             }
1336             break;
1337         }
1338 
1339         default:
1340         {
1341             // Interleaved or any other formats.
1342             auto readFromSrcImage = getReadFromImage(mSrcImage->getMediaImage2(), mSrcFormat);
1343             if (readFromSrcImage == nullptr) {
1344                 ALOGE("Cannot get a read function for this MediaImage2");
1345                 return ERROR_UNSUPPORTED;
1346             }
1347             for (size_t y = 0; y < src.cropHeight(); ++y) {
1348                 for (size_t x = 0; x < src.cropWidth(); x += 1) {
1349                     signed y1, y2, u, v;
1350                     readFromSrcImage(src_y, src_u, src_v, x, &y1, &u, &v);
1351 
1352                     signed u_b = u * _b_u;
1353                     signed u_g = u * _neg_g_u;
1354                     signed v_g = v * _neg_g_v;
1355                     signed v_r = v * _r_v;
1356 
1357                     y1 = y1 - _c16;
1358                     signed tmp1 = y1 * _y + 128;
1359                     signed b1 = (tmp1 + u_b) / 256;
1360                     signed g1 = (tmp1 + v_g + u_g) / 256;
1361                     signed r1 = (tmp1 + v_r) / 256;
1362 
1363                     writeToDst(dst_ptr + x * dst.mBpp, false, r1, g1, b1, 0, 0, 0);
1364                 }
1365                 src_y += src_stride_y;
1366                 src_u += (((y + 1) % uVertSubsampling) == 0) ? src_stride_u : 0;
1367                 src_v += (((y + 1) % vVertSubsampling) == 0) ? src_stride_v : 0;
1368 
1369                 dst_ptr += dst.mStride;
1370             }
1371         }
1372     }
1373     return OK;
1374 }
1375 
convertYUV420Planar16(const BitmapParams & src,const BitmapParams & dst)1376 status_t ColorConverter::convertYUV420Planar16(
1377         const BitmapParams &src, const BitmapParams &dst) {
1378     if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
1379         return convertYUV420Planar16ToY410(src, dst);
1380     }
1381 
1382     const struct Coeffs *matrix = getMatrix();
1383     if (!matrix) {
1384         return ERROR_UNSUPPORTED;
1385     }
1386 
1387     signed _b_u = matrix->_b_u;
1388     signed _neg_g_u = -matrix->_g_u;
1389     signed _neg_g_v = -matrix->_g_v;
1390     signed _r_v = matrix->_r_v;
1391     signed _y = matrix->_y;
1392     signed _c16 = matrix->_c16;
1393 
1394     uint8_t *kAdjustedClip = initClip();
1395 
1396     auto readFromSrc = getReadFromChromaHorizSubsampled2Image8b(std::nullopt, mSrcFormat);
1397     auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip);
1398 
1399     uint8_t *dst_ptr = (uint8_t *)dst.mBits
1400             + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
1401 
1402     uint8_t *src_y = (uint8_t *)src.mBits
1403             + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
1404 
1405     uint8_t *src_u = (uint8_t *)src.mBits + src.mStride * src.mHeight
1406             + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2 * src.mBpp;
1407 
1408     uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
1409 
1410     for (size_t y = 0; y < src.cropHeight(); ++y) {
1411         for (size_t x = 0; x < src.cropWidth(); x += 2) {
1412             signed y1, y2, u, v;
1413             readFromSrc(src_y, src_u, src_v, x, &y1, &y2, &u, &v);
1414 
1415             signed u_b = u * _b_u;
1416             signed u_g = u * _neg_g_u;
1417             signed v_g = v * _neg_g_v;
1418             signed v_r = v * _r_v;
1419 
1420             signed tmp1 = (y1 - _c16) * _y + 128;
1421             signed b1 = (tmp1 + u_b) / 256;
1422             signed g1 = (tmp1 + v_g + u_g) / 256;
1423             signed r1 = (tmp1 + v_r) / 256;
1424 
1425             signed tmp2 = (y2 - _c16) * _y + 128;
1426             signed b2 = (tmp2 + u_b) / 256;
1427             signed g2 = (tmp2 + v_g + u_g) / 256;
1428             signed r2 = (tmp2 + v_r) / 256;
1429 
1430             bool uncropped = x + 1 < src.cropWidth();
1431             writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
1432         }
1433 
1434         src_y += src.mStride;
1435 
1436         if (y & 1) {
1437             src_u += src.mStride / 2;
1438             src_v += src.mStride / 2;
1439         }
1440 
1441         dst_ptr += dst.mStride;
1442     }
1443     return OK;
1444 }
1445 
convertYUVP010(const BitmapParams & src,const BitmapParams & dst)1446 status_t ColorConverter::convertYUVP010(
1447         const BitmapParams &src, const BitmapParams &dst) {
1448     if (mDstFormat == COLOR_Format32bitABGR2101010) {
1449         return convertYUVP010ToRGBA1010102(src, dst);
1450     }
1451 
1452     return ERROR_UNSUPPORTED;
1453 }
1454 
convertYUVP010ToRGBA1010102(const BitmapParams & src,const BitmapParams & dst)1455 status_t ColorConverter::convertYUVP010ToRGBA1010102(
1456         const BitmapParams &src, const BitmapParams &dst) {
1457     const struct Coeffs *matrix = getMatrix();
1458     if (!matrix) {
1459         return ERROR_UNSUPPORTED;
1460     }
1461 
1462     signed _b_u = matrix->_b_u;
1463     signed _neg_g_u = -matrix->_g_u;
1464     signed _neg_g_v = -matrix->_g_v;
1465     signed _r_v = matrix->_r_v;
1466     signed _y = matrix->_y;
1467     signed _c64 = matrix->_c16 * 4;
1468 
1469     uint16_t *kAdjustedClip10bit = initClip10Bit();
1470 
1471 //    auto readFromSrc = getReadFromSrc(mSrcFormat);
1472     auto writeToDst = getWriteToDst(mDstFormat, (void *)kAdjustedClip10bit);
1473 
1474     uint8_t *dst_ptr = (uint8_t *)dst.mBits
1475             + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
1476 
1477     uint16_t *src_y = (uint16_t *)((uint8_t *)src.mBits
1478             + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp);
1479 
1480     uint16_t *src_uv = (uint16_t *)((uint8_t *)src.mBits
1481             + src.mStride * src.mHeight
1482             + (src.mCropTop / 2) * src.mStride + src.mCropLeft * src.mBpp);
1483 
1484     for (size_t y = 0; y < src.cropHeight(); ++y) {
1485         for (size_t x = 0; x < src.cropWidth(); x += 2) {
1486             signed y1, y2, u, v;
1487             y1 = (src_y[x] >> 6) - _c64;
1488             y2 = (src_y[x + 1] >> 6) - _c64;
1489             u = int(src_uv[x] >> 6) - 512;
1490             v = int(src_uv[x + 1] >> 6) - 512;
1491 
1492             signed u_b = u * _b_u;
1493             signed u_g = u * _neg_g_u;
1494             signed v_g = v * _neg_g_v;
1495             signed v_r = v * _r_v;
1496 
1497             signed tmp1 = y1 * _y + 128;
1498             signed b1 = (tmp1 + u_b) / 256;
1499             signed g1 = (tmp1 + v_g + u_g) / 256;
1500             signed r1 = (tmp1 + v_r) / 256;
1501 
1502             signed tmp2 = y2 * _y + 128;
1503             signed b2 = (tmp2 + u_b) / 256;
1504             signed g2 = (tmp2 + v_g + u_g) / 256;
1505             signed r2 = (tmp2 + v_r) / 256;
1506 
1507             bool uncropped = x + 1 < src.cropWidth();
1508 
1509             writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
1510         }
1511 
1512         src_y += src.mStride / 2;
1513 
1514         if (y & 1) {
1515             src_uv += src.mStride / 2;
1516         }
1517 
1518         dst_ptr += dst.mStride;
1519     }
1520 
1521     return OK;
1522 }
1523 
1524 
1525 #if !USE_NEON_Y410
1526 
convertYUV420Planar16ToY410(const BitmapParams & src,const BitmapParams & dst)1527 status_t ColorConverter::convertYUV420Planar16ToY410(
1528         const BitmapParams &src, const BitmapParams &dst) {
1529     uint8_t *dst_ptr = (uint8_t *)dst.mBits
1530         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
1531 
1532     const uint8_t *src_y =
1533         (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
1534 
1535     const uint8_t *src_u =
1536         (const uint8_t *)src.mBits + src.mStride * src.mHeight
1537         + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
1538 
1539     const uint8_t *src_v =
1540         src_u + (src.mStride / 2) * (src.mHeight / 2);
1541 
1542     // Converting two lines at a time, slightly faster
1543     for (size_t y = 0; y < src.cropHeight(); y += 2) {
1544         uint32_t *dst_top = (uint32_t *) dst_ptr;
1545         uint32_t *dst_bot = (uint32_t *) (dst_ptr + dst.mStride);
1546         uint16_t *ptr_ytop = (uint16_t*) src_y;
1547         uint16_t *ptr_ybot = (uint16_t*) (src_y + src.mStride);
1548         uint16_t *ptr_u = (uint16_t*) src_u;
1549         uint16_t *ptr_v = (uint16_t*) src_v;
1550 
1551         uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
1552         size_t x = 0;
1553         // x % 4 is always 0 so x + 3 will never overflow.
1554         for (; x + 3 < src.cropWidth(); x += 4) {
1555             u01 = *((uint32_t*)ptr_u); ptr_u += 2;
1556             v01 = *((uint32_t*)ptr_v); ptr_v += 2;
1557 
1558             y01 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
1559             y23 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
1560             y45 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
1561             y67 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
1562 
1563             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
1564             uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
1565 
1566             *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
1567             *dst_top++ = ((y01 >> 16) << 10) | uv0;
1568             *dst_top++ = ((y23 & 0x3FF) << 10) | uv1;
1569             *dst_top++ = ((y23 >> 16) << 10) | uv1;
1570 
1571             *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
1572             *dst_bot++ = ((y45 >> 16) << 10) | uv0;
1573             *dst_bot++ = ((y67 & 0x3FF) << 10) | uv1;
1574             *dst_bot++ = ((y67 >> 16) << 10) | uv1;
1575         }
1576 
1577         // There should be at most 2 more pixels to process. Note that we don't
1578         // need to consider odd case as the buffer is always aligned to even.
1579         if (x < src.cropWidth()) {
1580             u01 = *ptr_u;
1581             v01 = *ptr_v;
1582             y01 = *((uint32_t*)ptr_ytop);
1583             y45 = *((uint32_t*)ptr_ybot);
1584             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
1585             *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
1586             *dst_top++ = ((y01 >> 16) << 10) | uv0;
1587             *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
1588             *dst_bot++ = ((y45 >> 16) << 10) | uv0;
1589         }
1590 
1591         src_y += src.mStride * 2;
1592         src_u += src.mStride / 2;
1593         src_v += src.mStride / 2;
1594         dst_ptr += dst.mStride * 2;
1595     }
1596 
1597     return OK;
1598 }
1599 
1600 #else
1601 
convertYUV420Planar16ToY410(const BitmapParams & src,const BitmapParams & dst)1602 status_t ColorConverter::convertYUV420Planar16ToY410(
1603         const BitmapParams &src, const BitmapParams &dst) {
1604     uint8_t *out = (uint8_t *)dst.mBits
1605         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
1606 
1607     const uint8_t *src_y =
1608         (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
1609 
1610     const uint8_t *src_u =
1611         (const uint8_t *)src.mBits + src.mStride * src.mHeight
1612         + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
1613 
1614     const uint8_t *src_v =
1615         src_u + (src.mStride / 2) * (src.mHeight / 2);
1616 
1617     for (size_t y = 0; y < src.cropHeight(); y++) {
1618         uint16_t *ptr_y = (uint16_t*) src_y;
1619         uint16_t *ptr_u = (uint16_t*) src_u;
1620         uint16_t *ptr_v = (uint16_t*) src_v;
1621         uint32_t *ptr_out = (uint32_t *) out;
1622 
1623         // Process 16-pixel at a time.
1624         uint32_t *ptr_limit = ptr_out + (src.cropWidth() & ~15);
1625         while (ptr_out < ptr_limit) {
1626             uint16x4_t u0123 = vld1_u16(ptr_u); ptr_u += 4;
1627             uint16x4_t u4567 = vld1_u16(ptr_u); ptr_u += 4;
1628             uint16x4_t v0123 = vld1_u16(ptr_v); ptr_v += 4;
1629             uint16x4_t v4567 = vld1_u16(ptr_v); ptr_v += 4;
1630             uint16x4_t y0123 = vld1_u16(ptr_y); ptr_y += 4;
1631             uint16x4_t y4567 = vld1_u16(ptr_y); ptr_y += 4;
1632             uint16x4_t y89ab = vld1_u16(ptr_y); ptr_y += 4;
1633             uint16x4_t ycdef = vld1_u16(ptr_y); ptr_y += 4;
1634 
1635             uint32x2_t uvtempl;
1636             uint32x4_t uvtempq;
1637 
1638             uvtempq = vaddw_u16(vshll_n_u16(v0123, 20), u0123);
1639 
1640             uvtempl = vget_low_u32(uvtempq);
1641             uint32x4_t uv0011 = vreinterpretq_u32_u64(
1642                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
1643 
1644             uvtempl = vget_high_u32(uvtempq);
1645             uint32x4_t uv2233 = vreinterpretq_u32_u64(
1646                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
1647 
1648             uvtempq = vaddw_u16(vshll_n_u16(v4567, 20), u4567);
1649 
1650             uvtempl = vget_low_u32(uvtempq);
1651             uint32x4_t uv4455 = vreinterpretq_u32_u64(
1652                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
1653 
1654             uvtempl = vget_high_u32(uvtempq);
1655             uint32x4_t uv6677 = vreinterpretq_u32_u64(
1656                     vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
1657 
1658             uint32x4_t dsttemp;
1659 
1660             dsttemp = vorrq_u32(uv0011, vshll_n_u16(y0123, 10));
1661             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
1662 
1663             dsttemp = vorrq_u32(uv2233, vshll_n_u16(y4567, 10));
1664             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
1665 
1666             dsttemp = vorrq_u32(uv4455, vshll_n_u16(y89ab, 10));
1667             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
1668 
1669             dsttemp = vorrq_u32(uv6677, vshll_n_u16(ycdef, 10));
1670             vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
1671         }
1672 
1673         src_y += src.mStride;
1674         if (y & 1) {
1675             src_u += src.mStride / 2;
1676             src_v += src.mStride / 2;
1677         }
1678         out += dst.mStride;
1679     }
1680 
1681     // Process the left-overs out-of-loop, 2-pixel at a time. Note that we don't
1682     // need to consider odd case as the buffer is always aligned to even.
1683     if (src.cropWidth() & 15) {
1684         size_t xstart = (src.cropWidth() & ~15);
1685 
1686         uint8_t *out = (uint8_t *)dst.mBits + dst.mCropTop * dst.mStride
1687                 + (dst.mCropLeft + xstart) * dst.mBpp;
1688 
1689         const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mStride
1690                 + (src.mCropLeft + xstart) * src.mBpp;
1691 
1692         const uint8_t *src_u = (const uint8_t *)src.mBits + src.mStride * src.mHeight
1693             + (src.mCropTop / 2) * (src.mStride / 2)
1694             + ((src.mCropLeft + xstart) / 2) * src.mBpp;
1695 
1696         const uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
1697 
1698         for (size_t y = 0; y < src.cropHeight(); y++) {
1699             uint16_t *ptr_y = (uint16_t*) src_y;
1700             uint16_t *ptr_u = (uint16_t*) src_u;
1701             uint16_t *ptr_v = (uint16_t*) src_v;
1702             uint32_t *ptr_out = (uint32_t *) out;
1703             for (size_t x = xstart; x < src.cropWidth(); x += 2) {
1704                 uint16_t u = *ptr_u++;
1705                 uint16_t v = *ptr_v++;
1706                 uint32_t y01 = *((uint32_t*)ptr_y); ptr_y += 2;
1707                 uint32_t uv = u | (((uint32_t)v) << 20);
1708                 *ptr_out++ = ((y01 & 0x3FF) << 10) | uv;
1709                 *ptr_out++ = ((y01 >> 16) << 10) | uv;
1710             }
1711             src_y += src.mStride;
1712             if (y & 1) {
1713                 src_u += src.mStride / 2;
1714                 src_v += src.mStride / 2;
1715             }
1716             out += dst.mStride;
1717         }
1718     }
1719 
1720     return OK;
1721 }
1722 
1723 #endif // USE_NEON_Y410
1724 
initClip()1725 uint8_t *ColorConverter::initClip() {
1726     if (mClip == NULL) {
1727         mClip = new uint8_t[CLIP_RANGE_MAX_8BIT - CLIP_RANGE_MIN_8BIT + 1];
1728 
1729         for (signed i = CLIP_RANGE_MIN_8BIT; i <= CLIP_RANGE_MAX_8BIT; ++i) {
1730             mClip[i - CLIP_RANGE_MIN_8BIT] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
1731         }
1732     }
1733 
1734     return &mClip[-CLIP_RANGE_MIN_8BIT];
1735 }
1736 
initClip10Bit()1737 uint16_t *ColorConverter::initClip10Bit() {
1738     if (mClip10Bit == NULL) {
1739         mClip10Bit = new uint16_t[CLIP_RANGE_MAX_10BIT - CLIP_RANGE_MIN_10BIT + 1];
1740 
1741         for (signed i = CLIP_RANGE_MIN_10BIT; i <= CLIP_RANGE_MAX_10BIT; ++i) {
1742             mClip10Bit[i - CLIP_RANGE_MIN_10BIT] = (i < 0) ? 0 : (i > 1023) ? 1023 : (uint16_t)i;
1743         }
1744     }
1745 
1746     return &mClip10Bit[-CLIP_RANGE_MIN_10BIT];
1747 }
1748 
1749 }  // namespace android
1750