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