blob: 434246f5fc8e5b34fa14c3d184fa9faa14390ee5 [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 Mahendrakar1b1aef22021-12-30 19:12:51 -080035void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
36 const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
37 size_t srcUStride, size_t srcVStride, size_t dstYStride,
38 size_t dstUVStride, uint32_t width, uint32_t height,
39 bool isMonochrome) {
40 for (size_t i = 0; i < height; ++i) {
41 memcpy(dstY, srcY, width);
42 srcY += srcYStride;
43 dstY += dstYStride;
44 }
45
46 if (isMonochrome) {
47 // Fill with neutral U/V values.
48 for (size_t i = 0; i < height / 2; ++i) {
49 memset(dstV, kNeutralUVBitDepth8, width / 2);
50 memset(dstU, kNeutralUVBitDepth8, width / 2);
51 dstV += dstUVStride;
52 dstU += dstUVStride;
53 }
54 return;
55 }
56
57 for (size_t i = 0; i < height / 2; ++i) {
58 memcpy(dstV, srcV, width / 2);
59 srcV += srcVStride;
60 dstV += dstUVStride;
61 }
62
63 for (size_t i = 0; i < height / 2; ++i) {
64 memcpy(dstU, srcU, width / 2);
65 srcU += srcUStride;
66 dstU += dstUVStride;
67 }
68}
69
70void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
71 const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
72 size_t srcVStride, size_t dstStride, size_t width, size_t height) {
73 // Converting two lines at a time, slightly faster
74 for (size_t y = 0; y < height; y += 2) {
75 uint32_t *dstTop = (uint32_t *)dst;
76 uint32_t *dstBot = (uint32_t *)(dst + dstStride);
77 uint16_t *ySrcTop = (uint16_t *)srcY;
78 uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
79 uint16_t *uSrc = (uint16_t *)srcU;
80 uint16_t *vSrc = (uint16_t *)srcV;
81
82 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
83 size_t x = 0;
84 for (; x < width - 3; x += 4) {
85 u01 = *((uint32_t *)uSrc);
86 uSrc += 2;
87 v01 = *((uint32_t *)vSrc);
88 vSrc += 2;
89
90 y01 = *((uint32_t *)ySrcTop);
91 ySrcTop += 2;
92 y23 = *((uint32_t *)ySrcTop);
93 ySrcTop += 2;
94 y45 = *((uint32_t *)ySrcBot);
95 ySrcBot += 2;
96 y67 = *((uint32_t *)ySrcBot);
97 ySrcBot += 2;
98
99 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
100 uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
101
102 *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
103 *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
104 *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
105 *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
106
107 *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
108 *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
109 *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
110 *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
111 }
112
113 // There should be at most 2 more pixels to process. Note that we don't
114 // need to consider odd case as the buffer is always aligned to even.
115 if (x < width) {
116 u01 = *uSrc;
117 v01 = *vSrc;
118 y01 = *((uint32_t *)ySrcTop);
119 y45 = *((uint32_t *)ySrcBot);
120 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
121 *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
122 *dstTop++ = ((y01 >> 16) << 10) | uv0;
123 *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
124 *dstBot++ = ((y45 >> 16) << 10) | uv0;
125 }
126
127 srcY += srcYStride * 2;
128 srcU += srcUStride;
129 srcV += srcVStride;
130 dst += dstStride * 2;
131 }
132}
133
134void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
135 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
136 size_t srcUStride, size_t srcVStride, size_t dstYStride,
137 size_t dstUVStride, size_t width, size_t height,
138 bool isMonochrome) {
139 for (size_t y = 0; y < height; ++y) {
140 for (size_t x = 0; x < width; ++x) {
141 dstY[x] = (uint8_t)(srcY[x] >> 2);
142 }
143 srcY += srcYStride;
144 dstY += dstYStride;
145 }
146
147 if (isMonochrome) {
148 // Fill with neutral U/V values.
149 for (size_t y = 0; y < (height + 1) / 2; ++y) {
150 memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
151 memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
152 dstV += dstUVStride;
153 dstU += dstUVStride;
154 }
155 return;
156 }
157
158 for (size_t y = 0; y < (height + 1) / 2; ++y) {
159 for (size_t x = 0; x < (width + 1) / 2; ++x) {
160 dstU[x] = (uint8_t)(srcU[x] >> 2);
161 dstV[x] = (uint8_t)(srcV[x] >> 2);
162 }
163 srcU += srcUStride;
164 srcV += srcVStride;
165 dstU += dstUVStride;
166 dstV += dstUVStride;
167 }
168}
169
170void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
171 const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
172 size_t srcUStride, size_t srcVStride, size_t dstYStride,
173 size_t dstUVStride, size_t width, size_t height,
174 bool isMonochrome) {
175 for (size_t y = 0; y < height; ++y) {
176 for (size_t x = 0; x < width; ++x) {
177 dstY[x] = srcY[x] << 6;
178 }
179 srcY += srcYStride;
180 dstY += dstYStride;
181 }
182
183 if (isMonochrome) {
184 // Fill with neutral U/V values.
185 for (size_t y = 0; y < (height + 1) / 2; ++y) {
186 for (size_t x = 0; x < (width + 1) / 2; ++x) {
187 dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
188 dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
189 }
190 dstUV += dstUVStride;
191 }
192 return;
193 }
194
195 for (size_t y = 0; y < (height + 1) / 2; ++y) {
196 for (size_t x = 0; x < (width + 1) / 2; ++x) {
197 dstUV[2 * x] = srcU[x] << 6;
198 dstUV[2 * x + 1] = srcV[x] << 6;
199 }
200 srcU += srcUStride;
201 srcV += srcVStride;
202 dstUV += dstUVStride;
203 }
204}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800205std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
206 std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
207 mQueue.pop_front();
208 return work;
209}
210
211void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
212 mQueue.push_back({ std::move(work), NO_DRAIN });
213}
214
215bool SimpleC2Component::WorkQueue::empty() const {
216 return mQueue.empty();
217}
218
219void SimpleC2Component::WorkQueue::clear() {
220 mQueue.clear();
221}
222
223uint32_t SimpleC2Component::WorkQueue::drainMode() const {
224 return mQueue.front().drainMode;
225}
226
227void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
228 mQueue.push_back({ nullptr, drainMode });
229}
230
231////////////////////////////////////////////////////////////////////////////////
232
233SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
234
235void SimpleC2Component::WorkHandler::setComponent(
236 const std::shared_ptr<SimpleC2Component> &thiz) {
237 mThiz = thiz;
238}
239
240static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
241 sp<AReplyToken> replyId;
242 CHECK(msg->senderAwaitsResponse(&replyId));
243 sp<AMessage> reply = new AMessage;
244 if (err) {
245 reply->setInt32("err", *err);
246 }
247 reply->postReply(replyId);
248}
249
250void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
251 std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
252 if (!thiz) {
253 ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
254 sp<AReplyToken> replyId;
255 if (msg->senderAwaitsResponse(&replyId)) {
256 sp<AMessage> reply = new AMessage;
257 reply->setInt32("err", C2_CORRUPTED);
258 reply->postReply(replyId);
259 }
260 return;
261 }
262
263 switch (msg->what()) {
264 case kWhatProcess: {
265 if (mRunning) {
266 if (thiz->processQueue()) {
267 (new AMessage(kWhatProcess, this))->post();
268 }
269 } else {
270 ALOGV("Ignore process message as we're not running");
271 }
272 break;
273 }
274 case kWhatInit: {
275 int32_t err = thiz->onInit();
276 Reply(msg, &err);
277 [[fallthrough]];
278 }
279 case kWhatStart: {
280 mRunning = true;
281 break;
282 }
283 case kWhatStop: {
284 int32_t err = thiz->onStop();
Sungtak Lee810eace2021-04-12 22:16:44 -0700285 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800286 Reply(msg, &err);
287 break;
288 }
289 case kWhatReset: {
290 thiz->onReset();
Sungtak Lee810eace2021-04-12 22:16:44 -0700291 thiz->mOutputBlockPool.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800292 mRunning = false;
293 Reply(msg);
294 break;
295 }
296 case kWhatRelease: {
297 thiz->onRelease();
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 default: {
304 ALOGD("Unrecognized msg: %d", msg->what());
305 break;
306 }
307 }
308}
309
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800310class SimpleC2Component::BlockingBlockPool : public C2BlockPool {
311public:
312 BlockingBlockPool(const std::shared_ptr<C2BlockPool>& base): mBase{base} {}
313
314 virtual local_id_t getLocalId() const override {
315 return mBase->getLocalId();
316 }
317
318 virtual C2Allocator::id_t getAllocatorId() const override {
319 return mBase->getAllocatorId();
320 }
321
322 virtual c2_status_t fetchLinearBlock(
323 uint32_t capacity,
324 C2MemoryUsage usage,
325 std::shared_ptr<C2LinearBlock>* block) {
326 c2_status_t status;
327 do {
328 status = mBase->fetchLinearBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800329 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800330 return status;
331 }
332
333 virtual c2_status_t fetchCircularBlock(
334 uint32_t capacity,
335 C2MemoryUsage usage,
336 std::shared_ptr<C2CircularBlock>* block) {
337 c2_status_t status;
338 do {
339 status = mBase->fetchCircularBlock(capacity, usage, block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800340 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800341 return status;
342 }
343
344 virtual c2_status_t fetchGraphicBlock(
345 uint32_t width, uint32_t height, uint32_t format,
346 C2MemoryUsage usage,
347 std::shared_ptr<C2GraphicBlock>* block) {
348 c2_status_t status;
349 do {
350 status = mBase->fetchGraphicBlock(width, height, format, usage,
351 block);
Sungtak Lee5f3fb6f2019-01-31 11:53:22 -0800352 } while (status == C2_BLOCKING);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800353 return status;
354 }
355
356private:
357 std::shared_ptr<C2BlockPool> mBase;
358};
359
Pawin Vongmasa36653902018-11-15 00:10:25 -0800360////////////////////////////////////////////////////////////////////////////////
361
362namespace {
363
364struct DummyReadView : public C2ReadView {
365 DummyReadView() : C2ReadView(C2_NO_INIT) {}
366};
367
368} // namespace
369
370SimpleC2Component::SimpleC2Component(
371 const std::shared_ptr<C2ComponentInterface> &intf)
372 : mDummyReadView(DummyReadView()),
373 mIntf(intf),
374 mLooper(new ALooper),
375 mHandler(new WorkHandler) {
376 mLooper->setName(intf->getName().c_str());
377 (void)mLooper->registerHandler(mHandler);
378 mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
379}
380
381SimpleC2Component::~SimpleC2Component() {
382 mLooper->unregisterHandler(mHandler->id());
383 (void)mLooper->stop();
384}
385
386c2_status_t SimpleC2Component::setListener_vb(
387 const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
388 mHandler->setComponent(shared_from_this());
389
390 Mutexed<ExecState>::Locked state(mExecState);
391 if (state->mState == RUNNING) {
392 if (listener) {
393 return C2_BAD_STATE;
394 } else if (!mayBlock) {
395 return C2_BLOCKING;
396 }
397 }
398 state->mListener = listener;
399 // TODO: wait for listener change to have taken place before returning
400 // (e.g. if there is an ongoing listener callback)
401 return C2_OK;
402}
403
404c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
405 {
406 Mutexed<ExecState>::Locked state(mExecState);
407 if (state->mState != RUNNING) {
408 return C2_BAD_STATE;
409 }
410 }
411 bool queueWasEmpty = false;
412 {
413 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
414 queueWasEmpty = queue->empty();
415 while (!items->empty()) {
416 queue->push_back(std::move(items->front()));
417 items->pop_front();
418 }
419 }
420 if (queueWasEmpty) {
421 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
422 }
423 return C2_OK;
424}
425
426c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
427 (void)items;
428 return C2_OMITTED;
429}
430
431c2_status_t SimpleC2Component::flush_sm(
432 flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
433 (void)flushMode;
434 {
435 Mutexed<ExecState>::Locked state(mExecState);
436 if (state->mState != RUNNING) {
437 return C2_BAD_STATE;
438 }
439 }
440 {
441 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
442 queue->incGeneration();
443 // TODO: queue->splicedBy(flushedWork, flushedWork->end());
444 while (!queue->empty()) {
445 std::unique_ptr<C2Work> work = queue->pop_front();
446 if (work) {
447 flushedWork->push_back(std::move(work));
448 }
449 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700450 while (!queue->pending().empty()) {
451 flushedWork->push_back(std::move(queue->pending().begin()->second));
452 queue->pending().erase(queue->pending().begin());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800453 }
454 }
455
456 return C2_OK;
457}
458
459c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
460 if (drainMode == DRAIN_CHAIN) {
461 return C2_OMITTED;
462 }
463 {
464 Mutexed<ExecState>::Locked state(mExecState);
465 if (state->mState != RUNNING) {
466 return C2_BAD_STATE;
467 }
468 }
469 bool queueWasEmpty = false;
470 {
471 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
472 queueWasEmpty = queue->empty();
473 queue->markDrain(drainMode);
474 }
475 if (queueWasEmpty) {
476 (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
477 }
478
479 return C2_OK;
480}
481
482c2_status_t SimpleC2Component::start() {
483 Mutexed<ExecState>::Locked state(mExecState);
484 if (state->mState == RUNNING) {
485 return C2_BAD_STATE;
486 }
487 bool needsInit = (state->mState == UNINITIALIZED);
488 state.unlock();
489 if (needsInit) {
490 sp<AMessage> reply;
491 (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
492 int32_t err;
493 CHECK(reply->findInt32("err", &err));
494 if (err != C2_OK) {
495 return (c2_status_t)err;
496 }
497 } else {
498 (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
499 }
500 state.lock();
501 state->mState = RUNNING;
502 return C2_OK;
503}
504
505c2_status_t SimpleC2Component::stop() {
506 ALOGV("stop");
507 {
508 Mutexed<ExecState>::Locked state(mExecState);
509 if (state->mState != RUNNING) {
510 return C2_BAD_STATE;
511 }
512 state->mState = STOPPED;
513 }
514 {
515 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
516 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700517 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800518 }
519 sp<AMessage> reply;
520 (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
521 int32_t err;
522 CHECK(reply->findInt32("err", &err));
523 if (err != C2_OK) {
524 return (c2_status_t)err;
525 }
526 return C2_OK;
527}
528
529c2_status_t SimpleC2Component::reset() {
530 ALOGV("reset");
531 {
532 Mutexed<ExecState>::Locked state(mExecState);
533 state->mState = UNINITIALIZED;
534 }
535 {
536 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
537 queue->clear();
Wonsik Kime1226f52019-04-04 15:24:41 -0700538 queue->pending().clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800539 }
540 sp<AMessage> reply;
541 (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
542 return C2_OK;
543}
544
545c2_status_t SimpleC2Component::release() {
546 ALOGV("release");
547 sp<AMessage> reply;
548 (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
549 return C2_OK;
550}
551
552std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
553 return mIntf;
554}
555
556namespace {
557
558std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
559 std::list<std::unique_ptr<C2Work>> ret;
560 ret.push_back(std::move(work));
561 return ret;
562}
563
564} // namespace
565
566void SimpleC2Component::finish(
567 uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
568 std::unique_ptr<C2Work> work;
569 {
Wonsik Kime1226f52019-04-04 15:24:41 -0700570 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
571 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800572 ALOGW("unknown frame index: %" PRIu64, frameIndex);
573 return;
574 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700575 work = std::move(queue->pending().at(frameIndex));
576 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800577 }
578 if (work) {
579 fillWork(work);
580 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
581 listener->onWorkDone_nb(shared_from_this(), vec(work));
582 ALOGV("returning pending work");
583 }
584}
585
586void SimpleC2Component::cloneAndSend(
587 uint64_t frameIndex,
588 const std::unique_ptr<C2Work> &currentWork,
589 std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
590 std::unique_ptr<C2Work> work(new C2Work);
591 if (currentWork->input.ordinal.frameIndex == frameIndex) {
592 work->input.flags = currentWork->input.flags;
593 work->input.ordinal = currentWork->input.ordinal;
594 } else {
Wonsik Kime1226f52019-04-04 15:24:41 -0700595 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
596 if (queue->pending().count(frameIndex) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800597 ALOGW("unknown frame index: %" PRIu64, frameIndex);
598 return;
599 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700600 work->input.flags = queue->pending().at(frameIndex)->input.flags;
601 work->input.ordinal = queue->pending().at(frameIndex)->input.ordinal;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800602 }
603 work->worklets.emplace_back(new C2Worklet);
604 if (work) {
605 fillWork(work);
606 std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
607 listener->onWorkDone_nb(shared_from_this(), vec(work));
608 ALOGV("cloned and sending work");
609 }
610}
611
612bool SimpleC2Component::processQueue() {
613 std::unique_ptr<C2Work> work;
614 uint64_t generation;
615 int32_t drainMode;
616 bool isFlushPending = false;
617 bool hasQueuedWork = false;
618 {
619 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
620 if (queue->empty()) {
621 return false;
622 }
623
624 generation = queue->generation();
625 drainMode = queue->drainMode();
626 isFlushPending = queue->popPendingFlush();
627 work = queue->pop_front();
628 hasQueuedWork = !queue->empty();
629 }
630 if (isFlushPending) {
631 ALOGV("processing pending flush");
632 c2_status_t err = onFlush_sm();
633 if (err != C2_OK) {
634 ALOGD("flush err: %d", err);
635 // TODO: error
636 }
637 }
638
639 if (!mOutputBlockPool) {
640 c2_status_t err = [this] {
641 // TODO: don't use query_vb
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800642 C2StreamBufferTypeSetting::output outputFormat(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800643 std::vector<std::unique_ptr<C2Param>> params;
644 c2_status_t err = intf()->query_vb(
645 { &outputFormat },
646 { C2PortBlockPoolsTuning::output::PARAM_TYPE },
647 C2_DONT_BLOCK,
648 &params);
649 if (err != C2_OK && err != C2_BAD_INDEX) {
650 ALOGD("query err = %d", err);
651 return err;
652 }
653 C2BlockPool::local_id_t poolId =
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800654 outputFormat.value == C2BufferData::GRAPHIC
Pawin Vongmasa36653902018-11-15 00:10:25 -0800655 ? C2BlockPool::BASIC_GRAPHIC
656 : C2BlockPool::BASIC_LINEAR;
657 if (params.size()) {
658 C2PortBlockPoolsTuning::output *outputPools =
659 C2PortBlockPoolsTuning::output::From(params[0].get());
660 if (outputPools && outputPools->flexCount() >= 1) {
661 poolId = outputPools->m.values[0];
662 }
663 }
664
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800665 std::shared_ptr<C2BlockPool> blockPool;
666 err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800667 ALOGD("Using output block pool with poolID %llu => got %llu - %d",
668 (unsigned long long)poolId,
669 (unsigned long long)(
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800670 blockPool ? blockPool->getLocalId() : 111000111),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800671 err);
Wonsik Kim0cb5a092019-01-03 16:38:22 -0800672 if (err == C2_OK) {
673 mOutputBlockPool = std::make_shared<BlockingBlockPool>(blockPool);
674 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800675 return err;
676 }();
677 if (err != C2_OK) {
678 Mutexed<ExecState>::Locked state(mExecState);
679 std::shared_ptr<C2Component::Listener> listener = state->mListener;
680 state.unlock();
681 listener->onError_nb(shared_from_this(), err);
682 return hasQueuedWork;
683 }
684 }
685
686 if (!work) {
687 c2_status_t err = drain(drainMode, mOutputBlockPool);
688 if (err != C2_OK) {
689 Mutexed<ExecState>::Locked state(mExecState);
690 std::shared_ptr<C2Component::Listener> listener = state->mListener;
691 state.unlock();
692 listener->onError_nb(shared_from_this(), err);
693 }
694 return hasQueuedWork;
695 }
696
697 {
698 std::vector<C2Param *> updates;
699 for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
700 if (param) {
701 updates.emplace_back(param.get());
702 }
703 }
704 if (!updates.empty()) {
705 std::vector<std::unique_ptr<C2SettingResult>> failures;
706 c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
707 ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
708 }
709 }
710
711 ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800712 // If input buffer list is not empty, it means we have some input to process on.
713 // However, input could be a null buffer. In such case, clear the buffer list
714 // before making call to process().
715 if (!work->input.buffers.empty() && !work->input.buffers[0]) {
716 ALOGD("Encountered null input buffer. Clearing the input buffer");
717 work->input.buffers.clear();
718 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800719 process(work, mOutputBlockPool);
720 ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
Wonsik Kime1226f52019-04-04 15:24:41 -0700721 Mutexed<WorkQueue>::Locked queue(mWorkQueue);
722 if (queue->generation() != generation) {
723 ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
724 queue->generation(), generation);
725 work->result = C2_NOT_FOUND;
726 queue.unlock();
727
728 Mutexed<ExecState>::Locked state(mExecState);
729 std::shared_ptr<C2Component::Listener> listener = state->mListener;
730 state.unlock();
731 listener->onWorkDone_nb(shared_from_this(), vec(work));
732 return hasQueuedWork;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800733 }
734 if (work->workletsProcessed != 0u) {
Wonsik Kime1226f52019-04-04 15:24:41 -0700735 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800736 Mutexed<ExecState>::Locked state(mExecState);
737 ALOGV("returning this work");
738 std::shared_ptr<C2Component::Listener> listener = state->mListener;
739 state.unlock();
740 listener->onWorkDone_nb(shared_from_this(), vec(work));
741 } else {
742 ALOGV("queue pending work");
743 work->input.buffers.clear();
744 std::unique_ptr<C2Work> unexpected;
Wonsik Kime1226f52019-04-04 15:24:41 -0700745
746 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
747 if (queue->pending().count(frameIndex) != 0) {
748 unexpected = std::move(queue->pending().at(frameIndex));
749 queue->pending().erase(frameIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800750 }
Wonsik Kime1226f52019-04-04 15:24:41 -0700751 (void)queue->pending().insert({ frameIndex, std::move(work) });
752
753 queue.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800754 if (unexpected) {
755 ALOGD("unexpected pending work");
756 unexpected->result = C2_CORRUPTED;
757 Mutexed<ExecState>::Locked state(mExecState);
758 std::shared_ptr<C2Component::Listener> listener = state->mListener;
759 state.unlock();
760 listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
761 }
762 }
763 return hasQueuedWork;
764}
765
Harish Mahendrakar749a74c2022-01-27 16:47:09 -0800766int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
767 // Save supported hal pixel formats for bit depth of 10, the first time this is called
768 if (!mBitDepth10HalPixelFormats.size()) {
769 std::vector<int> halPixelFormats;
770 // TODO(b/178229371) Enable HAL_PIXEL_FORMAT_YCBCR_P010 once framework supports it
771 // halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
772
773 // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
774 // is populated only once, allowRGBA1010102 is not considered at this stage.
775 halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
776
777 for (int halPixelFormat : halPixelFormats) {
778 std::shared_ptr<C2GraphicBlock> block;
779
780 uint32_t gpuConsumerFlags = halPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102
781 ? C2AndroidMemoryUsage::HW_TEXTURE_READ
782 : 0;
783 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ | gpuConsumerFlags,
784 C2MemoryUsage::CPU_WRITE};
785 // TODO(b/214411172) Use AHardwareBuffer_isSupported once it supports P010
786 c2_status_t status =
787 mOutputBlockPool->fetchGraphicBlock(320, 240, halPixelFormat, usage, &block);
788 if (status == C2_OK) {
789 mBitDepth10HalPixelFormats.push_back(halPixelFormat);
790 }
791 }
792 // Add YV12 in the end as a fall-back option
793 mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
794 }
795 // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
796 // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
797 if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
798 return HAL_PIXEL_FORMAT_YV12;
799 }
800 // Return the first entry from supported formats
801 return mBitDepth10HalPixelFormats[0];
802}
Pawin Vongmasa36653902018-11-15 00:10:25 -0800803std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800804 const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
805 return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
806}
807
808std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800809 const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
810 return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
811}
812
813} // namespace android