blob: a71dc33fee2b72bf1bf8f0999d35f91c9e730960 [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}
140
141void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
142 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
143 size_t srcUStride, size_t srcVStride, size_t dstYStride,
144 size_t dstUVStride, size_t width, size_t height,
145 bool isMonochrome) {
146 for (size_t y = 0; y < height; ++y) {
147 for (size_t x = 0; x < width; ++x) {
148 dstY[x] = (uint8_t)(srcY[x] >> 2);
149 }
150 srcY += srcYStride;
151 dstY += dstYStride;
152 }
153
154 if (isMonochrome) {
155 // Fill with neutral U/V values.
156 for (size_t y = 0; y < (height + 1) / 2; ++y) {
157 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
158 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
159 dstV += dstUVStride;
160 dstU += dstUVStride;
161 }
162 return;
163 }
164
165 for (size_t y = 0; y < (height + 1) / 2; ++y) {
166 for (size_t x = 0; x < (width + 1) / 2; ++x) {
167 dstU[x] = (uint8_t)(srcU[x] >> 2);
168 dstV[x] = (uint8_t)(srcV[x] >> 2);
169 }
170 srcU += srcUStride;
171 srcV += srcVStride;
172 dstU += dstUVStride;
173 dstV += dstUVStride;
174 }
175}
176
177void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
178 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
179 size_t srcUStride, size_t srcVStride, size_t dstYStride,
180 size_t dstUVStride, size_t width, size_t height,
181 bool isMonochrome) {
182 for (size_t y = 0; y < height; ++y) {
183 for (size_t x = 0; x < width; ++x) {
184 dstY[x] = srcY[x] << 6;
185 }
186 srcY += srcYStride;
187 dstY += dstYStride;
188 }
189
190 if (isMonochrome) {
191 // Fill with neutral U/V values.
192 for (size_t y = 0; y < (height + 1) / 2; ++y) {
193 for (size_t x = 0; x < (width + 1) / 2; ++x) {
194 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
195 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
196 }
197 dstUV += dstUVStride;
198 }
199 return;
200 }
201
202 for (size_t y = 0; y < (height + 1) / 2; ++y) {
203 for (size_t x = 0; x < (width + 1) / 2; ++x) {
204 dstUV[2 * x] = srcU[x] << 6;
205 dstUV[2 * x + 1] = srcV[x] << 6;
206 }
207 srcU += srcUStride;
208 srcV += srcVStride;
209 dstUV += dstUVStride;
210 }
211}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800212std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
213 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
214 mQueue.pop_front();
215 return work;
216}
217
218void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
219 mQueue.push_back({ std::move(work), NO_DRAIN });
220}
221
222bool SimpleC2Component::WorkQueue::empty() const {
223 return mQueue.empty();
224}
225
226void SimpleC2Component::WorkQueue::clear() {
227 mQueue.clear();
228}
229
230uint32_t SimpleC2Component::WorkQueue::drainMode() const {
231 return mQueue.front().drainMode;
232}
233
234void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
235 mQueue.push_back({ nullptr, drainMode });
236}
237
238////////////////////////////////////////////////////////////////////////////////
239
240SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
241
242void SimpleC2Component::WorkHandler::setComponent(
243 const std::shared_ptr<SimpleC2Component> &thiz) {
244 mThiz = thiz;
245}
246
247static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
248 sp<AReplyToken> replyId;
249 CHECK(msg->senderAwaitsResponse(&replyId));
250 sp<AMessage> reply = new AMessage;
251 if (err) {
252 reply->setInt32("err", *err);
253 }
254 reply->postReply(replyId);
255}
256
257void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
258 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
259 if (!thiz) {
260 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
261 sp<AReplyToken> replyId;
262 if (msg->senderAwaitsResponse(&replyId)) {
263 sp<AMessage> reply = new AMessage;
264 reply->setInt32("err", C2_CORRUPTED);
265 reply->postReply(replyId);
266 }
267 return;
268 }
269
270 switch (msg->what()) {
271 case kWhatProcess: {
272 if (mRunning) {
273 if (thiz->processQueue()) {
274 (new AMessage(kWhatProcess, this))->post();
275 }
276 } else {
277 ALOGV("Ignore process message as we're not running");
278 }
279 break;
280 }
281 case kWhatInit: {
282 int32_t err = thiz->onInit();
283 Reply(msg, &err);
284 [[fallthrough]];
285 }
286 case kWhatStart: {
287 mRunning = true;
288 break;
289 }
290 case kWhatStop: {
291 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700292 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800293 Reply(msg, &err);
294 break;
295 }
296 case kWhatReset: {
297 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700298 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800299 mRunning = false;
300 Reply(msg);
301 break;
302 }
303 case kWhatRelease: {
304 thiz->onRelease();
Sungtak Lee810eace2021-04-12 22:16:44 -0700305 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800306 mRunning = false;
307 Reply(msg);
308 break;
309 }
310 default: {
311 ALOGD("Unrecognized msg: %d", msg->what());
312 break;
313 }
314 }
315}
316
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800317class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
318public:
319 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
320
321 virtual local_id_t getLocalId() const override {
322 return mBase->getLocalId();
323 }
324
325 virtual C2Allocator::id_t getAllocatorId() const override {
326 return mBase->getAllocatorId();
327 }
328
329 virtual c2_status_t fetchLinearBlock(
330 uint32_t capacity,
331 C2MemoryUsage usage,
332 std::shared_ptr<C2LinearBlock>* block) {
333 c2_status_t status;
334 do {
335 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800336 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800337 return status;
338 }
339
340 virtual c2_status_t fetchCircularBlock(
341 uint32_t capacity,
342 C2MemoryUsage usage,
343 std::shared_ptr<C2CircularBlock>* block) {
344 c2_status_t status;
345 do {
346 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800347 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800348 return status;
349 }
350
351 virtual c2_status_t fetchGraphicBlock(
352 uint32_t width, uint32_t height, uint32_t format,
353 C2MemoryUsage usage,
354 std::shared_ptr<C2GraphicBlock>* block) {
355 c2_status_t status;
356 do {
357 status = mBase->fetchGraphicBlock(width, height, format, usage,
358 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800359 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800360 return status;
361 }
362
363private:
364 std::shared_ptr<C2BlockPool> mBase;
365};
366
Pawin Vongmasa36653902018-11-15 00:10:25 -0800367////////////////////////////////////////////////////////////////////////////////
368
369namespace {
370
371struct DummyReadView : public C2ReadView {
372 DummyReadView() : C2ReadView(C2_NO_INIT) {}
373};
374
375} // namespace
376
377SimpleC2Component::SimpleC2Component(
378 const std::shared_ptr<C2ComponentInterface> &intf)
379 : mDummyReadView(DummyReadView()),
380 mIntf(intf),
381 mLooper(new ALooper),
382 mHandler(new WorkHandler) {
383 mLooper->setName(intf->getName().c_str());
384 (void)mLooper->registerHandler(mHandler);
385 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
386}
387
388SimpleC2Component::~SimpleC2Component() {
389 mLooper->unregisterHandler(mHandler->id());
390 (void)mLooper->stop();
391}
392
393c2_status_t SimpleC2Component::setListener_vb(
394 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
395 mHandler->setComponent(shared_from_this());
396
397 Mutexed<ExecState>::Locked state(mExecState);
398 if (state->mState == RUNNING) {
399 if (listener) {
400 return C2_BAD_STATE;
401 } else if (!mayBlock) {
402 return C2_BLOCKING;
403 }
404 }
405 state->mListener = listener;
406 // TODO: wait for listener change to have taken place before returning
407 // (e.g. if there is an ongoing listener callback)
408 return C2_OK;
409}
410
411c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
412 {
413 Mutexed<ExecState>::Locked state(mExecState);
414 if (state->mState != RUNNING) {
415 return C2_BAD_STATE;
416 }
417 }
418 bool queueWasEmpty = false;
419 {
420 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
421 queueWasEmpty = queue->empty();
422 while (!items->empty()) {
423 queue->push_back(std::move(items->front()));
424 items->pop_front();
425 }
426 }
427 if (queueWasEmpty) {
428 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
429 }
430 return C2_OK;
431}
432
433c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
434 (void)items;
435 return C2_OMITTED;
436}
437
438c2_status_t SimpleC2Component::flush_sm(
439 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
440 (void)flushMode;
441 {
442 Mutexed<ExecState>::Locked state(mExecState);
443 if (state->mState != RUNNING) {
444 return C2_BAD_STATE;
445 }
446 }
447 {
448 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
449 queue->incGeneration();
450 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
451 while (!queue->empty()) {
452 std::unique_ptr<C2Work> work = queue->pop_front();
453 if (work) {
454 flushedWork->push_back(std::move(work));
455 }
456 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700457 while (!queue->pending().empty()) {
458 flushedWork->push_back(std::move(queue->pending().begin()->second));
459 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800460 }
461 }
462
463 return C2_OK;
464}
465
466c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
467 if (drainMode == DRAIN_CHAIN) {
468 return C2_OMITTED;
469 }
470 {
471 Mutexed<ExecState>::Locked state(mExecState);
472 if (state->mState != RUNNING) {
473 return C2_BAD_STATE;
474 }
475 }
476 bool queueWasEmpty = false;
477 {
478 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
479 queueWasEmpty = queue->empty();
480 queue->markDrain(drainMode);
481 }
482 if (queueWasEmpty) {
483 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
484 }
485
486 return C2_OK;
487}
488
489c2_status_t SimpleC2Component::start() {
490 Mutexed<ExecState>::Locked state(mExecState);
491 if (state->mState == RUNNING) {
492 return C2_BAD_STATE;
493 }
494 bool needsInit = (state->mState == UNINITIALIZED);
495 state.unlock();
496 if (needsInit) {
497 sp<AMessage> reply;
498 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
499 int32_t err;
500 CHECK(reply->findInt32("err", &err));
501 if (err != C2_OK) {
502 return (c2_status_t)err;
503 }
504 } else {
505 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
506 }
507 state.lock();
508 state->mState = RUNNING;
509 return C2_OK;
510}
511
512c2_status_t SimpleC2Component::stop() {
513 ALOGV("stop");
514 {
515 Mutexed<ExecState>::Locked state(mExecState);
516 if (state->mState != RUNNING) {
517 return C2_BAD_STATE;
518 }
519 state->mState = STOPPED;
520 }
521 {
522 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
523 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700524 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800525 }
526 sp<AMessage> reply;
527 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
528 int32_t err;
529 CHECK(reply->findInt32("err", &err));
530 if (err != C2_OK) {
531 return (c2_status_t)err;
532 }
533 return C2_OK;
534}
535
536c2_status_t SimpleC2Component::reset() {
537 ALOGV("reset");
538 {
539 Mutexed<ExecState>::Locked state(mExecState);
540 state->mState = UNINITIALIZED;
541 }
542 {
543 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
544 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700545 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800546 }
547 sp<AMessage> reply;
548 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
549 return C2_OK;
550}
551
552c2_status_t SimpleC2Component::release() {
553 ALOGV("release");
554 sp<AMessage> reply;
555 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
556 return C2_OK;
557}
558
559std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
560 return mIntf;
561}
562
563namespace {
564
565std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
566 std::list<std::unique_ptr<C2Work>> ret;
567 ret.push_back(std::move(work));
568 return ret;
569}
570
571} // namespace
572
573void SimpleC2Component::finish(
574 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
575 std::unique_ptr<C2Work> work;
576 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700577 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
578 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800579 ALOGW("unknown frame index: %" PRIu64, frameIndex);
580 return;
581 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700582 work = std::move(queue->pending().at(frameIndex));
583 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800584 }
585 if (work) {
586 fillWork(work);
587 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
588 listener->onWorkDone_nb(shared_from_this(), vec(work));
589 ALOGV("returning pending work");
590 }
591}
592
593void SimpleC2Component::cloneAndSend(
594 uint64_t frameIndex,
595 const std::unique_ptr<C2Work> &currentWork,
596 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
597 std::unique_ptr<C2Work> work(new C2Work);
598 if (currentWork->input.ordinal.frameIndex == frameIndex) {
599 work->input.flags = currentWork->input.flags;
600 work->input.ordinal = currentWork->input.ordinal;
601 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700602 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
603 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800604 ALOGW("unknown frame index: %" PRIu64, frameIndex);
605 return;
606 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700607 work->input.flags = queue->pending().at(frameIndex)->input.flags;
608 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800609 }
610 work->worklets.emplace_back(new C2Worklet);
611 if (work) {
612 fillWork(work);
613 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
614 listener->onWorkDone_nb(shared_from_this(), vec(work));
615 ALOGV("cloned and sending work");
616 }
617}
618
619bool SimpleC2Component::processQueue() {
620 std::unique_ptr<C2Work> work;
621 uint64_t generation;
622 int32_t drainMode;
623 bool isFlushPending = false;
624 bool hasQueuedWork = false;
625 {
626 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
627 if (queue->empty()) {
628 return false;
629 }
630
631 generation = queue->generation();
632 drainMode = queue->drainMode();
633 isFlushPending = queue->popPendingFlush();
634 work = queue->pop_front();
635 hasQueuedWork = !queue->empty();
636 }
637 if (isFlushPending) {
638 ALOGV("processing pending flush");
639 c2_status_t err = onFlush_sm();
640 if (err != C2_OK) {
641 ALOGD("flush err: %d", err);
642 // TODO: error
643 }
644 }
645
646 if (!mOutputBlockPool) {
647 c2_status_t err = [this] {
648 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800649 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800650 std::vector<std::unique_ptr<C2Param>> params;
651 c2_status_t err = intf()->query_vb(
652 { &outputFormat },
653 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
654 C2_DONT_BLOCK,
655 &params);
656 if (err != C2_OK && err != C2_BAD_INDEX) {
657 ALOGD("query err = %d", err);
658 return err;
659 }
660 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800661 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800662 ? C2BlockPool::BASIC_GRAPHIC
663 : C2BlockPool::BASIC_LINEAR;
664 if (params.size()) {
665 C2PortBlockPoolsTuning::output *outputPools =
666 C2PortBlockPoolsTuning::output::From(params[0].get());
667 if (outputPools && outputPools->flexCount() >= 1) {
668 poolId = outputPools->m.values[0];
669 }
670 }
671
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800672 std::shared_ptr<C2BlockPool> blockPool;
673 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800674 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
675 (unsigned long long)poolId,
676 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800677 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800678 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800679 if (err == C2_OK) {
680 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
681 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800682 return err;
683 }();
684 if (err != C2_OK) {
685 Mutexed<ExecState>::Locked state(mExecState);
686 std::shared_ptr<C2Component::Listener> listener = state->mListener;
687 state.unlock();
688 listener->onError_nb(shared_from_this(), err);
689 return hasQueuedWork;
690 }
691 }
692
693 if (!work) {
694 c2_status_t err = drain(drainMode, mOutputBlockPool);
695 if (err != C2_OK) {
696 Mutexed<ExecState>::Locked state(mExecState);
697 std::shared_ptr<C2Component::Listener> listener = state->mListener;
698 state.unlock();
699 listener->onError_nb(shared_from_this(), err);
700 }
701 return hasQueuedWork;
702 }
703
704 {
705 std::vector<C2Param *> updates;
706 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
707 if (param) {
708 updates.emplace_back(param.get());
709 }
710 }
711 if (!updates.empty()) {
712 std::vector<std::unique_ptr<C2SettingResult>> failures;
713 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
714 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
715 }
716 }
717
718 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800719 // If input buffer list is not empty, it means we have some input to process on.
720 // However, input could be a null buffer. In such case, clear the buffer list
721 // before making call to process().
722 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
723 ALOGD("Encountered null input buffer. Clearing the input buffer");
724 work->input.buffers.clear();
725 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800726 process(work, mOutputBlockPool);
727 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -0700728 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
729 if (queue->generation() != generation) {
730 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
731 queue->generation(), generation);
732 work->result = C2_NOT_FOUND;
733 queue.unlock();
734
735 Mutexed<ExecState>::Locked state(mExecState);
736 std::shared_ptr<C2Component::Listener> listener = state->mListener;
737 state.unlock();
738 listener->onWorkDone_nb(shared_from_this(), vec(work));
739 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800740 }
741 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -0700742 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800743 Mutexed<ExecState>::Locked state(mExecState);
744 ALOGV("returning this work");
745 std::shared_ptr<C2Component::Listener> listener = state->mListener;
746 state.unlock();
747 listener->onWorkDone_nb(shared_from_this(), vec(work));
748 } else {
749 ALOGV("queue pending work");
750 work->input.buffers.clear();
751 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -0700752
753 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
754 if (queue->pending().count(frameIndex) != 0) {
755 unexpected = std::move(queue->pending().at(frameIndex));
756 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800757 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700758 (void)queue->pending().insert({ frameIndex, std::move(work) });
759
760 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800761 if (unexpected) {
762 ALOGD("unexpected pending work");
763 unexpected->result = C2_CORRUPTED;
764 Mutexed<ExecState>::Locked state(mExecState);
765 std::shared_ptr<C2Component::Listener> listener = state->mListener;
766 state.unlock();
767 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
768 }
769 }
770 return hasQueuedWork;
771}
772
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800773int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
774 // Save supported hal pixel formats for bit depth of 10, the first time this is called
775 if (!mBitDepth10HalPixelFormats.size()) {
776 std::vector<int> halPixelFormats;
Harish Mahendrakard4bbb762022-03-29 11:53:23 -0700777 if (isAtLeastT()) {
778 halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
779 }
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800780 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
781 // is populated only once, allowRGBA1010102 is not considered at this stage.
782 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
783
784 for (int halPixelFormat : halPixelFormats) {
785 std::shared_ptr<C2GraphicBlock> block;
786
787 uint32_t gpuConsumerFlags = halPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102
788 ? C2AndroidMemoryUsage::HW_TEXTURE_READ
789 : 0;
790 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ | gpuConsumerFlags,
791 C2MemoryUsage::CPU_WRITE};
792 // TODO(b/214411172) Use AHardwareBuffer_isSupported once it supports P010
793 c2_status_t status =
794 mOutputBlockPool->fetchGraphicBlock(320, 240, halPixelFormat, usage, &block);
795 if (status == C2_OK) {
796 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
797 }
798 }
799 // Add YV12 in the end as a fall-back option
800 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
801 }
802 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
803 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
804 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
805 return HAL_PIXEL_FORMAT_YV12;
806 }
807 // Return the first entry from supported formats
808 return mBitDepth10HalPixelFormats[0];
809}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800810std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800811 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
812 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
813}
814
815std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800816 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
817 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
818}
819
820} // namespace android