blob: ea67bf408fa2d2250704e2139e3cacd25419b871 [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>
Harish Mahendrakar29351ea2023-08-24 17:18:56 +053024#include <media/stagefright/foundation/AUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080025
26#include <inttypes.h>
Harish Mahendrakar29351ea2023-08-24 17:18:56 +053027#include <libyuv.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080028
29#include <C2Config.h>
30#include <C2Debug.h>
31#include <C2PlatformSupport.h>
Harish Mahendrakarf5dec502022-04-13 15:53:55 -070032#include <Codec2BufferUtils.h>
33#include <Codec2CommonUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080034#include <SimpleC2Component.h>
35
36namespace android {
Harish Mahendrakar29351ea2023-08-24 17:18:56 +053037
38// libyuv version required for I410ToAB30Matrix and I210ToAB30Matrix.
39#if LIBYUV_VERSION >= 1780
40#include <algorithm>
41#define HAVE_LIBYUV_I410_I210_TO_AB30 1
42#else
43#define HAVE_LIBYUV_I410_I210_TO_AB30 0
44#endif
45
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080046constexpr uint8_t kNeutralUVBitDepth8 = 128;
47constexpr uint16_t kNeutralUVBitDepth10 = 512;
Pawin Vongmasa36653902018-11-15 00:10:25 -080048
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080049void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
50 const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
51 size_t srcUStride, size_t srcVStride, size_t dstYStride,
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000052 size_t dstUStride, size_t dstVStride, uint32_t width,
53 uint32_t height, bool isMonochrome) {
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080054 for (size_t i = 0; i < height; ++i) {
55 memcpy(dstY, srcY, width);
56 srcY += srcYStride;
57 dstY += dstYStride;
58 }
59
60 if (isMonochrome) {
61 // Fill with neutral U/V values.
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080062 for (size_t i = 0; i < (height + 1) / 2; ++i) {
63 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
64 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000065 dstV += dstVStride;
66 dstU += dstUStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080067 }
68 return;
69 }
70
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080071 for (size_t i = 0; i < (height + 1) / 2; ++i) {
72 memcpy(dstV, srcV, (width + 1) / 2);
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080073 srcV += srcVStride;
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000074 dstV += dstVStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080075 }
76
Vignesh Venkatasubramanianc4d385f2022-02-22 10:49:46 -080077 for (size_t i = 0; i < (height + 1) / 2; ++i) {
78 memcpy(dstU, srcU, (width + 1) / 2);
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080079 srcU += srcUStride;
Vignesh Venkatasubramanian47b1d222023-01-12 21:45:40 +000080 dstU += dstUStride;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080081 }
82}
83
84void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
85 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
86 size_t srcVStride, size_t dstStride, size_t width, size_t height) {
87 // Converting two lines at a time, slightly faster
88 for (size_t y = 0; y < height; y += 2) {
89 uint32_t *dstTop = (uint32_t *)dst;
90 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
91 uint16_t *ySrcTop = (uint16_t *)srcY;
92 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
93 uint16_t *uSrc = (uint16_t *)srcU;
94 uint16_t *vSrc = (uint16_t *)srcV;
95
96 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
97 size_t x = 0;
98 for (; x < width - 3; x += 4) {
99 u01 = *((uint32_t *)uSrc);
100 uSrc += 2;
101 v01 = *((uint32_t *)vSrc);
102 vSrc += 2;
103
104 y01 = *((uint32_t *)ySrcTop);
105 ySrcTop += 2;
106 y23 = *((uint32_t *)ySrcTop);
107 ySrcTop += 2;
108 y45 = *((uint32_t *)ySrcBot);
109 ySrcBot += 2;
110 y67 = *((uint32_t *)ySrcBot);
111 ySrcBot += 2;
112
113 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
114 uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
115
116 *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
117 *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
118 *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
119 *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
120
121 *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
122 *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
123 *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
124 *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
125 }
126
127 // There should be at most 2 more pixels to process. Note that we don't
128 // need to consider odd case as the buffer is always aligned to even.
129 if (x < width) {
130 u01 = *uSrc;
131 v01 = *vSrc;
132 y01 = *((uint32_t *)ySrcTop);
133 y45 = *((uint32_t *)ySrcBot);
134 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
135 *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
136 *dstTop++ = ((y01 >> 16) << 10) | uv0;
137 *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
138 *dstBot++ = ((y45 >> 16) << 10) | uv0;
139 }
140
141 srcY += srcYStride * 2;
142 srcU += srcUStride;
143 srcV += srcVStride;
144 dst += dstStride * 2;
145 }
146}
Lajos Molnarc971e962022-06-01 20:24:38 -0700147
148namespace {
149
150static C2ColorAspectsStruct FillMissingColorAspects(
151 std::shared_ptr<const C2ColorAspectsStruct> aspects,
152 int32_t width, int32_t height) {
153 C2ColorAspectsStruct _aspects;
154 if (aspects) {
155 _aspects = *aspects;
156 }
157
158 // use matrix for conversion
159 if (_aspects.matrix == C2Color::MATRIX_UNSPECIFIED) {
160 // if not specified, deduce matrix from primaries
161 if (_aspects.primaries == C2Color::PRIMARIES_UNSPECIFIED) {
162 // if those are also not specified, deduce primaries first from transfer, then from
163 // width and height
164 if (_aspects.transfer == C2Color::TRANSFER_ST2084
165 || _aspects.transfer == C2Color::TRANSFER_HLG) {
166 _aspects.primaries = C2Color::PRIMARIES_BT2020;
167 } else if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
168 // TODO: stagefright defaults to BT.2020 for UHD, but perhaps we should default to
169 // BT.709 for non-HDR 10-bit UHD content
170 // (see media/libstagefright/foundation/ColorUtils.cpp)
171 _aspects.primaries = C2Color::PRIMARIES_BT2020;
172 } else if ((width <= 720 && height <= 576)
173 || (height <= 720 && width <= 576)) {
174 // note: it does not actually matter whether to use 525 or 625 here as the
175 // conversion is the same
176 _aspects.primaries = C2Color::PRIMARIES_BT601_625;
177 } else {
178 _aspects.primaries = C2Color::PRIMARIES_BT709;
179 }
180 }
181
182 switch (_aspects.primaries) {
183 case C2Color::PRIMARIES_BT601_525:
184 case C2Color::PRIMARIES_BT601_625:
185 _aspects.matrix = C2Color::MATRIX_BT601;
186 break;
187
188 case C2Color::PRIMARIES_BT709:
189 _aspects.matrix = C2Color::MATRIX_BT709;
190 break;
191
192 case C2Color::PRIMARIES_BT2020:
193 default:
194 _aspects.matrix = C2Color::MATRIX_BT2020;
195 }
196 }
197
198 return _aspects;
199}
200
201// matrix conversion coefficients
202// (see media/libstagefright/colorconverter/ColorConverter.cpp for more details)
203struct Coeffs {
Harish Mahendrakar36bd7942022-07-07 20:14:14 -0700204 int32_t _y, _r_v, _g_u, _g_v, _b_u, _c16;
Lajos Molnarc971e962022-06-01 20:24:38 -0700205};
206
207static const struct Coeffs GetCoeffsForAspects(const C2ColorAspectsStruct &aspects) {
208 bool isFullRange = aspects.range == C2Color::RANGE_FULL;
209
210 switch (aspects.matrix) {
211 case C2Color::MATRIX_BT601:
212 /**
213 * BT.601: K_R = 0.299; K_B = 0.114
214 */
215 if (isFullRange) {
216 return Coeffs { 1024, 1436, 352, 731, 1815, 0 };
217 } else {
218 return Coeffs { 1196, 1639, 402, 835, 2072, 64 };
219 }
220 break;
221
222 case C2Color::MATRIX_BT709:
223 /**
224 * BT.709: K_R = 0.2126; K_B = 0.0722
225 */
226 if (isFullRange) {
227 return Coeffs { 1024, 1613, 192, 479, 1900, 0 };
228 } else {
229 return Coeffs { 1196, 1841, 219, 547, 2169, 64 };
230 }
231 break;
232
233 case C2Color::MATRIX_BT2020:
234 default:
235 /**
236 * BT.2020: K_R = 0.2627; K_B = 0.0593
237 */
238 if (isFullRange) {
239 return Coeffs { 1024, 1510, 169, 585, 1927, 0 };
240 } else {
241 return Coeffs { 1196, 1724, 192, 668, 2200, 64 };
242 }
243 }
244}
245
246}
247
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700248#define CLIP3(min, v, max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
Lajos Molnarc971e962022-06-01 20:24:38 -0700249void convertYUV420Planar16ToRGBA1010102(
250 uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
251 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
252 size_t srcVStride, size_t dstStride, size_t width,
253 size_t height,
254 std::shared_ptr<const C2ColorAspectsStruct> aspects) {
255
256 C2ColorAspectsStruct _aspects = FillMissingColorAspects(aspects, width, height);
257
258 struct Coeffs coeffs = GetCoeffsForAspects(_aspects);
259
260 int32_t _y = coeffs._y;
261 int32_t _b_u = coeffs._b_u;
262 int32_t _neg_g_u = -coeffs._g_u;
263 int32_t _neg_g_v = -coeffs._g_v;
264 int32_t _r_v = coeffs._r_v;
265 int32_t _c16 = coeffs._c16;
266
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700267 // Converting two lines at a time, slightly faster
268 for (size_t y = 0; y < height; y += 2) {
269 uint32_t *dstTop = (uint32_t *)dst;
270 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
271 uint16_t *ySrcTop = (uint16_t *)srcY;
272 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
273 uint16_t *uSrc = (uint16_t *)srcU;
274 uint16_t *vSrc = (uint16_t *)srcV;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800275
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700276 for (size_t x = 0; x < width; x += 2) {
277 int32_t u, v, y00, y01, y10, y11;
278 u = *uSrc - 512;
279 uSrc += 1;
280 v = *vSrc - 512;
281 vSrc += 1;
282
Lajos Molnarc971e962022-06-01 20:24:38 -0700283 y00 = *ySrcTop - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700284 ySrcTop += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700285 y01 = *ySrcTop - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700286 ySrcTop += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700287 y10 = *ySrcBot - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700288 ySrcBot += 1;
Lajos Molnarc971e962022-06-01 20:24:38 -0700289 y11 = *ySrcBot - _c16;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700290 ySrcBot += 1;
291
Lajos Molnarc971e962022-06-01 20:24:38 -0700292 int32_t u_b = u * _b_u;
293 int32_t u_g = u * _neg_g_u;
294 int32_t v_g = v * _neg_g_v;
295 int32_t v_r = v * _r_v;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700296
297 int32_t yMult, b, g, r;
Lajos Molnarc971e962022-06-01 20:24:38 -0700298 yMult = y00 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700299 b = (yMult + u_b) / 1024;
300 g = (yMult + v_g + u_g) / 1024;
301 r = (yMult + v_r) / 1024;
302 b = CLIP3(0, b, 1023);
303 g = CLIP3(0, g, 1023);
304 r = CLIP3(0, r, 1023);
305 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
306
Lajos Molnarc971e962022-06-01 20:24:38 -0700307 yMult = y01 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700308 b = (yMult + u_b) / 1024;
309 g = (yMult + v_g + u_g) / 1024;
310 r = (yMult + v_r) / 1024;
311 b = CLIP3(0, b, 1023);
312 g = CLIP3(0, g, 1023);
313 r = CLIP3(0, r, 1023);
314 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
315
Lajos Molnarc971e962022-06-01 20:24:38 -0700316 yMult = y10 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700317 b = (yMult + u_b) / 1024;
318 g = (yMult + v_g + u_g) / 1024;
319 r = (yMult + v_r) / 1024;
320 b = CLIP3(0, b, 1023);
321 g = CLIP3(0, g, 1023);
322 r = CLIP3(0, r, 1023);
323 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
324
Lajos Molnarc971e962022-06-01 20:24:38 -0700325 yMult = y11 * _y + 512;
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700326 b = (yMult + u_b) / 1024;
327 g = (yMult + v_g + u_g) / 1024;
328 r = (yMult + v_r) / 1024;
329 b = CLIP3(0, b, 1023);
330 g = CLIP3(0, g, 1023);
331 r = CLIP3(0, r, 1023);
332 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
333 }
334
335 srcY += srcYStride * 2;
336 srcU += srcUStride;
337 srcV += srcVStride;
338 dst += dstStride * 2;
339 }
340}
341
Lajos Molnarc971e962022-06-01 20:24:38 -0700342void convertYUV420Planar16ToY410OrRGBA1010102(
343 uint32_t *dst, const uint16_t *srcY,
344 const uint16_t *srcU, const uint16_t *srcV,
345 size_t srcYStride, size_t srcUStride,
346 size_t srcVStride, size_t dstStride, size_t width, size_t height,
347 std::shared_ptr<const C2ColorAspectsStruct> aspects) {
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700348 if (isAtLeastT()) {
349 convertYUV420Planar16ToRGBA1010102(dst, srcY, srcU, srcV, srcYStride, srcUStride,
Lajos Molnarc971e962022-06-01 20:24:38 -0700350 srcVStride, dstStride, width, height, aspects);
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700351 } else {
352 convertYUV420Planar16ToY410(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
353 dstStride, width, height);
354 }
355}
Lajos Molnarc971e962022-06-01 20:24:38 -0700356
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800357void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
358 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
359 size_t srcUStride, size_t srcVStride, size_t dstYStride,
360 size_t dstUVStride, size_t width, size_t height,
361 bool isMonochrome) {
362 for (size_t y = 0; y < height; ++y) {
363 for (size_t x = 0; x < width; ++x) {
364 dstY[x] = (uint8_t)(srcY[x] >> 2);
365 }
366 srcY += srcYStride;
367 dstY += dstYStride;
368 }
369
370 if (isMonochrome) {
371 // Fill with neutral U/V values.
372 for (size_t y = 0; y < (height + 1) / 2; ++y) {
373 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
374 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
375 dstV += dstUVStride;
376 dstU += dstUVStride;
377 }
378 return;
379 }
380
381 for (size_t y = 0; y < (height + 1) / 2; ++y) {
382 for (size_t x = 0; x < (width + 1) / 2; ++x) {
383 dstU[x] = (uint8_t)(srcU[x] >> 2);
384 dstV[x] = (uint8_t)(srcV[x] >> 2);
385 }
386 srcU += srcUStride;
387 srcV += srcVStride;
388 dstU += dstUVStride;
389 dstV += dstUVStride;
390 }
391}
392
393void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
394 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
395 size_t srcUStride, size_t srcVStride, size_t dstYStride,
396 size_t dstUVStride, size_t width, size_t height,
397 bool isMonochrome) {
398 for (size_t y = 0; y < height; ++y) {
399 for (size_t x = 0; x < width; ++x) {
400 dstY[x] = srcY[x] << 6;
401 }
402 srcY += srcYStride;
403 dstY += dstYStride;
404 }
405
406 if (isMonochrome) {
407 // Fill with neutral U/V values.
408 for (size_t y = 0; y < (height + 1) / 2; ++y) {
409 for (size_t x = 0; x < (width + 1) / 2; ++x) {
410 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
411 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
412 }
413 dstUV += dstUVStride;
414 }
415 return;
416 }
417
418 for (size_t y = 0; y < (height + 1) / 2; ++y) {
419 for (size_t x = 0; x < (width + 1) / 2; ++x) {
420 dstUV[2 * x] = srcU[x] << 6;
421 dstUV[2 * x + 1] = srcV[x] << 6;
422 }
423 srcU += srcUStride;
424 srcV += srcVStride;
425 dstUV += dstUVStride;
426 }
427}
Fyodor Kyslovd97e9912022-11-07 19:23:21 +0000428
429void convertP010ToYUV420Planar16(uint16_t *dstY, uint16_t *dstU, uint16_t *dstV,
430 const uint16_t *srcY, const uint16_t *srcUV,
431 size_t srcYStride, size_t srcUVStride, size_t dstYStride,
432 size_t dstUStride, size_t dstVStride, size_t width,
433 size_t height, bool isMonochrome) {
434 for (size_t y = 0; y < height; ++y) {
435 for (size_t x = 0; x < width; ++x) {
436 dstY[x] = srcY[x] >> 6;
437 }
438 srcY += srcYStride;
439 dstY += dstYStride;
440 }
441
442 if (isMonochrome) {
443 // Fill with neutral U/V values.
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] = kNeutralUVBitDepth10;
447 dstV[x] = kNeutralUVBitDepth10;
448 }
449 dstU += dstUStride;
450 dstV += dstVStride;
451 }
452 return;
453 }
454
455 for (size_t y = 0; y < (height + 1) / 2; ++y) {
456 for (size_t x = 0; x < (width + 1) / 2; ++x) {
457 dstU[x] = srcUV[2 * x] >> 6;
458 dstV[x] = srcUV[2 * x + 1] >> 6;
459 }
460 dstU += dstUStride;
461 dstV += dstVStride;
462 srcUV += srcUVStride;
463 }
464}
465
Fyodor Kyslov7f64e012024-11-15 20:17:33 +0000466void convertP010ToP210(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY, const uint16_t *srcUV,
467 size_t srcUVStride, size_t dstUVStride, size_t width, size_t height) {
468 std::memcpy(dstY, srcY, width * height * sizeof(uint16_t));
469
470 int32_t offsetTop, offsetBot;
471 for (size_t y = 0; y < (height + 1) / 2; ++y) {
472 offsetTop = (y * 2) * dstUVStride;
473 offsetBot = (y * 2 + 1) * dstUVStride;
474 std::memcpy(dstUV + offsetTop, srcUV + (y * srcUVStride), srcUVStride * sizeof(uint16_t));
475 std::memcpy(dstUV + offsetBot, srcUV + (y * srcUVStride), srcUVStride * sizeof(uint16_t));
476 }
477}
478
Aayush Soni5e82a6c2023-02-27 18:34:23 +0530479static const int16_t bt709Matrix_10bit[2][3][3] = {
480 { { 218, 732, 74 }, { -117, -395, 512 }, { 512, -465, -47 } }, /* RANGE_FULL */
481 { { 186, 627, 63 }, { -103, -345, 448 }, { 448, -407, -41 } }, /* RANGE_LIMITED */
482};
483
484static const int16_t bt2020Matrix_10bit[2][3][3] = {
485 { { 269, 694, 61 }, { -143, -369, 512 }, { 512, -471, -41 } }, /* RANGE_FULL */
486 { { 230, 594, 52 }, { -125, -323, 448 }, { 448, -412, -36 } }, /* RANGE_LIMITED */
487};
488
489void convertRGBA1010102ToYUV420Planar16(uint16_t* dstY, uint16_t* dstU, uint16_t* dstV,
490 const uint32_t* srcRGBA, size_t srcRGBStride, size_t width,
491 size_t height, C2Color::matrix_t colorMatrix,
492 C2Color::range_t colorRange) {
493 uint16_t r, g, b;
494 int32_t i32Y, i32U, i32V;
495 uint16_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 64;
496 uint16_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 1023 : 940;
497 uint16_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 1023 : 960;
498 // set default range as limited
499 if (colorRange != C2Color::RANGE_FULL) {
500 colorRange = C2Color::RANGE_LIMITED;
501 }
502 const int16_t(*weights)[3] = (colorMatrix == C2Color::MATRIX_BT709)
503 ? bt709Matrix_10bit[colorRange - 1]
504 : bt2020Matrix_10bit[colorRange - 1];
505
506 for (size_t y = 0; y < height; ++y) {
507 for (size_t x = 0; x < width; ++x) {
508 b = (srcRGBA[x] >> 20) & 0x3FF;
509 g = (srcRGBA[x] >> 10) & 0x3FF;
510 r = srcRGBA[x] & 0x3FF;
511
512 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2] + 512) >> 10) +
513 zeroLvl;
514 dstY[x] = CLIP3(zeroLvl, i32Y, maxLvlLuma);
515 if (y % 2 == 0 && x % 2 == 0) {
516 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2] + 512) >> 10) +
517 512;
518 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2] + 512) >> 10) +
519 512;
520 dstU[x >> 1] = CLIP3(zeroLvl, i32U, maxLvlChroma);
521 dstV[x >> 1] = CLIP3(zeroLvl, i32V, maxLvlChroma);
522 }
523 }
524 srcRGBA += srcRGBStride;
525 dstY += width;
526 if (y % 2 == 0) {
527 dstU += width / 2;
528 dstV += width / 2;
529 }
530 }
531}
532
Fyodor Kyslov7f64e012024-11-15 20:17:33 +0000533void convertRGBA1010102ToP210(uint16_t* dstY, uint16_t* dstUV, const uint32_t* srcRGBA,
534 size_t srcRGBStride, size_t width, size_t height,
535 C2Color::matrix_t colorMatrix, C2Color::range_t colorRange) {
536 uint16_t r, g, b;
537 int32_t i32Y, i32U, i32V;
538 uint16_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 64;
539 uint16_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 1023 : 940;
540 uint16_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 1023 : 960;
541 // set default range as limited
542 if (colorRange != C2Color::RANGE_FULL) {
543 colorRange = C2Color::RANGE_LIMITED;
544 }
545 const int16_t(*weights)[3] = (colorMatrix == C2Color::MATRIX_BT709)
546 ? bt709Matrix_10bit[colorRange - 1]
547 : bt2020Matrix_10bit[colorRange - 1];
548
549 for (size_t y = 0; y < height; ++y) {
550 for (size_t x = 0; x < width; ++x) {
551 b = (srcRGBA[x] >> 20) & 0x3FF;
552 g = (srcRGBA[x] >> 10) & 0x3FF;
553 r = srcRGBA[x] & 0x3FF;
554
555 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2] + 512) >> 10) +
556 zeroLvl;
557 dstY[x] = (CLIP3(zeroLvl, i32Y, maxLvlLuma) << 6) & 0xFFC0;
558 if (x % 2 == 0) {
559 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2] + 512) >> 10) +
560 512;
561 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2] + 512) >> 10) +
562 512;
563 dstUV[x] = (CLIP3(zeroLvl, i32U, maxLvlChroma) << 6) & 0xFFC0;
564 dstUV[x + 1] = (CLIP3(zeroLvl, i32V, maxLvlChroma) << 6) & 0xFFC0;
565 }
566 }
567 srcRGBA += srcRGBStride;
568 dstY += width;
569 }
570}
571
Harish Mahendrakar29351ea2023-08-24 17:18:56 +0530572void convertPlanar16ToY410OrRGBA1010102(uint8_t* dst, const uint16_t* srcY, const uint16_t* srcU,
573 const uint16_t* srcV, size_t srcYStride, size_t srcUStride,
574 size_t srcVStride, size_t dstStride, size_t width,
575 size_t height,
576 std::shared_ptr<const C2ColorAspectsStruct> aspects,
577 CONV_FORMAT_T format) {
578 bool processed = false;
579#if HAVE_LIBYUV_I410_I210_TO_AB30
580 if (format == CONV_FORMAT_I444) {
581 libyuv::I410ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
582 dstStride, &libyuv::kYuvV2020Constants, width, height);
583 processed = true;
584 } else if (format == CONV_FORMAT_I422) {
585 libyuv::I210ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
586 dstStride, &libyuv::kYuvV2020Constants, width, height);
587 processed = true;
588 }
589#endif // HAVE_LIBYUV_I410_I210_TO_AB30
590 if (!processed) {
591 convertYUV420Planar16ToY410OrRGBA1010102(
592 (uint32_t*)dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
593 dstStride / sizeof(uint32_t), width, height,
594 std::static_pointer_cast<const C2ColorAspectsStruct>(aspects));
595 }
596}
597
598void convertPlanar16ToP010(uint16_t* dstY, uint16_t* dstUV, const uint16_t* srcY,
599 const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
600 size_t srcUStride, size_t srcVStride, size_t dstYStride,
601 size_t dstUStride, size_t dstVStride, size_t width, size_t height,
602 bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
603 size_t tmpFrameBufferSize) {
604#if LIBYUV_VERSION >= 1779
605 if ((format == CONV_FORMAT_I444) || (format == CONV_FORMAT_I422)) {
606 // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010
607 // and libyuv::I210ToP010 when they are available. Note it may be safe to alias dstY
608 // in I010ToP010, but the libyuv API doesn't make any guarantees.
609 const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
610 CHECK(tmpSize <= tmpFrameBufferSize);
611
612 uint16_t* const tmpY = tmpFrameBuffer;
613 uint16_t* const tmpU = tmpY + dstYStride * height;
614 uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
615 if (format == CONV_FORMAT_I444) {
616 libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
617 dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
618 } else {
619 libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
620 dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
621 }
622 libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride, dstY, dstYStride,
623 dstUV, dstUStride, width, height);
624 } else {
625 convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride,
626 srcVStride, dstYStride, dstUStride, width, height,
627 isMonochrome);
628 }
629#else // LIBYUV_VERSION < 1779
630 convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
631 dstYStride, dstUStride, width, height, isMonochrome);
632#endif // LIBYUV_VERSION >= 1779
633}
634
635void convertPlanar16ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint16_t* srcY,
636 const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
637 size_t srcUStride, size_t srcVStride, size_t dstYStride,
638 size_t dstUStride, size_t dstVStride, size_t width, size_t height,
639 bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
640 size_t tmpFrameBufferSize) {
641#if LIBYUV_VERSION >= 1779
642 if (format == CONV_FORMAT_I444) {
643 // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420
644 // when it's available.
645 const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
646 CHECK(tmpSize <= tmpFrameBufferSize);
647
648 uint16_t* const tmpY = tmpFrameBuffer;
649 uint16_t* const tmpU = tmpY + dstYStride * height;
650 uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
651 libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY, dstYStride,
652 tmpU, dstUStride, tmpV, dstVStride, width, height);
653 libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride, dstY, dstYStride,
654 dstU, dstUStride, dstV, dstVStride, width, height);
655 } else if (format == CONV_FORMAT_I422) {
656 libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
657 dstU, dstUStride, dstV, dstVStride, width, height);
658 } else {
659 convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
660 srcVStride, dstYStride, dstUStride, width, height,
661 isMonochrome);
662 }
663#else // LIBYUV_VERSION < 1779
664 convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
665 srcVStride, dstYStride, dstUStride, width, height, isMonochrome);
666#endif // LIBYUV_VERSION >= 1779
667}
668
669void convertPlanar8ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint8_t* srcY,
670 const uint8_t* srcU, const uint8_t* srcV, size_t srcYStride,
671 size_t srcUStride, size_t srcVStride, size_t dstYStride,
672 size_t dstUStride, size_t dstVStride, uint32_t width, uint32_t height,
673 bool isMonochrome, CONV_FORMAT_T format) {
674 if (format == CONV_FORMAT_I444) {
675 libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
676 dstU, dstUStride, dstV, dstVStride, width, height);
677 } else if (format == CONV_FORMAT_I422) {
678 libyuv::I422ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
679 dstU, dstUStride, dstV, dstVStride, width, height);
680 } else {
681 convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
682 srcVStride, dstYStride, dstUStride, dstVStride, width, height,
683 isMonochrome);
684 }
685}
Fyodor Kyslov7f64e012024-11-15 20:17:33 +0000686
687void convertSemiPlanar8ToP210(uint16_t *dstY, uint16_t *dstUV,
688 const uint8_t *srcY, const uint8_t *srcUV,
689 size_t srcYStride, size_t srcUVStride,
690 size_t dstYStride, size_t dstUVStride,
691 uint32_t width, uint32_t height,
692 CONV_FORMAT_T format) {
693 if (format != CONV_FORMAT_I420) {
694 ALOGE("No support for semi-planar8 to P210. format is %d", format);
695 return;
696 }
697
698 for (int32_t y = 0; y < height; ++y) {
699 for (int32_t x = 0; x < width; ++x) {
700 dstY[x] = ((uint16_t)((double)srcY[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
701 }
702 dstY += dstYStride;
703 srcY += srcYStride;
704 }
705
706 for (int32_t y = 0; y < height / 2; ++y) {
707 for (int32_t x = 0; x < width; ++x) {
708 dstUV[x] = dstUV[dstUVStride + x] =
709 ((uint16_t)((double)srcUV[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
710 }
711 srcUV += srcUVStride;
712 dstUV += dstUVStride << 1;
713 }
714}
715
Fyodor Kyslovd97db432024-12-04 23:30:50 +0000716void convertPlanar8ToP210(uint16_t *dstY, uint16_t *dstUV,
717 const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
718 size_t srcYStride, size_t srcUStride, size_t srcVStride,
719 size_t dstYStride, size_t dstUVStride,
720 uint32_t width, uint32_t height,
721 CONV_FORMAT_T format) {
722 if (format != CONV_FORMAT_I420) {
723 ALOGE("No support for planar8 to P210. format is %d", format);
724 return;
725 }
726
727 for (int32_t y = 0; y < height; ++y) {
728 for (int32_t x = 0; x < width; ++x) {
729 dstY[x] = ((uint16_t)((double)srcY[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
730 }
731 dstY += dstYStride;
732 srcY += srcYStride;
733 }
734
735 for (int32_t y = 0; y < height / 2; ++y) {
736 for (int32_t x = 0; x < width / 2; ++x) {
737 dstUV[x<<1] = dstUV[(x<<1) + dstUVStride] =
738 ((uint16_t)((double)srcU[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
739 dstUV[(x<<1) + 1] = dstUV[(x<<1) + dstUVStride + 1] =
740 ((uint16_t)((double)srcV[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
741 }
742 dstUV += dstUVStride << 1;
743 srcU += srcUStride;
744 srcV += srcVStride;
745 }
746}
747
748
Pawin Vongmasa36653902018-11-15 00:10:25 -0800749std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
750 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
751 mQueue.pop_front();
752 return work;
753}
754
755void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
756 mQueue.push_back({ std::move(work), NO_DRAIN });
757}
758
759bool SimpleC2Component::WorkQueue::empty() const {
760 return mQueue.empty();
761}
762
763void SimpleC2Component::WorkQueue::clear() {
764 mQueue.clear();
765}
766
767uint32_t SimpleC2Component::WorkQueue::drainMode() const {
768 return mQueue.front().drainMode;
769}
770
771void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
772 mQueue.push_back({ nullptr, drainMode });
773}
774
775////////////////////////////////////////////////////////////////////////////////
776
777SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
778
779void SimpleC2Component::WorkHandler::setComponent(
780 const std::shared_ptr<SimpleC2Component> &thiz) {
781 mThiz = thiz;
782}
783
784static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
785 sp<AReplyToken> replyId;
786 CHECK(msg->senderAwaitsResponse(&replyId));
787 sp<AMessage> reply = new AMessage;
788 if (err) {
789 reply->setInt32("err", *err);
790 }
791 reply->postReply(replyId);
792}
793
794void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
795 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
796 if (!thiz) {
797 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
798 sp<AReplyToken> replyId;
799 if (msg->senderAwaitsResponse(&replyId)) {
800 sp<AMessage> reply = new AMessage;
801 reply->setInt32("err", C2_CORRUPTED);
802 reply->postReply(replyId);
803 }
804 return;
805 }
806
807 switch (msg->what()) {
808 case kWhatProcess: {
809 if (mRunning) {
810 if (thiz->processQueue()) {
811 (new AMessage(kWhatProcess, this))->post();
812 }
813 } else {
814 ALOGV("Ignore process message as we're not running");
815 }
816 break;
817 }
818 case kWhatInit: {
819 int32_t err = thiz->onInit();
820 Reply(msg, &err);
821 [[fallthrough]];
822 }
823 case kWhatStart: {
824 mRunning = true;
825 break;
826 }
827 case kWhatStop: {
828 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700829 thiz->mOutputBlockPool.reset();
Sungtak Lee8175aea2024-05-07 22:32:38 +0000830 mRunning = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800831 Reply(msg, &err);
832 break;
833 }
834 case kWhatReset: {
835 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700836 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800837 mRunning = false;
838 Reply(msg);
839 break;
840 }
841 case kWhatRelease: {
842 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700843 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800844 mRunning = false;
845 Reply(msg);
846 break;
847 }
848 default: {
849 ALOGD("Unrecognized msg: %d", msg->what());
850 break;
851 }
852 }
853}
854
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800855class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
856public:
857 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
858
859 virtual local_id_t getLocalId() const override {
860 return mBase->getLocalId();
861 }
862
863 virtual C2Allocator::id_t getAllocatorId() const override {
864 return mBase->getAllocatorId();
865 }
866
867 virtual c2_status_t fetchLinearBlock(
868 uint32_t capacity,
869 C2MemoryUsage usage,
870 std::shared_ptr<C2LinearBlock>* block) {
871 c2_status_t status;
872 do {
873 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800874 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800875 return status;
876 }
877
878 virtual c2_status_t fetchCircularBlock(
879 uint32_t capacity,
880 C2MemoryUsage usage,
881 std::shared_ptr<C2CircularBlock>* block) {
882 c2_status_t status;
883 do {
884 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800885 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800886 return status;
887 }
888
889 virtual c2_status_t fetchGraphicBlock(
890 uint32_t width, uint32_t height, uint32_t format,
891 C2MemoryUsage usage,
892 std::shared_ptr<C2GraphicBlock>* block) {
893 c2_status_t status;
894 do {
895 status = mBase->fetchGraphicBlock(width, height, format, usage,
896 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800897 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800898 return status;
899 }
900
901private:
902 std::shared_ptr<C2BlockPool> mBase;
903};
904
Pawin Vongmasa36653902018-11-15 00:10:25 -0800905////////////////////////////////////////////////////////////////////////////////
906
907namespace {
908
909struct DummyReadView : public C2ReadView {
910 DummyReadView() : C2ReadView(C2_NO_INIT) {}
911};
912
913} // namespace
914
915SimpleC2Component::SimpleC2Component(
916 const std::shared_ptr<C2ComponentInterface> &intf)
917 : mDummyReadView(DummyReadView()),
918 mIntf(intf),
919 mLooper(new ALooper),
920 mHandler(new WorkHandler) {
921 mLooper->setName(intf->getName().c_str());
922 (void)mLooper->registerHandler(mHandler);
923 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
924}
925
926SimpleC2Component::~SimpleC2Component() {
927 mLooper->unregisterHandler(mHandler->id());
928 (void)mLooper->stop();
929}
930
931c2_status_t SimpleC2Component::setListener_vb(
932 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
933 mHandler->setComponent(shared_from_this());
934
935 Mutexed<ExecState>::Locked state(mExecState);
936 if (state->mState == RUNNING) {
937 if (listener) {
938 return C2_BAD_STATE;
939 } else if (!mayBlock) {
940 return C2_BLOCKING;
941 }
942 }
943 state->mListener = listener;
944 // TODO: wait for listener change to have taken place before returning
945 // (e.g. if there is an ongoing listener callback)
946 return C2_OK;
947}
948
949c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
950 {
951 Mutexed<ExecState>::Locked state(mExecState);
952 if (state->mState != RUNNING) {
953 return C2_BAD_STATE;
954 }
955 }
956 bool queueWasEmpty = false;
957 {
958 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
959 queueWasEmpty = queue->empty();
960 while (!items->empty()) {
961 queue->push_back(std::move(items->front()));
962 items->pop_front();
963 }
964 }
965 if (queueWasEmpty) {
966 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
967 }
968 return C2_OK;
969}
970
971c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
972 (void)items;
973 return C2_OMITTED;
974}
975
976c2_status_t SimpleC2Component::flush_sm(
977 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
978 (void)flushMode;
979 {
980 Mutexed<ExecState>::Locked state(mExecState);
981 if (state->mState != RUNNING) {
982 return C2_BAD_STATE;
983 }
984 }
985 {
986 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
987 queue->incGeneration();
988 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
989 while (!queue->empty()) {
990 std::unique_ptr<C2Work> work = queue->pop_front();
991 if (work) {
992 flushedWork->push_back(std::move(work));
993 }
994 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700995 while (!queue->pending().empty()) {
996 flushedWork->push_back(std::move(queue->pending().begin()->second));
997 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800998 }
999 }
1000
1001 return C2_OK;
1002}
1003
1004c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
1005 if (drainMode == DRAIN_CHAIN) {
1006 return C2_OMITTED;
1007 }
1008 {
1009 Mutexed<ExecState>::Locked state(mExecState);
1010 if (state->mState != RUNNING) {
1011 return C2_BAD_STATE;
1012 }
1013 }
1014 bool queueWasEmpty = false;
1015 {
1016 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1017 queueWasEmpty = queue->empty();
1018 queue->markDrain(drainMode);
1019 }
1020 if (queueWasEmpty) {
1021 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
1022 }
1023
1024 return C2_OK;
1025}
1026
1027c2_status_t SimpleC2Component::start() {
1028 Mutexed<ExecState>::Locked state(mExecState);
1029 if (state->mState == RUNNING) {
1030 return C2_BAD_STATE;
1031 }
1032 bool needsInit = (state->mState == UNINITIALIZED);
1033 state.unlock();
1034 if (needsInit) {
1035 sp<AMessage> reply;
1036 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
1037 int32_t err;
1038 CHECK(reply->findInt32("err", &err));
1039 if (err != C2_OK) {
1040 return (c2_status_t)err;
1041 }
1042 } else {
1043 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
1044 }
1045 state.lock();
1046 state->mState = RUNNING;
1047 return C2_OK;
1048}
1049
1050c2_status_t SimpleC2Component::stop() {
1051 ALOGV("stop");
1052 {
1053 Mutexed<ExecState>::Locked state(mExecState);
1054 if (state->mState != RUNNING) {
1055 return C2_BAD_STATE;
1056 }
1057 state->mState = STOPPED;
1058 }
1059 {
1060 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1061 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -07001062 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001063 }
1064 sp<AMessage> reply;
1065 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
1066 int32_t err;
1067 CHECK(reply->findInt32("err", &err));
1068 if (err != C2_OK) {
1069 return (c2_status_t)err;
1070 }
1071 return C2_OK;
1072}
1073
1074c2_status_t SimpleC2Component::reset() {
1075 ALOGV("reset");
1076 {
1077 Mutexed<ExecState>::Locked state(mExecState);
1078 state->mState = UNINITIALIZED;
1079 }
1080 {
1081 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1082 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -07001083 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001084 }
1085 sp<AMessage> reply;
1086 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
1087 return C2_OK;
1088}
1089
1090c2_status_t SimpleC2Component::release() {
1091 ALOGV("release");
1092 sp<AMessage> reply;
1093 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
1094 return C2_OK;
1095}
1096
1097std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
1098 return mIntf;
1099}
1100
1101namespace {
1102
1103std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
1104 std::list<std::unique_ptr<C2Work>> ret;
1105 ret.push_back(std::move(work));
1106 return ret;
1107}
1108
1109} // namespace
1110
1111void SimpleC2Component::finish(
1112 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
1113 std::unique_ptr<C2Work> work;
1114 {
Wonsik Kime1226f52019-04-04 15:24:41 -07001115 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1116 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001117 ALOGW("unknown frame index: %" PRIu64, frameIndex);
1118 return;
1119 }
Wonsik Kime1226f52019-04-04 15:24:41 -07001120 work = std::move(queue->pending().at(frameIndex));
1121 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001122 }
1123 if (work) {
1124 fillWork(work);
1125 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
1126 listener->onWorkDone_nb(shared_from_this(), vec(work));
1127 ALOGV("returning pending work");
1128 }
1129}
1130
1131void SimpleC2Component::cloneAndSend(
1132 uint64_t frameIndex,
1133 const std::unique_ptr<C2Work> &currentWork,
1134 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
1135 std::unique_ptr<C2Work> work(new C2Work);
1136 if (currentWork->input.ordinal.frameIndex == frameIndex) {
1137 work->input.flags = currentWork->input.flags;
1138 work->input.ordinal = currentWork->input.ordinal;
1139 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -07001140 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1141 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001142 ALOGW("unknown frame index: %" PRIu64, frameIndex);
1143 return;
1144 }
Wonsik Kime1226f52019-04-04 15:24:41 -07001145 work->input.flags = queue->pending().at(frameIndex)->input.flags;
1146 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001147 }
1148 work->worklets.emplace_back(new C2Worklet);
1149 if (work) {
1150 fillWork(work);
1151 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
1152 listener->onWorkDone_nb(shared_from_this(), vec(work));
1153 ALOGV("cloned and sending work");
1154 }
1155}
1156
1157bool SimpleC2Component::processQueue() {
1158 std::unique_ptr<C2Work> work;
1159 uint64_t generation;
1160 int32_t drainMode;
1161 bool isFlushPending = false;
1162 bool hasQueuedWork = false;
1163 {
1164 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1165 if (queue->empty()) {
1166 return false;
1167 }
1168
1169 generation = queue->generation();
1170 drainMode = queue->drainMode();
1171 isFlushPending = queue->popPendingFlush();
1172 work = queue->pop_front();
1173 hasQueuedWork = !queue->empty();
1174 }
1175 if (isFlushPending) {
1176 ALOGV("processing pending flush");
1177 c2_status_t err = onFlush_sm();
1178 if (err != C2_OK) {
1179 ALOGD("flush err: %d", err);
1180 // TODO: error
1181 }
1182 }
1183
1184 if (!mOutputBlockPool) {
1185 c2_status_t err = [this] {
1186 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001187 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001188 std::vector<std::unique_ptr<C2Param>> params;
1189 c2_status_t err = intf()->query_vb(
1190 { &outputFormat },
1191 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
1192 C2_DONT_BLOCK,
1193 &params);
1194 if (err != C2_OK && err != C2_BAD_INDEX) {
1195 ALOGD("query err = %d", err);
1196 return err;
1197 }
1198 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001199 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -08001200 ? C2BlockPool::BASIC_GRAPHIC
1201 : C2BlockPool::BASIC_LINEAR;
1202 if (params.size()) {
1203 C2PortBlockPoolsTuning::output *outputPools =
1204 C2PortBlockPoolsTuning::output::From(params[0].get());
1205 if (outputPools && outputPools->flexCount() >= 1) {
1206 poolId = outputPools->m.values[0];
1207 }
1208 }
1209
Wonsik Kim0cb5a092019-01-03 16:38:22 -08001210 std::shared_ptr<C2BlockPool> blockPool;
1211 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001212 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
1213 (unsigned long long)poolId,
1214 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -08001215 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -08001216 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -08001217 if (err == C2_OK) {
1218 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
1219 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001220 return err;
1221 }();
1222 if (err != C2_OK) {
1223 Mutexed<ExecState>::Locked state(mExecState);
1224 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1225 state.unlock();
1226 listener->onError_nb(shared_from_this(), err);
1227 return hasQueuedWork;
1228 }
1229 }
1230
1231 if (!work) {
1232 c2_status_t err = drain(drainMode, mOutputBlockPool);
1233 if (err != C2_OK) {
1234 Mutexed<ExecState>::Locked state(mExecState);
1235 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1236 state.unlock();
1237 listener->onError_nb(shared_from_this(), err);
1238 }
1239 return hasQueuedWork;
1240 }
1241
1242 {
1243 std::vector<C2Param *> updates;
1244 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
1245 if (param) {
1246 updates.emplace_back(param.get());
1247 }
1248 }
1249 if (!updates.empty()) {
1250 std::vector<std::unique_ptr<C2SettingResult>> failures;
1251 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
1252 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
1253 }
1254 }
1255
1256 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001257 // If input buffer list is not empty, it means we have some input to process on.
1258 // However, input could be a null buffer. In such case, clear the buffer list
1259 // before making call to process().
1260 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
1261 ALOGD("Encountered null input buffer. Clearing the input buffer");
1262 work->input.buffers.clear();
1263 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001264 process(work, mOutputBlockPool);
1265 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -07001266 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1267 if (queue->generation() != generation) {
1268 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
1269 queue->generation(), generation);
1270 work->result = C2_NOT_FOUND;
1271 queue.unlock();
1272
1273 Mutexed<ExecState>::Locked state(mExecState);
1274 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1275 state.unlock();
1276 listener->onWorkDone_nb(shared_from_this(), vec(work));
1277 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001278 }
1279 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -07001280 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001281 Mutexed<ExecState>::Locked state(mExecState);
1282 ALOGV("returning this work");
1283 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1284 state.unlock();
1285 listener->onWorkDone_nb(shared_from_this(), vec(work));
1286 } else {
1287 ALOGV("queue pending work");
1288 work->input.buffers.clear();
1289 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -07001290
1291 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
1292 if (queue->pending().count(frameIndex) != 0) {
1293 unexpected = std::move(queue->pending().at(frameIndex));
1294 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001295 }
Wonsik Kime1226f52019-04-04 15:24:41 -07001296 (void)queue->pending().insert({ frameIndex, std::move(work) });
1297
1298 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001299 if (unexpected) {
1300 ALOGD("unexpected pending work");
1301 unexpected->result = C2_CORRUPTED;
1302 Mutexed<ExecState>::Locked state(mExecState);
1303 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1304 state.unlock();
1305 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
1306 }
1307 }
1308 return hasQueuedWork;
1309}
1310
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001311int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
1312 // Save supported hal pixel formats for bit depth of 10, the first time this is called
1313 if (!mBitDepth10HalPixelFormats.size()) {
1314 std::vector<int> halPixelFormats;
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001315 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
1316
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001317 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
1318 // is populated only once, allowRGBA1010102 is not considered at this stage.
1319 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
1320
1321 for (int halPixelFormat : halPixelFormats) {
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001322 if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001323 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
1324 }
1325 }
1326 // Add YV12 in the end as a fall-back option
1327 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
1328 }
Harish Mahendrakar5c467652022-04-28 19:47:28 -07001329 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
1330 // RGBA 1010102 format unlike earlier versions where it was used to represent
1331 // YUVA 1010102 data
1332 if (!isAtLeastT()) {
1333 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
1334 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
1335 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
1336 return HAL_PIXEL_FORMAT_YV12;
1337 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001338 }
1339 // Return the first entry from supported formats
1340 return mBitDepth10HalPixelFormats[0];
1341}
Pawin Vongmasa36653902018-11-15 00:10:25 -08001342std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001343 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
1344 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
1345}
1346
1347std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001348 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
1349 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
1350}
1351
1352} // namespace android