blob: c2ec66591c4a2770d5d03f38d8fa162c6a25a1e8 [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 Vongmasa9b906982020-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 Kim41d83432020-04-27 16:40:49 -070027#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070028
29#include "CCodecBuffers.h"
Wonsik Kimd79ee1f2020-08-27 17:41:56 -070030#include "Codec2Mapper.h"
Wonsik Kim469c8342019-04-11 16:46:09 -070031
32namespace android {
33
34namespace {
35
36sp<GraphicBlockBuffer> AllocateGraphicBuffer(
37 const std::shared_ptr<C2BlockPool> &pool,
38 const sp<AMessage> &format,
39 uint32_t pixelFormat,
40 const C2MemoryUsage &usage,
41 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
42 int32_t width, height;
43 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
44 ALOGD("format lacks width or height");
45 return nullptr;
46 }
47
48 std::shared_ptr<C2GraphicBlock> block;
49 c2_status_t err = pool->fetchGraphicBlock(
50 width, height, pixelFormat, usage, &block);
51 if (err != C2_OK) {
52 ALOGD("fetch graphic block failed: %d", err);
53 return nullptr;
54 }
55
56 return GraphicBlockBuffer::Allocate(
57 format,
58 block,
59 [localBufferPool](size_t capacity) {
60 return localBufferPool->newBuffer(capacity);
61 });
62}
63
64} // namespace
65
66// CCodecBuffers
67
68void CCodecBuffers::setFormat(const sp<AMessage> &format) {
69 CHECK(format != nullptr);
70 mFormat = format;
71}
72
73sp<AMessage> CCodecBuffers::dupFormat() {
74 return mFormat != nullptr ? mFormat->dup() : nullptr;
75}
76
77void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
78 sp<ABuffer> imageDataCandidate = buffer->getImageData();
79 if (imageDataCandidate == nullptr) {
80 return;
81 }
82 sp<ABuffer> imageData;
83 if (!mFormat->findBuffer("image-data", &imageData)
84 || imageDataCandidate->size() != imageData->size()
85 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
86 ALOGD("[%s] updating image-data", mName);
87 sp<AMessage> newFormat = dupFormat();
88 newFormat->setBuffer("image-data", imageDataCandidate);
89 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
90 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
91 int32_t stride = img->mPlane[0].mRowInc;
92 newFormat->setInt32(KEY_STRIDE, stride);
93 ALOGD("[%s] updating stride = %d", mName, stride);
94 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +090095 int64_t offsetDelta =
96 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
97 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim469c8342019-04-11 16:46:09 -070098 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
99 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800100 buffer->setRange(
101 img->mPlane[0].mOffset,
102 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700103 }
104 }
105 setFormat(newFormat);
106 buffer->setFormat(newFormat);
107 }
108}
109
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700110// InputBuffers
111
112sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
113 sp<Codec2Buffer> copy = createNewBuffer();
114 if (copy == nullptr) {
115 return nullptr;
116 }
117 std::shared_ptr<C2Buffer> c2buffer;
118 if (!releaseBuffer(buffer, &c2buffer, true)) {
119 return nullptr;
120 }
121 if (!copy->canCopy(c2buffer)) {
122 return nullptr;
123 }
124 if (!copy->copy(c2buffer)) {
125 return nullptr;
126 }
127 return copy;
128}
129
Wonsik Kim469c8342019-04-11 16:46:09 -0700130// OutputBuffers
131
Wonsik Kim41d83432020-04-27 16:40:49 -0700132OutputBuffers::OutputBuffers(const char *componentName, const char *name)
133 : CCodecBuffers(componentName, name) { }
134
135OutputBuffers::~OutputBuffers() = default;
136
Wonsik Kim469c8342019-04-11 16:46:09 -0700137void OutputBuffers::initSkipCutBuffer(
138 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
139 CHECK(mSkipCutBuffer == nullptr);
140 mDelay = delay;
141 mPadding = padding;
142 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700143 mChannelCount = channelCount;
144 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700145}
146
147void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
148 if (mSkipCutBuffer == nullptr) {
149 return;
150 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700151 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
152 return;
153 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700154 int32_t delay = mDelay;
155 int32_t padding = mPadding;
156 if (sampleRate != mSampleRate) {
157 delay = ((int64_t)delay * sampleRate) / mSampleRate;
158 padding = ((int64_t)padding * sampleRate) / mSampleRate;
159 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700160 mSampleRate = sampleRate;
161 mChannelCount = channelCount;
162 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700163}
164
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800165void OutputBuffers::updateSkipCutBuffer(
166 const sp<AMessage> &format, bool notify) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700167 AString mediaType;
168 if (format->findString(KEY_MIME, &mediaType)
169 && mediaType == MIMETYPE_AUDIO_RAW) {
170 int32_t channelCount;
171 int32_t sampleRate;
172 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
173 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
174 updateSkipCutBuffer(sampleRate, channelCount);
175 }
176 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800177 if (notify) {
178 mUnreportedFormat = nullptr;
179 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700180}
181
Wonsik Kim469c8342019-04-11 16:46:09 -0700182void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
183 if (mSkipCutBuffer != nullptr) {
184 mSkipCutBuffer->submit(buffer);
185 }
186}
187
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700188void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700189 if (mSkipCutBuffer != nullptr) {
190 size_t prevSize = mSkipCutBuffer->size();
191 if (prevSize != 0u) {
192 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
193 }
194 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700195 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700196}
197
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700198void OutputBuffers::clearStash() {
199 mPending.clear();
200 mReorderStash.clear();
201 mDepth = 0;
202 mKey = C2Config::ORDINAL;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800203 mUnreportedFormat = nullptr;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700204}
205
206void OutputBuffers::flushStash() {
207 for (StashEntry& e : mPending) {
208 e.notify = false;
209 }
210 for (StashEntry& e : mReorderStash) {
211 e.notify = false;
212 }
213}
214
215uint32_t OutputBuffers::getReorderDepth() const {
216 return mDepth;
217}
218
219void OutputBuffers::setReorderDepth(uint32_t depth) {
220 mPending.splice(mPending.end(), mReorderStash);
221 mDepth = depth;
222}
223
224void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
225 mPending.splice(mPending.end(), mReorderStash);
226 mKey = key;
227}
228
229void OutputBuffers::pushToStash(
230 const std::shared_ptr<C2Buffer>& buffer,
231 bool notify,
232 int64_t timestamp,
233 int32_t flags,
234 const sp<AMessage>& format,
235 const C2WorkOrdinalStruct& ordinal) {
236 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
237 if (!buffer && eos) {
238 // TRICKY: we may be violating ordering of the stash here. Because we
239 // don't expect any more emplace() calls after this, the ordering should
240 // not matter.
241 mReorderStash.emplace_back(
242 buffer, notify, timestamp, flags, format, ordinal);
243 } else {
244 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
245 auto it = mReorderStash.begin();
246 for (; it != mReorderStash.end(); ++it) {
247 if (less(ordinal, it->ordinal)) {
248 break;
249 }
250 }
251 mReorderStash.emplace(it,
252 buffer, notify, timestamp, flags, format, ordinal);
253 if (eos) {
254 mReorderStash.back().flags =
255 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
256 }
257 }
258 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
259 mPending.push_back(mReorderStash.front());
260 mReorderStash.pop_front();
261 }
262 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
263}
264
265OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
266 std::shared_ptr<C2Buffer>* c2Buffer,
267 size_t* index,
268 sp<MediaCodecBuffer>* outBuffer) {
269 if (mPending.empty()) {
270 return SKIP;
271 }
272
273 // Retrieve the first entry.
274 StashEntry &entry = mPending.front();
275
276 *c2Buffer = entry.buffer;
277 sp<AMessage> outputFormat = entry.format;
278
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800279 // The output format can be processed without a registered slot.
280 if (outputFormat) {
281 updateSkipCutBuffer(outputFormat, entry.notify);
282 }
283
284 if (entry.notify) {
285 if (outputFormat) {
286 setFormat(outputFormat);
287 } else if (mUnreportedFormat) {
288 outputFormat = mUnreportedFormat;
289 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700290 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800291 mUnreportedFormat = nullptr;
292 } else {
293 if (outputFormat) {
294 mUnreportedFormat = outputFormat;
295 } else if (!mUnreportedFormat) {
296 mUnreportedFormat = mFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700297 }
298 }
299
300 // Flushing mReorderStash because no other buffers should come after output
301 // EOS.
302 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
303 // Flush reorder stash
304 setReorderDepth(0);
305 }
306
307 if (!entry.notify) {
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800308 if (outputFormat) {
309 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
310 mName, outputFormat->debugString().c_str());
311 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700312 mPending.pop_front();
313 return DISCARD;
314 }
315
316 // Try to register the buffer.
317 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
318 if (err != OK) {
319 if (err != WOULD_BLOCK) {
320 return REALLOCATE;
321 }
322 return RETRY;
323 }
324
325 // Append information from the front stash entry to outBuffer.
326 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
327 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800328 if (outputFormat) {
329 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
330 mName, outputFormat->debugString().c_str());
331 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700332 ALOGV("[%s] popFromStashAndRegister: "
333 "out buffer index = %zu [%p] => %p + %zu (%lld)",
334 mName, *index, outBuffer->get(),
335 (*outBuffer)->data(), (*outBuffer)->size(),
336 (long long)entry.timestamp);
337
338 // The front entry of mPending will be removed now that the registration
339 // succeeded.
340 mPending.pop_front();
341 return NOTIFY_CLIENT;
342}
343
344bool OutputBuffers::popPending(StashEntry *entry) {
345 if (mPending.empty()) {
346 return false;
347 }
348 *entry = mPending.front();
349 mPending.pop_front();
350 return true;
351}
352
353void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
354 mPending.push_front(entry);
355}
356
357bool OutputBuffers::hasPending() const {
358 return !mPending.empty();
359}
360
361bool OutputBuffers::less(
362 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
363 switch (mKey) {
364 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
365 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
366 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
367 default:
368 ALOGD("Unrecognized key; default to timestamp");
369 return o1.frameIndex < o2.frameIndex;
370 }
371}
372
Wonsik Kim469c8342019-04-11 16:46:09 -0700373// LocalBufferPool
374
Wonsik Kim41d83432020-04-27 16:40:49 -0700375constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
376constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
377
378std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
379 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700380}
381
382sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
383 Mutex::Autolock lock(mMutex);
384 auto it = std::find_if(
385 mPool.begin(), mPool.end(),
386 [capacity](const std::vector<uint8_t> &vec) {
387 return vec.capacity() >= capacity;
388 });
389 if (it != mPool.end()) {
390 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
391 mPool.erase(it);
392 return buffer;
393 }
394 if (mUsedSize + capacity > mPoolCapacity) {
395 while (!mPool.empty()) {
396 mUsedSize -= mPool.back().capacity();
397 mPool.pop_back();
398 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700399 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
400 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
401 mPoolCapacity, mPoolCapacity * 2);
402 mPoolCapacity *= 2;
403 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700404 if (mUsedSize + capacity > mPoolCapacity) {
405 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
406 mUsedSize, capacity, mPoolCapacity);
407 return nullptr;
408 }
409 }
410 std::vector<uint8_t> vec(capacity);
411 mUsedSize += vec.capacity();
412 return new VectorBuffer(std::move(vec), shared_from_this());
413}
414
415LocalBufferPool::VectorBuffer::VectorBuffer(
416 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
417 : ABuffer(vec.data(), vec.capacity()),
418 mVec(std::move(vec)),
419 mPool(pool) {
420}
421
422LocalBufferPool::VectorBuffer::~VectorBuffer() {
423 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
424 if (pool) {
425 // If pool is alive, return the vector back to the pool so that
426 // it can be recycled.
427 pool->returnVector(std::move(mVec));
428 }
429}
430
431void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
432 Mutex::Autolock lock(mMutex);
433 mPool.push_front(std::move(vec));
434}
435
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700436// FlexBuffersImpl
437
Wonsik Kim469c8342019-04-11 16:46:09 -0700438size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
439 for (size_t i = 0; i < mBuffers.size(); ++i) {
440 if (mBuffers[i].clientBuffer == nullptr
441 && mBuffers[i].compBuffer.expired()) {
442 mBuffers[i].clientBuffer = buffer;
443 return i;
444 }
445 }
446 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
447 return mBuffers.size() - 1;
448}
449
Wonsik Kim469c8342019-04-11 16:46:09 -0700450bool FlexBuffersImpl::releaseSlot(
451 const sp<MediaCodecBuffer> &buffer,
452 std::shared_ptr<C2Buffer> *c2buffer,
453 bool release) {
454 sp<Codec2Buffer> clientBuffer;
455 size_t index = mBuffers.size();
456 for (size_t i = 0; i < mBuffers.size(); ++i) {
457 if (mBuffers[i].clientBuffer == buffer) {
458 clientBuffer = mBuffers[i].clientBuffer;
459 if (release) {
460 mBuffers[i].clientBuffer.clear();
461 }
462 index = i;
463 break;
464 }
465 }
466 if (clientBuffer == nullptr) {
467 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
468 return false;
469 }
470 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
471 if (!result) {
472 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700473 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700474 mBuffers[index].compBuffer = result;
475 }
476 if (c2buffer) {
477 *c2buffer = result;
478 }
479 return true;
480}
481
482bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
483 for (size_t i = 0; i < mBuffers.size(); ++i) {
484 std::shared_ptr<C2Buffer> compBuffer =
485 mBuffers[i].compBuffer.lock();
486 if (!compBuffer || compBuffer != c2buffer) {
487 continue;
488 }
489 mBuffers[i].compBuffer.reset();
490 ALOGV("[%s] codec released buffer #%zu", mName, i);
491 return true;
492 }
493 ALOGV("[%s] codec released an unknown buffer", mName);
494 return false;
495}
496
497void FlexBuffersImpl::flush() {
498 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
499 mBuffers.clear();
500}
501
Wonsik Kim0487b782020-10-28 11:45:50 -0700502size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700503 return std::count_if(
504 mBuffers.begin(), mBuffers.end(),
505 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700506 return (entry.clientBuffer != nullptr
507 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700508 });
509}
510
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700511size_t FlexBuffersImpl::numComponentBuffers() const {
512 return std::count_if(
513 mBuffers.begin(), mBuffers.end(),
514 [](const Entry &entry) {
515 return !entry.compBuffer.expired();
516 });
517}
518
Wonsik Kim469c8342019-04-11 16:46:09 -0700519// BuffersArrayImpl
520
521void BuffersArrayImpl::initialize(
522 const FlexBuffersImpl &impl,
523 size_t minSize,
524 std::function<sp<Codec2Buffer>()> allocate) {
525 mImplName = impl.mImplName + "[N]";
526 mName = mImplName.c_str();
527 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
528 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
529 bool ownedByClient = (clientBuffer != nullptr);
530 if (!ownedByClient) {
531 clientBuffer = allocate();
532 }
533 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
534 }
535 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
536 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
537 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
538 }
539}
540
541status_t BuffersArrayImpl::grabBuffer(
542 size_t *index,
543 sp<Codec2Buffer> *buffer,
544 std::function<bool(const sp<Codec2Buffer> &)> match) {
545 // allBuffersDontMatch remains true if all buffers are available but
546 // match() returns false for every buffer.
547 bool allBuffersDontMatch = true;
548 for (size_t i = 0; i < mBuffers.size(); ++i) {
549 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
550 if (match(mBuffers[i].clientBuffer)) {
551 mBuffers[i].ownedByClient = true;
552 *buffer = mBuffers[i].clientBuffer;
553 (*buffer)->meta()->clear();
554 (*buffer)->setRange(0, (*buffer)->capacity());
555 *index = i;
556 return OK;
557 }
558 } else {
559 allBuffersDontMatch = false;
560 }
561 }
562 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
563}
564
565bool BuffersArrayImpl::returnBuffer(
566 const sp<MediaCodecBuffer> &buffer,
567 std::shared_ptr<C2Buffer> *c2buffer,
568 bool release) {
569 sp<Codec2Buffer> clientBuffer;
570 size_t index = mBuffers.size();
571 for (size_t i = 0; i < mBuffers.size(); ++i) {
572 if (mBuffers[i].clientBuffer == buffer) {
573 if (!mBuffers[i].ownedByClient) {
574 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
575 mName, i);
576 }
577 clientBuffer = mBuffers[i].clientBuffer;
578 if (release) {
579 mBuffers[i].ownedByClient = false;
580 }
581 index = i;
582 break;
583 }
584 }
585 if (clientBuffer == nullptr) {
586 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
587 return false;
588 }
589 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
590 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
591 if (!result) {
592 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700593 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700594 mBuffers[index].compBuffer = result;
595 }
596 if (c2buffer) {
597 *c2buffer = result;
598 }
599 return true;
600}
601
602bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
603 for (size_t i = 0; i < mBuffers.size(); ++i) {
604 std::shared_ptr<C2Buffer> compBuffer =
605 mBuffers[i].compBuffer.lock();
606 if (!compBuffer) {
607 continue;
608 }
609 if (c2buffer == compBuffer) {
610 if (mBuffers[i].ownedByClient) {
611 // This should not happen.
612 ALOGD("[%s] codec released a buffer owned by client "
613 "(index %zu)", mName, i);
614 }
615 mBuffers[i].compBuffer.reset();
616 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
617 return true;
618 }
619 }
620 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
621 return false;
622}
623
624void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
625 array->clear();
626 for (const Entry &entry : mBuffers) {
627 array->push(entry.clientBuffer);
628 }
629}
630
631void BuffersArrayImpl::flush() {
632 for (Entry &entry : mBuffers) {
633 entry.ownedByClient = false;
634 }
635}
636
637void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
638 size_t size = mBuffers.size();
639 mBuffers.clear();
640 for (size_t i = 0; i < size; ++i) {
641 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
642 }
643}
644
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700645void BuffersArrayImpl::grow(
646 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
647 CHECK_LT(mBuffers.size(), newSize);
648 while (mBuffers.size() < newSize) {
649 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
650 }
651}
652
Wonsik Kim0487b782020-10-28 11:45:50 -0700653size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700654 return std::count_if(
655 mBuffers.begin(), mBuffers.end(),
656 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700657 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700658 });
659}
660
Wonsik Kima39882b2019-06-20 16:13:56 -0700661size_t BuffersArrayImpl::arraySize() const {
662 return mBuffers.size();
663}
664
Wonsik Kim469c8342019-04-11 16:46:09 -0700665// InputBuffersArray
666
667void InputBuffersArray::initialize(
668 const FlexBuffersImpl &impl,
669 size_t minSize,
670 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700671 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700672 mImpl.initialize(impl, minSize, allocate);
673}
674
675void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
676 mImpl.getArray(array);
677}
678
679bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
680 sp<Codec2Buffer> c2Buffer;
681 status_t err = mImpl.grabBuffer(index, &c2Buffer);
682 if (err == OK) {
683 c2Buffer->setFormat(mFormat);
684 handleImageData(c2Buffer);
685 *buffer = c2Buffer;
686 return true;
687 }
688 return false;
689}
690
691bool InputBuffersArray::releaseBuffer(
692 const sp<MediaCodecBuffer> &buffer,
693 std::shared_ptr<C2Buffer> *c2buffer,
694 bool release) {
695 return mImpl.returnBuffer(buffer, c2buffer, release);
696}
697
698bool InputBuffersArray::expireComponentBuffer(
699 const std::shared_ptr<C2Buffer> &c2buffer) {
700 return mImpl.expireComponentBuffer(c2buffer);
701}
702
703void InputBuffersArray::flush() {
704 mImpl.flush();
705}
706
Wonsik Kim0487b782020-10-28 11:45:50 -0700707size_t InputBuffersArray::numActiveSlots() const {
708 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700709}
710
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700711sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
712 return mAllocate();
713}
714
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800715// SlotInputBuffers
716
717bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
718 sp<Codec2Buffer> newBuffer = createNewBuffer();
719 *index = mImpl.assignSlot(newBuffer);
720 *buffer = newBuffer;
721 return true;
722}
723
724bool SlotInputBuffers::releaseBuffer(
725 const sp<MediaCodecBuffer> &buffer,
726 std::shared_ptr<C2Buffer> *c2buffer,
727 bool release) {
728 return mImpl.releaseSlot(buffer, c2buffer, release);
729}
730
731bool SlotInputBuffers::expireComponentBuffer(
732 const std::shared_ptr<C2Buffer> &c2buffer) {
733 return mImpl.expireComponentBuffer(c2buffer);
734}
735
736void SlotInputBuffers::flush() {
737 mImpl.flush();
738}
739
740std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
741 TRESPASS("Array mode should not be called at non-legacy mode");
742 return nullptr;
743}
744
Wonsik Kim0487b782020-10-28 11:45:50 -0700745size_t SlotInputBuffers::numActiveSlots() const {
746 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800747}
748
749sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
750 return new DummyContainerBuffer{mFormat, nullptr};
751}
752
Wonsik Kim469c8342019-04-11 16:46:09 -0700753// LinearInputBuffers
754
755bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700756 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700757 if (newBuffer == nullptr) {
758 return false;
759 }
760 *index = mImpl.assignSlot(newBuffer);
761 *buffer = newBuffer;
762 return true;
763}
764
765bool LinearInputBuffers::releaseBuffer(
766 const sp<MediaCodecBuffer> &buffer,
767 std::shared_ptr<C2Buffer> *c2buffer,
768 bool release) {
769 return mImpl.releaseSlot(buffer, c2buffer, release);
770}
771
772bool LinearInputBuffers::expireComponentBuffer(
773 const std::shared_ptr<C2Buffer> &c2buffer) {
774 return mImpl.expireComponentBuffer(c2buffer);
775}
776
777void LinearInputBuffers::flush() {
778 // This is no-op by default unless we're in array mode where we need to keep
779 // track of the flushed work.
780 mImpl.flush();
781}
782
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700783std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700784 std::unique_ptr<InputBuffersArray> array(
785 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
786 array->setPool(mPool);
787 array->setFormat(mFormat);
788 array->initialize(
789 mImpl,
790 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700791 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
792 return Alloc(pool, format);
793 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700794 return std::move(array);
795}
796
Wonsik Kim0487b782020-10-28 11:45:50 -0700797size_t LinearInputBuffers::numActiveSlots() const {
798 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700799}
800
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700801// static
802sp<Codec2Buffer> LinearInputBuffers::Alloc(
803 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
804 int32_t capacity = kLinearBufferSize;
805 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
806 if ((size_t)capacity > kMaxLinearBufferSize) {
807 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
808 capacity = kMaxLinearBufferSize;
809 }
810
811 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700812 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
813 std::shared_ptr<C2LinearBlock> block;
814
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700815 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700816 if (err != C2_OK) {
817 return nullptr;
818 }
819
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700820 return LinearBlockBuffer::Allocate(format, block);
821}
822
823sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
824 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700825}
826
827// EncryptedLinearInputBuffers
828
829EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
830 bool secure,
831 const sp<MemoryDealer> &dealer,
832 const sp<ICrypto> &crypto,
833 int32_t heapSeqNum,
834 size_t capacity,
835 size_t numInputSlots,
836 const char *componentName, const char *name)
837 : LinearInputBuffers(componentName, name),
838 mUsage({0, 0}),
839 mDealer(dealer),
840 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700841 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700842 if (secure) {
843 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
844 } else {
845 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
846 }
847 for (size_t i = 0; i < numInputSlots; ++i) {
848 sp<IMemory> memory = mDealer->allocate(capacity);
849 if (memory == nullptr) {
850 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
851 mName, i);
852 break;
853 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700854 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700855 }
856}
857
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700858std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
859 std::unique_ptr<InputBuffersArray> array(
860 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
861 array->setPool(mPool);
862 array->setFormat(mFormat);
863 array->initialize(
864 mImpl,
865 size,
866 [pool = mPool,
867 format = mFormat,
868 usage = mUsage,
869 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
870 return Alloc(pool, format, usage, memoryVector);
871 });
872 return std::move(array);
873}
874
875
876// static
877sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
878 const std::shared_ptr<C2BlockPool> &pool,
879 const sp<AMessage> &format,
880 C2MemoryUsage usage,
881 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
882 int32_t capacity = kLinearBufferSize;
883 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
884 if ((size_t)capacity > kMaxLinearBufferSize) {
885 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
886 capacity = kMaxLinearBufferSize;
887 }
888
Wonsik Kim469c8342019-04-11 16:46:09 -0700889 sp<IMemory> memory;
890 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700891 int32_t heapSeqNum = -1;
892 for (; slot < memoryVector->size(); ++slot) {
893 if (memoryVector->at(slot).block.expired()) {
894 memory = memoryVector->at(slot).memory;
895 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700896 break;
897 }
898 }
899 if (memory == nullptr) {
900 return nullptr;
901 }
902
903 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700904 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700905 if (err != C2_OK || block == nullptr) {
906 return nullptr;
907 }
908
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700909 memoryVector->at(slot).block = block;
910 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
911}
912
913sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
914 // TODO: android_2020
915 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700916}
917
918// GraphicMetadataInputBuffers
919
920GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
921 const char *componentName, const char *name)
922 : InputBuffers(componentName, name),
923 mImpl(mName),
924 mStore(GetCodec2PlatformAllocatorStore()) { }
925
926bool GraphicMetadataInputBuffers::requestNewBuffer(
927 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700928 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700929 if (newBuffer == nullptr) {
930 return false;
931 }
932 *index = mImpl.assignSlot(newBuffer);
933 *buffer = newBuffer;
934 return true;
935}
936
937bool GraphicMetadataInputBuffers::releaseBuffer(
938 const sp<MediaCodecBuffer> &buffer,
939 std::shared_ptr<C2Buffer> *c2buffer,
940 bool release) {
941 return mImpl.releaseSlot(buffer, c2buffer, release);
942}
943
944bool GraphicMetadataInputBuffers::expireComponentBuffer(
945 const std::shared_ptr<C2Buffer> &c2buffer) {
946 return mImpl.expireComponentBuffer(c2buffer);
947}
948
949void GraphicMetadataInputBuffers::flush() {
950 // This is no-op by default unless we're in array mode where we need to keep
951 // track of the flushed work.
952}
953
954std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
955 size_t size) {
956 std::shared_ptr<C2Allocator> alloc;
957 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
958 if (err != C2_OK) {
959 return nullptr;
960 }
961 std::unique_ptr<InputBuffersArray> array(
962 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
963 array->setPool(mPool);
964 array->setFormat(mFormat);
965 array->initialize(
966 mImpl,
967 size,
968 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
969 return new GraphicMetadataBuffer(format, alloc);
970 });
971 return std::move(array);
972}
973
Wonsik Kim0487b782020-10-28 11:45:50 -0700974size_t GraphicMetadataInputBuffers::numActiveSlots() const {
975 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700976}
977
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700978sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
979 std::shared_ptr<C2Allocator> alloc;
980 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
981 if (err != C2_OK) {
982 return nullptr;
983 }
984 return new GraphicMetadataBuffer(mFormat, alloc);
985}
986
Wonsik Kim469c8342019-04-11 16:46:09 -0700987// GraphicInputBuffers
988
989GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700990 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700991 : InputBuffers(componentName, name),
992 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700993 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700994
995bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700996 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700997 if (newBuffer == nullptr) {
998 return false;
999 }
1000 *index = mImpl.assignSlot(newBuffer);
1001 handleImageData(newBuffer);
1002 *buffer = newBuffer;
1003 return true;
1004}
1005
1006bool GraphicInputBuffers::releaseBuffer(
1007 const sp<MediaCodecBuffer> &buffer,
1008 std::shared_ptr<C2Buffer> *c2buffer,
1009 bool release) {
1010 return mImpl.releaseSlot(buffer, c2buffer, release);
1011}
1012
1013bool GraphicInputBuffers::expireComponentBuffer(
1014 const std::shared_ptr<C2Buffer> &c2buffer) {
1015 return mImpl.expireComponentBuffer(c2buffer);
1016}
1017
1018void GraphicInputBuffers::flush() {
1019 // This is no-op by default unless we're in array mode where we need to keep
1020 // track of the flushed work.
1021}
1022
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001023static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1024 int32_t frameworkColorFormat = 0;
1025 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1026 return PIXEL_FORMAT_UNKNOWN;
1027 }
1028 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1029 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1030 return pixelFormat;
1031 }
1032 return PIXEL_FORMAT_UNKNOWN;
1033}
1034
Wonsik Kim469c8342019-04-11 16:46:09 -07001035std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1036 std::unique_ptr<InputBuffersArray> array(
1037 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1038 array->setPool(mPool);
1039 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001040 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001041 array->initialize(
1042 mImpl,
1043 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001044 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1045 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001046 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1047 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001048 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001049 });
1050 return std::move(array);
1051}
1052
Wonsik Kim0487b782020-10-28 11:45:50 -07001053size_t GraphicInputBuffers::numActiveSlots() const {
1054 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001055}
1056
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001057sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1058 // TODO: read usage from intf
1059 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1060 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001061 mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001062}
1063
Wonsik Kim469c8342019-04-11 16:46:09 -07001064// OutputBuffersArray
1065
1066void OutputBuffersArray::initialize(
1067 const FlexBuffersImpl &impl,
1068 size_t minSize,
1069 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001070 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001071 mImpl.initialize(impl, minSize, allocate);
1072}
1073
1074status_t OutputBuffersArray::registerBuffer(
1075 const std::shared_ptr<C2Buffer> &buffer,
1076 size_t *index,
1077 sp<MediaCodecBuffer> *clientBuffer) {
1078 sp<Codec2Buffer> c2Buffer;
1079 status_t err = mImpl.grabBuffer(
1080 index,
1081 &c2Buffer,
1082 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1083 return clientBuffer->canCopy(buffer);
1084 });
1085 if (err == WOULD_BLOCK) {
1086 ALOGV("[%s] buffers temporarily not available", mName);
1087 return err;
1088 } else if (err != OK) {
1089 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1090 return err;
1091 }
1092 c2Buffer->setFormat(mFormat);
1093 if (!c2Buffer->copy(buffer)) {
1094 ALOGD("[%s] copy buffer failed", mName);
1095 return WOULD_BLOCK;
1096 }
1097 submit(c2Buffer);
1098 handleImageData(c2Buffer);
1099 *clientBuffer = c2Buffer;
1100 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1101 return OK;
1102}
1103
1104status_t OutputBuffersArray::registerCsd(
1105 const C2StreamInitDataInfo::output *csd,
1106 size_t *index,
1107 sp<MediaCodecBuffer> *clientBuffer) {
1108 sp<Codec2Buffer> c2Buffer;
1109 status_t err = mImpl.grabBuffer(
1110 index,
1111 &c2Buffer,
1112 [csd](const sp<Codec2Buffer> &clientBuffer) {
1113 return clientBuffer->base() != nullptr
1114 && clientBuffer->capacity() >= csd->flexCount();
1115 });
1116 if (err != OK) {
1117 return err;
1118 }
1119 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1120 c2Buffer->setRange(0, csd->flexCount());
1121 c2Buffer->setFormat(mFormat);
1122 *clientBuffer = c2Buffer;
1123 return OK;
1124}
1125
1126bool OutputBuffersArray::releaseBuffer(
1127 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1128 return mImpl.returnBuffer(buffer, c2buffer, true);
1129}
1130
1131void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1132 (void)flushedWork;
1133 mImpl.flush();
1134 if (mSkipCutBuffer != nullptr) {
1135 mSkipCutBuffer->clear();
1136 }
1137}
1138
1139void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1140 mImpl.getArray(array);
1141}
1142
Wonsik Kim0487b782020-10-28 11:45:50 -07001143size_t OutputBuffersArray::numActiveSlots() const {
1144 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001145}
1146
Wonsik Kim469c8342019-04-11 16:46:09 -07001147void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001148 switch (c2buffer->data().type()) {
1149 case C2BufferData::LINEAR: {
1150 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001151 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1152 const uint32_t block_size = linear_blocks.front().size();
1153 if (block_size < kMaxLinearBufferSize / 2) {
1154 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001155 } else {
1156 size = kMaxLinearBufferSize;
1157 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001158 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001159 return new LocalLinearBuffer(format, new ABuffer(size));
1160 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001161 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001162 break;
1163 }
1164
Wonsik Kima39882b2019-06-20 16:13:56 -07001165 case C2BufferData::GRAPHIC: {
1166 // This is only called for RawGraphicOutputBuffers.
1167 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001168 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001169 return ConstGraphicBlockBuffer::AllocateEmpty(
1170 format,
1171 [lbp](size_t capacity) {
1172 return lbp->newBuffer(capacity);
1173 });
1174 };
1175 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1176 mName, mFormat->debugString().c_str());
1177 break;
1178 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001179
1180 case C2BufferData::INVALID: [[fallthrough]];
1181 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1182 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1183 default:
1184 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1185 return;
1186 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001187 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001188}
1189
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001190void OutputBuffersArray::grow(size_t newSize) {
1191 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001192}
1193
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001194void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1195 mFormat = source->mFormat;
1196 mSkipCutBuffer = source->mSkipCutBuffer;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -08001197 mUnreportedFormat = source->mUnreportedFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001198 mPending = std::move(source->mPending);
1199 mReorderStash = std::move(source->mReorderStash);
1200 mDepth = source->mDepth;
1201 mKey = source->mKey;
1202}
1203
Wonsik Kim469c8342019-04-11 16:46:09 -07001204// FlexOutputBuffers
1205
1206status_t FlexOutputBuffers::registerBuffer(
1207 const std::shared_ptr<C2Buffer> &buffer,
1208 size_t *index,
1209 sp<MediaCodecBuffer> *clientBuffer) {
1210 sp<Codec2Buffer> newBuffer = wrap(buffer);
1211 if (newBuffer == nullptr) {
1212 return NO_MEMORY;
1213 }
1214 newBuffer->setFormat(mFormat);
1215 *index = mImpl.assignSlot(newBuffer);
1216 handleImageData(newBuffer);
1217 *clientBuffer = newBuffer;
1218 ALOGV("[%s] registered buffer %zu", mName, *index);
1219 return OK;
1220}
1221
1222status_t FlexOutputBuffers::registerCsd(
1223 const C2StreamInitDataInfo::output *csd,
1224 size_t *index,
1225 sp<MediaCodecBuffer> *clientBuffer) {
1226 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1227 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1228 *index = mImpl.assignSlot(newBuffer);
1229 *clientBuffer = newBuffer;
1230 return OK;
1231}
1232
1233bool FlexOutputBuffers::releaseBuffer(
1234 const sp<MediaCodecBuffer> &buffer,
1235 std::shared_ptr<C2Buffer> *c2buffer) {
1236 return mImpl.releaseSlot(buffer, c2buffer, true);
1237}
1238
1239void FlexOutputBuffers::flush(
1240 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1241 (void) flushedWork;
1242 // This is no-op by default unless we're in array mode where we need to keep
1243 // track of the flushed work.
1244}
1245
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001246std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001247 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001248 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001249 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1250 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001251 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001252}
1253
Wonsik Kim0487b782020-10-28 11:45:50 -07001254size_t FlexOutputBuffers::numActiveSlots() const {
1255 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001256}
1257
1258// LinearOutputBuffers
1259
1260void LinearOutputBuffers::flush(
1261 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1262 if (mSkipCutBuffer != nullptr) {
1263 mSkipCutBuffer->clear();
1264 }
1265 FlexOutputBuffers::flush(flushedWork);
1266}
1267
1268sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1269 if (buffer == nullptr) {
1270 ALOGV("[%s] using a dummy buffer", mName);
1271 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1272 }
1273 if (buffer->data().type() != C2BufferData::LINEAR) {
1274 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1275 // We expect linear output buffers from the component.
1276 return nullptr;
1277 }
1278 if (buffer->data().linearBlocks().size() != 1u) {
1279 ALOGV("[%s] no linear buffers", mName);
1280 // We expect one and only one linear block from the component.
1281 return nullptr;
1282 }
1283 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1284 if (clientBuffer == nullptr) {
1285 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1286 return nullptr;
1287 }
1288 submit(clientBuffer);
1289 return clientBuffer;
1290}
1291
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001292std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1293 return [format = mFormat]{
1294 // TODO: proper max output size
1295 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1296 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001297}
1298
1299// GraphicOutputBuffers
1300
1301sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1302 return new DummyContainerBuffer(mFormat, buffer);
1303}
1304
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001305std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1306 return [format = mFormat]{
1307 return new DummyContainerBuffer(format);
1308 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001309}
1310
1311// RawGraphicOutputBuffers
1312
1313RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001314 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001315 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001316 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001317
1318sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1319 if (buffer == nullptr) {
1320 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1321 mFormat,
1322 [lbp = mLocalBufferPool](size_t capacity) {
1323 return lbp->newBuffer(capacity);
1324 });
1325 if (c2buffer == nullptr) {
1326 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1327 return nullptr;
1328 }
1329 c2buffer->setRange(0, 0);
1330 return c2buffer;
1331 } else {
1332 return ConstGraphicBlockBuffer::Allocate(
1333 mFormat,
1334 buffer,
1335 [lbp = mLocalBufferPool](size_t capacity) {
1336 return lbp->newBuffer(capacity);
1337 });
1338 }
1339}
1340
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001341std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1342 return [format = mFormat, lbp = mLocalBufferPool]{
1343 return ConstGraphicBlockBuffer::AllocateEmpty(
1344 format,
1345 [lbp](size_t capacity) {
1346 return lbp->newBuffer(capacity);
1347 });
1348 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001349}
1350
1351} // namespace android