• 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 dstUVStride,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 dstUVStride, uint32_t width, uint32_t height,
42                                 bool isMonochrome) {
43     for (size_t i = 0; i < height; ++i) {
44         memcpy(dstY, srcY, width);
45         srcY += srcYStride;
46         dstY += dstYStride;
47     }
48 
49     if (isMonochrome) {
50         // Fill with neutral U/V values.
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 += dstUVStride;
55             dstU += dstUVStride;
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 += dstUVStride;
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 += dstUVStride;
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, _b_u, _g_u, _g_v, _r_v, _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 }
pop_front()417 std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
418     std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
419     mQueue.pop_front();
420     return work;
421 }
422 
push_back(std::unique_ptr<C2Work> work)423 void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
424     mQueue.push_back({ std::move(work), NO_DRAIN });
425 }
426 
empty() const427 bool SimpleC2Component::WorkQueue::empty() const {
428     return mQueue.empty();
429 }
430 
clear()431 void SimpleC2Component::WorkQueue::clear() {
432     mQueue.clear();
433 }
434 
drainMode() const435 uint32_t SimpleC2Component::WorkQueue::drainMode() const {
436     return mQueue.front().drainMode;
437 }
438 
markDrain(uint32_t drainMode)439 void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
440     mQueue.push_back({ nullptr, drainMode });
441 }
442 
443 ////////////////////////////////////////////////////////////////////////////////
444 
WorkHandler()445 SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
446 
setComponent(const std::shared_ptr<SimpleC2Component> & thiz)447 void SimpleC2Component::WorkHandler::setComponent(
448         const std::shared_ptr<SimpleC2Component> &thiz) {
449     mThiz = thiz;
450 }
451 
Reply(const sp<AMessage> & msg,int32_t * err=nullptr)452 static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
453     sp<AReplyToken> replyId;
454     CHECK(msg->senderAwaitsResponse(&replyId));
455     sp<AMessage> reply = new AMessage;
456     if (err) {
457         reply->setInt32("err", *err);
458     }
459     reply->postReply(replyId);
460 }
461 
onMessageReceived(const sp<AMessage> & msg)462 void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
463     std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
464     if (!thiz) {
465         ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
466         sp<AReplyToken> replyId;
467         if (msg->senderAwaitsResponse(&replyId)) {
468             sp<AMessage> reply = new AMessage;
469             reply->setInt32("err", C2_CORRUPTED);
470             reply->postReply(replyId);
471         }
472         return;
473     }
474 
475     switch (msg->what()) {
476         case kWhatProcess: {
477             if (mRunning) {
478                 if (thiz->processQueue()) {
479                     (new AMessage(kWhatProcess, this))->post();
480                 }
481             } else {
482                 ALOGV("Ignore process message as we're not running");
483             }
484             break;
485         }
486         case kWhatInit: {
487             int32_t err = thiz->onInit();
488             Reply(msg, &err);
489             [[fallthrough]];
490         }
491         case kWhatStart: {
492             mRunning = true;
493             break;
494         }
495         case kWhatStop: {
496             int32_t err = thiz->onStop();
497             thiz->mOutputBlockPool.reset();
498             Reply(msg, &err);
499             break;
500         }
501         case kWhatReset: {
502             thiz->onReset();
503             thiz->mOutputBlockPool.reset();
504             mRunning = false;
505             Reply(msg);
506             break;
507         }
508         case kWhatRelease: {
509             thiz->onRelease();
510             thiz->mOutputBlockPool.reset();
511             mRunning = false;
512             Reply(msg);
513             break;
514         }
515         default: {
516             ALOGD("Unrecognized msg: %d", msg->what());
517             break;
518         }
519     }
520 }
521 
522 class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
523 public:
BlockingBlockPool(const std::shared_ptr<C2BlockPool> & base)524     BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
525 
getLocalId() const526     virtual local_id_t getLocalId() const override {
527         return mBase->getLocalId();
528     }
529 
getAllocatorId() const530     virtual C2Allocator::id_t getAllocatorId() const override {
531         return mBase->getAllocatorId();
532     }
533 
fetchLinearBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2LinearBlock> * block)534     virtual c2_status_t fetchLinearBlock(
535             uint32_t capacity,
536             C2MemoryUsage usage,
537             std::shared_ptr<C2LinearBlock>* block) {
538         c2_status_t status;
539         do {
540             status = mBase->fetchLinearBlock(capacity, usage, block);
541         } while (status == C2_BLOCKING);
542         return status;
543     }
544 
fetchCircularBlock(uint32_t capacity,C2MemoryUsage usage,std::shared_ptr<C2CircularBlock> * block)545     virtual c2_status_t fetchCircularBlock(
546             uint32_t capacity,
547             C2MemoryUsage usage,
548             std::shared_ptr<C2CircularBlock>* block) {
549         c2_status_t status;
550         do {
551             status = mBase->fetchCircularBlock(capacity, usage, block);
552         } while (status == C2_BLOCKING);
553         return status;
554     }
555 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)556     virtual c2_status_t fetchGraphicBlock(
557             uint32_t width, uint32_t height, uint32_t format,
558             C2MemoryUsage usage,
559             std::shared_ptr<C2GraphicBlock>* block) {
560         c2_status_t status;
561         do {
562             status = mBase->fetchGraphicBlock(width, height, format, usage,
563                                               block);
564         } while (status == C2_BLOCKING);
565         return status;
566     }
567 
568 private:
569     std::shared_ptr<C2BlockPool> mBase;
570 };
571 
572 ////////////////////////////////////////////////////////////////////////////////
573 
574 namespace {
575 
576 struct DummyReadView : public C2ReadView {
DummyReadViewandroid::__anon1c7701d10211::DummyReadView577     DummyReadView() : C2ReadView(C2_NO_INIT) {}
578 };
579 
580 }  // namespace
581 
SimpleC2Component(const std::shared_ptr<C2ComponentInterface> & intf)582 SimpleC2Component::SimpleC2Component(
583         const std::shared_ptr<C2ComponentInterface> &intf)
584     : mDummyReadView(DummyReadView()),
585       mIntf(intf),
586       mLooper(new ALooper),
587       mHandler(new WorkHandler) {
588     mLooper->setName(intf->getName().c_str());
589     (void)mLooper->registerHandler(mHandler);
590     mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
591 }
592 
~SimpleC2Component()593 SimpleC2Component::~SimpleC2Component() {
594     mLooper->unregisterHandler(mHandler->id());
595     (void)mLooper->stop();
596 }
597 
setListener_vb(const std::shared_ptr<C2Component::Listener> & listener,c2_blocking_t mayBlock)598 c2_status_t SimpleC2Component::setListener_vb(
599         const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
600     mHandler->setComponent(shared_from_this());
601 
602     Mutexed<ExecState>::Locked state(mExecState);
603     if (state->mState == RUNNING) {
604         if (listener) {
605             return C2_BAD_STATE;
606         } else if (!mayBlock) {
607             return C2_BLOCKING;
608         }
609     }
610     state->mListener = listener;
611     // TODO: wait for listener change to have taken place before returning
612     // (e.g. if there is an ongoing listener callback)
613     return C2_OK;
614 }
615 
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)616 c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
617     {
618         Mutexed<ExecState>::Locked state(mExecState);
619         if (state->mState != RUNNING) {
620             return C2_BAD_STATE;
621         }
622     }
623     bool queueWasEmpty = false;
624     {
625         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
626         queueWasEmpty = queue->empty();
627         while (!items->empty()) {
628             queue->push_back(std::move(items->front()));
629             items->pop_front();
630         }
631     }
632     if (queueWasEmpty) {
633         (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
634     }
635     return C2_OK;
636 }
637 
announce_nb(const std::vector<C2WorkOutline> & items)638 c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
639     (void)items;
640     return C2_OMITTED;
641 }
642 
flush_sm(flush_mode_t flushMode,std::list<std::unique_ptr<C2Work>> * const flushedWork)643 c2_status_t SimpleC2Component::flush_sm(
644         flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
645     (void)flushMode;
646     {
647         Mutexed<ExecState>::Locked state(mExecState);
648         if (state->mState != RUNNING) {
649             return C2_BAD_STATE;
650         }
651     }
652     {
653         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
654         queue->incGeneration();
655         // TODO: queue->splicedBy(flushedWork, flushedWork->end());
656         while (!queue->empty()) {
657             std::unique_ptr<C2Work> work = queue->pop_front();
658             if (work) {
659                 flushedWork->push_back(std::move(work));
660             }
661         }
662         while (!queue->pending().empty()) {
663             flushedWork->push_back(std::move(queue->pending().begin()->second));
664             queue->pending().erase(queue->pending().begin());
665         }
666     }
667 
668     return C2_OK;
669 }
670 
drain_nb(drain_mode_t drainMode)671 c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
672     if (drainMode == DRAIN_CHAIN) {
673         return C2_OMITTED;
674     }
675     {
676         Mutexed<ExecState>::Locked state(mExecState);
677         if (state->mState != RUNNING) {
678             return C2_BAD_STATE;
679         }
680     }
681     bool queueWasEmpty = false;
682     {
683         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
684         queueWasEmpty = queue->empty();
685         queue->markDrain(drainMode);
686     }
687     if (queueWasEmpty) {
688         (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
689     }
690 
691     return C2_OK;
692 }
693 
start()694 c2_status_t SimpleC2Component::start() {
695     Mutexed<ExecState>::Locked state(mExecState);
696     if (state->mState == RUNNING) {
697         return C2_BAD_STATE;
698     }
699     bool needsInit = (state->mState == UNINITIALIZED);
700     state.unlock();
701     if (needsInit) {
702         sp<AMessage> reply;
703         (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
704         int32_t err;
705         CHECK(reply->findInt32("err", &err));
706         if (err != C2_OK) {
707             return (c2_status_t)err;
708         }
709     } else {
710         (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
711     }
712     state.lock();
713     state->mState = RUNNING;
714     return C2_OK;
715 }
716 
stop()717 c2_status_t SimpleC2Component::stop() {
718     ALOGV("stop");
719     {
720         Mutexed<ExecState>::Locked state(mExecState);
721         if (state->mState != RUNNING) {
722             return C2_BAD_STATE;
723         }
724         state->mState = STOPPED;
725     }
726     {
727         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
728         queue->clear();
729         queue->pending().clear();
730     }
731     sp<AMessage> reply;
732     (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
733     int32_t err;
734     CHECK(reply->findInt32("err", &err));
735     if (err != C2_OK) {
736         return (c2_status_t)err;
737     }
738     return C2_OK;
739 }
740 
reset()741 c2_status_t SimpleC2Component::reset() {
742     ALOGV("reset");
743     {
744         Mutexed<ExecState>::Locked state(mExecState);
745         state->mState = UNINITIALIZED;
746     }
747     {
748         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
749         queue->clear();
750         queue->pending().clear();
751     }
752     sp<AMessage> reply;
753     (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
754     return C2_OK;
755 }
756 
release()757 c2_status_t SimpleC2Component::release() {
758     ALOGV("release");
759     sp<AMessage> reply;
760     (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
761     return C2_OK;
762 }
763 
intf()764 std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
765     return mIntf;
766 }
767 
768 namespace {
769 
vec(std::unique_ptr<C2Work> & work)770 std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
771     std::list<std::unique_ptr<C2Work>> ret;
772     ret.push_back(std::move(work));
773     return ret;
774 }
775 
776 }  // namespace
777 
finish(uint64_t frameIndex,std::function<void (const std::unique_ptr<C2Work> &)> fillWork)778 void SimpleC2Component::finish(
779         uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
780     std::unique_ptr<C2Work> work;
781     {
782         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
783         if (queue->pending().count(frameIndex) == 0) {
784             ALOGW("unknown frame index: %" PRIu64, frameIndex);
785             return;
786         }
787         work = std::move(queue->pending().at(frameIndex));
788         queue->pending().erase(frameIndex);
789     }
790     if (work) {
791         fillWork(work);
792         std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
793         listener->onWorkDone_nb(shared_from_this(), vec(work));
794         ALOGV("returning pending work");
795     }
796 }
797 
cloneAndSend(uint64_t frameIndex,const std::unique_ptr<C2Work> & currentWork,std::function<void (const std::unique_ptr<C2Work> &)> fillWork)798 void SimpleC2Component::cloneAndSend(
799         uint64_t frameIndex,
800         const std::unique_ptr<C2Work> &currentWork,
801         std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
802     std::unique_ptr<C2Work> work(new C2Work);
803     if (currentWork->input.ordinal.frameIndex == frameIndex) {
804         work->input.flags = currentWork->input.flags;
805         work->input.ordinal = currentWork->input.ordinal;
806     } else {
807         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
808         if (queue->pending().count(frameIndex) == 0) {
809             ALOGW("unknown frame index: %" PRIu64, frameIndex);
810             return;
811         }
812         work->input.flags = queue->pending().at(frameIndex)->input.flags;
813         work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
814     }
815     work->worklets.emplace_back(new C2Worklet);
816     if (work) {
817         fillWork(work);
818         std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
819         listener->onWorkDone_nb(shared_from_this(), vec(work));
820         ALOGV("cloned and sending work");
821     }
822 }
823 
processQueue()824 bool SimpleC2Component::processQueue() {
825     std::unique_ptr<C2Work> work;
826     uint64_t generation;
827     int32_t drainMode;
828     bool isFlushPending = false;
829     bool hasQueuedWork = false;
830     {
831         Mutexed<WorkQueue>::Locked queue(mWorkQueue);
832         if (queue->empty()) {
833             return false;
834         }
835 
836         generation = queue->generation();
837         drainMode = queue->drainMode();
838         isFlushPending = queue->popPendingFlush();
839         work = queue->pop_front();
840         hasQueuedWork = !queue->empty();
841     }
842     if (isFlushPending) {
843         ALOGV("processing pending flush");
844         c2_status_t err = onFlush_sm();
845         if (err != C2_OK) {
846             ALOGD("flush err: %d", err);
847             // TODO: error
848         }
849     }
850 
851     if (!mOutputBlockPool) {
852         c2_status_t err = [this] {
853             // TODO: don't use query_vb
854             C2StreamBufferTypeSetting::output outputFormat(0u);
855             std::vector<std::unique_ptr<C2Param>> params;
856             c2_status_t err = intf()->query_vb(
857                     { &outputFormat },
858                     { C2PortBlockPoolsTuning::output::PARAM_TYPE },
859                     C2_DONT_BLOCK,
860                     &params);
861             if (err != C2_OK && err != C2_BAD_INDEX) {
862                 ALOGD("query err = %d", err);
863                 return err;
864             }
865             C2BlockPool::local_id_t poolId =
866                 outputFormat.value == C2BufferData::GRAPHIC
867                         ? C2BlockPool::BASIC_GRAPHIC
868                         : C2BlockPool::BASIC_LINEAR;
869             if (params.size()) {
870                 C2PortBlockPoolsTuning::output *outputPools =
871                     C2PortBlockPoolsTuning::output::From(params[0].get());
872                 if (outputPools && outputPools->flexCount() >= 1) {
873                     poolId = outputPools->m.values[0];
874                 }
875             }
876 
877             std::shared_ptr<C2BlockPool> blockPool;
878             err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
879             ALOGD("Using output block pool with poolID %llu => got %llu - %d",
880                     (unsigned long long)poolId,
881                     (unsigned long long)(
882                             blockPool ? blockPool->getLocalId() : 111000111),
883                     err);
884             if (err == C2_OK) {
885                 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
886             }
887             return err;
888         }();
889         if (err != C2_OK) {
890             Mutexed<ExecState>::Locked state(mExecState);
891             std::shared_ptr<C2Component::Listener> listener = state->mListener;
892             state.unlock();
893             listener->onError_nb(shared_from_this(), err);
894             return hasQueuedWork;
895         }
896     }
897 
898     if (!work) {
899         c2_status_t err = drain(drainMode, mOutputBlockPool);
900         if (err != C2_OK) {
901             Mutexed<ExecState>::Locked state(mExecState);
902             std::shared_ptr<C2Component::Listener> listener = state->mListener;
903             state.unlock();
904             listener->onError_nb(shared_from_this(), err);
905         }
906         return hasQueuedWork;
907     }
908 
909     {
910         std::vector<C2Param *> updates;
911         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
912             if (param) {
913                 updates.emplace_back(param.get());
914             }
915         }
916         if (!updates.empty()) {
917             std::vector<std::unique_ptr<C2SettingResult>> failures;
918             c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
919             ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
920         }
921     }
922 
923     ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
924     // If input buffer list is not empty, it means we have some input to process on.
925     // However, input could be a null buffer. In such case, clear the buffer list
926     // before making call to process().
927     if (!work->input.buffers.empty() && !work->input.buffers[0]) {
928         ALOGD("Encountered null input buffer. Clearing the input buffer");
929         work->input.buffers.clear();
930     }
931     process(work, mOutputBlockPool);
932     ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
933     Mutexed<WorkQueue>::Locked queue(mWorkQueue);
934     if (queue->generation() != generation) {
935         ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
936                 queue->generation(), generation);
937         work->result = C2_NOT_FOUND;
938         queue.unlock();
939 
940         Mutexed<ExecState>::Locked state(mExecState);
941         std::shared_ptr<C2Component::Listener> listener = state->mListener;
942         state.unlock();
943         listener->onWorkDone_nb(shared_from_this(), vec(work));
944         return hasQueuedWork;
945     }
946     if (work->workletsProcessed != 0u) {
947         queue.unlock();
948         Mutexed<ExecState>::Locked state(mExecState);
949         ALOGV("returning this work");
950         std::shared_ptr<C2Component::Listener> listener = state->mListener;
951         state.unlock();
952         listener->onWorkDone_nb(shared_from_this(), vec(work));
953     } else {
954         ALOGV("queue pending work");
955         work->input.buffers.clear();
956         std::unique_ptr<C2Work> unexpected;
957 
958         uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
959         if (queue->pending().count(frameIndex) != 0) {
960             unexpected = std::move(queue->pending().at(frameIndex));
961             queue->pending().erase(frameIndex);
962         }
963         (void)queue->pending().insert({ frameIndex, std::move(work) });
964 
965         queue.unlock();
966         if (unexpected) {
967             ALOGD("unexpected pending work");
968             unexpected->result = C2_CORRUPTED;
969             Mutexed<ExecState>::Locked state(mExecState);
970             std::shared_ptr<C2Component::Listener> listener = state->mListener;
971             state.unlock();
972             listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
973         }
974     }
975     return hasQueuedWork;
976 }
977 
getHalPixelFormatForBitDepth10(bool allowRGBA1010102)978 int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
979     // Save supported hal pixel formats for bit depth of 10, the first time this is called
980     if (!mBitDepth10HalPixelFormats.size()) {
981         std::vector<int> halPixelFormats;
982         halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
983 
984         // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
985         // is populated only once, allowRGBA1010102 is not considered at this stage.
986         halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
987 
988         for (int halPixelFormat : halPixelFormats) {
989             if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
990                 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
991             }
992         }
993         // Add YV12 in the end as a fall-back option
994         mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
995     }
996     // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
997     // RGBA 1010102 format unlike earlier versions where it was used to represent
998     // YUVA 1010102 data
999     if (!isAtLeastT()) {
1000         // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
1001         // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
1002         if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
1003             return HAL_PIXEL_FORMAT_YV12;
1004         }
1005     }
1006     // Return the first entry from supported formats
1007     return mBitDepth10HalPixelFormats[0];
1008 }
createLinearBuffer(const std::shared_ptr<C2LinearBlock> & block,size_t offset,size_t size)1009 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
1010         const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
1011     return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
1012 }
1013 
createGraphicBuffer(const std::shared_ptr<C2GraphicBlock> & block,const C2Rect & crop)1014 std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
1015         const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
1016     return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
1017 }
1018 
1019 } // namespace android
1020