1 /*
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
21 #include <android/hardware_buffer.h>
22 #include <cutils/properties.h>
23 #include <media/stagefright/foundation/AMessage.h>
24 #include <media/stagefright/foundation/AUtils.h>
25
26 #include <inttypes.h>
27 #include <libyuv.h>
28
29 #include <C2Config.h>
30 #include <C2Debug.h>
31 #include <C2PlatformSupport.h>
32 #include <Codec2BufferUtils.h>
33 #include <Codec2CommonUtils.h>
34 #include <SimpleC2Component.h>
35
36 namespace android {
37
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
46 constexpr uint8_t kNeutralUVBitDepth8 = 128;
47 constexpr uint16_t kNeutralUVBitDepth10 = 512;
48
convertYUV420Planar8ToYV12(uint8_t * dstY,uint8_t * dstU,uint8_t * dstV,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUStride,size_t dstVStride,uint32_t width,uint32_t height,bool isMonochrome)49 void 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,
52 size_t dstUStride, size_t dstVStride, uint32_t width,
53 uint32_t height, bool isMonochrome) {
54 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.
62 for (size_t i = 0; i < (height + 1) / 2; ++i) {
63 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
64 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
65 dstV += dstVStride;
66 dstU += dstUStride;
67 }
68 return;
69 }
70
71 for (size_t i = 0; i < (height + 1) / 2; ++i) {
72 memcpy(dstV, srcV, (width + 1) / 2);
73 srcV += srcVStride;
74 dstV += dstVStride;
75 }
76
77 for (size_t i = 0; i < (height + 1) / 2; ++i) {
78 memcpy(dstU, srcU, (width + 1) / 2);
79 srcU += srcUStride;
80 dstU += dstUStride;
81 }
82 }
83
convertYUV420Planar16ToY410(uint32_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstStride,size_t width,size_t height)84 void 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 }
147
148 namespace {
149
FillMissingColorAspects(std::shared_ptr<const C2ColorAspectsStruct> aspects,int32_t width,int32_t height)150 static 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)
203 struct Coeffs {
204 int32_t _y, _r_v, _g_u, _g_v, _b_u, _c16;
205 };
206
GetCoeffsForAspects(const C2ColorAspectsStruct & aspects)207 static 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
248 #define CLIP3(min, v, max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
convertYUV420Planar16ToRGBA1010102(uint32_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstStride,size_t width,size_t height,std::shared_ptr<const C2ColorAspectsStruct> aspects)249 void 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
267 // 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;
275
276 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
283 y00 = *ySrcTop - _c16;
284 ySrcTop += 1;
285 y01 = *ySrcTop - _c16;
286 ySrcTop += 1;
287 y10 = *ySrcBot - _c16;
288 ySrcBot += 1;
289 y11 = *ySrcBot - _c16;
290 ySrcBot += 1;
291
292 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;
296
297 int32_t yMult, b, g, r;
298 yMult = y00 * _y + 512;
299 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
307 yMult = y01 * _y + 512;
308 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
316 yMult = y10 * _y + 512;
317 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
325 yMult = y11 * _y + 512;
326 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
convertYUV420Planar16ToY410OrRGBA1010102(uint32_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstStride,size_t width,size_t height,std::shared_ptr<const C2ColorAspectsStruct> aspects)342 void 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) {
348 if (isAtLeastT()) {
349 convertYUV420Planar16ToRGBA1010102(dst, srcY, srcU, srcV, srcYStride, srcUStride,
350 srcVStride, dstStride, width, height, aspects);
351 } else {
352 convertYUV420Planar16ToY410(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
353 dstStride, width, height);
354 }
355 }
356
convertP210ToRGBA1010102(uint32_t * dst,const uint16_t * srcY,const uint16_t * srcUV,size_t srcYStride,size_t srcUVStride,size_t dstStride,size_t width,size_t height,std::shared_ptr<const C2ColorAspectsStruct> aspects)357 void convertP210ToRGBA1010102(uint32_t* dst, const uint16_t* srcY, const uint16_t* srcUV,
358 size_t srcYStride, size_t srcUVStride, size_t dstStride,
359 size_t width, size_t height,
360 std::shared_ptr<const C2ColorAspectsStruct> aspects) {
361 C2ColorAspectsStruct _aspects = FillMissingColorAspects(aspects, width, height);
362 struct Coeffs coeffs = GetCoeffsForAspects(_aspects);
363
364 int32_t _y = coeffs._y;
365 int32_t _b_u = coeffs._b_u;
366 int32_t _neg_g_u = -coeffs._g_u;
367 int32_t _neg_g_v = -coeffs._g_v;
368 int32_t _r_v = coeffs._r_v;
369 int32_t _c16 = coeffs._c16;
370
371 for (size_t y = 0; y < height; y++) {
372 uint32_t *dstTop = (uint32_t *)dst;
373 uint16_t *ySrcTop = (uint16_t *)srcY;
374 uint16_t *uSrc = (uint16_t *)srcUV;
375 uint16_t *vSrc = (uint16_t *)(srcUV + 1);
376 for (size_t x = 0; x < width; x += 2) {
377 int32_t u, v, y00, y01;
378 u = ((*uSrc) >> 6) - 512;
379 uSrc += 2;
380 v = ((*vSrc) >> 6) - 512;
381 vSrc += 2;
382
383 y00 = ((*ySrcTop) >> 6) - _c16;
384 ySrcTop += 1;
385 y01 = ((*ySrcTop) >> 6) - _c16;
386 ySrcTop += 1;
387
388 int32_t u_b = u * _b_u;
389 int32_t u_g = u * _neg_g_u;
390 int32_t v_g = v * _neg_g_v;
391 int32_t v_r = v * _r_v;
392
393 int32_t yMult, b, g, r;
394 yMult = y00 * _y + 512;
395 b = (yMult + u_b) / 1024;
396 g = (yMult + v_g + u_g) / 1024;
397 r = (yMult + v_r) / 1024;
398 b = CLIP3(0, b, 1023);
399 g = CLIP3(0, g, 1023);
400 r = CLIP3(0, r, 1023);
401 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
402
403 yMult = y01 * _y + 512;
404 b = (yMult + u_b) / 1024;
405 g = (yMult + v_g + u_g) / 1024;
406 r = (yMult + v_r) / 1024;
407 b = CLIP3(0, b, 1023);
408 g = CLIP3(0, g, 1023);
409 r = CLIP3(0, r, 1023);
410 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
411 }
412 srcY += srcYStride;
413 srcUV += srcUVStride;
414 dst += dstStride;
415 }
416 }
417
convertYUV420Planar16ToYV12(uint8_t * dstY,uint8_t * dstU,uint8_t * dstV,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height,bool isMonochrome)418 void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
419 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
420 size_t srcUStride, size_t srcVStride, size_t dstYStride,
421 size_t dstUVStride, size_t width, size_t height,
422 bool isMonochrome) {
423 for (size_t y = 0; y < height; ++y) {
424 for (size_t x = 0; x < width; ++x) {
425 dstY[x] = (uint8_t)(srcY[x] >> 2);
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 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
435 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
436 dstV += dstUVStride;
437 dstU += dstUVStride;
438 }
439 return;
440 }
441
442 for (size_t y = 0; y < (height + 1) / 2; ++y) {
443 for (size_t x = 0; x < (width + 1) / 2; ++x) {
444 dstU[x] = (uint8_t)(srcU[x] >> 2);
445 dstV[x] = (uint8_t)(srcV[x] >> 2);
446 }
447 srcU += srcUStride;
448 srcV += srcVStride;
449 dstU += dstUVStride;
450 dstV += dstUVStride;
451 }
452 }
453
convertYUV420Planar16ToP010(uint16_t * dstY,uint16_t * dstUV,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height,bool isMonochrome)454 void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
455 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
456 size_t srcUStride, size_t srcVStride, size_t dstYStride,
457 size_t dstUVStride, size_t width, size_t height,
458 bool isMonochrome) {
459 for (size_t y = 0; y < height; ++y) {
460 for (size_t x = 0; x < width; ++x) {
461 dstY[x] = srcY[x] << 6;
462 }
463 srcY += srcYStride;
464 dstY += dstYStride;
465 }
466
467 if (isMonochrome) {
468 // Fill with neutral U/V values.
469 for (size_t y = 0; y < (height + 1) / 2; ++y) {
470 for (size_t x = 0; x < (width + 1) / 2; ++x) {
471 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
472 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
473 }
474 dstUV += dstUVStride;
475 }
476 return;
477 }
478
479 for (size_t y = 0; y < (height + 1) / 2; ++y) {
480 for (size_t x = 0; x < (width + 1) / 2; ++x) {
481 dstUV[2 * x] = srcU[x] << 6;
482 dstUV[2 * x + 1] = srcV[x] << 6;
483 }
484 srcU += srcUStride;
485 srcV += srcVStride;
486 dstUV += dstUVStride;
487 }
488 }
489
convertP010ToYUV420Planar16(uint16_t * dstY,uint16_t * dstU,uint16_t * dstV,const uint16_t * srcY,const uint16_t * srcUV,size_t srcYStride,size_t srcUVStride,size_t dstYStride,size_t dstUStride,size_t dstVStride,size_t width,size_t height,bool isMonochrome)490 void convertP010ToYUV420Planar16(uint16_t *dstY, uint16_t *dstU, uint16_t *dstV,
491 const uint16_t *srcY, const uint16_t *srcUV,
492 size_t srcYStride, size_t srcUVStride, size_t dstYStride,
493 size_t dstUStride, size_t dstVStride, size_t width,
494 size_t height, bool isMonochrome) {
495 for (size_t y = 0; y < height; ++y) {
496 for (size_t x = 0; x < width; ++x) {
497 dstY[x] = srcY[x] >> 6;
498 }
499 srcY += srcYStride;
500 dstY += dstYStride;
501 }
502
503 if (isMonochrome) {
504 // Fill with neutral U/V values.
505 for (size_t y = 0; y < (height + 1) / 2; ++y) {
506 for (size_t x = 0; x < (width + 1) / 2; ++x) {
507 dstU[x] = kNeutralUVBitDepth10;
508 dstV[x] = kNeutralUVBitDepth10;
509 }
510 dstU += dstUStride;
511 dstV += dstVStride;
512 }
513 return;
514 }
515
516 for (size_t y = 0; y < (height + 1) / 2; ++y) {
517 for (size_t x = 0; x < (width + 1) / 2; ++x) {
518 dstU[x] = srcUV[2 * x] >> 6;
519 dstV[x] = srcUV[2 * x + 1] >> 6;
520 }
521 dstU += dstUStride;
522 dstV += dstVStride;
523 srcUV += srcUVStride;
524 }
525 }
526
convertP010ToP210(uint16_t * dstY,uint16_t * dstUV,const uint16_t * srcY,const uint16_t * srcUV,size_t srcYStride,size_t srcUVStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height)527 void convertP010ToP210(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY, const uint16_t *srcUV,
528 size_t srcYStride, size_t srcUVStride, size_t dstYStride, size_t dstUVStride,
529 size_t width, size_t height) {
530 for (size_t y = 0; y < height; ++y) {
531 std::memcpy(dstY + (y * dstYStride), srcY + (y * srcYStride), width * sizeof(uint16_t));
532 }
533
534 int32_t offsetTop, offsetBot;
535 for (size_t y = 0; y < (height + 1) / 2; ++y) {
536 std::memcpy(dstUV, srcUV, width * sizeof(uint16_t));
537 std::memcpy(dstUV + dstUVStride, srcUV, width * sizeof(uint16_t));
538 srcUV += srcUVStride;
539 dstUV += dstUVStride << 1;
540 }
541 }
542
543 static const int16_t bt709Matrix_10bit[2][3][3] = {
544 { { 218, 732, 74 }, { -117, -395, 512 }, { 512, -465, -47 } }, /* RANGE_FULL */
545 { { 186, 627, 63 }, { -103, -345, 448 }, { 448, -407, -41 } }, /* RANGE_LIMITED */
546 };
547
548 static const int16_t bt2020Matrix_10bit[2][3][3] = {
549 { { 269, 694, 61 }, { -143, -369, 512 }, { 512, -471, -41 } }, /* RANGE_FULL */
550 { { 230, 594, 52 }, { -125, -323, 448 }, { 448, -412, -36 } }, /* RANGE_LIMITED */
551 };
552
convertRGBA1010102ToYUV420Planar16(uint16_t * dstY,uint16_t * dstU,uint16_t * dstV,const uint32_t * srcRGBA,size_t srcRGBStride,size_t width,size_t height,C2Color::matrix_t colorMatrix,C2Color::range_t colorRange)553 void convertRGBA1010102ToYUV420Planar16(uint16_t* dstY, uint16_t* dstU, uint16_t* dstV,
554 const uint32_t* srcRGBA, size_t srcRGBStride, size_t width,
555 size_t height, C2Color::matrix_t colorMatrix,
556 C2Color::range_t colorRange) {
557 uint16_t r, g, b;
558 int32_t i32Y, i32U, i32V;
559 uint16_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 64;
560 uint16_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 1023 : 940;
561 uint16_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 1023 : 960;
562 // set default range as limited
563 if (colorRange != C2Color::RANGE_FULL) {
564 colorRange = C2Color::RANGE_LIMITED;
565 }
566 const int16_t(*weights)[3] = (colorMatrix == C2Color::MATRIX_BT709)
567 ? bt709Matrix_10bit[colorRange - 1]
568 : bt2020Matrix_10bit[colorRange - 1];
569
570 for (size_t y = 0; y < height; ++y) {
571 for (size_t x = 0; x < width; ++x) {
572 b = (srcRGBA[x] >> 20) & 0x3FF;
573 g = (srcRGBA[x] >> 10) & 0x3FF;
574 r = srcRGBA[x] & 0x3FF;
575
576 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2] + 512) >> 10) +
577 zeroLvl;
578 dstY[x] = CLIP3(zeroLvl, i32Y, maxLvlLuma);
579 if (y % 2 == 0 && x % 2 == 0) {
580 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2] + 512) >> 10) +
581 512;
582 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2] + 512) >> 10) +
583 512;
584 dstU[x >> 1] = CLIP3(zeroLvl, i32U, maxLvlChroma);
585 dstV[x >> 1] = CLIP3(zeroLvl, i32V, maxLvlChroma);
586 }
587 }
588 srcRGBA += srcRGBStride;
589 dstY += width;
590 if (y % 2 == 0) {
591 dstU += width / 2;
592 dstV += width / 2;
593 }
594 }
595 }
596
convertRGBA1010102ToP210(uint16_t * dstY,uint16_t * dstUV,const uint32_t * srcRGBA,size_t srcRGBStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height,C2Color::matrix_t colorMatrix,C2Color::range_t colorRange)597 void convertRGBA1010102ToP210(uint16_t* dstY, uint16_t* dstUV, const uint32_t* srcRGBA,
598 size_t srcRGBStride, size_t dstYStride, size_t dstUVStride,
599 size_t width, size_t height, C2Color::matrix_t colorMatrix,
600 C2Color::range_t colorRange) {
601 uint16_t r, g, b;
602 int32_t i32Y, i32U, i32V;
603 uint16_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 64;
604 uint16_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 1023 : 940;
605 uint16_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 1023 : 960;
606 // set default range as limited
607 if (colorRange != C2Color::RANGE_FULL) {
608 colorRange = C2Color::RANGE_LIMITED;
609 }
610 const int16_t(*weights)[3] = (colorMatrix == C2Color::MATRIX_BT709)
611 ? bt709Matrix_10bit[colorRange - 1]
612 : bt2020Matrix_10bit[colorRange - 1];
613
614 for (size_t y = 0; y < height; ++y) {
615 for (size_t x = 0; x < width; ++x) {
616 b = (srcRGBA[x] >> 20) & 0x3FF;
617 g = (srcRGBA[x] >> 10) & 0x3FF;
618 r = srcRGBA[x] & 0x3FF;
619
620 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2] + 512) >> 10) +
621 zeroLvl;
622 dstY[x] = (CLIP3(zeroLvl, i32Y, maxLvlLuma) << 6) & 0xFFC0;
623 if (x % 2 == 0) {
624 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2] + 512) >> 10) +
625 512;
626 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2] + 512) >> 10) +
627 512;
628 dstUV[x] = (CLIP3(zeroLvl, i32U, maxLvlChroma) << 6) & 0xFFC0;
629 dstUV[x + 1] = (CLIP3(zeroLvl, i32V, maxLvlChroma) << 6) & 0xFFC0;
630 }
631 }
632 srcRGBA += srcRGBStride;
633 dstY += dstYStride;
634 dstUV += dstUVStride;
635 }
636 }
637
638 // Matrix coefficient to convert RGB to Planar YUV data.
639 // Each sub-array represents the 3X3 coeff used with R, G and B
640 static const int16_t bt601Matrix[2][3][3] = {
641 { { 77, 150, 29 }, { -43, -85, 128 }, { 128, -107, -21 } }, /* RANGE_FULL */
642 { { 66, 129, 25 }, { -38, -74, 112 }, { 112, -94, -18 } }, /* RANGE_LIMITED */
643 };
644
645 static const int16_t bt709Matrix[2][3][3] = {
646 // TRICKY: 18 is adjusted to 19 so that sum of row 1 is 256
647 { { 54, 183, 19 }, { -29, -99, 128 }, { 128, -116, -12 } }, /* RANGE_FULL */
648 // TRICKY: -87 is adjusted to -86 so that sum of row 2 is 0
649 { { 47, 157, 16 }, { -26, -86, 112 }, { 112, -102, -10 } }, /* RANGE_LIMITED */
650 };
651
convertRGBToP210(uint16_t * dstY,uint16_t * dstUV,const uint32_t * srcRGBA,size_t srcRGBStride,size_t dstYStride,size_t dstUVStride,size_t width,size_t height,C2Color::matrix_t colorMatrix,C2Color::range_t colorRange)652 void convertRGBToP210(uint16_t* dstY, uint16_t* dstUV, const uint32_t* srcRGBA,
653 size_t srcRGBStride, size_t dstYStride, size_t dstUVStride,
654 size_t width, size_t height,
655 C2Color::matrix_t colorMatrix, C2Color::range_t colorRange) {
656 uint8_t r, g, b;
657 uint8_t i8Y, i8U, i8V;
658 int32_t i32Y, i32U, i32V;
659 uint8_t zeroLvl = colorRange == C2Color::RANGE_FULL ? 0 : 16;
660 uint8_t maxLvlLuma = colorRange == C2Color::RANGE_FULL ? 255 : 235;
661 uint8_t maxLvlChroma = colorRange == C2Color::RANGE_FULL ? 255 : 240;
662 // set default range as limited
663 if (colorRange != C2Color::RANGE_FULL && colorRange != C2Color::RANGE_LIMITED) {
664 colorRange = C2Color::RANGE_LIMITED;
665 }
666 const int16_t (*weights)[3] =
667 (colorMatrix == C2Color::MATRIX_BT709) ?
668 bt709Matrix[colorRange - 1] : bt601Matrix[colorRange - 1];
669 for (size_t y = 0; y < height; ++y) {
670 for (size_t x = 0; x < width; ++x) {
671 b = (srcRGBA[x] >> 16) & 0xFF;
672 g = (srcRGBA[x] >> 8) & 0xFF;
673 r = srcRGBA[x] & 0xFF;
674
675 i32Y = ((r * weights[0][0] + g * weights[0][1] + b * weights[0][2]) >> 8) + zeroLvl;
676 i8Y = CLIP3(zeroLvl, i32Y, maxLvlLuma);
677 dstY[x] = ((uint16_t)((double)i8Y * 1023 / 255 + 0.5) << 6) & 0xFFC0;
678 if (x % 2 == 0) {
679 i32U = ((r * weights[1][0] + g * weights[1][1] + b * weights[1][2]) >> 8) + 128;
680 i32V = ((r * weights[2][0] + g * weights[2][1] + b * weights[2][2]) >> 8) + 128;
681 i8U = CLIP3(zeroLvl, i32U, maxLvlChroma);
682 i8V = CLIP3(zeroLvl, i32V, maxLvlChroma);
683 dstUV[x] = ((uint16_t)((double)i8U * 1023 / 255 + 0.5) << 6) & 0xFFC0;
684 dstUV[x + 1] = ((uint16_t)((double)i8V * 1023 / 255 + 0.5) << 6) & 0xFFC0;
685 }
686 }
687 srcRGBA += srcRGBStride;
688 dstY += dstYStride;
689 dstUV += dstUVStride;
690 }
691 }
692
convertPlanar16ToY410OrRGBA1010102(uint8_t * dst,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstStride,size_t width,size_t height,std::shared_ptr<const C2ColorAspectsStruct> aspects,CONV_FORMAT_T format)693 void convertPlanar16ToY410OrRGBA1010102(uint8_t* dst, const uint16_t* srcY, const uint16_t* srcU,
694 const uint16_t* srcV, size_t srcYStride, size_t srcUStride,
695 size_t srcVStride, size_t dstStride, size_t width,
696 size_t height,
697 std::shared_ptr<const C2ColorAspectsStruct> aspects,
698 CONV_FORMAT_T format) {
699 bool processed = false;
700 #if HAVE_LIBYUV_I410_I210_TO_AB30
701 if (format == CONV_FORMAT_I444) {
702 libyuv::I410ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
703 dstStride, &libyuv::kYuvV2020Constants, width, height);
704 processed = true;
705 } else if (format == CONV_FORMAT_I422) {
706 libyuv::I210ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
707 dstStride, &libyuv::kYuvV2020Constants, width, height);
708 processed = true;
709 }
710 #endif // HAVE_LIBYUV_I410_I210_TO_AB30
711 if (!processed) {
712 convertYUV420Planar16ToY410OrRGBA1010102(
713 (uint32_t*)dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
714 dstStride / sizeof(uint32_t), width, height,
715 std::static_pointer_cast<const C2ColorAspectsStruct>(aspects));
716 }
717 }
718
convertPlanar16ToP010(uint16_t * dstY,uint16_t * dstUV,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUStride,size_t dstVStride,size_t width,size_t height,bool isMonochrome,CONV_FORMAT_T format,uint16_t * tmpFrameBuffer,size_t tmpFrameBufferSize)719 void convertPlanar16ToP010(uint16_t* dstY, uint16_t* dstUV, const uint16_t* srcY,
720 const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
721 size_t srcUStride, size_t srcVStride, size_t dstYStride,
722 size_t dstUStride, size_t dstVStride, size_t width, size_t height,
723 bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
724 size_t tmpFrameBufferSize) {
725 #if LIBYUV_VERSION >= 1779
726 if ((format == CONV_FORMAT_I444) || (format == CONV_FORMAT_I422)) {
727 // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010
728 // and libyuv::I210ToP010 when they are available. Note it may be safe to alias dstY
729 // in I010ToP010, but the libyuv API doesn't make any guarantees.
730 const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
731 CHECK(tmpSize <= tmpFrameBufferSize);
732
733 uint16_t* const tmpY = tmpFrameBuffer;
734 uint16_t* const tmpU = tmpY + dstYStride * height;
735 uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
736 if (format == CONV_FORMAT_I444) {
737 libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
738 dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
739 } else {
740 libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
741 dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
742 }
743 libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride, dstY, dstYStride,
744 dstUV, dstUStride, width, height);
745 } else {
746 convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride,
747 srcVStride, dstYStride, dstUStride, width, height,
748 isMonochrome);
749 }
750 #else // LIBYUV_VERSION < 1779
751 convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
752 dstYStride, dstUStride, width, height, isMonochrome);
753 #endif // LIBYUV_VERSION >= 1779
754 }
755
convertPlanar16ToYV12(uint8_t * dstY,uint8_t * dstU,uint8_t * dstV,const uint16_t * srcY,const uint16_t * srcU,const uint16_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUStride,size_t dstVStride,size_t width,size_t height,bool isMonochrome,CONV_FORMAT_T format,uint16_t * tmpFrameBuffer,size_t tmpFrameBufferSize)756 void convertPlanar16ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint16_t* srcY,
757 const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
758 size_t srcUStride, size_t srcVStride, size_t dstYStride,
759 size_t dstUStride, size_t dstVStride, size_t width, size_t height,
760 bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
761 size_t tmpFrameBufferSize) {
762 #if LIBYUV_VERSION >= 1779
763 if (format == CONV_FORMAT_I444) {
764 // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420
765 // when it's available.
766 const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
767 CHECK(tmpSize <= tmpFrameBufferSize);
768
769 uint16_t* const tmpY = tmpFrameBuffer;
770 uint16_t* const tmpU = tmpY + dstYStride * height;
771 uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
772 libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY, dstYStride,
773 tmpU, dstUStride, tmpV, dstVStride, width, height);
774 libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride, dstY, dstYStride,
775 dstU, dstUStride, dstV, dstVStride, width, height);
776 } else if (format == CONV_FORMAT_I422) {
777 libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
778 dstU, dstUStride, dstV, dstVStride, width, height);
779 } else {
780 convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
781 srcVStride, dstYStride, dstUStride, width, height,
782 isMonochrome);
783 }
784 #else // LIBYUV_VERSION < 1779
785 convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
786 srcVStride, dstYStride, dstUStride, width, height, isMonochrome);
787 #endif // LIBYUV_VERSION >= 1779
788 }
789
convertPlanar8ToYV12(uint8_t * dstY,uint8_t * dstU,uint8_t * dstV,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUStride,size_t dstVStride,uint32_t width,uint32_t height,bool isMonochrome,CONV_FORMAT_T format)790 void convertPlanar8ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint8_t* srcY,
791 const uint8_t* srcU, const uint8_t* srcV, size_t srcYStride,
792 size_t srcUStride, size_t srcVStride, size_t dstYStride,
793 size_t dstUStride, size_t dstVStride, uint32_t width, uint32_t height,
794 bool isMonochrome, CONV_FORMAT_T format) {
795 if (format == CONV_FORMAT_I444) {
796 libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
797 dstU, dstUStride, dstV, dstVStride, width, height);
798 } else if (format == CONV_FORMAT_I422) {
799 libyuv::I422ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
800 dstU, dstUStride, dstV, dstVStride, width, height);
801 } else {
802 convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
803 srcVStride, dstYStride, dstUStride, dstVStride, width, height,
804 isMonochrome);
805 }
806 }
807
convertSemiPlanar8ToP210(uint16_t * dstY,uint16_t * dstUV,const uint8_t * srcY,const uint8_t * srcUV,size_t srcYStride,size_t srcUVStride,size_t dstYStride,size_t dstUVStride,uint32_t width,uint32_t height,CONV_FORMAT_T format,bool isNV12)808 void convertSemiPlanar8ToP210(uint16_t *dstY, uint16_t *dstUV,
809 const uint8_t *srcY, const uint8_t *srcUV,
810 size_t srcYStride, size_t srcUVStride,
811 size_t dstYStride, size_t dstUVStride,
812 uint32_t width, uint32_t height,
813 CONV_FORMAT_T format, bool isNV12) {
814 // This function assumes that dstStride/width are even.
815 // The check for this is performed by the caller
816 if (format != CONV_FORMAT_I420) {
817 ALOGE("No support for semi-planar8 to P210. format is %d", format);
818 return;
819 }
820
821 for (int32_t y = 0; y < height; ++y) {
822 for (int32_t x = 0; x < width; ++x) {
823 dstY[x] = ((uint16_t)((double)srcY[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
824 }
825 dstY += dstYStride;
826 srcY += srcYStride;
827 }
828
829 if (isNV12) {
830 for (int32_t y = 0; y < (height + 1) / 2; ++y) {
831 for (int32_t x = 0; x < width; x++) {
832 dstUV[x] = dstUV[dstUVStride + x] =
833 ((uint16_t)((double)srcUV[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
834 }
835 srcUV += srcUVStride;
836 dstUV += dstUVStride << 1;
837 }
838 } else { //NV21
839 for (int32_t y = 0; y < (height + 1) / 2; ++y) {
840 for (int32_t x = 0; x < width; x+=2) {
841 dstUV[x+1] = dstUV[dstUVStride + x + 1] =
842 ((uint16_t)((double)srcUV[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
843 dstUV[x] = dstUV[dstUVStride + x] =
844 ((uint16_t)((double)srcUV[x + 1] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
845 }
846 srcUV += srcUVStride;
847 dstUV += dstUVStride << 1;
848 }
849 }
850 }
851
convertPlanar8ToP210(uint16_t * dstY,uint16_t * dstUV,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride,size_t dstYStride,size_t dstUVStride,uint32_t width,uint32_t height,CONV_FORMAT_T format)852 void convertPlanar8ToP210(uint16_t *dstY, uint16_t *dstUV,
853 const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
854 size_t srcYStride, size_t srcUStride, size_t srcVStride,
855 size_t dstYStride, size_t dstUVStride,
856 uint32_t width, uint32_t height,
857 CONV_FORMAT_T format) {
858 if (format != CONV_FORMAT_I420) {
859 ALOGE("No support for planar8 to P210. format is %d", format);
860 return;
861 }
862
863 for (int32_t y = 0; y < height; ++y) {
864 for (int32_t x = 0; x < width; ++x) {
865 dstY[x] = ((uint16_t)((double)srcY[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
866 }
867 dstY += dstYStride;
868 srcY += srcYStride;
869 }
870
871 for (int32_t y = 0; y < height / 2; ++y) {
872 for (int32_t x = 0; x < width / 2; ++x) {
873 dstUV[x<<1] = dstUV[(x<<1) + dstUVStride] =
874 ((uint16_t)((double)srcU[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
875 dstUV[(x<<1) + 1] = dstUV[(x<<1) + dstUVStride + 1] =
876 ((uint16_t)((double)srcV[x] * 1023 / 255 + 0.5) << 6) & 0xFFC0;
877 }
878 dstUV += dstUVStride << 1;
879 srcU += srcUStride;
880 srcV += srcVStride;
881 }
882 }
883
884
pop_front()885 std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
886 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
887 mQueue.pop_front();
888 return work;
889 }
890
push_back(std::unique_ptr<C2Work> work)891 void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
892 mQueue.push_back({ std::move(work), NO_DRAIN });
893 }
894
empty() const895 bool SimpleC2Component::WorkQueue::empty() const {
896 return mQueue.empty();
897 }
898
clear()899 void SimpleC2Component::WorkQueue::clear() {
900 mQueue.clear();
901 }
902
drainMode() const903 uint32_t SimpleC2Component::WorkQueue::drainMode() const {
904 return mQueue.front().drainMode;
905 }
906
markDrain(uint32_t drainMode)907 void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
908 mQueue.push_back({ nullptr, drainMode });
909 }
910
911 ////////////////////////////////////////////////////////////////////////////////
912
WorkHandler()913 SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
914
setComponent(const std::shared_ptr<SimpleC2Component> & thiz)915 void SimpleC2Component::WorkHandler::setComponent(
916 const std::shared_ptr<SimpleC2Component> &thiz) {
917 mThiz = thiz;
918 }
919
Reply(const sp<AMessage> & msg,int32_t * err=nullptr)920 static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
921 sp<AReplyToken> replyId;
922 CHECK(msg->senderAwaitsResponse(&replyId));
923 sp<AMessage> reply = new AMessage;
924 if (err) {
925 reply->setInt32("err", *err);
926 }
927 reply->postReply(replyId);
928 }
929
onMessageReceived(const sp<AMessage> & msg)930 void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
931 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
932 if (!thiz) {
933 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
934 sp<AReplyToken> replyId;
935 if (msg->senderAwaitsResponse(&replyId)) {
936 sp<AMessage> reply = new AMessage;
937 reply->setInt32("err", C2_CORRUPTED);
938 reply->postReply(replyId);
939 }
940 return;
941 }
942
943 switch (msg->what()) {
944 case kWhatProcess: {
945 if (mRunning) {
946 if (thiz->processQueue()) {
947 (new AMessage(kWhatProcess, this))->post();
948 }
949 } else {
950 ALOGV("Ignore process message as we're not running");
951 }
952 break;
953 }
954 case kWhatInit: {
955 int32_t err = thiz->onInit();
956 Reply(msg, &err);
957 [[fallthrough]];
958 }
959 case kWhatStart: {
960 mRunning = true;
961 break;
962 }
963 case kWhatStop: {
964 int32_t err = thiz->onStop();
965 thiz->mOutputBlockPool.reset();
966 mRunning = false;
967 Reply(msg, &err);
968 break;
969 }
970 case kWhatReset: {
971 thiz->onReset();
972 thiz->mOutputBlockPool.reset();
973 mRunning = false;
974 Reply(msg);
975 break;
976 }
977 case kWhatRelease: {
978 thiz->onRelease();
979 thiz->mOutputBlockPool.reset();
980 mRunning = false;
981 Reply(msg);
982 break;
983 }
984 default: {
985 ALOGD("Unrecognized msg: %d", msg->what());
986 break;
987 }
988 }
989 }
990
991 class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
992 public:
BlockingBlockPool(const std::shared_ptr<C2BlockPool> & base)993 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
994
getLocalId() const995 virtual local_id_t getLocalId() const override {
996 return mBase->getLocalId();
997 }
998
getAllocatorId() const999 virtual C2Allocator::id_t getAllocatorId() const override {
1000 return mBase->getAllocatorId();
1001 }
1002
fetchLinearBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearBlock> * block)1003 virtual c2_status_t fetchLinearBlock(
1004 uint32_t capacity,
1005 C2MemoryUsage usage,
1006 std::shared_ptr<C2LinearBlock>* block) {
1007 c2_status_t status;
1008 do {
1009 status = mBase->fetchLinearBlock(capacity, usage, block);
1010 } while (status == C2_BLOCKING);
1011 return status;
1012 }
1013
fetchCircularBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2CircularBlock> * block)1014 virtual c2_status_t fetchCircularBlock(
1015 uint32_t capacity,
1016 C2MemoryUsage usage,
1017 std::shared_ptr<C2CircularBlock>* block) {
1018 c2_status_t status;
1019 do {
1020 status = mBase->fetchCircularBlock(capacity, usage, block);
1021 } while (status == C2_BLOCKING);
1022 return status;
1023 }
1024
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)1025 virtual c2_status_t fetchGraphicBlock(
1026 uint32_t width, uint32_t height, uint32_t format,
1027 C2MemoryUsage usage,
1028 std::shared_ptr<C2GraphicBlock>* block) {
1029 c2_status_t status;
1030 do {
1031 status = mBase->fetchGraphicBlock(width, height, format, usage,
1032 block);
1033 } while (status == C2_BLOCKING);
1034 return status;
1035 }
1036
1037 private:
1038 std::shared_ptr<C2BlockPool> mBase;
1039 };
1040
1041 ////////////////////////////////////////////////////////////////////////////////
1042
1043 namespace {
1044
1045 struct DummyReadView : public C2ReadView {
DummyReadViewandroid::__anonb3d76c5b0211::DummyReadView1046 DummyReadView() : C2ReadView(C2_NO_INIT) {}
1047 };
1048
1049 } // namespace
1050
SimpleC2Component(const std::shared_ptr<C2ComponentInterface> & intf)1051 SimpleC2Component::SimpleC2Component(
1052 const std::shared_ptr<C2ComponentInterface> &intf)
1053 : mDummyReadView(DummyReadView()),
1054 mIntf(intf),
1055 mLooper(new ALooper),
1056 mHandler(new WorkHandler) {
1057 mLooper->setName(intf->getName().c_str());
1058 (void)mLooper->registerHandler(mHandler);
1059 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
1060 }
1061
~SimpleC2Component()1062 SimpleC2Component::~SimpleC2Component() {
1063 mLooper->unregisterHandler(mHandler->id());
1064 (void)mLooper->stop();
1065 }
1066
setListener_vb(const std::shared_ptr<C2Component::Listener> & listener,c2_blocking_t mayBlock)1067 c2_status_t SimpleC2Component::setListener_vb(
1068 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
1069 mHandler->setComponent(shared_from_this());
1070
1071 Mutexed<ExecState>::Locked state(mExecState);
1072 if (state->mState == RUNNING) {
1073 if (listener) {
1074 return C2_BAD_STATE;
1075 } else if (!mayBlock) {
1076 return C2_BLOCKING;
1077 }
1078 }
1079 state->mListener = listener;
1080 // TODO: wait for listener change to have taken place before returning
1081 // (e.g. if there is an ongoing listener callback)
1082 return C2_OK;
1083 }
1084
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)1085 c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
1086 {
1087 Mutexed<ExecState>::Locked state(mExecState);
1088 if (state->mState != RUNNING) {
1089 return C2_BAD_STATE;
1090 }
1091 }
1092 bool queueWasEmpty = false;
1093 {
1094 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1095 queueWasEmpty = queue->empty();
1096 while (!items->empty()) {
1097 queue->push_back(std::move(items->front()));
1098 items->pop_front();
1099 }
1100 }
1101 if (queueWasEmpty) {
1102 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
1103 }
1104 return C2_OK;
1105 }
1106
announce_nb(const std::vector<C2WorkOutline> & items)1107 c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
1108 (void)items;
1109 return C2_OMITTED;
1110 }
1111
flush_sm(flush_mode_t flushMode,std::list<std::unique_ptr<C2Work>> * const flushedWork)1112 c2_status_t SimpleC2Component::flush_sm(
1113 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
1114 (void)flushMode;
1115 {
1116 Mutexed<ExecState>::Locked state(mExecState);
1117 if (state->mState != RUNNING) {
1118 return C2_BAD_STATE;
1119 }
1120 }
1121 {
1122 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1123 queue->incGeneration();
1124 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
1125 while (!queue->empty()) {
1126 std::unique_ptr<C2Work> work = queue->pop_front();
1127 if (work) {
1128 flushedWork->push_back(std::move(work));
1129 }
1130 }
1131 while (!queue->pending().empty()) {
1132 flushedWork->push_back(std::move(queue->pending().begin()->second));
1133 queue->pending().erase(queue->pending().begin());
1134 }
1135 }
1136
1137 return C2_OK;
1138 }
1139
drain_nb(drain_mode_t drainMode)1140 c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
1141 if (drainMode == DRAIN_CHAIN) {
1142 return C2_OMITTED;
1143 }
1144 {
1145 Mutexed<ExecState>::Locked state(mExecState);
1146 if (state->mState != RUNNING) {
1147 return C2_BAD_STATE;
1148 }
1149 }
1150 bool queueWasEmpty = false;
1151 {
1152 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1153 queueWasEmpty = queue->empty();
1154 queue->markDrain(drainMode);
1155 }
1156 if (queueWasEmpty) {
1157 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
1158 }
1159
1160 return C2_OK;
1161 }
1162
start()1163 c2_status_t SimpleC2Component::start() {
1164 Mutexed<ExecState>::Locked state(mExecState);
1165 if (state->mState == RUNNING) {
1166 return C2_BAD_STATE;
1167 }
1168 bool needsInit = (state->mState == UNINITIALIZED);
1169 state.unlock();
1170 if (needsInit) {
1171 sp<AMessage> reply;
1172 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
1173 int32_t err;
1174 CHECK(reply->findInt32("err", &err));
1175 if (err != C2_OK) {
1176 return (c2_status_t)err;
1177 }
1178 } else {
1179 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
1180 }
1181 state.lock();
1182 state->mState = RUNNING;
1183 return C2_OK;
1184 }
1185
stop()1186 c2_status_t SimpleC2Component::stop() {
1187 ALOGV("stop");
1188 {
1189 Mutexed<ExecState>::Locked state(mExecState);
1190 if (state->mState != RUNNING) {
1191 return C2_BAD_STATE;
1192 }
1193 state->mState = STOPPED;
1194 }
1195 {
1196 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1197 queue->clear();
1198 queue->pending().clear();
1199 }
1200 sp<AMessage> reply;
1201 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
1202 int32_t err;
1203 CHECK(reply->findInt32("err", &err));
1204 if (err != C2_OK) {
1205 return (c2_status_t)err;
1206 }
1207 return C2_OK;
1208 }
1209
reset()1210 c2_status_t SimpleC2Component::reset() {
1211 ALOGV("reset");
1212 {
1213 Mutexed<ExecState>::Locked state(mExecState);
1214 state->mState = UNINITIALIZED;
1215 }
1216 {
1217 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1218 queue->clear();
1219 queue->pending().clear();
1220 }
1221 sp<AMessage> reply;
1222 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
1223 return C2_OK;
1224 }
1225
release()1226 c2_status_t SimpleC2Component::release() {
1227 ALOGV("release");
1228 sp<AMessage> reply;
1229 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
1230 return C2_OK;
1231 }
1232
intf()1233 std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
1234 return mIntf;
1235 }
1236
1237 namespace {
1238
vec(std::unique_ptr<C2Work> & work)1239 std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
1240 std::list<std::unique_ptr<C2Work>> ret;
1241 ret.push_back(std::move(work));
1242 return ret;
1243 }
1244
1245 } // namespace
1246
finish(uint64_t frameIndex,std::function<void (const std::unique_ptr<C2Work> &)> fillWork)1247 void SimpleC2Component::finish(
1248 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
1249 std::unique_ptr<C2Work> work;
1250 {
1251 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1252 if (queue->pending().count(frameIndex) == 0) {
1253 ALOGW("unknown frame index: %" PRIu64, frameIndex);
1254 return;
1255 }
1256 work = std::move(queue->pending().at(frameIndex));
1257 queue->pending().erase(frameIndex);
1258 }
1259 if (work) {
1260 fillWork(work);
1261 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
1262 listener->onWorkDone_nb(shared_from_this(), vec(work));
1263 ALOGV("returning pending work");
1264 }
1265 }
1266
cloneAndSend(uint64_t frameIndex,const std::unique_ptr<C2Work> & currentWork,std::function<void (const std::unique_ptr<C2Work> &)> fillWork)1267 void SimpleC2Component::cloneAndSend(
1268 uint64_t frameIndex,
1269 const std::unique_ptr<C2Work> ¤tWork,
1270 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
1271 std::unique_ptr<C2Work> work(new C2Work);
1272 if (currentWork->input.ordinal.frameIndex == frameIndex) {
1273 work->input.flags = currentWork->input.flags;
1274 work->input.ordinal = currentWork->input.ordinal;
1275 } else {
1276 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1277 if (queue->pending().count(frameIndex) == 0) {
1278 ALOGW("unknown frame index: %" PRIu64, frameIndex);
1279 return;
1280 }
1281 work->input.flags = queue->pending().at(frameIndex)->input.flags;
1282 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
1283 }
1284 work->worklets.emplace_back(new C2Worklet);
1285 if (work) {
1286 fillWork(work);
1287 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
1288 listener->onWorkDone_nb(shared_from_this(), vec(work));
1289 ALOGV("cloned and sending work");
1290 }
1291 }
1292
processQueue()1293 bool SimpleC2Component::processQueue() {
1294 std::unique_ptr<C2Work> work;
1295 uint64_t generation;
1296 int32_t drainMode;
1297 bool isFlushPending = false;
1298 bool hasQueuedWork = false;
1299 {
1300 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1301 if (queue->empty()) {
1302 return false;
1303 }
1304
1305 generation = queue->generation();
1306 drainMode = queue->drainMode();
1307 isFlushPending = queue->popPendingFlush();
1308 work = queue->pop_front();
1309 hasQueuedWork = !queue->empty();
1310 }
1311 if (isFlushPending) {
1312 ALOGV("processing pending flush");
1313 c2_status_t err = onFlush_sm();
1314 if (err != C2_OK) {
1315 ALOGD("flush err: %d", err);
1316 // TODO: error
1317 }
1318 }
1319
1320 if (!mOutputBlockPool) {
1321 c2_status_t err = [this] {
1322 // TODO: don't use query_vb
1323 C2StreamBufferTypeSetting::output outputFormat(0u);
1324 std::vector<std::unique_ptr<C2Param>> params;
1325 c2_status_t err = intf()->query_vb(
1326 { &outputFormat },
1327 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
1328 C2_DONT_BLOCK,
1329 ¶ms);
1330 if (err != C2_OK && err != C2_BAD_INDEX) {
1331 ALOGD("query err = %d", err);
1332 return err;
1333 }
1334 C2BlockPool::local_id_t poolId =
1335 outputFormat.value == C2BufferData::GRAPHIC
1336 ? C2BlockPool::BASIC_GRAPHIC
1337 : C2BlockPool::BASIC_LINEAR;
1338 if (params.size()) {
1339 C2PortBlockPoolsTuning::output *outputPools =
1340 C2PortBlockPoolsTuning::output::From(params[0].get());
1341 if (outputPools && outputPools->flexCount() >= 1) {
1342 poolId = outputPools->m.values[0];
1343 }
1344 }
1345
1346 std::shared_ptr<C2BlockPool> blockPool;
1347 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
1348 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
1349 (unsigned long long)poolId,
1350 (unsigned long long)(
1351 blockPool ? blockPool->getLocalId() : 111000111),
1352 err);
1353 if (err == C2_OK) {
1354 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
1355 }
1356 return err;
1357 }();
1358 if (err != C2_OK) {
1359 Mutexed<ExecState>::Locked state(mExecState);
1360 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1361 state.unlock();
1362 listener->onError_nb(shared_from_this(), err);
1363 return hasQueuedWork;
1364 }
1365 }
1366
1367 if (!work) {
1368 c2_status_t err = drain(drainMode, mOutputBlockPool);
1369 if (err != C2_OK) {
1370 Mutexed<ExecState>::Locked state(mExecState);
1371 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1372 state.unlock();
1373 listener->onError_nb(shared_from_this(), err);
1374 }
1375 return hasQueuedWork;
1376 }
1377
1378 {
1379 std::vector<C2Param *> updates;
1380 for (const std::unique_ptr<C2Param> ¶m: work->input.configUpdate) {
1381 if (param) {
1382 updates.emplace_back(param.get());
1383 }
1384 }
1385 if (!updates.empty()) {
1386 std::vector<std::unique_ptr<C2SettingResult>> failures;
1387 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
1388 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
1389 }
1390 }
1391
1392 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
1393 // If input buffer list is not empty, it means we have some input to process on.
1394 // However, input could be a null buffer. In such case, clear the buffer list
1395 // before making call to process().
1396 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
1397 ALOGD("Encountered null input buffer. Clearing the input buffer");
1398 work->input.buffers.clear();
1399 }
1400 process(work, mOutputBlockPool);
1401 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
1402 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
1403 if (queue->generation() != generation) {
1404 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
1405 queue->generation(), generation);
1406 work->result = C2_NOT_FOUND;
1407 queue.unlock();
1408
1409 Mutexed<ExecState>::Locked state(mExecState);
1410 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1411 state.unlock();
1412 listener->onWorkDone_nb(shared_from_this(), vec(work));
1413 return hasQueuedWork;
1414 }
1415 if (work->workletsProcessed != 0u) {
1416 queue.unlock();
1417 Mutexed<ExecState>::Locked state(mExecState);
1418 ALOGV("returning this work");
1419 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1420 state.unlock();
1421 listener->onWorkDone_nb(shared_from_this(), vec(work));
1422 } else {
1423 ALOGV("queue pending work");
1424 work->input.buffers.clear();
1425 std::unique_ptr<C2Work> unexpected;
1426
1427 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
1428 if (queue->pending().count(frameIndex) != 0) {
1429 unexpected = std::move(queue->pending().at(frameIndex));
1430 queue->pending().erase(frameIndex);
1431 }
1432 (void)queue->pending().insert({ frameIndex, std::move(work) });
1433
1434 queue.unlock();
1435 if (unexpected) {
1436 ALOGD("unexpected pending work");
1437 unexpected->result = C2_CORRUPTED;
1438 Mutexed<ExecState>::Locked state(mExecState);
1439 std::shared_ptr<C2Component::Listener> listener = state->mListener;
1440 state.unlock();
1441 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
1442 }
1443 }
1444 return hasQueuedWork;
1445 }
1446
getHalPixelFormatForBitDepth10(bool allowRGBA1010102)1447 int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
1448 // Save supported hal pixel formats for bit depth of 10, the first time this is called
1449 if (!mBitDepth10HalPixelFormats.size()) {
1450 std::vector<int> halPixelFormats;
1451 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
1452
1453 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
1454 // is populated only once, allowRGBA1010102 is not considered at this stage.
1455 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
1456
1457 for (int halPixelFormat : halPixelFormats) {
1458 if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
1459 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
1460 }
1461 }
1462 // Add YV12 in the end as a fall-back option
1463 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
1464 }
1465 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
1466 // RGBA 1010102 format unlike earlier versions where it was used to represent
1467 // YUVA 1010102 data
1468 if (!isAtLeastT()) {
1469 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
1470 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
1471 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
1472 return HAL_PIXEL_FORMAT_YV12;
1473 }
1474 }
1475 // Return the first entry from supported formats
1476 return mBitDepth10HalPixelFormats[0];
1477 }
createLinearBuffer(const std::shared_ptr<C2LinearBlock> & block,size_t offset,size_t size)1478 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
1479 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
1480 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
1481 }
1482
createGraphicBuffer(const std::shared_ptr<C2GraphicBlock> & block,const C2Rect & crop)1483 std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
1484 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
1485 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
1486 }
1487
1488 } // namespace android
1489