blob: 01f5ffb14ffb06b3c8d62f64b10ef22dbded01d1 [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
Harish Mahendrakarf5dec502022-04-13 15:53:55 -070021#include <android/hardware_buffer.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080022#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>
Harish Mahendrakarf5dec502022-04-13 15:53:55 -070030#include <Codec2BufferUtils.h>
31#include <Codec2CommonUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080032#include <SimpleC2Component.h>
33
34namespace android {
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080035constexpr uint8_t kNeutralUVBitDepth8 = 128;
36constexpr uint16_t kNeutralUVBitDepth10 = 512;
Pawin Vongmasa36653902018-11-15 00:10:25 -080037
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -080038void 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 / 2; ++i) {
52 memset(dstV, kNeutralUVBitDepth8, width / 2);
53 memset(dstU, kNeutralUVBitDepth8, width / 2);
54 dstV += dstUVStride;
55 dstU += dstUVStride;
56 }
57 return;
58 }
59
60 for (size_t i = 0; i < height / 2; ++i) {
61 memcpy(dstV, srcV, width / 2);
62 srcV += srcVStride;
63 dstV += dstUVStride;
64 }
65
66 for (size_t i = 0; i < height / 2; ++i) {
67 memcpy(dstU, srcU, width / 2);
68 srcU += srcUStride;
69 dstU += dstUVStride;
70 }
71}
72
73void 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}
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700136#define CLIP3(min, v, max) (((v) < (min)) ? (min) : (((max) > (v)) ? (v) : (max)))
137void convertYUV420Planar16ToRGBA1010102(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
138 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
139 size_t srcVStride, size_t dstStride, size_t width,
140 size_t height) {
141 // Converting two lines at a time, slightly faster
142 for (size_t y = 0; y < height; y += 2) {
143 uint32_t *dstTop = (uint32_t *)dst;
144 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
145 uint16_t *ySrcTop = (uint16_t *)srcY;
146 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
147 uint16_t *uSrc = (uint16_t *)srcU;
148 uint16_t *vSrc = (uint16_t *)srcV;
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800149
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700150 // BT.2020 Limited Range conversion
151
152 // B = 1.168 *(Y - 64) + 2.148 *(U - 512)
153 // G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512)
154 // R = 1.168 *(Y - 64) + 1.683 *(V - 512)
155
156 // B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512)
157 // G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512)
158 // R = .................... + 1723/1024 *(V - 512)
159
160 // min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175
161 // min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504
162 // min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937
163
164 // max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218
165 // max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551
166 // max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980
167
168 int32_t mY = 1196, mU_B = 2200, mV_G = -668, mV_R = 1723, mU_G = -192;
169 for (size_t x = 0; x < width; x += 2) {
170 int32_t u, v, y00, y01, y10, y11;
171 u = *uSrc - 512;
172 uSrc += 1;
173 v = *vSrc - 512;
174 vSrc += 1;
175
176 y00 = *ySrcTop - 64;
177 ySrcTop += 1;
178 y01 = *ySrcTop - 64;
179 ySrcTop += 1;
180 y10 = *ySrcBot - 64;
181 ySrcBot += 1;
182 y11 = *ySrcBot - 64;
183 ySrcBot += 1;
184
185 int32_t u_b = u * mU_B;
186 int32_t u_g = u * mU_G;
187 int32_t v_g = v * mV_G;
188 int32_t v_r = v * mV_R;
189
190 int32_t yMult, b, g, r;
191 yMult = y00 * mY;
192 b = (yMult + u_b) / 1024;
193 g = (yMult + v_g + u_g) / 1024;
194 r = (yMult + v_r) / 1024;
195 b = CLIP3(0, b, 1023);
196 g = CLIP3(0, g, 1023);
197 r = CLIP3(0, r, 1023);
198 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
199
200 yMult = y01 * mY;
201 b = (yMult + u_b) / 1024;
202 g = (yMult + v_g + u_g) / 1024;
203 r = (yMult + v_r) / 1024;
204 b = CLIP3(0, b, 1023);
205 g = CLIP3(0, g, 1023);
206 r = CLIP3(0, r, 1023);
207 *dstTop++ = 3 << 30 | (b << 20) | (g << 10) | r;
208
209 yMult = y10 * mY;
210 b = (yMult + u_b) / 1024;
211 g = (yMult + v_g + u_g) / 1024;
212 r = (yMult + v_r) / 1024;
213 b = CLIP3(0, b, 1023);
214 g = CLIP3(0, g, 1023);
215 r = CLIP3(0, r, 1023);
216 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
217
218 yMult = y11 * mY;
219 b = (yMult + u_b) / 1024;
220 g = (yMult + v_g + u_g) / 1024;
221 r = (yMult + v_r) / 1024;
222 b = CLIP3(0, b, 1023);
223 g = CLIP3(0, g, 1023);
224 r = CLIP3(0, r, 1023);
225 *dstBot++ = 3 << 30 | (b << 20) | (g << 10) | r;
226 }
227
228 srcY += srcYStride * 2;
229 srcU += srcUStride;
230 srcV += srcVStride;
231 dst += dstStride * 2;
232 }
233}
234
235void convertYUV420Planar16ToY410OrRGBA1010102(uint32_t *dst, const uint16_t *srcY,
236 const uint16_t *srcU, const uint16_t *srcV,
237 size_t srcYStride, size_t srcUStride,
238 size_t srcVStride, size_t dstStride, size_t width,
239 size_t height) {
240 if (isAtLeastT()) {
241 convertYUV420Planar16ToRGBA1010102(dst, srcY, srcU, srcV, srcYStride, srcUStride,
242 srcVStride, dstStride, width, height);
243 } else {
244 convertYUV420Planar16ToY410(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
245 dstStride, width, height);
246 }
247}
Harish Mahendrakar1b1aef22021-12-30 19:12:51 -0800248void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
249 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
250 size_t srcUStride, size_t srcVStride, size_t dstYStride,
251 size_t dstUVStride, size_t width, size_t height,
252 bool isMonochrome) {
253 for (size_t y = 0; y < height; ++y) {
254 for (size_t x = 0; x < width; ++x) {
255 dstY[x] = (uint8_t)(srcY[x] >> 2);
256 }
257 srcY += srcYStride;
258 dstY += dstYStride;
259 }
260
261 if (isMonochrome) {
262 // Fill with neutral U/V values.
263 for (size_t y = 0; y < (height + 1) / 2; ++y) {
264 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
265 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
266 dstV += dstUVStride;
267 dstU += dstUVStride;
268 }
269 return;
270 }
271
272 for (size_t y = 0; y < (height + 1) / 2; ++y) {
273 for (size_t x = 0; x < (width + 1) / 2; ++x) {
274 dstU[x] = (uint8_t)(srcU[x] >> 2);
275 dstV[x] = (uint8_t)(srcV[x] >> 2);
276 }
277 srcU += srcUStride;
278 srcV += srcVStride;
279 dstU += dstUVStride;
280 dstV += dstUVStride;
281 }
282}
283
284void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
285 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
286 size_t srcUStride, size_t srcVStride, size_t dstYStride,
287 size_t dstUVStride, size_t width, size_t height,
288 bool isMonochrome) {
289 for (size_t y = 0; y < height; ++y) {
290 for (size_t x = 0; x < width; ++x) {
291 dstY[x] = srcY[x] << 6;
292 }
293 srcY += srcYStride;
294 dstY += dstYStride;
295 }
296
297 if (isMonochrome) {
298 // Fill with neutral U/V values.
299 for (size_t y = 0; y < (height + 1) / 2; ++y) {
300 for (size_t x = 0; x < (width + 1) / 2; ++x) {
301 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
302 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
303 }
304 dstUV += dstUVStride;
305 }
306 return;
307 }
308
309 for (size_t y = 0; y < (height + 1) / 2; ++y) {
310 for (size_t x = 0; x < (width + 1) / 2; ++x) {
311 dstUV[2 * x] = srcU[x] << 6;
312 dstUV[2 * x + 1] = srcV[x] << 6;
313 }
314 srcU += srcUStride;
315 srcV += srcVStride;
316 dstUV += dstUVStride;
317 }
318}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800319std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
320 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
321 mQueue.pop_front();
322 return work;
323}
324
325void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
326 mQueue.push_back({ std::move(work), NO_DRAIN });
327}
328
329bool SimpleC2Component::WorkQueue::empty() const {
330 return mQueue.empty();
331}
332
333void SimpleC2Component::WorkQueue::clear() {
334 mQueue.clear();
335}
336
337uint32_t SimpleC2Component::WorkQueue::drainMode() const {
338 return mQueue.front().drainMode;
339}
340
341void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
342 mQueue.push_back({ nullptr, drainMode });
343}
344
345////////////////////////////////////////////////////////////////////////////////
346
347SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
348
349void SimpleC2Component::WorkHandler::setComponent(
350 const std::shared_ptr<SimpleC2Component> &thiz) {
351 mThiz = thiz;
352}
353
354static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
355 sp<AReplyToken> replyId;
356 CHECK(msg->senderAwaitsResponse(&replyId));
357 sp<AMessage> reply = new AMessage;
358 if (err) {
359 reply->setInt32("err", *err);
360 }
361 reply->postReply(replyId);
362}
363
364void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
365 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
366 if (!thiz) {
367 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
368 sp<AReplyToken> replyId;
369 if (msg->senderAwaitsResponse(&replyId)) {
370 sp<AMessage> reply = new AMessage;
371 reply->setInt32("err", C2_CORRUPTED);
372 reply->postReply(replyId);
373 }
374 return;
375 }
376
377 switch (msg->what()) {
378 case kWhatProcess: {
379 if (mRunning) {
380 if (thiz->processQueue()) {
381 (new AMessage(kWhatProcess, this))->post();
382 }
383 } else {
384 ALOGV("Ignore process message as we're not running");
385 }
386 break;
387 }
388 case kWhatInit: {
389 int32_t err = thiz->onInit();
390 Reply(msg, &err);
391 [[fallthrough]];
392 }
393 case kWhatStart: {
394 mRunning = true;
395 break;
396 }
397 case kWhatStop: {
398 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700399 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800400 Reply(msg, &err);
401 break;
402 }
403 case kWhatReset: {
404 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700405 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800406 mRunning = false;
407 Reply(msg);
408 break;
409 }
410 case kWhatRelease: {
411 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700412 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800413 mRunning = false;
414 Reply(msg);
415 break;
416 }
417 default: {
418 ALOGD("Unrecognized msg: %d", msg->what());
419 break;
420 }
421 }
422}
423
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800424class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
425public:
426 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
427
428 virtual local_id_t getLocalId() const override {
429 return mBase->getLocalId();
430 }
431
432 virtual C2Allocator::id_t getAllocatorId() const override {
433 return mBase->getAllocatorId();
434 }
435
436 virtual c2_status_t fetchLinearBlock(
437 uint32_t capacity,
438 C2MemoryUsage usage,
439 std::shared_ptr<C2LinearBlock>* block) {
440 c2_status_t status;
441 do {
442 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800443 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800444 return status;
445 }
446
447 virtual c2_status_t fetchCircularBlock(
448 uint32_t capacity,
449 C2MemoryUsage usage,
450 std::shared_ptr<C2CircularBlock>* block) {
451 c2_status_t status;
452 do {
453 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800454 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800455 return status;
456 }
457
458 virtual c2_status_t fetchGraphicBlock(
459 uint32_t width, uint32_t height, uint32_t format,
460 C2MemoryUsage usage,
461 std::shared_ptr<C2GraphicBlock>* block) {
462 c2_status_t status;
463 do {
464 status = mBase->fetchGraphicBlock(width, height, format, usage,
465 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800466 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800467 return status;
468 }
469
470private:
471 std::shared_ptr<C2BlockPool> mBase;
472};
473
Pawin Vongmasa36653902018-11-15 00:10:25 -0800474////////////////////////////////////////////////////////////////////////////////
475
476namespace {
477
478struct DummyReadView : public C2ReadView {
479 DummyReadView() : C2ReadView(C2_NO_INIT) {}
480};
481
482} // namespace
483
484SimpleC2Component::SimpleC2Component(
485 const std::shared_ptr<C2ComponentInterface> &intf)
486 : mDummyReadView(DummyReadView()),
487 mIntf(intf),
488 mLooper(new ALooper),
489 mHandler(new WorkHandler) {
490 mLooper->setName(intf->getName().c_str());
491 (void)mLooper->registerHandler(mHandler);
492 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
493}
494
495SimpleC2Component::~SimpleC2Component() {
496 mLooper->unregisterHandler(mHandler->id());
497 (void)mLooper->stop();
498}
499
500c2_status_t SimpleC2Component::setListener_vb(
501 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
502 mHandler->setComponent(shared_from_this());
503
504 Mutexed<ExecState>::Locked state(mExecState);
505 if (state->mState == RUNNING) {
506 if (listener) {
507 return C2_BAD_STATE;
508 } else if (!mayBlock) {
509 return C2_BLOCKING;
510 }
511 }
512 state->mListener = listener;
513 // TODO: wait for listener change to have taken place before returning
514 // (e.g. if there is an ongoing listener callback)
515 return C2_OK;
516}
517
518c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
519 {
520 Mutexed<ExecState>::Locked state(mExecState);
521 if (state->mState != RUNNING) {
522 return C2_BAD_STATE;
523 }
524 }
525 bool queueWasEmpty = false;
526 {
527 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
528 queueWasEmpty = queue->empty();
529 while (!items->empty()) {
530 queue->push_back(std::move(items->front()));
531 items->pop_front();
532 }
533 }
534 if (queueWasEmpty) {
535 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
536 }
537 return C2_OK;
538}
539
540c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
541 (void)items;
542 return C2_OMITTED;
543}
544
545c2_status_t SimpleC2Component::flush_sm(
546 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
547 (void)flushMode;
548 {
549 Mutexed<ExecState>::Locked state(mExecState);
550 if (state->mState != RUNNING) {
551 return C2_BAD_STATE;
552 }
553 }
554 {
555 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
556 queue->incGeneration();
557 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
558 while (!queue->empty()) {
559 std::unique_ptr<C2Work> work = queue->pop_front();
560 if (work) {
561 flushedWork->push_back(std::move(work));
562 }
563 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700564 while (!queue->pending().empty()) {
565 flushedWork->push_back(std::move(queue->pending().begin()->second));
566 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800567 }
568 }
569
570 return C2_OK;
571}
572
573c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
574 if (drainMode == DRAIN_CHAIN) {
575 return C2_OMITTED;
576 }
577 {
578 Mutexed<ExecState>::Locked state(mExecState);
579 if (state->mState != RUNNING) {
580 return C2_BAD_STATE;
581 }
582 }
583 bool queueWasEmpty = false;
584 {
585 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
586 queueWasEmpty = queue->empty();
587 queue->markDrain(drainMode);
588 }
589 if (queueWasEmpty) {
590 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
591 }
592
593 return C2_OK;
594}
595
596c2_status_t SimpleC2Component::start() {
597 Mutexed<ExecState>::Locked state(mExecState);
598 if (state->mState == RUNNING) {
599 return C2_BAD_STATE;
600 }
601 bool needsInit = (state->mState == UNINITIALIZED);
602 state.unlock();
603 if (needsInit) {
604 sp<AMessage> reply;
605 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
606 int32_t err;
607 CHECK(reply->findInt32("err", &err));
608 if (err != C2_OK) {
609 return (c2_status_t)err;
610 }
611 } else {
612 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
613 }
614 state.lock();
615 state->mState = RUNNING;
616 return C2_OK;
617}
618
619c2_status_t SimpleC2Component::stop() {
620 ALOGV("stop");
621 {
622 Mutexed<ExecState>::Locked state(mExecState);
623 if (state->mState != RUNNING) {
624 return C2_BAD_STATE;
625 }
626 state->mState = STOPPED;
627 }
628 {
629 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
630 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700631 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800632 }
633 sp<AMessage> reply;
634 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
635 int32_t err;
636 CHECK(reply->findInt32("err", &err));
637 if (err != C2_OK) {
638 return (c2_status_t)err;
639 }
640 return C2_OK;
641}
642
643c2_status_t SimpleC2Component::reset() {
644 ALOGV("reset");
645 {
646 Mutexed<ExecState>::Locked state(mExecState);
647 state->mState = UNINITIALIZED;
648 }
649 {
650 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
651 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700652 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800653 }
654 sp<AMessage> reply;
655 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
656 return C2_OK;
657}
658
659c2_status_t SimpleC2Component::release() {
660 ALOGV("release");
661 sp<AMessage> reply;
662 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
663 return C2_OK;
664}
665
666std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
667 return mIntf;
668}
669
670namespace {
671
672std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
673 std::list<std::unique_ptr<C2Work>> ret;
674 ret.push_back(std::move(work));
675 return ret;
676}
677
678} // namespace
679
680void SimpleC2Component::finish(
681 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
682 std::unique_ptr<C2Work> work;
683 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700684 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
685 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800686 ALOGW("unknown frame index: %" PRIu64, frameIndex);
687 return;
688 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700689 work = std::move(queue->pending().at(frameIndex));
690 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800691 }
692 if (work) {
693 fillWork(work);
694 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
695 listener->onWorkDone_nb(shared_from_this(), vec(work));
696 ALOGV("returning pending work");
697 }
698}
699
700void SimpleC2Component::cloneAndSend(
701 uint64_t frameIndex,
702 const std::unique_ptr<C2Work> &currentWork,
703 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
704 std::unique_ptr<C2Work> work(new C2Work);
705 if (currentWork->input.ordinal.frameIndex == frameIndex) {
706 work->input.flags = currentWork->input.flags;
707 work->input.ordinal = currentWork->input.ordinal;
708 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700709 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
710 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800711 ALOGW("unknown frame index: %" PRIu64, frameIndex);
712 return;
713 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700714 work->input.flags = queue->pending().at(frameIndex)->input.flags;
715 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800716 }
717 work->worklets.emplace_back(new C2Worklet);
718 if (work) {
719 fillWork(work);
720 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
721 listener->onWorkDone_nb(shared_from_this(), vec(work));
722 ALOGV("cloned and sending work");
723 }
724}
725
726bool SimpleC2Component::processQueue() {
727 std::unique_ptr<C2Work> work;
728 uint64_t generation;
729 int32_t drainMode;
730 bool isFlushPending = false;
731 bool hasQueuedWork = false;
732 {
733 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
734 if (queue->empty()) {
735 return false;
736 }
737
738 generation = queue->generation();
739 drainMode = queue->drainMode();
740 isFlushPending = queue->popPendingFlush();
741 work = queue->pop_front();
742 hasQueuedWork = !queue->empty();
743 }
744 if (isFlushPending) {
745 ALOGV("processing pending flush");
746 c2_status_t err = onFlush_sm();
747 if (err != C2_OK) {
748 ALOGD("flush err: %d", err);
749 // TODO: error
750 }
751 }
752
753 if (!mOutputBlockPool) {
754 c2_status_t err = [this] {
755 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800756 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800757 std::vector<std::unique_ptr<C2Param>> params;
758 c2_status_t err = intf()->query_vb(
759 { &outputFormat },
760 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
761 C2_DONT_BLOCK,
762 &params);
763 if (err != C2_OK && err != C2_BAD_INDEX) {
764 ALOGD("query err = %d", err);
765 return err;
766 }
767 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800768 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800769 ? C2BlockPool::BASIC_GRAPHIC
770 : C2BlockPool::BASIC_LINEAR;
771 if (params.size()) {
772 C2PortBlockPoolsTuning::output *outputPools =
773 C2PortBlockPoolsTuning::output::From(params[0].get());
774 if (outputPools && outputPools->flexCount() >= 1) {
775 poolId = outputPools->m.values[0];
776 }
777 }
778
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800779 std::shared_ptr<C2BlockPool> blockPool;
780 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800781 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
782 (unsigned long long)poolId,
783 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800784 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800785 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800786 if (err == C2_OK) {
787 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
788 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800789 return err;
790 }();
791 if (err != C2_OK) {
792 Mutexed<ExecState>::Locked state(mExecState);
793 std::shared_ptr<C2Component::Listener> listener = state->mListener;
794 state.unlock();
795 listener->onError_nb(shared_from_this(), err);
796 return hasQueuedWork;
797 }
798 }
799
800 if (!work) {
801 c2_status_t err = drain(drainMode, mOutputBlockPool);
802 if (err != C2_OK) {
803 Mutexed<ExecState>::Locked state(mExecState);
804 std::shared_ptr<C2Component::Listener> listener = state->mListener;
805 state.unlock();
806 listener->onError_nb(shared_from_this(), err);
807 }
808 return hasQueuedWork;
809 }
810
811 {
812 std::vector<C2Param *> updates;
813 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
814 if (param) {
815 updates.emplace_back(param.get());
816 }
817 }
818 if (!updates.empty()) {
819 std::vector<std::unique_ptr<C2SettingResult>> failures;
820 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
821 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
822 }
823 }
824
825 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800826 // If input buffer list is not empty, it means we have some input to process on.
827 // However, input could be a null buffer. In such case, clear the buffer list
828 // before making call to process().
829 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
830 ALOGD("Encountered null input buffer. Clearing the input buffer");
831 work->input.buffers.clear();
832 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800833 process(work, mOutputBlockPool);
834 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -0700835 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
836 if (queue->generation() != generation) {
837 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
838 queue->generation(), generation);
839 work->result = C2_NOT_FOUND;
840 queue.unlock();
841
842 Mutexed<ExecState>::Locked state(mExecState);
843 std::shared_ptr<C2Component::Listener> listener = state->mListener;
844 state.unlock();
845 listener->onWorkDone_nb(shared_from_this(), vec(work));
846 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800847 }
848 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -0700849 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800850 Mutexed<ExecState>::Locked state(mExecState);
851 ALOGV("returning this work");
852 std::shared_ptr<C2Component::Listener> listener = state->mListener;
853 state.unlock();
854 listener->onWorkDone_nb(shared_from_this(), vec(work));
855 } else {
856 ALOGV("queue pending work");
857 work->input.buffers.clear();
858 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -0700859
860 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
861 if (queue->pending().count(frameIndex) != 0) {
862 unexpected = std::move(queue->pending().at(frameIndex));
863 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800864 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700865 (void)queue->pending().insert({ frameIndex, std::move(work) });
866
867 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800868 if (unexpected) {
869 ALOGD("unexpected pending work");
870 unexpected->result = C2_CORRUPTED;
871 Mutexed<ExecState>::Locked state(mExecState);
872 std::shared_ptr<C2Component::Listener> listener = state->mListener;
873 state.unlock();
874 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
875 }
876 }
877 return hasQueuedWork;
878}
879
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800880int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
881 // Save supported hal pixel formats for bit depth of 10, the first time this is called
882 if (!mBitDepth10HalPixelFormats.size()) {
883 std::vector<int> halPixelFormats;
Harish Mahendrakarf5dec502022-04-13 15:53:55 -0700884 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
885
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800886 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
887 // is populated only once, allowRGBA1010102 is not considered at this stage.
888 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
889
890 for (int halPixelFormat : halPixelFormats) {
Harish Mahendrakarf5dec502022-04-13 15:53:55 -0700891 if (isHalPixelFormatSupported((AHardwareBuffer_Format)halPixelFormat)) {
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800892 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
893 }
894 }
895 // Add YV12 in the end as a fall-back option
896 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
897 }
Harish Mahendrakar5c467652022-04-28 19:47:28 -0700898 // From Android T onwards, HAL_PIXEL_FORMAT_RGBA_1010102 corresponds to true
899 // RGBA 1010102 format unlike earlier versions where it was used to represent
900 // YUVA 1010102 data
901 if (!isAtLeastT()) {
902 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
903 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
904 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
905 return HAL_PIXEL_FORMAT_YV12;
906 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800907 }
908 // Return the first entry from supported formats
909 return mBitDepth10HalPixelFormats[0];
910}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800911std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800912 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
913 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
914}
915
916std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800917 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
918 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
919}
920
921} // namespace android