blob: 4ce13aabe99b791f74034b0299fafbe01c45ff0a [file] [log] [blame]
Wonsik Kim469c8342019-04-11 16:46:09 -07001/*
2 * Copyright 2019, 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 "CCodecBuffers"
19#include <utils/Log.h>
20
21#include <C2PlatformSupport.h>
22
23#include <media/stagefright/foundation/ADebug.h>
Pawin Vongmasab18c1af2020-04-11 05:07:15 -070024#include <media/stagefright/MediaCodec.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070025#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070026#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070027
28#include "CCodecBuffers.h"
29
30namespace android {
31
32namespace {
33
34sp<GraphicBlockBuffer> AllocateGraphicBuffer(
35 const std::shared_ptr<C2BlockPool> &pool,
36 const sp<AMessage> &format,
37 uint32_t pixelFormat,
38 const C2MemoryUsage &usage,
39 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
40 int32_t width, height;
41 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
42 ALOGD("format lacks width or height");
43 return nullptr;
44 }
45
46 std::shared_ptr<C2GraphicBlock> block;
47 c2_status_t err = pool->fetchGraphicBlock(
48 width, height, pixelFormat, usage, &block);
49 if (err != C2_OK) {
50 ALOGD("fetch graphic block failed: %d", err);
51 return nullptr;
52 }
53
54 return GraphicBlockBuffer::Allocate(
55 format,
56 block,
57 [localBufferPool](size_t capacity) {
58 return localBufferPool->newBuffer(capacity);
59 });
60}
61
62} // namespace
63
64// CCodecBuffers
65
66void CCodecBuffers::setFormat(const sp<AMessage> &format) {
67 CHECK(format != nullptr);
68 mFormat = format;
69}
70
71sp<AMessage> CCodecBuffers::dupFormat() {
72 return mFormat != nullptr ? mFormat->dup() : nullptr;
73}
74
75void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
76 sp<ABuffer> imageDataCandidate = buffer->getImageData();
77 if (imageDataCandidate == nullptr) {
78 return;
79 }
80 sp<ABuffer> imageData;
81 if (!mFormat->findBuffer("image-data", &imageData)
82 || imageDataCandidate->size() != imageData->size()
83 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
84 ALOGD("[%s] updating image-data", mName);
85 sp<AMessage> newFormat = dupFormat();
86 newFormat->setBuffer("image-data", imageDataCandidate);
87 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
88 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
89 int32_t stride = img->mPlane[0].mRowInc;
90 newFormat->setInt32(KEY_STRIDE, stride);
91 ALOGD("[%s] updating stride = %d", mName, stride);
92 if (img->mNumPlanes > 1 && stride > 0) {
93 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
94 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
95 ALOGD("[%s] updating vstride = %d", mName, vstride);
96 }
97 }
98 setFormat(newFormat);
99 buffer->setFormat(newFormat);
100 }
101}
102
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700103// InputBuffers
104
105sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
106 sp<Codec2Buffer> copy = createNewBuffer();
107 if (copy == nullptr) {
108 return nullptr;
109 }
110 std::shared_ptr<C2Buffer> c2buffer;
111 if (!releaseBuffer(buffer, &c2buffer, true)) {
112 return nullptr;
113 }
114 if (!copy->canCopy(c2buffer)) {
115 return nullptr;
116 }
117 if (!copy->copy(c2buffer)) {
118 return nullptr;
119 }
120 return copy;
121}
122
Wonsik Kim469c8342019-04-11 16:46:09 -0700123// OutputBuffers
124
125void OutputBuffers::initSkipCutBuffer(
126 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
127 CHECK(mSkipCutBuffer == nullptr);
128 mDelay = delay;
129 mPadding = padding;
130 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700131 mChannelCount = channelCount;
132 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700133}
134
135void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
136 if (mSkipCutBuffer == nullptr) {
137 return;
138 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700139 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
140 return;
141 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700142 int32_t delay = mDelay;
143 int32_t padding = mPadding;
144 if (sampleRate != mSampleRate) {
145 delay = ((int64_t)delay * sampleRate) / mSampleRate;
146 padding = ((int64_t)padding * sampleRate) / mSampleRate;
147 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700148 mSampleRate = sampleRate;
149 mChannelCount = channelCount;
150 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700151}
152
Pawin Vongmasab18c1af2020-04-11 05:07:15 -0700153void OutputBuffers::updateSkipCutBuffer(
154 const sp<AMessage> &format, bool notify) {
155 AString mediaType;
156 if (format->findString(KEY_MIME, &mediaType)
157 && mediaType == MIMETYPE_AUDIO_RAW) {
158 int32_t channelCount;
159 int32_t sampleRate;
160 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
161 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
162 updateSkipCutBuffer(sampleRate, channelCount);
163 }
164 }
165 if (notify) {
166 mUnreportedFormat = nullptr;
167 }
168}
169
Wonsik Kim469c8342019-04-11 16:46:09 -0700170void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
171 if (mSkipCutBuffer != nullptr) {
172 mSkipCutBuffer->submit(buffer);
173 }
174}
175
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700176void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700177 if (mSkipCutBuffer != nullptr) {
178 size_t prevSize = mSkipCutBuffer->size();
179 if (prevSize != 0u) {
180 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
181 }
182 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700183 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700184}
185
Pawin Vongmasab18c1af2020-04-11 05:07:15 -0700186void OutputBuffers::clearStash() {
187 mPending.clear();
188 mReorderStash.clear();
189 mDepth = 0;
190 mKey = C2Config::ORDINAL;
191 mUnreportedFormat = nullptr;
192}
193
194void OutputBuffers::flushStash() {
195 for (StashEntry& e : mPending) {
196 e.notify = false;
197 }
198 for (StashEntry& e : mReorderStash) {
199 e.notify = false;
200 }
201}
202
203uint32_t OutputBuffers::getReorderDepth() const {
204 return mDepth;
205}
206
207void OutputBuffers::setReorderDepth(uint32_t depth) {
208 mPending.splice(mPending.end(), mReorderStash);
209 mDepth = depth;
210}
211
212void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
213 mPending.splice(mPending.end(), mReorderStash);
214 mKey = key;
215}
216
217void OutputBuffers::pushToStash(
218 const std::shared_ptr<C2Buffer>& buffer,
219 bool notify,
220 int64_t timestamp,
221 int32_t flags,
222 const sp<AMessage>& format,
223 const C2WorkOrdinalStruct& ordinal) {
224 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
225 if (!buffer && eos) {
226 // TRICKY: we may be violating ordering of the stash here. Because we
227 // don't expect any more emplace() calls after this, the ordering should
228 // not matter.
229 mReorderStash.emplace_back(
230 buffer, notify, timestamp, flags, format, ordinal);
231 } else {
232 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
233 auto it = mReorderStash.begin();
234 for (; it != mReorderStash.end(); ++it) {
235 if (less(ordinal, it->ordinal)) {
236 break;
237 }
238 }
239 mReorderStash.emplace(it,
240 buffer, notify, timestamp, flags, format, ordinal);
241 if (eos) {
242 mReorderStash.back().flags =
243 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
244 }
245 }
246 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
247 mPending.push_back(mReorderStash.front());
248 mReorderStash.pop_front();
249 }
250 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
251}
252
253OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
254 std::shared_ptr<C2Buffer>* c2Buffer,
255 size_t* index,
256 sp<MediaCodecBuffer>* outBuffer) {
257 if (mPending.empty()) {
258 return SKIP;
259 }
260
261 // Retrieve the first entry.
262 StashEntry &entry = mPending.front();
263
264 *c2Buffer = entry.buffer;
265 sp<AMessage> outputFormat = entry.format;
266
267 // The output format can be processed without a registered slot.
268 if (outputFormat) {
269 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
270 mName, outputFormat->debugString().c_str());
271 updateSkipCutBuffer(outputFormat, entry.notify);
272 }
273
274 if (entry.notify) {
275 if (outputFormat) {
276 setFormat(outputFormat);
277 } else if (mUnreportedFormat) {
278 outputFormat = mUnreportedFormat->dup();
279 setFormat(outputFormat);
280 }
281 mUnreportedFormat = nullptr;
282 } else {
283 if (outputFormat) {
284 mUnreportedFormat = outputFormat;
285 } else if (!mUnreportedFormat) {
286 mUnreportedFormat = mFormat;
287 }
288 }
289
290 // Flushing mReorderStash because no other buffers should come after output
291 // EOS.
292 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
293 // Flush reorder stash
294 setReorderDepth(0);
295 }
296
297 if (!entry.notify) {
298 mPending.pop_front();
299 return DISCARD;
300 }
301
302 // Try to register the buffer.
303 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
304 if (err != OK) {
305 if (err != WOULD_BLOCK) {
306 return REALLOCATE;
307 }
308 return RETRY;
309 }
310
311 // Append information from the front stash entry to outBuffer.
312 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
313 (*outBuffer)->meta()->setInt32("flags", entry.flags);
314 ALOGV("[%s] popFromStashAndRegister: "
315 "out buffer index = %zu [%p] => %p + %zu (%lld)",
316 mName, *index, outBuffer->get(),
317 (*outBuffer)->data(), (*outBuffer)->size(),
318 (long long)entry.timestamp);
319
320 // The front entry of mPending will be removed now that the registration
321 // succeeded.
322 mPending.pop_front();
323 return NOTIFY_CLIENT;
324}
325
326bool OutputBuffers::popPending(StashEntry *entry) {
327 if (mPending.empty()) {
328 return false;
329 }
330 *entry = mPending.front();
331 mPending.pop_front();
332 return true;
333}
334
335void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
336 mPending.push_front(entry);
337}
338
339bool OutputBuffers::hasPending() const {
340 return !mPending.empty();
341}
342
343bool OutputBuffers::less(
344 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
345 switch (mKey) {
346 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
347 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
348 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
349 default:
350 ALOGD("Unrecognized key; default to timestamp");
351 return o1.frameIndex < o2.frameIndex;
352 }
353}
354
Wonsik Kim469c8342019-04-11 16:46:09 -0700355// LocalBufferPool
356
357std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
358 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
359}
360
361sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
362 Mutex::Autolock lock(mMutex);
363 auto it = std::find_if(
364 mPool.begin(), mPool.end(),
365 [capacity](const std::vector<uint8_t> &vec) {
366 return vec.capacity() >= capacity;
367 });
368 if (it != mPool.end()) {
369 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
370 mPool.erase(it);
371 return buffer;
372 }
373 if (mUsedSize + capacity > mPoolCapacity) {
374 while (!mPool.empty()) {
375 mUsedSize -= mPool.back().capacity();
376 mPool.pop_back();
377 }
378 if (mUsedSize + capacity > mPoolCapacity) {
379 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
380 mUsedSize, capacity, mPoolCapacity);
381 return nullptr;
382 }
383 }
384 std::vector<uint8_t> vec(capacity);
385 mUsedSize += vec.capacity();
386 return new VectorBuffer(std::move(vec), shared_from_this());
387}
388
389LocalBufferPool::VectorBuffer::VectorBuffer(
390 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
391 : ABuffer(vec.data(), vec.capacity()),
392 mVec(std::move(vec)),
393 mPool(pool) {
394}
395
396LocalBufferPool::VectorBuffer::~VectorBuffer() {
397 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
398 if (pool) {
399 // If pool is alive, return the vector back to the pool so that
400 // it can be recycled.
401 pool->returnVector(std::move(mVec));
402 }
403}
404
405void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
406 Mutex::Autolock lock(mMutex);
407 mPool.push_front(std::move(vec));
408}
409
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700410// FlexBuffersImpl
411
Wonsik Kim469c8342019-04-11 16:46:09 -0700412size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
413 for (size_t i = 0; i < mBuffers.size(); ++i) {
414 if (mBuffers[i].clientBuffer == nullptr
415 && mBuffers[i].compBuffer.expired()) {
416 mBuffers[i].clientBuffer = buffer;
417 return i;
418 }
419 }
420 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
421 return mBuffers.size() - 1;
422}
423
Wonsik Kim469c8342019-04-11 16:46:09 -0700424bool FlexBuffersImpl::releaseSlot(
425 const sp<MediaCodecBuffer> &buffer,
426 std::shared_ptr<C2Buffer> *c2buffer,
427 bool release) {
428 sp<Codec2Buffer> clientBuffer;
429 size_t index = mBuffers.size();
430 for (size_t i = 0; i < mBuffers.size(); ++i) {
431 if (mBuffers[i].clientBuffer == buffer) {
432 clientBuffer = mBuffers[i].clientBuffer;
433 if (release) {
434 mBuffers[i].clientBuffer.clear();
435 }
436 index = i;
437 break;
438 }
439 }
440 if (clientBuffer == nullptr) {
441 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
442 return false;
443 }
444 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
445 if (!result) {
446 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700447 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700448 mBuffers[index].compBuffer = result;
449 }
450 if (c2buffer) {
451 *c2buffer = result;
452 }
453 return true;
454}
455
456bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
457 for (size_t i = 0; i < mBuffers.size(); ++i) {
458 std::shared_ptr<C2Buffer> compBuffer =
459 mBuffers[i].compBuffer.lock();
460 if (!compBuffer || compBuffer != c2buffer) {
461 continue;
462 }
463 mBuffers[i].compBuffer.reset();
464 ALOGV("[%s] codec released buffer #%zu", mName, i);
465 return true;
466 }
467 ALOGV("[%s] codec released an unknown buffer", mName);
468 return false;
469}
470
471void FlexBuffersImpl::flush() {
472 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
473 mBuffers.clear();
474}
475
476size_t FlexBuffersImpl::numClientBuffers() const {
477 return std::count_if(
478 mBuffers.begin(), mBuffers.end(),
479 [](const Entry &entry) {
480 return (entry.clientBuffer != nullptr);
481 });
482}
483
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700484size_t FlexBuffersImpl::numComponentBuffers() const {
485 return std::count_if(
486 mBuffers.begin(), mBuffers.end(),
487 [](const Entry &entry) {
488 return !entry.compBuffer.expired();
489 });
490}
491
Wonsik Kim469c8342019-04-11 16:46:09 -0700492// BuffersArrayImpl
493
494void BuffersArrayImpl::initialize(
495 const FlexBuffersImpl &impl,
496 size_t minSize,
497 std::function<sp<Codec2Buffer>()> allocate) {
498 mImplName = impl.mImplName + "[N]";
499 mName = mImplName.c_str();
500 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
501 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
502 bool ownedByClient = (clientBuffer != nullptr);
503 if (!ownedByClient) {
504 clientBuffer = allocate();
505 }
506 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
507 }
508 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
509 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
510 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
511 }
512}
513
514status_t BuffersArrayImpl::grabBuffer(
515 size_t *index,
516 sp<Codec2Buffer> *buffer,
517 std::function<bool(const sp<Codec2Buffer> &)> match) {
518 // allBuffersDontMatch remains true if all buffers are available but
519 // match() returns false for every buffer.
520 bool allBuffersDontMatch = true;
521 for (size_t i = 0; i < mBuffers.size(); ++i) {
522 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
523 if (match(mBuffers[i].clientBuffer)) {
524 mBuffers[i].ownedByClient = true;
525 *buffer = mBuffers[i].clientBuffer;
526 (*buffer)->meta()->clear();
527 (*buffer)->setRange(0, (*buffer)->capacity());
528 *index = i;
529 return OK;
530 }
531 } else {
532 allBuffersDontMatch = false;
533 }
534 }
535 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
536}
537
538bool BuffersArrayImpl::returnBuffer(
539 const sp<MediaCodecBuffer> &buffer,
540 std::shared_ptr<C2Buffer> *c2buffer,
541 bool release) {
542 sp<Codec2Buffer> clientBuffer;
543 size_t index = mBuffers.size();
544 for (size_t i = 0; i < mBuffers.size(); ++i) {
545 if (mBuffers[i].clientBuffer == buffer) {
546 if (!mBuffers[i].ownedByClient) {
547 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
548 mName, i);
549 }
550 clientBuffer = mBuffers[i].clientBuffer;
551 if (release) {
552 mBuffers[i].ownedByClient = false;
553 }
554 index = i;
555 break;
556 }
557 }
558 if (clientBuffer == nullptr) {
559 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
560 return false;
561 }
562 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
563 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
564 if (!result) {
565 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700566 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700567 mBuffers[index].compBuffer = result;
568 }
569 if (c2buffer) {
570 *c2buffer = result;
571 }
572 return true;
573}
574
575bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
576 for (size_t i = 0; i < mBuffers.size(); ++i) {
577 std::shared_ptr<C2Buffer> compBuffer =
578 mBuffers[i].compBuffer.lock();
579 if (!compBuffer) {
580 continue;
581 }
582 if (c2buffer == compBuffer) {
583 if (mBuffers[i].ownedByClient) {
584 // This should not happen.
585 ALOGD("[%s] codec released a buffer owned by client "
586 "(index %zu)", mName, i);
587 }
588 mBuffers[i].compBuffer.reset();
589 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
590 return true;
591 }
592 }
593 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
594 return false;
595}
596
597void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
598 array->clear();
599 for (const Entry &entry : mBuffers) {
600 array->push(entry.clientBuffer);
601 }
602}
603
604void BuffersArrayImpl::flush() {
605 for (Entry &entry : mBuffers) {
606 entry.ownedByClient = false;
607 }
608}
609
610void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
611 size_t size = mBuffers.size();
612 mBuffers.clear();
613 for (size_t i = 0; i < size; ++i) {
614 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
615 }
616}
617
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700618void BuffersArrayImpl::grow(
619 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
620 CHECK_LT(mBuffers.size(), newSize);
621 while (mBuffers.size() < newSize) {
622 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
623 }
624}
625
Wonsik Kim469c8342019-04-11 16:46:09 -0700626size_t BuffersArrayImpl::numClientBuffers() const {
627 return std::count_if(
628 mBuffers.begin(), mBuffers.end(),
629 [](const Entry &entry) {
630 return entry.ownedByClient;
631 });
632}
633
Wonsik Kima39882b2019-06-20 16:13:56 -0700634size_t BuffersArrayImpl::arraySize() const {
635 return mBuffers.size();
636}
637
Wonsik Kim469c8342019-04-11 16:46:09 -0700638// InputBuffersArray
639
640void InputBuffersArray::initialize(
641 const FlexBuffersImpl &impl,
642 size_t minSize,
643 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700644 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700645 mImpl.initialize(impl, minSize, allocate);
646}
647
648void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
649 mImpl.getArray(array);
650}
651
652bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
653 sp<Codec2Buffer> c2Buffer;
654 status_t err = mImpl.grabBuffer(index, &c2Buffer);
655 if (err == OK) {
656 c2Buffer->setFormat(mFormat);
657 handleImageData(c2Buffer);
658 *buffer = c2Buffer;
659 return true;
660 }
661 return false;
662}
663
664bool InputBuffersArray::releaseBuffer(
665 const sp<MediaCodecBuffer> &buffer,
666 std::shared_ptr<C2Buffer> *c2buffer,
667 bool release) {
668 return mImpl.returnBuffer(buffer, c2buffer, release);
669}
670
671bool InputBuffersArray::expireComponentBuffer(
672 const std::shared_ptr<C2Buffer> &c2buffer) {
673 return mImpl.expireComponentBuffer(c2buffer);
674}
675
676void InputBuffersArray::flush() {
677 mImpl.flush();
678}
679
680size_t InputBuffersArray::numClientBuffers() const {
681 return mImpl.numClientBuffers();
682}
683
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700684sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
685 return mAllocate();
686}
687
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800688// SlotInputBuffers
689
690bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
691 sp<Codec2Buffer> newBuffer = createNewBuffer();
692 *index = mImpl.assignSlot(newBuffer);
693 *buffer = newBuffer;
694 return true;
695}
696
697bool SlotInputBuffers::releaseBuffer(
698 const sp<MediaCodecBuffer> &buffer,
699 std::shared_ptr<C2Buffer> *c2buffer,
700 bool release) {
701 return mImpl.releaseSlot(buffer, c2buffer, release);
702}
703
704bool SlotInputBuffers::expireComponentBuffer(
705 const std::shared_ptr<C2Buffer> &c2buffer) {
706 return mImpl.expireComponentBuffer(c2buffer);
707}
708
709void SlotInputBuffers::flush() {
710 mImpl.flush();
711}
712
713std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
714 TRESPASS("Array mode should not be called at non-legacy mode");
715 return nullptr;
716}
717
718size_t SlotInputBuffers::numClientBuffers() const {
719 return mImpl.numClientBuffers();
720}
721
722sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
723 return new DummyContainerBuffer{mFormat, nullptr};
724}
725
Wonsik Kim469c8342019-04-11 16:46:09 -0700726// LinearInputBuffers
727
728bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700729 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700730 if (newBuffer == nullptr) {
731 return false;
732 }
733 *index = mImpl.assignSlot(newBuffer);
734 *buffer = newBuffer;
735 return true;
736}
737
738bool LinearInputBuffers::releaseBuffer(
739 const sp<MediaCodecBuffer> &buffer,
740 std::shared_ptr<C2Buffer> *c2buffer,
741 bool release) {
742 return mImpl.releaseSlot(buffer, c2buffer, release);
743}
744
745bool LinearInputBuffers::expireComponentBuffer(
746 const std::shared_ptr<C2Buffer> &c2buffer) {
747 return mImpl.expireComponentBuffer(c2buffer);
748}
749
750void LinearInputBuffers::flush() {
751 // This is no-op by default unless we're in array mode where we need to keep
752 // track of the flushed work.
753 mImpl.flush();
754}
755
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700756std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700757 std::unique_ptr<InputBuffersArray> array(
758 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
759 array->setPool(mPool);
760 array->setFormat(mFormat);
761 array->initialize(
762 mImpl,
763 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700764 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
765 return Alloc(pool, format);
766 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700767 return std::move(array);
768}
769
770size_t LinearInputBuffers::numClientBuffers() const {
771 return mImpl.numClientBuffers();
772}
773
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700774// static
775sp<Codec2Buffer> LinearInputBuffers::Alloc(
776 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
777 int32_t capacity = kLinearBufferSize;
778 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
779 if ((size_t)capacity > kMaxLinearBufferSize) {
780 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
781 capacity = kMaxLinearBufferSize;
782 }
783
784 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700785 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
786 std::shared_ptr<C2LinearBlock> block;
787
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700788 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700789 if (err != C2_OK) {
790 return nullptr;
791 }
792
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700793 return LinearBlockBuffer::Allocate(format, block);
794}
795
796sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
797 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700798}
799
800// EncryptedLinearInputBuffers
801
802EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
803 bool secure,
804 const sp<MemoryDealer> &dealer,
805 const sp<ICrypto> &crypto,
806 int32_t heapSeqNum,
807 size_t capacity,
808 size_t numInputSlots,
809 const char *componentName, const char *name)
810 : LinearInputBuffers(componentName, name),
811 mUsage({0, 0}),
812 mDealer(dealer),
813 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700814 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700815 if (secure) {
816 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
817 } else {
818 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
819 }
820 for (size_t i = 0; i < numInputSlots; ++i) {
821 sp<IMemory> memory = mDealer->allocate(capacity);
822 if (memory == nullptr) {
823 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
824 mName, i);
825 break;
826 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700827 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700828 }
829}
830
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700831std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
832 std::unique_ptr<InputBuffersArray> array(
833 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
834 array->setPool(mPool);
835 array->setFormat(mFormat);
836 array->initialize(
837 mImpl,
838 size,
839 [pool = mPool,
840 format = mFormat,
841 usage = mUsage,
842 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
843 return Alloc(pool, format, usage, memoryVector);
844 });
845 return std::move(array);
846}
847
848
849// static
850sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
851 const std::shared_ptr<C2BlockPool> &pool,
852 const sp<AMessage> &format,
853 C2MemoryUsage usage,
854 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
855 int32_t capacity = kLinearBufferSize;
856 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
857 if ((size_t)capacity > kMaxLinearBufferSize) {
858 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
859 capacity = kMaxLinearBufferSize;
860 }
861
Wonsik Kim469c8342019-04-11 16:46:09 -0700862 sp<IMemory> memory;
863 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700864 int32_t heapSeqNum = -1;
865 for (; slot < memoryVector->size(); ++slot) {
866 if (memoryVector->at(slot).block.expired()) {
867 memory = memoryVector->at(slot).memory;
868 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700869 break;
870 }
871 }
872 if (memory == nullptr) {
873 return nullptr;
874 }
875
876 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700877 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700878 if (err != C2_OK || block == nullptr) {
879 return nullptr;
880 }
881
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700882 memoryVector->at(slot).block = block;
883 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
884}
885
886sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
887 // TODO: android_2020
888 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700889}
890
891// GraphicMetadataInputBuffers
892
893GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
894 const char *componentName, const char *name)
895 : InputBuffers(componentName, name),
896 mImpl(mName),
897 mStore(GetCodec2PlatformAllocatorStore()) { }
898
899bool GraphicMetadataInputBuffers::requestNewBuffer(
900 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700901 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700902 if (newBuffer == nullptr) {
903 return false;
904 }
905 *index = mImpl.assignSlot(newBuffer);
906 *buffer = newBuffer;
907 return true;
908}
909
910bool GraphicMetadataInputBuffers::releaseBuffer(
911 const sp<MediaCodecBuffer> &buffer,
912 std::shared_ptr<C2Buffer> *c2buffer,
913 bool release) {
914 return mImpl.releaseSlot(buffer, c2buffer, release);
915}
916
917bool GraphicMetadataInputBuffers::expireComponentBuffer(
918 const std::shared_ptr<C2Buffer> &c2buffer) {
919 return mImpl.expireComponentBuffer(c2buffer);
920}
921
922void GraphicMetadataInputBuffers::flush() {
923 // This is no-op by default unless we're in array mode where we need to keep
924 // track of the flushed work.
925}
926
927std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
928 size_t size) {
929 std::shared_ptr<C2Allocator> alloc;
930 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
931 if (err != C2_OK) {
932 return nullptr;
933 }
934 std::unique_ptr<InputBuffersArray> array(
935 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
936 array->setPool(mPool);
937 array->setFormat(mFormat);
938 array->initialize(
939 mImpl,
940 size,
941 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
942 return new GraphicMetadataBuffer(format, alloc);
943 });
944 return std::move(array);
945}
946
947size_t GraphicMetadataInputBuffers::numClientBuffers() const {
948 return mImpl.numClientBuffers();
949}
950
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700951sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
952 std::shared_ptr<C2Allocator> alloc;
953 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
954 if (err != C2_OK) {
955 return nullptr;
956 }
957 return new GraphicMetadataBuffer(mFormat, alloc);
958}
959
Wonsik Kim469c8342019-04-11 16:46:09 -0700960// GraphicInputBuffers
961
962GraphicInputBuffers::GraphicInputBuffers(
963 size_t numInputSlots, const char *componentName, const char *name)
964 : InputBuffers(componentName, name),
965 mImpl(mName),
966 mLocalBufferPool(LocalBufferPool::Create(
967 kMaxLinearBufferSize * numInputSlots)) { }
968
969bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700970 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700971 if (newBuffer == nullptr) {
972 return false;
973 }
974 *index = mImpl.assignSlot(newBuffer);
975 handleImageData(newBuffer);
976 *buffer = newBuffer;
977 return true;
978}
979
980bool GraphicInputBuffers::releaseBuffer(
981 const sp<MediaCodecBuffer> &buffer,
982 std::shared_ptr<C2Buffer> *c2buffer,
983 bool release) {
984 return mImpl.releaseSlot(buffer, c2buffer, release);
985}
986
987bool GraphicInputBuffers::expireComponentBuffer(
988 const std::shared_ptr<C2Buffer> &c2buffer) {
989 return mImpl.expireComponentBuffer(c2buffer);
990}
991
992void GraphicInputBuffers::flush() {
993 // This is no-op by default unless we're in array mode where we need to keep
994 // track of the flushed work.
995}
996
997std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
998 std::unique_ptr<InputBuffersArray> array(
999 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1000 array->setPool(mPool);
1001 array->setFormat(mFormat);
1002 array->initialize(
1003 mImpl,
1004 size,
1005 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1006 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1007 return AllocateGraphicBuffer(
1008 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1009 });
1010 return std::move(array);
1011}
1012
1013size_t GraphicInputBuffers::numClientBuffers() const {
1014 return mImpl.numClientBuffers();
1015}
1016
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001017sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1018 // TODO: read usage from intf
1019 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1020 return AllocateGraphicBuffer(
1021 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1022}
1023
Wonsik Kim469c8342019-04-11 16:46:09 -07001024// OutputBuffersArray
1025
1026void OutputBuffersArray::initialize(
1027 const FlexBuffersImpl &impl,
1028 size_t minSize,
1029 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001030 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001031 mImpl.initialize(impl, minSize, allocate);
1032}
1033
1034status_t OutputBuffersArray::registerBuffer(
1035 const std::shared_ptr<C2Buffer> &buffer,
1036 size_t *index,
1037 sp<MediaCodecBuffer> *clientBuffer) {
1038 sp<Codec2Buffer> c2Buffer;
1039 status_t err = mImpl.grabBuffer(
1040 index,
1041 &c2Buffer,
1042 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1043 return clientBuffer->canCopy(buffer);
1044 });
1045 if (err == WOULD_BLOCK) {
1046 ALOGV("[%s] buffers temporarily not available", mName);
1047 return err;
1048 } else if (err != OK) {
1049 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1050 return err;
1051 }
1052 c2Buffer->setFormat(mFormat);
1053 if (!c2Buffer->copy(buffer)) {
1054 ALOGD("[%s] copy buffer failed", mName);
1055 return WOULD_BLOCK;
1056 }
1057 submit(c2Buffer);
1058 handleImageData(c2Buffer);
1059 *clientBuffer = c2Buffer;
1060 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1061 return OK;
1062}
1063
1064status_t OutputBuffersArray::registerCsd(
1065 const C2StreamInitDataInfo::output *csd,
1066 size_t *index,
1067 sp<MediaCodecBuffer> *clientBuffer) {
1068 sp<Codec2Buffer> c2Buffer;
1069 status_t err = mImpl.grabBuffer(
1070 index,
1071 &c2Buffer,
1072 [csd](const sp<Codec2Buffer> &clientBuffer) {
1073 return clientBuffer->base() != nullptr
1074 && clientBuffer->capacity() >= csd->flexCount();
1075 });
1076 if (err != OK) {
1077 return err;
1078 }
1079 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1080 c2Buffer->setRange(0, csd->flexCount());
1081 c2Buffer->setFormat(mFormat);
1082 *clientBuffer = c2Buffer;
1083 return OK;
1084}
1085
1086bool OutputBuffersArray::releaseBuffer(
1087 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1088 return mImpl.returnBuffer(buffer, c2buffer, true);
1089}
1090
1091void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1092 (void)flushedWork;
1093 mImpl.flush();
1094 if (mSkipCutBuffer != nullptr) {
1095 mSkipCutBuffer->clear();
1096 }
1097}
1098
1099void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1100 mImpl.getArray(array);
1101}
1102
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001103size_t OutputBuffersArray::numClientBuffers() const {
1104 return mImpl.numClientBuffers();
1105}
1106
Wonsik Kim469c8342019-04-11 16:46:09 -07001107void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001108 switch (c2buffer->data().type()) {
1109 case C2BufferData::LINEAR: {
1110 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001111 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1112 const uint32_t block_size = linear_blocks.front().size();
1113 if (block_size < kMaxLinearBufferSize / 2) {
1114 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001115 } else {
1116 size = kMaxLinearBufferSize;
1117 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001118 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001119 return new LocalLinearBuffer(format, new ABuffer(size));
1120 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001121 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001122 break;
1123 }
1124
Wonsik Kima39882b2019-06-20 16:13:56 -07001125 case C2BufferData::GRAPHIC: {
1126 // This is only called for RawGraphicOutputBuffers.
1127 mAlloc = [format = mFormat,
1128 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
1129 return ConstGraphicBlockBuffer::AllocateEmpty(
1130 format,
1131 [lbp](size_t capacity) {
1132 return lbp->newBuffer(capacity);
1133 });
1134 };
1135 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1136 mName, mFormat->debugString().c_str());
1137 break;
1138 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001139
1140 case C2BufferData::INVALID: [[fallthrough]];
1141 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1142 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1143 default:
1144 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1145 return;
1146 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001147 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001148}
1149
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001150void OutputBuffersArray::grow(size_t newSize) {
1151 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001152}
1153
Pawin Vongmasab18c1af2020-04-11 05:07:15 -07001154void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1155 mFormat = source->mFormat;
1156 mSkipCutBuffer = source->mSkipCutBuffer;
1157 mUnreportedFormat = source->mUnreportedFormat;
1158 mPending = std::move(source->mPending);
1159 mReorderStash = std::move(source->mReorderStash);
1160 mDepth = source->mDepth;
1161 mKey = source->mKey;
1162}
1163
Wonsik Kim469c8342019-04-11 16:46:09 -07001164// FlexOutputBuffers
1165
1166status_t FlexOutputBuffers::registerBuffer(
1167 const std::shared_ptr<C2Buffer> &buffer,
1168 size_t *index,
1169 sp<MediaCodecBuffer> *clientBuffer) {
1170 sp<Codec2Buffer> newBuffer = wrap(buffer);
1171 if (newBuffer == nullptr) {
1172 return NO_MEMORY;
1173 }
1174 newBuffer->setFormat(mFormat);
1175 *index = mImpl.assignSlot(newBuffer);
1176 handleImageData(newBuffer);
1177 *clientBuffer = newBuffer;
1178 ALOGV("[%s] registered buffer %zu", mName, *index);
1179 return OK;
1180}
1181
1182status_t FlexOutputBuffers::registerCsd(
1183 const C2StreamInitDataInfo::output *csd,
1184 size_t *index,
1185 sp<MediaCodecBuffer> *clientBuffer) {
1186 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1187 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1188 *index = mImpl.assignSlot(newBuffer);
1189 *clientBuffer = newBuffer;
1190 return OK;
1191}
1192
1193bool FlexOutputBuffers::releaseBuffer(
1194 const sp<MediaCodecBuffer> &buffer,
1195 std::shared_ptr<C2Buffer> *c2buffer) {
1196 return mImpl.releaseSlot(buffer, c2buffer, true);
1197}
1198
1199void FlexOutputBuffers::flush(
1200 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1201 (void) flushedWork;
1202 // This is no-op by default unless we're in array mode where we need to keep
1203 // track of the flushed work.
1204}
1205
Pawin Vongmasab18c1af2020-04-11 05:07:15 -07001206std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001207 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasab18c1af2020-04-11 05:07:15 -07001208 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001209 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1210 array->initialize(mImpl, size, alloc);
Pawin Vongmasab18c1af2020-04-11 05:07:15 -07001211 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001212}
1213
1214size_t FlexOutputBuffers::numClientBuffers() const {
1215 return mImpl.numClientBuffers();
1216}
1217
1218// LinearOutputBuffers
1219
1220void LinearOutputBuffers::flush(
1221 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1222 if (mSkipCutBuffer != nullptr) {
1223 mSkipCutBuffer->clear();
1224 }
1225 FlexOutputBuffers::flush(flushedWork);
1226}
1227
1228sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1229 if (buffer == nullptr) {
1230 ALOGV("[%s] using a dummy buffer", mName);
1231 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1232 }
1233 if (buffer->data().type() != C2BufferData::LINEAR) {
1234 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1235 // We expect linear output buffers from the component.
1236 return nullptr;
1237 }
1238 if (buffer->data().linearBlocks().size() != 1u) {
1239 ALOGV("[%s] no linear buffers", mName);
1240 // We expect one and only one linear block from the component.
1241 return nullptr;
1242 }
1243 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1244 if (clientBuffer == nullptr) {
1245 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1246 return nullptr;
1247 }
1248 submit(clientBuffer);
1249 return clientBuffer;
1250}
1251
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001252std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1253 return [format = mFormat]{
1254 // TODO: proper max output size
1255 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1256 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001257}
1258
1259// GraphicOutputBuffers
1260
1261sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1262 return new DummyContainerBuffer(mFormat, buffer);
1263}
1264
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001265std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1266 return [format = mFormat]{
1267 return new DummyContainerBuffer(format);
1268 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001269}
1270
1271// RawGraphicOutputBuffers
1272
1273RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1274 size_t numOutputSlots, const char *componentName, const char *name)
1275 : FlexOutputBuffers(componentName, name),
1276 mLocalBufferPool(LocalBufferPool::Create(
1277 kMaxLinearBufferSize * numOutputSlots)) { }
1278
1279sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1280 if (buffer == nullptr) {
1281 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1282 mFormat,
1283 [lbp = mLocalBufferPool](size_t capacity) {
1284 return lbp->newBuffer(capacity);
1285 });
1286 if (c2buffer == nullptr) {
1287 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1288 return nullptr;
1289 }
1290 c2buffer->setRange(0, 0);
1291 return c2buffer;
1292 } else {
1293 return ConstGraphicBlockBuffer::Allocate(
1294 mFormat,
1295 buffer,
1296 [lbp = mLocalBufferPool](size_t capacity) {
1297 return lbp->newBuffer(capacity);
1298 });
1299 }
1300}
1301
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001302std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1303 return [format = mFormat, lbp = mLocalBufferPool]{
1304 return ConstGraphicBlockBuffer::AllocateEmpty(
1305 format,
1306 [lbp](size_t capacity) {
1307 return lbp->newBuffer(capacity);
1308 });
1309 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001310}
1311
1312} // namespace android