blob: 1eec8f9955e2a10e3e8260afc5c5768691dde07f [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SimpleC2Component"
19#include <log/log.h>
20
21#include <cutils/properties.h>
22#include <media/stagefright/foundation/AMessage.h>
23
24#include <inttypes.h>
25
26#include <C2Config.h>
27#include <C2Debug.h>
28#include <C2PlatformSupport.h>
29#include <SimpleC2Component.h>
30
31namespace android {
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080032constexpr uint8_t kNeutralUVBitDepth8 = 128;
33constexpr uint16_t kNeutralUVBitDepth10 = 512;
Pawin Vongmasa36653902018-11-15 00:10:25 -080034
Harish Mahendrakard4bbb762022-03-29 11:53:23 -070035bool isAtLeastT() {
36 char deviceCodeName[PROP_VALUE_MAX];
37 __system_property_get("ro.build.version.codename", deviceCodeName);
38 return android_get_device_api_level() >= __ANDROID_API_T__ ||
39 !strcmp(deviceCodeName, "Tiramisu");
40}
41
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080042void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
43 const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
44 size_t srcUStride, size_t srcVStride, size_t dstYStride,
45 size_t dstUVStride, uint32_t width, uint32_t height,
46 bool isMonochrome) {
47 for (size_t i = 0; i < height; ++i) {
48 memcpy(dstY, srcY, width);
49 srcY += srcYStride;
50 dstY += dstYStride;
51 }
52
53 if (isMonochrome) {
54 // Fill with neutral U/V values.
55 for (size_t i = 0; i < height / 2; ++i) {
56 memset(dstV, kNeutralUVBitDepth8, width / 2);
57 memset(dstU, kNeutralUVBitDepth8, width / 2);
58 dstV += dstUVStride;
59 dstU += dstUVStride;
60 }
61 return;
62 }
63
64 for (size_t i = 0; i < height / 2; ++i) {
65 memcpy(dstV, srcV, width / 2);
66 srcV += srcVStride;
67 dstV += dstUVStride;
68 }
69
70 for (size_t i = 0; i < height / 2; ++i) {
71 memcpy(dstU, srcU, width / 2);
72 srcU += srcUStride;
73 dstU += dstUVStride;
74 }
75}
76
77void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
78 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
79 size_t srcVStride, size_t dstStride, size_t width, size_t height) {
80 // Converting two lines at a time, slightly faster
81 for (size_t y = 0; y < height; y += 2) {
82 uint32_t *dstTop = (uint32_t *)dst;
83 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
84 uint16_t *ySrcTop = (uint16_t *)srcY;
85 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
86 uint16_t *uSrc = (uint16_t *)srcU;
87 uint16_t *vSrc = (uint16_t *)srcV;
88
89 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
90 size_t x = 0;
91 for (; x < width - 3; x += 4) {
92 u01 = *((uint32_t *)uSrc);
93 uSrc += 2;
94 v01 = *((uint32_t *)vSrc);
95 vSrc += 2;
96
97 y01 = *((uint32_t *)ySrcTop);
98 ySrcTop += 2;
99 y23 = *((uint32_t *)ySrcTop);
100 ySrcTop += 2;
101 y45 = *((uint32_t *)ySrcBot);
102 ySrcBot += 2;
103 y67 = *((uint32_t *)ySrcBot);
104 ySrcBot += 2;
105
106 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
107 uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
108
109 *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
110 *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
111 *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
112 *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
113
114 *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
115 *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
116 *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
117 *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
118 }
119
120 // There should be at most 2 more pixels to process. Note that we don't
121 // need to consider odd case as the buffer is always aligned to even.
122 if (x < width) {
123 u01 = *uSrc;
124 v01 = *vSrc;
125 y01 = *((uint32_t *)ySrcTop);
126 y45 = *((uint32_t *)ySrcBot);
127 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
128 *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
129 *dstTop++ = ((y01 >> 16) << 10) | uv0;
130 *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
131 *dstBot++ = ((y45 >> 16) << 10) | uv0;
132 }
133
134 srcY += srcYStride * 2;
135 srcU += srcUStride;
136 srcV += srcVStride;
137 dst += dstStride * 2;
138 }
139}
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700140#define CLIP3(min, v, max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
141void convertYUV420Planar16ToRGBA1010102(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
142 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
143 size_t srcVStride, size_t dstStride, size_t width,
144 size_t height) {
145 // Converting two lines at a time, slightly faster
146 for (size_t y = 0; y < height; y += 2) {
147 uint32_t *dstTop = (uint32_t *)dst;
148 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
149 uint16_t *ySrcTop = (uint16_t *)srcY;
150 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
151 uint16_t *uSrc = (uint16_t *)srcU;
152 uint16_t *vSrc = (uint16_t *)srcV;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800153
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700154 // BT.2020 Limited Range conversion
155
156 // B = 1.168 *(Y - 64) + 2.148 *(U - 512)
157 // G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
158 // R = 1.168 *(Y - 64) + 1.683 *(V - 512)
159
160 // B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
161 // G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
162 // R = .................... + 1723/1024 *(V - 512)
163
164 // min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
165 // min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
166 // min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
167
168 // max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
169 // max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
170 // max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
171
172 int32_t mY = 1196, mU_B = 2200, mV_G = -668, mV_R = 1723, mU_G = -192;
173 for (size_t x = 0; x < width; x += 2) {
174 int32_t u, v, y00, y01, y10, y11;
175 u = *uSrc - 512;
176 uSrc += 1;
177 v = *vSrc - 512;
178 vSrc += 1;
179
180 y00 = *ySrcTop - 64;
181 ySrcTop += 1;
182 y01 = *ySrcTop - 64;
183 ySrcTop += 1;
184 y10 = *ySrcBot - 64;
185 ySrcBot += 1;
186 y11 = *ySrcBot - 64;
187 ySrcBot += 1;
188
189 int32_t u_b = u * mU_B;
190 int32_t u_g = u * mU_G;
191 int32_t v_g = v * mV_G;
192 int32_t v_r = v * mV_R;
193
194 int32_t yMult, b, g, r;
195 yMult = y00 * mY;
196 b = (yMult + u_b) / 1024;
197 g = (yMult + v_g + u_g) / 1024;
198 r = (yMult + v_r) / 1024;
199 b = CLIP3(0, b, 1023);
200 g = CLIP3(0, g, 1023);
201 r = CLIP3(0, r, 1023);
202 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
203
204 yMult = y01 * mY;
205 b = (yMult + u_b) / 1024;
206 g = (yMult + v_g + u_g) / 1024;
207 r = (yMult + v_r) / 1024;
208 b = CLIP3(0, b, 1023);
209 g = CLIP3(0, g, 1023);
210 r = CLIP3(0, r, 1023);
211 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
212
213 yMult = y10 * mY;
214 b = (yMult + u_b) / 1024;
215 g = (yMult + v_g + u_g) / 1024;
216 r = (yMult + v_r) / 1024;
217 b = CLIP3(0, b, 1023);
218 g = CLIP3(0, g, 1023);
219 r = CLIP3(0, r, 1023);
220 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
221
222 yMult = y11 * mY;
223 b = (yMult + u_b) / 1024;
224 g = (yMult + v_g + u_g) / 1024;
225 r = (yMult + v_r) / 1024;
226 b = CLIP3(0, b, 1023);
227 g = CLIP3(0, g, 1023);
228 r = CLIP3(0, r, 1023);
229 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
230 }
231
232 srcY += srcYStride * 2;
233 srcU += srcUStride;
234 srcV += srcVStride;
235 dst += dstStride * 2;
236 }
237}
238
239void convertYUV420Planar16ToY410OrRGBA1010102(uint32_t *dst, const uint16_t *srcY,
240 const uint16_t *srcU, const uint16_t *srcV,
241 size_t srcYStride, size_t srcUStride,
242 size_t srcVStride, size_t dstStride, size_t width,
243 size_t height) {
244 if (isAtLeastT()) {
245 convertYUV420Planar16ToRGBA1010102(dst, srcY, srcU, srcV, srcYStride, srcUStride,
246 srcVStride, dstStride, width, height);
247 } else {
248 convertYUV420Planar16ToY410(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
249 dstStride, width, height);
250 }
251}
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800252void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
253 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
254 size_t srcUStride, size_t srcVStride, size_t dstYStride,
255 size_t dstUVStride, size_t width, size_t height,
256 bool isMonochrome) {
257 for (size_t y = 0; y < height; ++y) {
258 for (size_t x = 0; x < width; ++x) {
259 dstY[x] = (uint8_t)(srcY[x] >> 2);
260 }
261 srcY += srcYStride;
262 dstY += dstYStride;
263 }
264
265 if (isMonochrome) {
266 // Fill with neutral U/V values.
267 for (size_t y = 0; y < (height + 1) / 2; ++y) {
268 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
269 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
270 dstV += dstUVStride;
271 dstU += dstUVStride;
272 }
273 return;
274 }
275
276 for (size_t y = 0; y < (height + 1) / 2; ++y) {
277 for (size_t x = 0; x < (width + 1) / 2; ++x) {
278 dstU[x] = (uint8_t)(srcU[x] >> 2);
279 dstV[x] = (uint8_t)(srcV[x] >> 2);
280 }
281 srcU += srcUStride;
282 srcV += srcVStride;
283 dstU += dstUVStride;
284 dstV += dstUVStride;
285 }
286}
287
288void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
289 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
290 size_t srcUStride, size_t srcVStride, size_t dstYStride,
291 size_t dstUVStride, size_t width, size_t height,
292 bool isMonochrome) {
293 for (size_t y = 0; y < height; ++y) {
294 for (size_t x = 0; x < width; ++x) {
295 dstY[x] = srcY[x] << 6;
296 }
297 srcY += srcYStride;
298 dstY += dstYStride;
299 }
300
301 if (isMonochrome) {
302 // Fill with neutral U/V values.
303 for (size_t y = 0; y < (height + 1) / 2; ++y) {
304 for (size_t x = 0; x < (width + 1) / 2; ++x) {
305 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
306 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
307 }
308 dstUV += dstUVStride;
309 }
310 return;
311 }
312
313 for (size_t y = 0; y < (height + 1) / 2; ++y) {
314 for (size_t x = 0; x < (width + 1) / 2; ++x) {
315 dstUV[2 * x] = srcU[x] << 6;
316 dstUV[2 * x + 1] = srcV[x] << 6;
317 }
318 srcU += srcUStride;
319 srcV += srcVStride;
320 dstUV += dstUVStride;
321 }
322}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800323std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
324 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
325 mQueue.pop_front();
326 return work;
327}
328
329void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
330 mQueue.push_back({ std::move(work), NO_DRAIN });
331}
332
333bool SimpleC2Component::WorkQueue::empty() const {
334 return mQueue.empty();
335}
336
337void SimpleC2Component::WorkQueue::clear() {
338 mQueue.clear();
339}
340
341uint32_t SimpleC2Component::WorkQueue::drainMode() const {
342 return mQueue.front().drainMode;
343}
344
345void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
346 mQueue.push_back({ nullptr, drainMode });
347}
348
349////////////////////////////////////////////////////////////////////////////////
350
351SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
352
353void SimpleC2Component::WorkHandler::setComponent(
354 const std::shared_ptr<SimpleC2Component> &thiz) {
355 mThiz = thiz;
356}
357
358static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
359 sp<AReplyToken> replyId;
360 CHECK(msg->senderAwaitsResponse(&replyId));
361 sp<AMessage> reply = new AMessage;
362 if (err) {
363 reply->setInt32("err", *err);
364 }
365 reply->postReply(replyId);
366}
367
368void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
369 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
370 if (!thiz) {
371 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
372 sp<AReplyToken> replyId;
373 if (msg->senderAwaitsResponse(&replyId)) {
374 sp<AMessage> reply = new AMessage;
375 reply->setInt32("err", C2_CORRUPTED);
376 reply->postReply(replyId);
377 }
378 return;
379 }
380
381 switch (msg->what()) {
382 case kWhatProcess: {
383 if (mRunning) {
384 if (thiz->processQueue()) {
385 (new AMessage(kWhatProcess, this))->post();
386 }
387 } else {
388 ALOGV("Ignore process message as we're not running");
389 }
390 break;
391 }
392 case kWhatInit: {
393 int32_t err = thiz->onInit();
394 Reply(msg, &err);
395 [[fallthrough]];
396 }
397 case kWhatStart: {
398 mRunning = true;
399 break;
400 }
401 case kWhatStop: {
402 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700403 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800404 Reply(msg, &err);
405 break;
406 }
407 case kWhatReset: {
408 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700409 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800410 mRunning = false;
411 Reply(msg);
412 break;
413 }
414 case kWhatRelease: {
415 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700416 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800417 mRunning = false;
418 Reply(msg);
419 break;
420 }
421 default: {
422 ALOGD("Unrecognized msg: %d", msg->what());
423 break;
424 }
425 }
426}
427
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800428class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
429public:
430 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
431
432 virtual local_id_t getLocalId() const override {
433 return mBase->getLocalId();
434 }
435
436 virtual C2Allocator::id_t getAllocatorId() const override {
437 return mBase->getAllocatorId();
438 }
439
440 virtual c2_status_t fetchLinearBlock(
441 uint32_t capacity,
442 C2MemoryUsage usage,
443 std::shared_ptr<C2LinearBlock>* block) {
444 c2_status_t status;
445 do {
446 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800447 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800448 return status;
449 }
450
451 virtual c2_status_t fetchCircularBlock(
452 uint32_t capacity,
453 C2MemoryUsage usage,
454 std::shared_ptr<C2CircularBlock>* block) {
455 c2_status_t status;
456 do {
457 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800458 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800459 return status;
460 }
461
462 virtual c2_status_t fetchGraphicBlock(
463 uint32_t width, uint32_t height, uint32_t format,
464 C2MemoryUsage usage,
465 std::shared_ptr<C2GraphicBlock>* block) {
466 c2_status_t status;
467 do {
468 status = mBase->fetchGraphicBlock(width, height, format, usage,
469 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800470 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800471 return status;
472 }
473
474private:
475 std::shared_ptr<C2BlockPool> mBase;
476};
477
Pawin Vongmasa36653902018-11-15 00:10:25 -0800478////////////////////////////////////////////////////////////////////////////////
479
480namespace {
481
482struct DummyReadView : public C2ReadView {
483 DummyReadView() : C2ReadView(C2_NO_INIT) {}
484};
485
486} // namespace
487
488SimpleC2Component::SimpleC2Component(
489 const std::shared_ptr<C2ComponentInterface> &intf)
490 : mDummyReadView(DummyReadView()),
491 mIntf(intf),
492 mLooper(new ALooper),
493 mHandler(new WorkHandler) {
494 mLooper->setName(intf->getName().c_str());
495 (void)mLooper->registerHandler(mHandler);
496 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
497}
498
499SimpleC2Component::~SimpleC2Component() {
500 mLooper->unregisterHandler(mHandler->id());
501 (void)mLooper->stop();
502}
503
504c2_status_t SimpleC2Component::setListener_vb(
505 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
506 mHandler->setComponent(shared_from_this());
507
508 Mutexed<ExecState>::Locked state(mExecState);
509 if (state->mState == RUNNING) {
510 if (listener) {
511 return C2_BAD_STATE;
512 } else if (!mayBlock) {
513 return C2_BLOCKING;
514 }
515 }
516 state->mListener = listener;
517 // TODO: wait for listener change to have taken place before returning
518 // (e.g. if there is an ongoing listener callback)
519 return C2_OK;
520}
521
522c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
523 {
524 Mutexed<ExecState>::Locked state(mExecState);
525 if (state->mState != RUNNING) {
526 return C2_BAD_STATE;
527 }
528 }
529 bool queueWasEmpty = false;
530 {
531 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
532 queueWasEmpty = queue->empty();
533 while (!items->empty()) {
534 queue->push_back(std::move(items->front()));
535 items->pop_front();
536 }
537 }
538 if (queueWasEmpty) {
539 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
540 }
541 return C2_OK;
542}
543
544c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
545 (void)items;
546 return C2_OMITTED;
547}
548
549c2_status_t SimpleC2Component::flush_sm(
550 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
551 (void)flushMode;
552 {
553 Mutexed<ExecState>::Locked state(mExecState);
554 if (state->mState != RUNNING) {
555 return C2_BAD_STATE;
556 }
557 }
558 {
559 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
560 queue->incGeneration();
561 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
562 while (!queue->empty()) {
563 std::unique_ptr<C2Work> work = queue->pop_front();
564 if (work) {
565 flushedWork->push_back(std::move(work));
566 }
567 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700568 while (!queue->pending().empty()) {
569 flushedWork->push_back(std::move(queue->pending().begin()->second));
570 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800571 }
572 }
573
574 return C2_OK;
575}
576
577c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
578 if (drainMode == DRAIN_CHAIN) {
579 return C2_OMITTED;
580 }
581 {
582 Mutexed<ExecState>::Locked state(mExecState);
583 if (state->mState != RUNNING) {
584 return C2_BAD_STATE;
585 }
586 }
587 bool queueWasEmpty = false;
588 {
589 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
590 queueWasEmpty = queue->empty();
591 queue->markDrain(drainMode);
592 }
593 if (queueWasEmpty) {
594 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
595 }
596
597 return C2_OK;
598}
599
600c2_status_t SimpleC2Component::start() {
601 Mutexed<ExecState>::Locked state(mExecState);
602 if (state->mState == RUNNING) {
603 return C2_BAD_STATE;
604 }
605 bool needsInit = (state->mState == UNINITIALIZED);
606 state.unlock();
607 if (needsInit) {
608 sp<AMessage> reply;
609 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
610 int32_t err;
611 CHECK(reply->findInt32("err", &err));
612 if (err != C2_OK) {
613 return (c2_status_t)err;
614 }
615 } else {
616 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
617 }
618 state.lock();
619 state->mState = RUNNING;
620 return C2_OK;
621}
622
623c2_status_t SimpleC2Component::stop() {
624 ALOGV("stop");
625 {
626 Mutexed<ExecState>::Locked state(mExecState);
627 if (state->mState != RUNNING) {
628 return C2_BAD_STATE;
629 }
630 state->mState = STOPPED;
631 }
632 {
633 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
634 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700635 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800636 }
637 sp<AMessage> reply;
638 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
639 int32_t err;
640 CHECK(reply->findInt32("err", &err));
641 if (err != C2_OK) {
642 return (c2_status_t)err;
643 }
644 return C2_OK;
645}
646
647c2_status_t SimpleC2Component::reset() {
648 ALOGV("reset");
649 {
650 Mutexed<ExecState>::Locked state(mExecState);
651 state->mState = UNINITIALIZED;
652 }
653 {
654 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
655 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700656 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800657 }
658 sp<AMessage> reply;
659 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
660 return C2_OK;
661}
662
663c2_status_t SimpleC2Component::release() {
664 ALOGV("release");
665 sp<AMessage> reply;
666 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
667 return C2_OK;
668}
669
670std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
671 return mIntf;
672}
673
674namespace {
675
676std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
677 std::list<std::unique_ptr<C2Work>> ret;
678 ret.push_back(std::move(work));
679 return ret;
680}
681
682} // namespace
683
684void SimpleC2Component::finish(
685 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
686 std::unique_ptr<C2Work> work;
687 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700688 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
689 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800690 ALOGW("unknown frame index: %" PRIu64, frameIndex);
691 return;
692 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700693 work = std::move(queue->pending().at(frameIndex));
694 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800695 }
696 if (work) {
697 fillWork(work);
698 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
699 listener->onWorkDone_nb(shared_from_this(), vec(work));
700 ALOGV("returning pending work");
701 }
702}
703
704void SimpleC2Component::cloneAndSend(
705 uint64_t frameIndex,
706 const std::unique_ptr<C2Work> &currentWork,
707 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
708 std::unique_ptr<C2Work> work(new C2Work);
709 if (currentWork->input.ordinal.frameIndex == frameIndex) {
710 work->input.flags = currentWork->input.flags;
711 work->input.ordinal = currentWork->input.ordinal;
712 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700713 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
714 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800715 ALOGW("unknown frame index: %" PRIu64, frameIndex);
716 return;
717 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700718 work->input.flags = queue->pending().at(frameIndex)->input.flags;
719 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800720 }
721 work->worklets.emplace_back(new C2Worklet);
722 if (work) {
723 fillWork(work);
724 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
725 listener->onWorkDone_nb(shared_from_this(), vec(work));
726 ALOGV("cloned and sending work");
727 }
728}
729
730bool SimpleC2Component::processQueue() {
731 std::unique_ptr<C2Work> work;
732 uint64_t generation;
733 int32_t drainMode;
734 bool isFlushPending = false;
735 bool hasQueuedWork = false;
736 {
737 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
738 if (queue->empty()) {
739 return false;
740 }
741
742 generation = queue->generation();
743 drainMode = queue->drainMode();
744 isFlushPending = queue->popPendingFlush();
745 work = queue->pop_front();
746 hasQueuedWork = !queue->empty();
747 }
748 if (isFlushPending) {
749 ALOGV("processing pending flush");
750 c2_status_t err = onFlush_sm();
751 if (err != C2_OK) {
752 ALOGD("flush err: %d", err);
753 // TODO: error
754 }
755 }
756
757 if (!mOutputBlockPool) {
758 c2_status_t err = [this] {
759 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800760 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800761 std::vector<std::unique_ptr<C2Param>> params;
762 c2_status_t err = intf()->query_vb(
763 { &outputFormat },
764 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
765 C2_DONT_BLOCK,
766 &params);
767 if (err != C2_OK && err != C2_BAD_INDEX) {
768 ALOGD("query err = %d", err);
769 return err;
770 }
771 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800772 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800773 ? C2BlockPool::BASIC_GRAPHIC
774 : C2BlockPool::BASIC_LINEAR;
775 if (params.size()) {
776 C2PortBlockPoolsTuning::output *outputPools =
777 C2PortBlockPoolsTuning::output::From(params[0].get());
778 if (outputPools && outputPools->flexCount() >= 1) {
779 poolId = outputPools->m.values[0];
780 }
781 }
782
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800783 std::shared_ptr<C2BlockPool> blockPool;
784 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800785 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
786 (unsigned long long)poolId,
787 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800788 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800789 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800790 if (err == C2_OK) {
791 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
792 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800793 return err;
794 }();
795 if (err != C2_OK) {
796 Mutexed<ExecState>::Locked state(mExecState);
797 std::shared_ptr<C2Component::Listener> listener = state->mListener;
798 state.unlock();
799 listener->onError_nb(shared_from_this(), err);
800 return hasQueuedWork;
801 }
802 }
803
804 if (!work) {
805 c2_status_t err = drain(drainMode, mOutputBlockPool);
806 if (err != C2_OK) {
807 Mutexed<ExecState>::Locked state(mExecState);
808 std::shared_ptr<C2Component::Listener> listener = state->mListener;
809 state.unlock();
810 listener->onError_nb(shared_from_this(), err);
811 }
812 return hasQueuedWork;
813 }
814
815 {
816 std::vector<C2Param *> updates;
817 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
818 if (param) {
819 updates.emplace_back(param.get());
820 }
821 }
822 if (!updates.empty()) {
823 std::vector<std::unique_ptr<C2SettingResult>> failures;
824 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
825 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
826 }
827 }
828
829 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800830 // If input buffer list is not empty, it means we have some input to process on.
831 // However, input could be a null buffer. In such case, clear the buffer list
832 // before making call to process().
833 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
834 ALOGD("Encountered null input buffer. Clearing the input buffer");
835 work->input.buffers.clear();
836 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800837 process(work, mOutputBlockPool);
838 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -0700839 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
840 if (queue->generation() != generation) {
841 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
842 queue->generation(), generation);
843 work->result = C2_NOT_FOUND;
844 queue.unlock();
845
846 Mutexed<ExecState>::Locked state(mExecState);
847 std::shared_ptr<C2Component::Listener> listener = state->mListener;
848 state.unlock();
849 listener->onWorkDone_nb(shared_from_this(), vec(work));
850 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800851 }
852 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -0700853 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800854 Mutexed<ExecState>::Locked state(mExecState);
855 ALOGV("returning this work");
856 std::shared_ptr<C2Component::Listener> listener = state->mListener;
857 state.unlock();
858 listener->onWorkDone_nb(shared_from_this(), vec(work));
859 } else {
860 ALOGV("queue pending work");
861 work->input.buffers.clear();
862 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -0700863
864 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
865 if (queue->pending().count(frameIndex) != 0) {
866 unexpected = std::move(queue->pending().at(frameIndex));
867 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800868 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700869 (void)queue->pending().insert({ frameIndex, std::move(work) });
870
871 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800872 if (unexpected) {
873 ALOGD("unexpected pending work");
874 unexpected->result = C2_CORRUPTED;
875 Mutexed<ExecState>::Locked state(mExecState);
876 std::shared_ptr<C2Component::Listener> listener = state->mListener;
877 state.unlock();
878 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
879 }
880 }
881 return hasQueuedWork;
882}
883
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800884int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
885 // Save supported hal pixel formats for bit depth of 10, the first time this is called
886 if (!mBitDepth10HalPixelFormats.size()) {
887 std::vector<int> halPixelFormats;
Harish Mahendrakard4bbb762022-03-29 11:53:23 -0700888 if (isAtLeastT()) {
889 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
890 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800891 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
892 // is populated only once, allowRGBA1010102 is not considered at this stage.
893 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
894
895 for (int halPixelFormat : halPixelFormats) {
896 std::shared_ptr<C2GraphicBlock> block;
897
898 uint32_t gpuConsumerFlags = halPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102
899 ? C2AndroidMemoryUsage::HW_TEXTURE_READ
900 : 0;
901 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ | gpuConsumerFlags,
902 C2MemoryUsage::CPU_WRITE};
903 // TODO(b/214411172) Use AHardwareBuffer_isSupported once it supports P010
904 c2_status_t status =
905 mOutputBlockPool->fetchGraphicBlock(320, 240, halPixelFormat, usage, &block);
906 if (status == C2_OK) {
907 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
908 }
909 }
910 // Add YV12 in the end as a fall-back option
911 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
912 }
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700913 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
914 // RGBA 1010102 format unlike earlier versions where it was used to represent
915 // YUVA 1010102 data
916 if (!isAtLeastT()) {
917 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
918 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
919 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
920 return HAL_PIXEL_FORMAT_YV12;
921 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800922 }
923 // Return the first entry from supported formats
924 return mBitDepth10HalPixelFormats[0];
925}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800926std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800927 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
928 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
929}
930
931std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800932 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
933 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
934}
935
936} // namespace android