blob: d549c3ba91db9bd550bb7bb5f2cc285a2f072fa6 [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,
41 size_t dstUVStride, uint32_t width, uint32_t height,
42 bool isMonochrome) {
43 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);
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080054 dstV += dstUVStride;
55 dstU += dstUVStride;
56 }
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;
63 dstV += dstUVStride;
64 }
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;
69 dstU += dstUVStride;
70 }
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
Pawin Vongmasa36653902018-11-15 00:10:25 -0800455std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
456 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
457 mQueue.pop_front();
458 return work;
459}
460
461void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
462 mQueue.push_back({ std::move(work), NO_DRAIN });
463}
464
465bool SimpleC2Component::WorkQueue::empty() const {
466 return mQueue.empty();
467}
468
469void SimpleC2Component::WorkQueue::clear() {
470 mQueue.clear();
471}
472
473uint32_t SimpleC2Component::WorkQueue::drainMode() const {
474 return mQueue.front().drainMode;
475}
476
477void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
478 mQueue.push_back({ nullptr, drainMode });
479}
480
481////////////////////////////////////////////////////////////////////////////////
482
483SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
484
485void SimpleC2Component::WorkHandler::setComponent(
486 const std::shared_ptr<SimpleC2Component> &thiz) {
487 mThiz = thiz;
488}
489
490static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
491 sp<AReplyToken> replyId;
492 CHECK(msg->senderAwaitsResponse(&replyId));
493 sp<AMessage> reply = new AMessage;
494 if (err) {
495 reply->setInt32("err", *err);
496 }
497 reply->postReply(replyId);
498}
499
500void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
501 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
502 if (!thiz) {
503 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
504 sp<AReplyToken> replyId;
505 if (msg->senderAwaitsResponse(&replyId)) {
506 sp<AMessage> reply = new AMessage;
507 reply->setInt32("err", C2_CORRUPTED);
508 reply->postReply(replyId);
509 }
510 return;
511 }
512
513 switch (msg->what()) {
514 case kWhatProcess: {
515 if (mRunning) {
516 if (thiz->processQueue()) {
517 (new AMessage(kWhatProcess, this))->post();
518 }
519 } else {
520 ALOGV("Ignore process message as we're not running");
521 }
522 break;
523 }
524 case kWhatInit: {
525 int32_t err = thiz->onInit();
526 Reply(msg, &err);
527 [[fallthrough]];
528 }
529 case kWhatStart: {
530 mRunning = true;
531 break;
532 }
533 case kWhatStop: {
534 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700535 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800536 Reply(msg, &err);
537 break;
538 }
539 case kWhatReset: {
540 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700541 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800542 mRunning = false;
543 Reply(msg);
544 break;
545 }
546 case kWhatRelease: {
547 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700548 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800549 mRunning = false;
550 Reply(msg);
551 break;
552 }
553 default: {
554 ALOGD("Unrecognized msg: %d", msg->what());
555 break;
556 }
557 }
558}
559
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800560class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
561public:
562 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
563
564 virtual local_id_t getLocalId() const override {
565 return mBase->getLocalId();
566 }
567
568 virtual C2Allocator::id_t getAllocatorId() const override {
569 return mBase->getAllocatorId();
570 }
571
572 virtual c2_status_t fetchLinearBlock(
573 uint32_t capacity,
574 C2MemoryUsage usage,
575 std::shared_ptr<C2LinearBlock>* block) {
576 c2_status_t status;
577 do {
578 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800579 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800580 return status;
581 }
582
583 virtual c2_status_t fetchCircularBlock(
584 uint32_t capacity,
585 C2MemoryUsage usage,
586 std::shared_ptr<C2CircularBlock>* block) {
587 c2_status_t status;
588 do {
589 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800590 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800591 return status;
592 }
593
594 virtual c2_status_t fetchGraphicBlock(
595 uint32_t width, uint32_t height, uint32_t format,
596 C2MemoryUsage usage,
597 std::shared_ptr<C2GraphicBlock>* block) {
598 c2_status_t status;
599 do {
600 status = mBase->fetchGraphicBlock(width, height, format, usage,
601 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800602 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800603 return status;
604 }
605
606private:
607 std::shared_ptr<C2BlockPool> mBase;
608};
609
Pawin Vongmasa36653902018-11-15 00:10:25 -0800610////////////////////////////////////////////////////////////////////////////////
611
612namespace {
613
614struct DummyReadView : public C2ReadView {
615 DummyReadView() : C2ReadView(C2_NO_INIT) {}
616};
617
618} // namespace
619
620SimpleC2Component::SimpleC2Component(
621 const std::shared_ptr<C2ComponentInterface> &intf)
622 : mDummyReadView(DummyReadView()),
623 mIntf(intf),
624 mLooper(new ALooper),
625 mHandler(new WorkHandler) {
626 mLooper->setName(intf->getName().c_str());
627 (void)mLooper->registerHandler(mHandler);
628 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
629}
630
631SimpleC2Component::~SimpleC2Component() {
632 mLooper->unregisterHandler(mHandler->id());
633 (void)mLooper->stop();
634}
635
636c2_status_t SimpleC2Component::setListener_vb(
637 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
638 mHandler->setComponent(shared_from_this());
639
640 Mutexed<ExecState>::Locked state(mExecState);
641 if (state->mState == RUNNING) {
642 if (listener) {
643 return C2_BAD_STATE;
644 } else if (!mayBlock) {
645 return C2_BLOCKING;
646 }
647 }
648 state->mListener = listener;
649 // TODO: wait for listener change to have taken place before returning
650 // (e.g. if there is an ongoing listener callback)
651 return C2_OK;
652}
653
654c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
655 {
656 Mutexed<ExecState>::Locked state(mExecState);
657 if (state->mState != RUNNING) {
658 return C2_BAD_STATE;
659 }
660 }
661 bool queueWasEmpty = false;
662 {
663 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
664 queueWasEmpty = queue->empty();
665 while (!items->empty()) {
666 queue->push_back(std::move(items->front()));
667 items->pop_front();
668 }
669 }
670 if (queueWasEmpty) {
671 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
672 }
673 return C2_OK;
674}
675
676c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
677 (void)items;
678 return C2_OMITTED;
679}
680
681c2_status_t SimpleC2Component::flush_sm(
682 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
683 (void)flushMode;
684 {
685 Mutexed<ExecState>::Locked state(mExecState);
686 if (state->mState != RUNNING) {
687 return C2_BAD_STATE;
688 }
689 }
690 {
691 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
692 queue->incGeneration();
693 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
694 while (!queue->empty()) {
695 std::unique_ptr<C2Work> work = queue->pop_front();
696 if (work) {
697 flushedWork->push_back(std::move(work));
698 }
699 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700700 while (!queue->pending().empty()) {
701 flushedWork->push_back(std::move(queue->pending().begin()->second));
702 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800703 }
704 }
705
706 return C2_OK;
707}
708
709c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
710 if (drainMode == DRAIN_CHAIN) {
711 return C2_OMITTED;
712 }
713 {
714 Mutexed<ExecState>::Locked state(mExecState);
715 if (state->mState != RUNNING) {
716 return C2_BAD_STATE;
717 }
718 }
719 bool queueWasEmpty = false;
720 {
721 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
722 queueWasEmpty = queue->empty();
723 queue->markDrain(drainMode);
724 }
725 if (queueWasEmpty) {
726 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
727 }
728
729 return C2_OK;
730}
731
732c2_status_t SimpleC2Component::start() {
733 Mutexed<ExecState>::Locked state(mExecState);
734 if (state->mState == RUNNING) {
735 return C2_BAD_STATE;
736 }
737 bool needsInit = (state->mState == UNINITIALIZED);
738 state.unlock();
739 if (needsInit) {
740 sp<AMessage> reply;
741 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
742 int32_t err;
743 CHECK(reply->findInt32("err", &err));
744 if (err != C2_OK) {
745 return (c2_status_t)err;
746 }
747 } else {
748 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
749 }
750 state.lock();
751 state->mState = RUNNING;
752 return C2_OK;
753}
754
755c2_status_t SimpleC2Component::stop() {
756 ALOGV("stop");
757 {
758 Mutexed<ExecState>::Locked state(mExecState);
759 if (state->mState != RUNNING) {
760 return C2_BAD_STATE;
761 }
762 state->mState = STOPPED;
763 }
764 {
765 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
766 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700767 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800768 }
769 sp<AMessage> reply;
770 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
771 int32_t err;
772 CHECK(reply->findInt32("err", &err));
773 if (err != C2_OK) {
774 return (c2_status_t)err;
775 }
776 return C2_OK;
777}
778
779c2_status_t SimpleC2Component::reset() {
780 ALOGV("reset");
781 {
782 Mutexed<ExecState>::Locked state(mExecState);
783 state->mState = UNINITIALIZED;
784 }
785 {
786 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
787 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700788 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800789 }
790 sp<AMessage> reply;
791 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
792 return C2_OK;
793}
794
795c2_status_t SimpleC2Component::release() {
796 ALOGV("release");
797 sp<AMessage> reply;
798 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
799 return C2_OK;
800}
801
802std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
803 return mIntf;
804}
805
806namespace {
807
808std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
809 std::list<std::unique_ptr<C2Work>> ret;
810 ret.push_back(std::move(work));
811 return ret;
812}
813
814} // namespace
815
816void SimpleC2Component::finish(
817 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
818 std::unique_ptr<C2Work> work;
819 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700820 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
821 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800822 ALOGW("unknown frame index: %" PRIu64, frameIndex);
823 return;
824 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700825 work = std::move(queue->pending().at(frameIndex));
826 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800827 }
828 if (work) {
829 fillWork(work);
830 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
831 listener->onWorkDone_nb(shared_from_this(), vec(work));
832 ALOGV("returning pending work");
833 }
834}
835
836void SimpleC2Component::cloneAndSend(
837 uint64_t frameIndex,
838 const std::unique_ptr<C2Work> &currentWork,
839 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
840 std::unique_ptr<C2Work> work(new C2Work);
841 if (currentWork->input.ordinal.frameIndex == frameIndex) {
842 work->input.flags = currentWork->input.flags;
843 work->input.ordinal = currentWork->input.ordinal;
844 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700845 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
846 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800847 ALOGW("unknown frame index: %" PRIu64, frameIndex);
848 return;
849 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700850 work->input.flags = queue->pending().at(frameIndex)->input.flags;
851 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800852 }
853 work->worklets.emplace_back(new C2Worklet);
854 if (work) {
855 fillWork(work);
856 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
857 listener->onWorkDone_nb(shared_from_this(), vec(work));
858 ALOGV("cloned and sending work");
859 }
860}
861
862bool SimpleC2Component::processQueue() {
863 std::unique_ptr<C2Work> work;
864 uint64_t generation;
865 int32_t drainMode;
866 bool isFlushPending = false;
867 bool hasQueuedWork = false;
868 {
869 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
870 if (queue->empty()) {
871 return false;
872 }
873
874 generation = queue->generation();
875 drainMode = queue->drainMode();
876 isFlushPending = queue->popPendingFlush();
877 work = queue->pop_front();
878 hasQueuedWork = !queue->empty();
879 }
880 if (isFlushPending) {
881 ALOGV("processing pending flush");
882 c2_status_t err = onFlush_sm();
883 if (err != C2_OK) {
884 ALOGD("flush err: %d", err);
885 // TODO: error
886 }
887 }
888
889 if (!mOutputBlockPool) {
890 c2_status_t err = [this] {
891 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800892 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800893 std::vector<std::unique_ptr<C2Param>> params;
894 c2_status_t err = intf()->query_vb(
895 { &outputFormat },
896 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
897 C2_DONT_BLOCK,
898 &params);
899 if (err != C2_OK && err != C2_BAD_INDEX) {
900 ALOGD("query err = %d", err);
901 return err;
902 }
903 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800904 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800905 ? C2BlockPool::BASIC_GRAPHIC
906 : C2BlockPool::BASIC_LINEAR;
907 if (params.size()) {
908 C2PortBlockPoolsTuning::output *outputPools =
909 C2PortBlockPoolsTuning::output::From(params[0].get());
910 if (outputPools && outputPools->flexCount() >= 1) {
911 poolId = outputPools->m.values[0];
912 }
913 }
914
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800915 std::shared_ptr<C2BlockPool> blockPool;
916 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800917 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
918 (unsigned long long)poolId,
919 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800920 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800921 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800922 if (err == C2_OK) {
923 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
924 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800925 return err;
926 }();
927 if (err != C2_OK) {
928 Mutexed<ExecState>::Locked state(mExecState);
929 std::shared_ptr<C2Component::Listener> listener = state->mListener;
930 state.unlock();
931 listener->onError_nb(shared_from_this(), err);
932 return hasQueuedWork;
933 }
934 }
935
936 if (!work) {
937 c2_status_t err = drain(drainMode, mOutputBlockPool);
938 if (err != C2_OK) {
939 Mutexed<ExecState>::Locked state(mExecState);
940 std::shared_ptr<C2Component::Listener> listener = state->mListener;
941 state.unlock();
942 listener->onError_nb(shared_from_this(), err);
943 }
944 return hasQueuedWork;
945 }
946
947 {
948 std::vector<C2Param *> updates;
949 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
950 if (param) {
951 updates.emplace_back(param.get());
952 }
953 }
954 if (!updates.empty()) {
955 std::vector<std::unique_ptr<C2SettingResult>> failures;
956 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
957 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
958 }
959 }
960
961 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800962 // If input buffer list is not empty, it means we have some input to process on.
963 // However, input could be a null buffer. In such case, clear the buffer list
964 // before making call to process().
965 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
966 ALOGD("Encountered null input buffer. Clearing the input buffer");
967 work->input.buffers.clear();
968 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800969 process(work, mOutputBlockPool);
970 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -0700971 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
972 if (queue->generation() != generation) {
973 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
974 queue->generation(), generation);
975 work->result = C2_NOT_FOUND;
976 queue.unlock();
977
978 Mutexed<ExecState>::Locked state(mExecState);
979 std::shared_ptr<C2Component::Listener> listener = state->mListener;
980 state.unlock();
981 listener->onWorkDone_nb(shared_from_this(), vec(work));
982 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800983 }
984 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -0700985 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800986 Mutexed<ExecState>::Locked state(mExecState);
987 ALOGV("returning this work");
988 std::shared_ptr<C2Component::Listener> listener = state->mListener;
989 state.unlock();
990 listener->onWorkDone_nb(shared_from_this(), vec(work));
991 } else {
992 ALOGV("queue pending work");
993 work->input.buffers.clear();
994 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -0700995
996 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
997 if (queue->pending().count(frameIndex) != 0) {
998 unexpected = std::move(queue->pending().at(frameIndex));
999 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001000 }
Wonsik Kime1226f52019-04-04 15:24:41 -07001001 (void)queue->pending().insert({ frameIndex, std::move(work) });
1002
1003 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001004 if (unexpected) {
1005 ALOGD("unexpected pending work");
1006 unexpected->result = C2_CORRUPTED;
1007 Mutexed<ExecState>::Locked state(mExecState);
1008 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1009 state.unlock();
1010 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
1011 }
1012 }
1013 return hasQueuedWork;
1014}
1015
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001016int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
1017 // Save supported hal pixel formats for bit depth of 10, the first time this is called
1018 if (!mBitDepth10HalPixelFormats.size()) {
1019 std::vector<int> halPixelFormats;
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001020 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
1021
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001022 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
1023 // is populated only once, allowRGBA1010102 is not considered at this stage.
1024 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
1025
1026 for (int halPixelFormat : halPixelFormats) {
Harish Mahendrakarf5dec502022-04-13 15:53:55 -07001027 if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001028 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
1029 }
1030 }
1031 // Add YV12 in the end as a fall-back option
1032 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
1033 }
Harish Mahendrakar5c467652022-04-28 19:47:28 -07001034 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
1035 // RGBA 1010102 format unlike earlier versions where it was used to represent
1036 // YUVA 1010102 data
1037 if (!isAtLeastT()) {
1038 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
1039 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
1040 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
1041 return HAL_PIXEL_FORMAT_YV12;
1042 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -08001043 }
1044 // Return the first entry from supported formats
1045 return mBitDepth10HalPixelFormats[0];
1046}
Pawin Vongmasa36653902018-11-15 00:10:25 -08001047std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001048 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
1049 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
1050}
1051
1052std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001053 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
1054 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
1055}
1056
1057} // namespace android