blob: 55a1164d5df992026d9b9c945c3694352c3912ef [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2017 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 "SimpleC2Component"
19#include <log/log.h>
20
Harish Mahendrakarf5dec502022-04-13 15:53:55 -070021#include <android/hardware_buffer.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080022#include <cutils/properties.h>
23#include <media/stagefright/foundation/AMessage.h>
24
25#include <inttypes.h>
26
27#include <C2Config.h>
28#include <C2Debug.h>
29#include <C2PlatformSupport.h>
Harish Mahendrakarf5dec502022-04-13 15:53:55 -070030#include <Codec2BufferUtils.h>
31#include <Codec2CommonUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080032#include <SimpleC2Component.h>
33
34namespace android {
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080035constexpr uint8_t kNeutralUVBitDepth8 = 128;
36constexpr uint16_t kNeutralUVBitDepth10 = 512;
Pawin Vongmasa36653902018-11-15 00:10:25 -080037
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080038void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
39 const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
40 size_t srcUStride, size_t srcVStride, size_t dstYStride,
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000041 size_t dstUStride, size_t dstVStride, uint32_t width,
42 uint32_t height, bool isMonochrome) {
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080043 for (size_t i = 0; i < height; ++i) {
44 memcpy(dstY, srcY, width);
45 srcY += srcYStride;
46 dstY += dstYStride;
47 }
48
49 if (isMonochrome) {
50 // Fill with neutral U/V values.
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080051 for (size_t i = 0; i < (height + 1) / 2; ++i) {
52 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
53 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000054 dstV += dstVStride;
55 dstU += dstUStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080056 }
57 return;
58 }
59
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080060 for (size_t i = 0; i < (height + 1) / 2; ++i) {
61 memcpy(dstV, srcV, (width + 1) / 2);
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080062 srcV += srcVStride;
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000063 dstV += dstVStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080064 }
65
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080066 for (size_t i = 0; i < (height + 1) / 2; ++i) {
67 memcpy(dstU, srcU, (width + 1) / 2);
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080068 srcU += srcUStride;
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000069 dstU += dstUStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080070 }
71}
72
73void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
74 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
75 size_t srcVStride, size_t dstStride, size_t width, size_t height) {
76 // Converting two lines at a time, slightly faster
77 for (size_t y = 0; y < height; y += 2) {
78 uint32_t *dstTop = (uint32_t *)dst;
79 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
80 uint16_t *ySrcTop = (uint16_t *)srcY;
81 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
82 uint16_t *uSrc = (uint16_t *)srcU;
83 uint16_t *vSrc = (uint16_t *)srcV;
84
85 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
86 size_t x = 0;
87 for (; x < width - 3; x += 4) {
88 u01 = *((uint32_t *)uSrc);
89 uSrc += 2;
90 v01 = *((uint32_t *)vSrc);
91 vSrc += 2;
92
93 y01 = *((uint32_t *)ySrcTop);
94 ySrcTop += 2;
95 y23 = *((uint32_t *)ySrcTop);
96 ySrcTop += 2;
97 y45 = *((uint32_t *)ySrcBot);
98 ySrcBot += 2;
99 y67 = *((uint32_t *)ySrcBot);
100 ySrcBot += 2;
101
102 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
103 uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
104
105 *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
106 *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
107 *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
108 *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
109
110 *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
111 *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
112 *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
113 *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
114 }
115
116 // There should be at most 2 more pixels to process. Note that we don't
117 // need to consider odd case as the buffer is always aligned to even.
118 if (x < width) {
119 u01 = *uSrc;
120 v01 = *vSrc;
121 y01 = *((uint32_t *)ySrcTop);
122 y45 = *((uint32_t *)ySrcBot);
123 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
124 *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
125 *dstTop++ = ((y01 >> 16) << 10) | uv0;
126 *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
127 *dstBot++ = ((y45 >> 16) << 10) | uv0;
128 }
129
130 srcY += srcYStride * 2;
131 srcU += srcUStride;
132 srcV += srcVStride;
133 dst += dstStride * 2;
134 }
135}
Lajos Molnarc971e962022-06-01 20:24:38 -0700136
137namespace {
138
139static C2ColorAspectsStruct FillMissingColorAspects(
140 std::shared_ptr<const C2ColorAspectsStruct> aspects,
141 int32_t width, int32_t height) {
142 C2ColorAspectsStruct _aspects;
143 if (aspects) {
144 _aspects = *aspects;
145 }
146
147 // use matrix for conversion
148 if (_aspects.matrix == C2Color::MATRIX_UNSPECIFIED) {
149 // if not specified, deduce matrix from primaries
150 if (_aspects.primaries == C2Color::PRIMARIES_UNSPECIFIED) {
151 // if those are also not specified, deduce primaries first from transfer, then from
152 // width and height
153 if (_aspects.transfer == C2Color::TRANSFER_ST2084
154 || _aspects.transfer == C2Color::TRANSFER_HLG) {
155 _aspects.primaries = C2Color::PRIMARIES_BT2020;
156 } else if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
157 // TODO: stagefright defaults to BT.2020 for UHD, but perhaps we should default to
158 // BT.709 for non-HDR 10-bit UHD content
159 // (see media/libstagefright/foundation/ColorUtils.cpp)
160 _aspects.primaries = C2Color::PRIMARIES_BT2020;
161 } else if ((width <= 720 && height <= 576)
162 || (height <= 720 && width <= 576)) {
163 // note: it does not actually matter whether to use 525 or 625 here as the
164 // conversion is the same
165 _aspects.primaries = C2Color::PRIMARIES_BT601_625;
166 } else {
167 _aspects.primaries = C2Color::PRIMARIES_BT709;
168 }
169 }
170
171 switch (_aspects.primaries) {
172 case C2Color::PRIMARIES_BT601_525:
173 case C2Color::PRIMARIES_BT601_625:
174 _aspects.matrix = C2Color::MATRIX_BT601;
175 break;
176
177 case C2Color::PRIMARIES_BT709:
178 _aspects.matrix = C2Color::MATRIX_BT709;
179 break;
180
181 case C2Color::PRIMARIES_BT2020:
182 default:
183 _aspects.matrix = C2Color::MATRIX_BT2020;
184 }
185 }
186
187 return _aspects;
188}
189
190// matrix conversion coefficients
191// (see media/libstagefright/colorconverter/ColorConverter.cpp for more details)
192struct Coeffs {
Harish Mahendrakar36bd7942022-07-07 20:14:14 -0700193 int32_t _y, _r_v, _g_u, _g_v, _b_u, _c16;
Lajos Molnarc971e962022-06-01 20:24:38 -0700194};
195
196static const struct Coeffs GetCoeffsForAspects(const C2ColorAspectsStruct &aspects) {
197 bool isFullRange = aspects.range == C2Color::RANGE_FULL;
198
199 switch (aspects.matrix) {
200 case C2Color::MATRIX_BT601:
201 /**
202 * BT.601: K_R = 0.299; K_B = 0.114
203 */
204 if (isFullRange) {
205 return Coeffs { 1024, 1436, 352, 731, 1815, 0 };
206 } else {
207 return Coeffs { 1196, 1639, 402, 835, 2072, 64 };
208 }
209 break;
210
211 case C2Color::MATRIX_BT709:
212 /**
213 * BT.709: K_R = 0.2126; K_B = 0.0722
214 */
215 if (isFullRange) {
216 return Coeffs { 1024, 1613, 192, 479, 1900, 0 };
217 } else {
218 return Coeffs { 1196, 1841, 219, 547, 2169, 64 };
219 }
220 break;
221
222 case C2Color::MATRIX_BT2020:
223 default:
224 /**
225 * BT.2020: K_R = 0.2627; K_B = 0.0593
226 */
227 if (isFullRange) {
228 return Coeffs { 1024, 1510, 169, 585, 1927, 0 };
229 } else {
230 return Coeffs { 1196, 1724, 192, 668, 2200, 64 };
231 }
232 }
233}
234
235}
236
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700237#define CLIP3(min, v, max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
Lajos Molnarc971e962022-06-01 20:24:38 -0700238void convertYUV420Planar16ToRGBA1010102(
239 uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
240 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
241 size_t srcVStride, size_t dstStride, size_t width,
242 size_t height,
243 std::shared_ptr<const C2ColorAspectsStruct> aspects) {
244
245 C2ColorAspectsStruct _aspects = FillMissingColorAspects(aspects, width, height);
246
247 struct Coeffs coeffs = GetCoeffsForAspects(_aspects);
248
249 int32_t _y = coeffs._y;
250 int32_t _b_u = coeffs._b_u;
251 int32_t _neg_g_u = -coeffs._g_u;
252 int32_t _neg_g_v = -coeffs._g_v;
253 int32_t _r_v = coeffs._r_v;
254 int32_t _c16 = coeffs._c16;
255
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700256 // Converting two lines at a time, slightly faster
257 for (size_t y = 0; y < height; y += 2) {
258 uint32_t *dstTop = (uint32_t *)dst;
259 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
260 uint16_t *ySrcTop = (uint16_t *)srcY;
261 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
262 uint16_t *uSrc = (uint16_t *)srcU;
263 uint16_t *vSrc = (uint16_t *)srcV;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800264
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700265 for (size_t x = 0; x < width; x += 2) {
266 int32_t u, v, y00, y01, y10, y11;
267 u = *uSrc - 512;
268 uSrc += 1;
269 v = *vSrc - 512;
270 vSrc += 1;
271
Lajos Molnarc971e962022-06-01 20:24:38 -0700272 y00 = *ySrcTop - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700273 ySrcTop += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700274 y01 = *ySrcTop - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700275 ySrcTop += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700276 y10 = *ySrcBot - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700277 ySrcBot += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700278 y11 = *ySrcBot - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700279 ySrcBot += 1;
280
Lajos Molnarc971e962022-06-01 20:24:38 -0700281 int32_t u_b = u * _b_u;
282 int32_t u_g = u * _neg_g_u;
283 int32_t v_g = v * _neg_g_v;
284 int32_t v_r = v * _r_v;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700285
286 int32_t yMult, b, g, r;
Lajos Molnarc971e962022-06-01 20:24:38 -0700287 yMult = y00 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700288 b = (yMult + u_b) / 1024;
289 g = (yMult + v_g + u_g) / 1024;
290 r = (yMult + v_r) / 1024;
291 b = CLIP3(0, b, 1023);
292 g = CLIP3(0, g, 1023);
293 r = CLIP3(0, r, 1023);
294 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
295
Lajos Molnarc971e962022-06-01 20:24:38 -0700296 yMult = y01 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700297 b = (yMult + u_b) / 1024;
298 g = (yMult + v_g + u_g) / 1024;
299 r = (yMult + v_r) / 1024;
300 b = CLIP3(0, b, 1023);
301 g = CLIP3(0, g, 1023);
302 r = CLIP3(0, r, 1023);
303 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
304
Lajos Molnarc971e962022-06-01 20:24:38 -0700305 yMult = y10 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700306 b = (yMult + u_b) / 1024;
307 g = (yMult + v_g + u_g) / 1024;
308 r = (yMult + v_r) / 1024;
309 b = CLIP3(0, b, 1023);
310 g = CLIP3(0, g, 1023);
311 r = CLIP3(0, r, 1023);
312 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
313
Lajos Molnarc971e962022-06-01 20:24:38 -0700314 yMult = y11 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700315 b = (yMult + u_b) / 1024;
316 g = (yMult + v_g + u_g) / 1024;
317 r = (yMult + v_r) / 1024;
318 b = CLIP3(0, b, 1023);
319 g = CLIP3(0, g, 1023);
320 r = CLIP3(0, r, 1023);
321 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
322 }
323
324 srcY += srcYStride * 2;
325 srcU += srcUStride;
326 srcV += srcVStride;
327 dst += dstStride * 2;
328 }
329}
330
Lajos Molnarc971e962022-06-01 20:24:38 -0700331void convertYUV420Planar16ToY410OrRGBA1010102(
332 uint32_t *dst, const uint16_t *srcY,
333 const uint16_t *srcU, const uint16_t *srcV,
334 size_t srcYStride, size_t srcUStride,
335 size_t srcVStride, size_t dstStride, size_t width, size_t height,
336 std::shared_ptr<const C2ColorAspectsStruct> aspects) {
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700337 if (isAtLeastT()) {
338 convertYUV420Planar16ToRGBA1010102(dst, srcY, srcU, srcV, srcYStride, srcUStride,
Lajos Molnarc971e962022-06-01 20:24:38 -0700339 srcVStride, dstStride, width, height, aspects);
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700340 } else {
341 convertYUV420Planar16ToY410(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
342 dstStride, width, height);
343 }
344}
Lajos Molnarc971e962022-06-01 20:24:38 -0700345
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800346void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
347 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
348 size_t srcUStride, size_t srcVStride, size_t dstYStride,
349 size_t dstUVStride, size_t width, size_t height,
350 bool isMonochrome) {
351 for (size_t y = 0; y < height; ++y) {
352 for (size_t x = 0; x < width; ++x) {
353 dstY[x] = (uint8_t)(srcY[x] >> 2);
354 }
355 srcY += srcYStride;
356 dstY += dstYStride;
357 }
358
359 if (isMonochrome) {
360 // Fill with neutral U/V values.
361 for (size_t y = 0; y < (height + 1) / 2; ++y) {
362 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
363 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
364 dstV += dstUVStride;
365 dstU += dstUVStride;
366 }
367 return;
368 }
369
370 for (size_t y = 0; y < (height + 1) / 2; ++y) {
371 for (size_t x = 0; x < (width + 1) / 2; ++x) {
372 dstU[x] = (uint8_t)(srcU[x] >> 2);
373 dstV[x] = (uint8_t)(srcV[x] >> 2);
374 }
375 srcU += srcUStride;
376 srcV += srcVStride;
377 dstU += dstUVStride;
378 dstV += dstUVStride;
379 }
380}
381
382void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
383 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
384 size_t srcUStride, size_t srcVStride, size_t dstYStride,
385 size_t dstUVStride, size_t width, size_t height,
386 bool isMonochrome) {
387 for (size_t y = 0; y < height; ++y) {
388 for (size_t x = 0; x < width; ++x) {
389 dstY[x] = srcY[x] << 6;
390 }
391 srcY += srcYStride;
392 dstY += dstYStride;
393 }
394
395 if (isMonochrome) {
396 // Fill with neutral U/V values.
397 for (size_t y = 0; y < (height + 1) / 2; ++y) {
398 for (size_t x = 0; x < (width + 1) / 2; ++x) {
399 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
400 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
401 }
402 dstUV += dstUVStride;
403 }
404 return;
405 }
406
407 for (size_t y = 0; y < (height + 1) / 2; ++y) {
408 for (size_t x = 0; x < (width + 1) / 2; ++x) {
409 dstUV[2 * x] = srcU[x] << 6;
410 dstUV[2 * x + 1] = srcV[x] << 6;
411 }
412 srcU += srcUStride;
413 srcV += srcVStride;
414 dstUV += dstUVStride;
415 }
416}
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000417
418void convertP010ToYUV420Planar16(uint16_t *dstY, uint16_t *dstU, uint16_t *dstV,
419 const uint16_t *srcY, const uint16_t *srcUV,
420 size_t srcYStride, size_t srcUVStride, size_t dstYStride,
421 size_t dstUStride, size_t dstVStride, size_t width,
422 size_t height, bool isMonochrome) {
423 for (size_t y = 0; y < height; ++y) {
424 for (size_t x = 0; x < width; ++x) {
425 dstY[x] = srcY[x] >> 6;
426 }
427 srcY += srcYStride;
428 dstY += dstYStride;
429 }
430
431 if (isMonochrome) {
432 // Fill with neutral U/V values.
433 for (size_t y = 0; y < (height + 1) / 2; ++y) {
434 for (size_t x = 0; x < (width + 1) / 2; ++x) {
435 dstU[x] = kNeutralUVBitDepth10;
436 dstV[x] = kNeutralUVBitDepth10;
437 }
438 dstU += dstUStride;
439 dstV += dstVStride;
440 }
441 return;
442 }
443
444 for (size_t y = 0; y < (height + 1) / 2; ++y) {
445 for (size_t x = 0; x < (width + 1) / 2; ++x) {
446 dstU[x] = srcUV[2 * x] >> 6;
447 dstV[x] = srcUV[2 * x + 1] >> 6;
448 }
449 dstU += dstUStride;
450 dstV += dstVStride;
451 srcUV += srcUVStride;
452 }
453}
454
Aayush Soni5e82a6c2023-02-27 18:34:23 +0530455static const int16_t bt709Matrix_10bit[2][3][3] = {
456 { { 218, 732, 74 }, { -117, -395, 512 }, { 512, -465, -47 } }, /* RANGE_FULL */
457 { { 186, 627, 63 }, { -103, -345, 448 }, { 448, -407, -41 } }, /* RANGE_LIMITED */
458};
459
460static const int16_t bt2020Matrix_10bit[2][3][3] = {
461 { { 269, 694, 61 }, { -143, -369, 512 }, { 512, -471, -41 } }, /* RANGE_FULL */
462 { { 230, 594, 52 }, { -125, -323, 448 }, { 448, -412, -36 } }, /* RANGE_LIMITED */
463};
464
465void convertRGBA1010102ToYUV420Planar16(uint16_t* dstY, uint16_t* dstU, uint16_t* dstV,
466 const uint32_t* srcRGBA, size_t srcRGBStride, size_t width,
467 size_t height, C2Color::matrix_t colorMatrix,
468 C2Color::range_t colorRange) {
469 uint16_t r, g, b;
470 int32_t i32Y, i32U, i32V;
471 uint16_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 64;
472 uint16_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 1023 : 940;
473 uint16_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 1023 : 960;
474 // set default range as limited
475 if (colorRange != C2Color::RANGE_FULL) {
476 colorRange = C2Color::RANGE_LIMITED;
477 }
478 const int16_t(*weights)[3] = (colorMatrix == C2Color::MATRIX_BT709)
479 ? bt709Matrix_10bit[colorRange - 1]
480 : bt2020Matrix_10bit[colorRange - 1];
481
482 for (size_t y = 0; y < height; ++y) {
483 for (size_t x = 0; x < width; ++x) {
484 b = (srcRGBA[x] >> 20) & 0x3FF;
485 g = (srcRGBA[x] >> 10) & 0x3FF;
486 r = srcRGBA[x] & 0x3FF;
487
488 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2] + 512) >> 10) +
489 zeroLvl;
490 dstY[x] = CLIP3(zeroLvl, i32Y, maxLvlLuma);
491 if (y % 2 == 0 && x % 2 == 0) {
492 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2] + 512) >> 10) +
493 512;
494 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2] + 512) >> 10) +
495 512;
496 dstU[x >> 1] = CLIP3(zeroLvl, i32U, maxLvlChroma);
497 dstV[x >> 1] = CLIP3(zeroLvl, i32V, maxLvlChroma);
498 }
499 }
500 srcRGBA += srcRGBStride;
501 dstY += width;
502 if (y % 2 == 0) {
503 dstU += width / 2;
504 dstV += width / 2;
505 }
506 }
507}
508
Pawin Vongmasa36653902018-11-15 00:10:25 -0800509std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
510 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
511 mQueue.pop_front();
512 return work;
513}
514
515void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
516 mQueue.push_back({ std::move(work), NO_DRAIN });
517}
518
519bool SimpleC2Component::WorkQueue::empty() const {
520 return mQueue.empty();
521}
522
523void SimpleC2Component::WorkQueue::clear() {
524 mQueue.clear();
525}
526
527uint32_t SimpleC2Component::WorkQueue::drainMode() const {
528 return mQueue.front().drainMode;
529}
530
531void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
532 mQueue.push_back({ nullptr, drainMode });
533}
534
535////////////////////////////////////////////////////////////////////////////////
536
537SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
538
539void SimpleC2Component::WorkHandler::setComponent(
540 const std::shared_ptr<SimpleC2Component> &thiz) {
541 mThiz = thiz;
542}
543
544static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
545 sp<AReplyToken> replyId;
546 CHECK(msg->senderAwaitsResponse(&replyId));
547 sp<AMessage> reply = new AMessage;
548 if (err) {
549 reply->setInt32("err", *err);
550 }
551 reply->postReply(replyId);
552}
553
554void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
555 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
556 if (!thiz) {
557 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
558 sp<AReplyToken> replyId;
559 if (msg->senderAwaitsResponse(&replyId)) {
560 sp<AMessage> reply = new AMessage;
561 reply->setInt32("err", C2_CORRUPTED);
562 reply->postReply(replyId);
563 }
564 return;
565 }
566
567 switch (msg->what()) {
568 case kWhatProcess: {
569 if (mRunning) {
570 if (thiz->processQueue()) {
571 (new AMessage(kWhatProcess, this))->post();
572 }
573 } else {
574 ALOGV("Ignore process message as we're not running");
575 }
576 break;
577 }
578 case kWhatInit: {
579 int32_t err = thiz->onInit();
580 Reply(msg, &err);
581 [[fallthrough]];
582 }
583 case kWhatStart: {
584 mRunning = true;
585 break;
586 }
587 case kWhatStop: {
588 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700589 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800590 Reply(msg, &err);
591 break;
592 }
593 case kWhatReset: {
594 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700595 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800596 mRunning = false;
597 Reply(msg);
598 break;
599 }
600 case kWhatRelease: {
601 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700602 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800603 mRunning = false;
604 Reply(msg);
605 break;
606 }
607 default: {
608 ALOGD("Unrecognized msg: %d", msg->what());
609 break;
610 }
611 }
612}
613
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800614class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
615public:
616 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
617
618 virtual local_id_t getLocalId() const override {
619 return mBase->getLocalId();
620 }
621
622 virtual C2Allocator::id_t getAllocatorId() const override {
623 return mBase->getAllocatorId();
624 }
625
626 virtual c2_status_t fetchLinearBlock(
627 uint32_t capacity,
628 C2MemoryUsage usage,
629 std::shared_ptr<C2LinearBlock>* block) {
630 c2_status_t status;
631 do {
632 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800633 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800634 return status;
635 }
636
637 virtual c2_status_t fetchCircularBlock(
638 uint32_t capacity,
639 C2MemoryUsage usage,
640 std::shared_ptr<C2CircularBlock>* block) {
641 c2_status_t status;
642 do {
643 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800644 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800645 return status;
646 }
647
648 virtual c2_status_t fetchGraphicBlock(
649 uint32_t width, uint32_t height, uint32_t format,
650 C2MemoryUsage usage,
651 std::shared_ptr<C2GraphicBlock>* block) {
652 c2_status_t status;
653 do {
654 status = mBase->fetchGraphicBlock(width, height, format, usage,
655 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800656 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800657 return status;
658 }
659
660private:
661 std::shared_ptr<C2BlockPool> mBase;
662};
663
Pawin Vongmasa36653902018-11-15 00:10:25 -0800664////////////////////////////////////////////////////////////////////////////////
665
666namespace {
667
668struct DummyReadView : public C2ReadView {
669 DummyReadView() : C2ReadView(C2_NO_INIT) {}
670};
671
672} // namespace
673
674SimpleC2Component::SimpleC2Component(
675 const std::shared_ptr<C2ComponentInterface> &intf)
676 : mDummyReadView(DummyReadView()),
677 mIntf(intf),
678 mLooper(new ALooper),
679 mHandler(new WorkHandler) {
680 mLooper->setName(intf->getName().c_str());
681 (void)mLooper->registerHandler(mHandler);
682 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
683}
684
685SimpleC2Component::~SimpleC2Component() {
686 mLooper->unregisterHandler(mHandler->id());
687 (void)mLooper->stop();
688}
689
690c2_status_t SimpleC2Component::setListener_vb(
691 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
692 mHandler->setComponent(shared_from_this());
693
694 Mutexed<ExecState>::Locked state(mExecState);
695 if (state->mState == RUNNING) {
696 if (listener) {
697 return C2_BAD_STATE;
698 } else if (!mayBlock) {
699 return C2_BLOCKING;
700 }
701 }
702 state->mListener = listener;
703 // TODO: wait for listener change to have taken place before returning
704 // (e.g. if there is an ongoing listener callback)
705 return C2_OK;
706}
707
708c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
709 {
710 Mutexed<ExecState>::Locked state(mExecState);
711 if (state->mState != RUNNING) {
712 return C2_BAD_STATE;
713 }
714 }
715 bool queueWasEmpty = false;
716 {
717 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
718 queueWasEmpty = queue->empty();
719 while (!items->empty()) {
720 queue->push_back(std::move(items->front()));
721 items->pop_front();
722 }
723 }
724 if (queueWasEmpty) {
725 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
726 }
727 return C2_OK;
728}
729
730c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
731 (void)items;
732 return C2_OMITTED;
733}
734
735c2_status_t SimpleC2Component::flush_sm(
736 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
737 (void)flushMode;
738 {
739 Mutexed<ExecState>::Locked state(mExecState);
740 if (state->mState != RUNNING) {
741 return C2_BAD_STATE;
742 }
743 }
744 {
745 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
746 queue->incGeneration();
747 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
748 while (!queue->empty()) {
749 std::unique_ptr<C2Work> work = queue->pop_front();
750 if (work) {
751 flushedWork->push_back(std::move(work));
752 }
753 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700754 while (!queue->pending().empty()) {
755 flushedWork->push_back(std::move(queue->pending().begin()->second));
756 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800757 }
758 }
759
760 return C2_OK;
761}
762
763c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
764 if (drainMode == DRAIN_CHAIN) {
765 return C2_OMITTED;
766 }
767 {
768 Mutexed<ExecState>::Locked state(mExecState);
769 if (state->mState != RUNNING) {
770 return C2_BAD_STATE;
771 }
772 }
773 bool queueWasEmpty = false;
774 {
775 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
776 queueWasEmpty = queue->empty();
777 queue->markDrain(drainMode);
778 }
779 if (queueWasEmpty) {
780 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
781 }
782
783 return C2_OK;
784}
785
786c2_status_t SimpleC2Component::start() {
787 Mutexed<ExecState>::Locked state(mExecState);
788 if (state->mState == RUNNING) {
789 return C2_BAD_STATE;
790 }
791 bool needsInit = (state->mState == UNINITIALIZED);
792 state.unlock();
793 if (needsInit) {
794 sp<AMessage> reply;
795 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
796 int32_t err;
797 CHECK(reply->findInt32("err", &err));
798 if (err != C2_OK) {
799 return (c2_status_t)err;
800 }
801 } else {
802 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
803 }
804 state.lock();
805 state->mState = RUNNING;
806 return C2_OK;
807}
808
809c2_status_t SimpleC2Component::stop() {
810 ALOGV("stop");
811 {
812 Mutexed<ExecState>::Locked state(mExecState);
813 if (state->mState != RUNNING) {
814 return C2_BAD_STATE;
815 }
816 state->mState = STOPPED;
817 }
818 {
819 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
820 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700821 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800822 }
823 sp<AMessage> reply;
824 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
825 int32_t err;
826 CHECK(reply->findInt32("err", &err));
827 if (err != C2_OK) {
828 return (c2_status_t)err;
829 }
830 return C2_OK;
831}
832
833c2_status_t SimpleC2Component::reset() {
834 ALOGV("reset");
835 {
836 Mutexed<ExecState>::Locked state(mExecState);
837 state->mState = UNINITIALIZED;
838 }
839 {
840 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
841 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700842 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800843 }
844 sp<AMessage> reply;
845 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
846 return C2_OK;
847}
848
849c2_status_t SimpleC2Component::release() {
850 ALOGV("release");
851 sp<AMessage> reply;
852 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
853 return C2_OK;
854}
855
856std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
857 return mIntf;
858}
859
860namespace {
861
862std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
863 std::list<std::unique_ptr<C2Work>> ret;
864 ret.push_back(std::move(work));
865 return ret;
866}
867
868} // namespace
869
870void SimpleC2Component::finish(
871 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
872 std::unique_ptr<C2Work> work;
873 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700874 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
875 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800876 ALOGW("unknown frame index: %" PRIu64, frameIndex);
877 return;
878 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700879 work = std::move(queue->pending().at(frameIndex));
880 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800881 }
882 if (work) {
883 fillWork(work);
884 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
885 listener->onWorkDone_nb(shared_from_this(), vec(work));
886 ALOGV("returning pending work");
887 }
888}
889
890void SimpleC2Component::cloneAndSend(
891 uint64_t frameIndex,
892 const std::unique_ptr<C2Work> &currentWork,
893 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
894 std::unique_ptr<C2Work> work(new C2Work);
895 if (currentWork->input.ordinal.frameIndex == frameIndex) {
896 work->input.flags = currentWork->input.flags;
897 work->input.ordinal = currentWork->input.ordinal;
898 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700899 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
900 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800901 ALOGW("unknown frame index: %" PRIu64, frameIndex);
902 return;
903 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700904 work->input.flags = queue->pending().at(frameIndex)->input.flags;
905 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800906 }
907 work->worklets.emplace_back(new C2Worklet);
908 if (work) {
909 fillWork(work);
910 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
911 listener->onWorkDone_nb(shared_from_this(), vec(work));
912 ALOGV("cloned and sending work");
913 }
914}
915
916bool SimpleC2Component::processQueue() {
917 std::unique_ptr<C2Work> work;
918 uint64_t generation;
919 int32_t drainMode;
920 bool isFlushPending = false;
921 bool hasQueuedWork = false;
922 {
923 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
924 if (queue->empty()) {
925 return false;
926 }
927
928 generation = queue->generation();
929 drainMode = queue->drainMode();
930 isFlushPending = queue->popPendingFlush();
931 work = queue->pop_front();
932 hasQueuedWork = !queue->empty();
933 }
934 if (isFlushPending) {
935 ALOGV("processing pending flush");
936 c2_status_t err = onFlush_sm();
937 if (err != C2_OK) {
938 ALOGD("flush err: %d", err);
939 // TODO: error
940 }
941 }
942
943 if (!mOutputBlockPool) {
944 c2_status_t err = [this] {
945 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800946 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800947 std::vector<std::unique_ptr<C2Param>> params;
948 c2_status_t err = intf()->query_vb(
949 { &outputFormat },
950 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
951 C2_DONT_BLOCK,
952 &params);
953 if (err != C2_OK && err != C2_BAD_INDEX) {
954 ALOGD("query err = %d", err);
955 return err;
956 }
957 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800958 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800959 ? C2BlockPool::BASIC_GRAPHIC
960 : C2BlockPool::BASIC_LINEAR;
961 if (params.size()) {
962 C2PortBlockPoolsTuning::output *outputPools =
963 C2PortBlockPoolsTuning::output::From(params[0].get());
964 if (outputPools && outputPools->flexCount() >= 1) {
965 poolId = outputPools->m.values[0];
966 }
967 }
968
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800969 std::shared_ptr<C2BlockPool> blockPool;
970 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800971 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
972 (unsigned long long)poolId,
973 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800974 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800975 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800976 if (err == C2_OK) {
977 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
978 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800979 return err;
980 }();
981 if (err != C2_OK) {
982 Mutexed<ExecState>::Locked state(mExecState);
983 std::shared_ptr<C2Component::Listener> listener = state->mListener;
984 state.unlock();
985 listener->onError_nb(shared_from_this(), err);
986 return hasQueuedWork;
987 }
988 }
989
990 if (!work) {
991 c2_status_t err = drain(drainMode, mOutputBlockPool);
992 if (err != C2_OK) {
993 Mutexed<ExecState>::Locked state(mExecState);
994 std::shared_ptr<C2Component::Listener> listener = state->mListener;
995 state.unlock();
996 listener->onError_nb(shared_from_this(), err);
997 }
998 return hasQueuedWork;
999 }
1000
1001 {
1002 std::vector<C2Param *> updates;
1003 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
1004 if (param) {
1005 updates.emplace_back(param.get());
1006 }
1007 }
1008 if (!updates.empty()) {
1009 std::vector<std::unique_ptr<C2SettingResult>> failures;
1010 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
1011 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
1012 }
1013 }
1014
1015 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001016 // If input buffer list is not empty, it means we have some input to process on.
1017 // However, input could be a null buffer. In such case, clear the buffer list
1018 // before making call to process().
1019 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
1020 ALOGD("Encountered null input buffer. Clearing the input buffer");
1021 work->input.buffers.clear();
1022 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001023 process(work, mOutputBlockPool);
1024 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -07001025 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1026 if (queue->generation() != generation) {
1027 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
1028 queue->generation(), generation);
1029 work->result = C2_NOT_FOUND;
1030 queue.unlock();
1031
1032 Mutexed<ExecState>::Locked state(mExecState);
1033 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1034 state.unlock();
1035 listener->onWorkDone_nb(shared_from_this(), vec(work));
1036 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001037 }
1038 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -07001039 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001040 Mutexed<ExecState>::Locked state(mExecState);
1041 ALOGV("returning this work");
1042 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1043 state.unlock();
1044 listener->onWorkDone_nb(shared_from_this(), vec(work));
1045 } else {
1046 ALOGV("queue pending work");
1047 work->input.buffers.clear();
1048 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -07001049
1050 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
1051 if (queue->pending().count(frameIndex) != 0) {
1052 unexpected = std::move(queue->pending().at(frameIndex));
1053 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001054 }
Wonsik Kime1226f52019-04-04 15:24:41 -07001055 (void)queue->pending().insert({ frameIndex, std::move(work) });
1056
1057 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001058 if (unexpected) {
1059 ALOGD("unexpected pending work");
1060 unexpected->result = C2_CORRUPTED;
1061 Mutexed<ExecState>::Locked state(mExecState);
1062 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1063 state.unlock();
1064 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
1065 }
1066 }
1067 return hasQueuedWork;
1068}
1069
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001070int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
1071 // Save supported hal pixel formats for bit depth of 10, the first time this is called
1072 if (!mBitDepth10HalPixelFormats.size()) {
1073 std::vector<int> halPixelFormats;
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001074 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
1075
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001076 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
1077 // is populated only once, allowRGBA1010102 is not considered at this stage.
1078 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
1079
1080 for (int halPixelFormat : halPixelFormats) {
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001081 if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001082 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
1083 }
1084 }
1085 // Add YV12 in the end as a fall-back option
1086 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
1087 }
Harish Mahendrakar5c467652022-04-28 19:47:28 -07001088 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
1089 // RGBA 1010102 format unlike earlier versions where it was used to represent
1090 // YUVA 1010102 data
1091 if (!isAtLeastT()) {
1092 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
1093 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
1094 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
1095 return HAL_PIXEL_FORMAT_YV12;
1096 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001097 }
1098 // Return the first entry from supported formats
1099 return mBitDepth10HalPixelFormats[0];
1100}
Pawin Vongmasa36653902018-11-15 00:10:25 -08001101std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001102 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
1103 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
1104}
1105
1106std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001107 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
1108 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
1109}
1110
1111} // namespace android