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