• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &currentWork,
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                     &params);
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> &param: 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