blob: 1b2d3d360c769c29c33f2c4914618bc3b5abaf9d [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"
30
31namespace android {
32
33namespace {
34
35sp<GraphicBlockBuffer> AllocateGraphicBuffer(
36 const std::shared_ptr<C2BlockPool> &pool,
37 const sp<AMessage> &format,
38 uint32_t pixelFormat,
39 const C2MemoryUsage &usage,
40 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
41 int32_t width, height;
42 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
43 ALOGD("format lacks width or height");
44 return nullptr;
45 }
46
47 std::shared_ptr<C2GraphicBlock> block;
48 c2_status_t err = pool->fetchGraphicBlock(
49 width, height, pixelFormat, usage, &block);
50 if (err != C2_OK) {
51 ALOGD("fetch graphic block failed: %d", err);
52 return nullptr;
53 }
54
55 return GraphicBlockBuffer::Allocate(
56 format,
57 block,
58 [localBufferPool](size_t capacity) {
59 return localBufferPool->newBuffer(capacity);
60 });
61}
62
63} // namespace
64
65// CCodecBuffers
66
67void CCodecBuffers::setFormat(const sp<AMessage> &format) {
68 CHECK(format != nullptr);
69 mFormat = format;
70}
71
72sp<AMessage> CCodecBuffers::dupFormat() {
73 return mFormat != nullptr ? mFormat->dup() : nullptr;
74}
75
76void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
77 sp<ABuffer> imageDataCandidate = buffer->getImageData();
78 if (imageDataCandidate == nullptr) {
79 return;
80 }
81 sp<ABuffer> imageData;
82 if (!mFormat->findBuffer("image-data", &imageData)
83 || imageDataCandidate->size() != imageData->size()
84 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
85 ALOGD("[%s] updating image-data", mName);
86 sp<AMessage> newFormat = dupFormat();
87 newFormat->setBuffer("image-data", imageDataCandidate);
88 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
89 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
90 int32_t stride = img->mPlane[0].mRowInc;
91 newFormat->setInt32(KEY_STRIDE, stride);
92 ALOGD("[%s] updating stride = %d", mName, stride);
93 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +090094 int64_t offsetDelta =
95 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
96 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim469c8342019-04-11 16:46:09 -070097 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
98 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -080099 buffer->setRange(
100 img->mPlane[0].mOffset,
101 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700102 }
103 }
104 setFormat(newFormat);
105 buffer->setFormat(newFormat);
106 }
107}
108
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700109// InputBuffers
110
111sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
112 sp<Codec2Buffer> copy = createNewBuffer();
113 if (copy == nullptr) {
114 return nullptr;
115 }
116 std::shared_ptr<C2Buffer> c2buffer;
117 if (!releaseBuffer(buffer, &c2buffer, true)) {
118 return nullptr;
119 }
120 if (!copy->canCopy(c2buffer)) {
121 return nullptr;
122 }
123 if (!copy->copy(c2buffer)) {
124 return nullptr;
125 }
126 return copy;
127}
128
Wonsik Kim469c8342019-04-11 16:46:09 -0700129// OutputBuffers
130
Wonsik Kim41d83432020-04-27 16:40:49 -0700131OutputBuffers::OutputBuffers(const char *componentName, const char *name)
132 : CCodecBuffers(componentName, name) { }
133
134OutputBuffers::~OutputBuffers() = default;
135
Wonsik Kim469c8342019-04-11 16:46:09 -0700136void OutputBuffers::initSkipCutBuffer(
137 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
138 CHECK(mSkipCutBuffer == nullptr);
139 mDelay = delay;
140 mPadding = padding;
141 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700142 mChannelCount = channelCount;
143 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700144}
145
146void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
147 if (mSkipCutBuffer == nullptr) {
148 return;
149 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700150 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
151 return;
152 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700153 int32_t delay = mDelay;
154 int32_t padding = mPadding;
155 if (sampleRate != mSampleRate) {
156 delay = ((int64_t)delay * sampleRate) / mSampleRate;
157 padding = ((int64_t)padding * sampleRate) / mSampleRate;
158 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700159 mSampleRate = sampleRate;
160 mChannelCount = channelCount;
161 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700162}
163
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800164void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700165 AString mediaType;
166 if (format->findString(KEY_MIME, &mediaType)
167 && mediaType == MIMETYPE_AUDIO_RAW) {
168 int32_t channelCount;
169 int32_t sampleRate;
170 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
171 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
172 updateSkipCutBuffer(sampleRate, channelCount);
173 }
174 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700175}
176
Wonsik Kim469c8342019-04-11 16:46:09 -0700177void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
178 if (mSkipCutBuffer != nullptr) {
179 mSkipCutBuffer->submit(buffer);
180 }
181}
182
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700183void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700184 if (mSkipCutBuffer != nullptr) {
185 size_t prevSize = mSkipCutBuffer->size();
186 if (prevSize != 0u) {
187 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
188 }
189 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700190 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700191}
192
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700193void OutputBuffers::clearStash() {
194 mPending.clear();
195 mReorderStash.clear();
196 mDepth = 0;
197 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700198}
199
200void OutputBuffers::flushStash() {
201 for (StashEntry& e : mPending) {
202 e.notify = false;
203 }
204 for (StashEntry& e : mReorderStash) {
205 e.notify = false;
206 }
207}
208
209uint32_t OutputBuffers::getReorderDepth() const {
210 return mDepth;
211}
212
213void OutputBuffers::setReorderDepth(uint32_t depth) {
214 mPending.splice(mPending.end(), mReorderStash);
215 mDepth = depth;
216}
217
218void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
219 mPending.splice(mPending.end(), mReorderStash);
220 mKey = key;
221}
222
223void OutputBuffers::pushToStash(
224 const std::shared_ptr<C2Buffer>& buffer,
225 bool notify,
226 int64_t timestamp,
227 int32_t flags,
228 const sp<AMessage>& format,
229 const C2WorkOrdinalStruct& ordinal) {
230 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
231 if (!buffer && eos) {
232 // TRICKY: we may be violating ordering of the stash here. Because we
233 // don't expect any more emplace() calls after this, the ordering should
234 // not matter.
235 mReorderStash.emplace_back(
236 buffer, notify, timestamp, flags, format, ordinal);
237 } else {
238 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
239 auto it = mReorderStash.begin();
240 for (; it != mReorderStash.end(); ++it) {
241 if (less(ordinal, it->ordinal)) {
242 break;
243 }
244 }
245 mReorderStash.emplace(it,
246 buffer, notify, timestamp, flags, format, ordinal);
247 if (eos) {
248 mReorderStash.back().flags =
249 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
250 }
251 }
252 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
253 mPending.push_back(mReorderStash.front());
254 mReorderStash.pop_front();
255 }
256 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
257}
258
259OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
260 std::shared_ptr<C2Buffer>* c2Buffer,
261 size_t* index,
262 sp<MediaCodecBuffer>* outBuffer) {
263 if (mPending.empty()) {
264 return SKIP;
265 }
266
267 // Retrieve the first entry.
268 StashEntry &entry = mPending.front();
269
270 *c2Buffer = entry.buffer;
271 sp<AMessage> outputFormat = entry.format;
272
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800273 if (entry.notify && mFormat != outputFormat) {
274 updateSkipCutBuffer(outputFormat);
275 sp<ABuffer> imageData;
276 if (mFormat->findBuffer("image-data", &imageData)) {
277 outputFormat->setBuffer("image-data", imageData);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700278 }
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800279 int32_t stride;
280 if (mFormat->findInt32(KEY_STRIDE, &stride)) {
281 outputFormat->setInt32(KEY_STRIDE, stride);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700282 }
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800283 int32_t sliceHeight;
284 if (mFormat->findInt32(KEY_SLICE_HEIGHT, &sliceHeight)) {
285 outputFormat->setInt32(KEY_SLICE_HEIGHT, sliceHeight);
286 }
287 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
288 mName, mFormat.get(), outputFormat.get());
289 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
290 mName, outputFormat->debugString().c_str());
291 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700292 }
293
294 // Flushing mReorderStash because no other buffers should come after output
295 // EOS.
296 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
297 // Flush reorder stash
298 setReorderDepth(0);
299 }
300
301 if (!entry.notify) {
302 mPending.pop_front();
303 return DISCARD;
304 }
305
306 // Try to register the buffer.
307 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
308 if (err != OK) {
309 if (err != WOULD_BLOCK) {
310 return REALLOCATE;
311 }
312 return RETRY;
313 }
314
315 // Append information from the front stash entry to outBuffer.
316 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
317 (*outBuffer)->meta()->setInt32("flags", entry.flags);
318 ALOGV("[%s] popFromStashAndRegister: "
319 "out buffer index = %zu [%p] => %p + %zu (%lld)",
320 mName, *index, outBuffer->get(),
321 (*outBuffer)->data(), (*outBuffer)->size(),
322 (long long)entry.timestamp);
323
324 // The front entry of mPending will be removed now that the registration
325 // succeeded.
326 mPending.pop_front();
327 return NOTIFY_CLIENT;
328}
329
330bool OutputBuffers::popPending(StashEntry *entry) {
331 if (mPending.empty()) {
332 return false;
333 }
334 *entry = mPending.front();
335 mPending.pop_front();
336 return true;
337}
338
339void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
340 mPending.push_front(entry);
341}
342
343bool OutputBuffers::hasPending() const {
344 return !mPending.empty();
345}
346
347bool OutputBuffers::less(
348 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
349 switch (mKey) {
350 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
351 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
352 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
353 default:
354 ALOGD("Unrecognized key; default to timestamp");
355 return o1.frameIndex < o2.frameIndex;
356 }
357}
358
Wonsik Kim469c8342019-04-11 16:46:09 -0700359// LocalBufferPool
360
Wonsik Kim41d83432020-04-27 16:40:49 -0700361constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
362constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
363
364std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
365 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700366}
367
368sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
369 Mutex::Autolock lock(mMutex);
370 auto it = std::find_if(
371 mPool.begin(), mPool.end(),
372 [capacity](const std::vector<uint8_t> &vec) {
373 return vec.capacity() >= capacity;
374 });
375 if (it != mPool.end()) {
376 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
377 mPool.erase(it);
378 return buffer;
379 }
380 if (mUsedSize + capacity > mPoolCapacity) {
381 while (!mPool.empty()) {
382 mUsedSize -= mPool.back().capacity();
383 mPool.pop_back();
384 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700385 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
386 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
387 mPoolCapacity, mPoolCapacity * 2);
388 mPoolCapacity *= 2;
389 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700390 if (mUsedSize + capacity > mPoolCapacity) {
391 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
392 mUsedSize, capacity, mPoolCapacity);
393 return nullptr;
394 }
395 }
396 std::vector<uint8_t> vec(capacity);
397 mUsedSize += vec.capacity();
398 return new VectorBuffer(std::move(vec), shared_from_this());
399}
400
401LocalBufferPool::VectorBuffer::VectorBuffer(
402 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
403 : ABuffer(vec.data(), vec.capacity()),
404 mVec(std::move(vec)),
405 mPool(pool) {
406}
407
408LocalBufferPool::VectorBuffer::~VectorBuffer() {
409 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
410 if (pool) {
411 // If pool is alive, return the vector back to the pool so that
412 // it can be recycled.
413 pool->returnVector(std::move(mVec));
414 }
415}
416
417void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
418 Mutex::Autolock lock(mMutex);
419 mPool.push_front(std::move(vec));
420}
421
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700422// FlexBuffersImpl
423
Wonsik Kim469c8342019-04-11 16:46:09 -0700424size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
425 for (size_t i = 0; i < mBuffers.size(); ++i) {
426 if (mBuffers[i].clientBuffer == nullptr
427 && mBuffers[i].compBuffer.expired()) {
428 mBuffers[i].clientBuffer = buffer;
429 return i;
430 }
431 }
432 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
433 return mBuffers.size() - 1;
434}
435
Wonsik Kim469c8342019-04-11 16:46:09 -0700436bool FlexBuffersImpl::releaseSlot(
437 const sp<MediaCodecBuffer> &buffer,
438 std::shared_ptr<C2Buffer> *c2buffer,
439 bool release) {
440 sp<Codec2Buffer> clientBuffer;
441 size_t index = mBuffers.size();
442 for (size_t i = 0; i < mBuffers.size(); ++i) {
443 if (mBuffers[i].clientBuffer == buffer) {
444 clientBuffer = mBuffers[i].clientBuffer;
445 if (release) {
446 mBuffers[i].clientBuffer.clear();
447 }
448 index = i;
449 break;
450 }
451 }
452 if (clientBuffer == nullptr) {
453 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
454 return false;
455 }
456 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
457 if (!result) {
458 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700459 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700460 mBuffers[index].compBuffer = result;
461 }
462 if (c2buffer) {
463 *c2buffer = result;
464 }
465 return true;
466}
467
468bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
469 for (size_t i = 0; i < mBuffers.size(); ++i) {
470 std::shared_ptr<C2Buffer> compBuffer =
471 mBuffers[i].compBuffer.lock();
472 if (!compBuffer || compBuffer != c2buffer) {
473 continue;
474 }
475 mBuffers[i].compBuffer.reset();
476 ALOGV("[%s] codec released buffer #%zu", mName, i);
477 return true;
478 }
479 ALOGV("[%s] codec released an unknown buffer", mName);
480 return false;
481}
482
483void FlexBuffersImpl::flush() {
484 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
485 mBuffers.clear();
486}
487
Wonsik Kim0487b782020-10-28 11:45:50 -0700488size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700489 return std::count_if(
490 mBuffers.begin(), mBuffers.end(),
491 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700492 return (entry.clientBuffer != nullptr
493 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700494 });
495}
496
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700497size_t FlexBuffersImpl::numComponentBuffers() const {
498 return std::count_if(
499 mBuffers.begin(), mBuffers.end(),
500 [](const Entry &entry) {
501 return !entry.compBuffer.expired();
502 });
503}
504
Wonsik Kim469c8342019-04-11 16:46:09 -0700505// BuffersArrayImpl
506
507void BuffersArrayImpl::initialize(
508 const FlexBuffersImpl &impl,
509 size_t minSize,
510 std::function<sp<Codec2Buffer>()> allocate) {
511 mImplName = impl.mImplName + "[N]";
512 mName = mImplName.c_str();
513 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
514 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
515 bool ownedByClient = (clientBuffer != nullptr);
516 if (!ownedByClient) {
517 clientBuffer = allocate();
518 }
519 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
520 }
521 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
522 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
523 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
524 }
525}
526
527status_t BuffersArrayImpl::grabBuffer(
528 size_t *index,
529 sp<Codec2Buffer> *buffer,
530 std::function<bool(const sp<Codec2Buffer> &)> match) {
531 // allBuffersDontMatch remains true if all buffers are available but
532 // match() returns false for every buffer.
533 bool allBuffersDontMatch = true;
534 for (size_t i = 0; i < mBuffers.size(); ++i) {
535 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
536 if (match(mBuffers[i].clientBuffer)) {
537 mBuffers[i].ownedByClient = true;
538 *buffer = mBuffers[i].clientBuffer;
539 (*buffer)->meta()->clear();
540 (*buffer)->setRange(0, (*buffer)->capacity());
541 *index = i;
542 return OK;
543 }
544 } else {
545 allBuffersDontMatch = false;
546 }
547 }
548 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
549}
550
551bool BuffersArrayImpl::returnBuffer(
552 const sp<MediaCodecBuffer> &buffer,
553 std::shared_ptr<C2Buffer> *c2buffer,
554 bool release) {
555 sp<Codec2Buffer> clientBuffer;
556 size_t index = mBuffers.size();
557 for (size_t i = 0; i < mBuffers.size(); ++i) {
558 if (mBuffers[i].clientBuffer == buffer) {
559 if (!mBuffers[i].ownedByClient) {
560 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
561 mName, i);
562 }
563 clientBuffer = mBuffers[i].clientBuffer;
564 if (release) {
565 mBuffers[i].ownedByClient = false;
566 }
567 index = i;
568 break;
569 }
570 }
571 if (clientBuffer == nullptr) {
572 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
573 return false;
574 }
575 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
576 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
577 if (!result) {
578 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700579 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700580 mBuffers[index].compBuffer = result;
581 }
582 if (c2buffer) {
583 *c2buffer = result;
584 }
585 return true;
586}
587
588bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
589 for (size_t i = 0; i < mBuffers.size(); ++i) {
590 std::shared_ptr<C2Buffer> compBuffer =
591 mBuffers[i].compBuffer.lock();
592 if (!compBuffer) {
593 continue;
594 }
595 if (c2buffer == compBuffer) {
596 if (mBuffers[i].ownedByClient) {
597 // This should not happen.
598 ALOGD("[%s] codec released a buffer owned by client "
599 "(index %zu)", mName, i);
600 }
601 mBuffers[i].compBuffer.reset();
602 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
603 return true;
604 }
605 }
606 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
607 return false;
608}
609
610void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
611 array->clear();
612 for (const Entry &entry : mBuffers) {
613 array->push(entry.clientBuffer);
614 }
615}
616
617void BuffersArrayImpl::flush() {
618 for (Entry &entry : mBuffers) {
619 entry.ownedByClient = false;
620 }
621}
622
623void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
624 size_t size = mBuffers.size();
625 mBuffers.clear();
626 for (size_t i = 0; i < size; ++i) {
627 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
628 }
629}
630
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700631void BuffersArrayImpl::grow(
632 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
633 CHECK_LT(mBuffers.size(), newSize);
634 while (mBuffers.size() < newSize) {
635 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
636 }
637}
638
Wonsik Kim0487b782020-10-28 11:45:50 -0700639size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700640 return std::count_if(
641 mBuffers.begin(), mBuffers.end(),
642 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700643 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700644 });
645}
646
Wonsik Kima39882b2019-06-20 16:13:56 -0700647size_t BuffersArrayImpl::arraySize() const {
648 return mBuffers.size();
649}
650
Wonsik Kim469c8342019-04-11 16:46:09 -0700651// InputBuffersArray
652
653void InputBuffersArray::initialize(
654 const FlexBuffersImpl &impl,
655 size_t minSize,
656 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700657 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700658 mImpl.initialize(impl, minSize, allocate);
659}
660
661void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
662 mImpl.getArray(array);
663}
664
665bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
666 sp<Codec2Buffer> c2Buffer;
667 status_t err = mImpl.grabBuffer(index, &c2Buffer);
668 if (err == OK) {
669 c2Buffer->setFormat(mFormat);
670 handleImageData(c2Buffer);
671 *buffer = c2Buffer;
672 return true;
673 }
674 return false;
675}
676
677bool InputBuffersArray::releaseBuffer(
678 const sp<MediaCodecBuffer> &buffer,
679 std::shared_ptr<C2Buffer> *c2buffer,
680 bool release) {
681 return mImpl.returnBuffer(buffer, c2buffer, release);
682}
683
684bool InputBuffersArray::expireComponentBuffer(
685 const std::shared_ptr<C2Buffer> &c2buffer) {
686 return mImpl.expireComponentBuffer(c2buffer);
687}
688
689void InputBuffersArray::flush() {
690 mImpl.flush();
691}
692
Wonsik Kim0487b782020-10-28 11:45:50 -0700693size_t InputBuffersArray::numActiveSlots() const {
694 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700695}
696
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700697sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
698 return mAllocate();
699}
700
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800701// SlotInputBuffers
702
703bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
704 sp<Codec2Buffer> newBuffer = createNewBuffer();
705 *index = mImpl.assignSlot(newBuffer);
706 *buffer = newBuffer;
707 return true;
708}
709
710bool SlotInputBuffers::releaseBuffer(
711 const sp<MediaCodecBuffer> &buffer,
712 std::shared_ptr<C2Buffer> *c2buffer,
713 bool release) {
714 return mImpl.releaseSlot(buffer, c2buffer, release);
715}
716
717bool SlotInputBuffers::expireComponentBuffer(
718 const std::shared_ptr<C2Buffer> &c2buffer) {
719 return mImpl.expireComponentBuffer(c2buffer);
720}
721
722void SlotInputBuffers::flush() {
723 mImpl.flush();
724}
725
726std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
727 TRESPASS("Array mode should not be called at non-legacy mode");
728 return nullptr;
729}
730
Wonsik Kim0487b782020-10-28 11:45:50 -0700731size_t SlotInputBuffers::numActiveSlots() const {
732 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800733}
734
735sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
736 return new DummyContainerBuffer{mFormat, nullptr};
737}
738
Wonsik Kim469c8342019-04-11 16:46:09 -0700739// LinearInputBuffers
740
741bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700742 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700743 if (newBuffer == nullptr) {
744 return false;
745 }
746 *index = mImpl.assignSlot(newBuffer);
747 *buffer = newBuffer;
748 return true;
749}
750
751bool LinearInputBuffers::releaseBuffer(
752 const sp<MediaCodecBuffer> &buffer,
753 std::shared_ptr<C2Buffer> *c2buffer,
754 bool release) {
755 return mImpl.releaseSlot(buffer, c2buffer, release);
756}
757
758bool LinearInputBuffers::expireComponentBuffer(
759 const std::shared_ptr<C2Buffer> &c2buffer) {
760 return mImpl.expireComponentBuffer(c2buffer);
761}
762
763void LinearInputBuffers::flush() {
764 // This is no-op by default unless we're in array mode where we need to keep
765 // track of the flushed work.
766 mImpl.flush();
767}
768
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700769std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700770 std::unique_ptr<InputBuffersArray> array(
771 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
772 array->setPool(mPool);
773 array->setFormat(mFormat);
774 array->initialize(
775 mImpl,
776 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700777 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
778 return Alloc(pool, format);
779 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700780 return std::move(array);
781}
782
Wonsik Kim0487b782020-10-28 11:45:50 -0700783size_t LinearInputBuffers::numActiveSlots() const {
784 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700785}
786
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700787// static
788sp<Codec2Buffer> LinearInputBuffers::Alloc(
789 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
790 int32_t capacity = kLinearBufferSize;
791 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
792 if ((size_t)capacity > kMaxLinearBufferSize) {
793 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
794 capacity = kMaxLinearBufferSize;
795 }
796
797 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700798 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
799 std::shared_ptr<C2LinearBlock> block;
800
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700801 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700802 if (err != C2_OK) {
803 return nullptr;
804 }
805
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700806 return LinearBlockBuffer::Allocate(format, block);
807}
808
809sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
810 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700811}
812
813// EncryptedLinearInputBuffers
814
815EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
816 bool secure,
817 const sp<MemoryDealer> &dealer,
818 const sp<ICrypto> &crypto,
819 int32_t heapSeqNum,
820 size_t capacity,
821 size_t numInputSlots,
822 const char *componentName, const char *name)
823 : LinearInputBuffers(componentName, name),
824 mUsage({0, 0}),
825 mDealer(dealer),
826 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700827 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700828 if (secure) {
829 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
830 } else {
831 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
832 }
833 for (size_t i = 0; i < numInputSlots; ++i) {
834 sp<IMemory> memory = mDealer->allocate(capacity);
835 if (memory == nullptr) {
836 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
837 mName, i);
838 break;
839 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700840 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700841 }
842}
843
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700844std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
845 std::unique_ptr<InputBuffersArray> array(
846 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
847 array->setPool(mPool);
848 array->setFormat(mFormat);
849 array->initialize(
850 mImpl,
851 size,
852 [pool = mPool,
853 format = mFormat,
854 usage = mUsage,
855 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
856 return Alloc(pool, format, usage, memoryVector);
857 });
858 return std::move(array);
859}
860
861
862// static
863sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
864 const std::shared_ptr<C2BlockPool> &pool,
865 const sp<AMessage> &format,
866 C2MemoryUsage usage,
867 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
868 int32_t capacity = kLinearBufferSize;
869 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
870 if ((size_t)capacity > kMaxLinearBufferSize) {
871 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
872 capacity = kMaxLinearBufferSize;
873 }
874
Wonsik Kim469c8342019-04-11 16:46:09 -0700875 sp<IMemory> memory;
876 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700877 int32_t heapSeqNum = -1;
878 for (; slot < memoryVector->size(); ++slot) {
879 if (memoryVector->at(slot).block.expired()) {
880 memory = memoryVector->at(slot).memory;
881 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700882 break;
883 }
884 }
885 if (memory == nullptr) {
886 return nullptr;
887 }
888
889 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700890 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700891 if (err != C2_OK || block == nullptr) {
892 return nullptr;
893 }
894
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700895 memoryVector->at(slot).block = block;
896 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
897}
898
899sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
900 // TODO: android_2020
901 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700902}
903
904// GraphicMetadataInputBuffers
905
906GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
907 const char *componentName, const char *name)
908 : InputBuffers(componentName, name),
909 mImpl(mName),
910 mStore(GetCodec2PlatformAllocatorStore()) { }
911
912bool GraphicMetadataInputBuffers::requestNewBuffer(
913 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700914 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700915 if (newBuffer == nullptr) {
916 return false;
917 }
918 *index = mImpl.assignSlot(newBuffer);
919 *buffer = newBuffer;
920 return true;
921}
922
923bool GraphicMetadataInputBuffers::releaseBuffer(
924 const sp<MediaCodecBuffer> &buffer,
925 std::shared_ptr<C2Buffer> *c2buffer,
926 bool release) {
927 return mImpl.releaseSlot(buffer, c2buffer, release);
928}
929
930bool GraphicMetadataInputBuffers::expireComponentBuffer(
931 const std::shared_ptr<C2Buffer> &c2buffer) {
932 return mImpl.expireComponentBuffer(c2buffer);
933}
934
935void GraphicMetadataInputBuffers::flush() {
936 // This is no-op by default unless we're in array mode where we need to keep
937 // track of the flushed work.
938}
939
940std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
941 size_t size) {
942 std::shared_ptr<C2Allocator> alloc;
943 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
944 if (err != C2_OK) {
945 return nullptr;
946 }
947 std::unique_ptr<InputBuffersArray> array(
948 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
949 array->setPool(mPool);
950 array->setFormat(mFormat);
951 array->initialize(
952 mImpl,
953 size,
954 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
955 return new GraphicMetadataBuffer(format, alloc);
956 });
957 return std::move(array);
958}
959
Wonsik Kim0487b782020-10-28 11:45:50 -0700960size_t GraphicMetadataInputBuffers::numActiveSlots() const {
961 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700962}
963
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700964sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
965 std::shared_ptr<C2Allocator> alloc;
966 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
967 if (err != C2_OK) {
968 return nullptr;
969 }
970 return new GraphicMetadataBuffer(mFormat, alloc);
971}
972
Wonsik Kim469c8342019-04-11 16:46:09 -0700973// GraphicInputBuffers
974
975GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700976 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700977 : InputBuffers(componentName, name),
978 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700979 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700980
981bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700982 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700983 if (newBuffer == nullptr) {
984 return false;
985 }
986 *index = mImpl.assignSlot(newBuffer);
987 handleImageData(newBuffer);
988 *buffer = newBuffer;
989 return true;
990}
991
992bool GraphicInputBuffers::releaseBuffer(
993 const sp<MediaCodecBuffer> &buffer,
994 std::shared_ptr<C2Buffer> *c2buffer,
995 bool release) {
996 return mImpl.releaseSlot(buffer, c2buffer, release);
997}
998
999bool GraphicInputBuffers::expireComponentBuffer(
1000 const std::shared_ptr<C2Buffer> &c2buffer) {
1001 return mImpl.expireComponentBuffer(c2buffer);
1002}
1003
1004void GraphicInputBuffers::flush() {
1005 // This is no-op by default unless we're in array mode where we need to keep
1006 // track of the flushed work.
1007}
1008
1009std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1010 std::unique_ptr<InputBuffersArray> array(
1011 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1012 array->setPool(mPool);
1013 array->setFormat(mFormat);
1014 array->initialize(
1015 mImpl,
1016 size,
1017 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1018 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1019 return AllocateGraphicBuffer(
1020 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1021 });
1022 return std::move(array);
1023}
1024
Wonsik Kim0487b782020-10-28 11:45:50 -07001025size_t GraphicInputBuffers::numActiveSlots() const {
1026 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001027}
1028
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001029sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1030 // TODO: read usage from intf
1031 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1032 return AllocateGraphicBuffer(
1033 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1034}
1035
Wonsik Kim469c8342019-04-11 16:46:09 -07001036// OutputBuffersArray
1037
1038void OutputBuffersArray::initialize(
1039 const FlexBuffersImpl &impl,
1040 size_t minSize,
1041 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001042 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001043 mImpl.initialize(impl, minSize, allocate);
1044}
1045
1046status_t OutputBuffersArray::registerBuffer(
1047 const std::shared_ptr<C2Buffer> &buffer,
1048 size_t *index,
1049 sp<MediaCodecBuffer> *clientBuffer) {
1050 sp<Codec2Buffer> c2Buffer;
1051 status_t err = mImpl.grabBuffer(
1052 index,
1053 &c2Buffer,
1054 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1055 return clientBuffer->canCopy(buffer);
1056 });
1057 if (err == WOULD_BLOCK) {
1058 ALOGV("[%s] buffers temporarily not available", mName);
1059 return err;
1060 } else if (err != OK) {
1061 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1062 return err;
1063 }
1064 c2Buffer->setFormat(mFormat);
1065 if (!c2Buffer->copy(buffer)) {
1066 ALOGD("[%s] copy buffer failed", mName);
1067 return WOULD_BLOCK;
1068 }
1069 submit(c2Buffer);
1070 handleImageData(c2Buffer);
1071 *clientBuffer = c2Buffer;
1072 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1073 return OK;
1074}
1075
1076status_t OutputBuffersArray::registerCsd(
1077 const C2StreamInitDataInfo::output *csd,
1078 size_t *index,
1079 sp<MediaCodecBuffer> *clientBuffer) {
1080 sp<Codec2Buffer> c2Buffer;
1081 status_t err = mImpl.grabBuffer(
1082 index,
1083 &c2Buffer,
1084 [csd](const sp<Codec2Buffer> &clientBuffer) {
1085 return clientBuffer->base() != nullptr
1086 && clientBuffer->capacity() >= csd->flexCount();
1087 });
1088 if (err != OK) {
1089 return err;
1090 }
1091 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1092 c2Buffer->setRange(0, csd->flexCount());
1093 c2Buffer->setFormat(mFormat);
1094 *clientBuffer = c2Buffer;
1095 return OK;
1096}
1097
1098bool OutputBuffersArray::releaseBuffer(
1099 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1100 return mImpl.returnBuffer(buffer, c2buffer, true);
1101}
1102
1103void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1104 (void)flushedWork;
1105 mImpl.flush();
1106 if (mSkipCutBuffer != nullptr) {
1107 mSkipCutBuffer->clear();
1108 }
1109}
1110
1111void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1112 mImpl.getArray(array);
1113}
1114
Wonsik Kim0487b782020-10-28 11:45:50 -07001115size_t OutputBuffersArray::numActiveSlots() const {
1116 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001117}
1118
Wonsik Kim469c8342019-04-11 16:46:09 -07001119void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001120 switch (c2buffer->data().type()) {
1121 case C2BufferData::LINEAR: {
1122 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001123 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1124 const uint32_t block_size = linear_blocks.front().size();
1125 if (block_size < kMaxLinearBufferSize / 2) {
1126 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001127 } else {
1128 size = kMaxLinearBufferSize;
1129 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001130 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001131 return new LocalLinearBuffer(format, new ABuffer(size));
1132 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001133 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001134 break;
1135 }
1136
Wonsik Kima39882b2019-06-20 16:13:56 -07001137 case C2BufferData::GRAPHIC: {
1138 // This is only called for RawGraphicOutputBuffers.
1139 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001140 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001141 return ConstGraphicBlockBuffer::AllocateEmpty(
1142 format,
1143 [lbp](size_t capacity) {
1144 return lbp->newBuffer(capacity);
1145 });
1146 };
1147 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1148 mName, mFormat->debugString().c_str());
1149 break;
1150 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001151
1152 case C2BufferData::INVALID: [[fallthrough]];
1153 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1154 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1155 default:
1156 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1157 return;
1158 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001159 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001160}
1161
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001162void OutputBuffersArray::grow(size_t newSize) {
1163 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001164}
1165
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001166void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1167 mFormat = source->mFormat;
1168 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001169 mPending = std::move(source->mPending);
1170 mReorderStash = std::move(source->mReorderStash);
1171 mDepth = source->mDepth;
1172 mKey = source->mKey;
1173}
1174
Wonsik Kim469c8342019-04-11 16:46:09 -07001175// FlexOutputBuffers
1176
1177status_t FlexOutputBuffers::registerBuffer(
1178 const std::shared_ptr<C2Buffer> &buffer,
1179 size_t *index,
1180 sp<MediaCodecBuffer> *clientBuffer) {
1181 sp<Codec2Buffer> newBuffer = wrap(buffer);
1182 if (newBuffer == nullptr) {
1183 return NO_MEMORY;
1184 }
1185 newBuffer->setFormat(mFormat);
1186 *index = mImpl.assignSlot(newBuffer);
1187 handleImageData(newBuffer);
1188 *clientBuffer = newBuffer;
1189 ALOGV("[%s] registered buffer %zu", mName, *index);
1190 return OK;
1191}
1192
1193status_t FlexOutputBuffers::registerCsd(
1194 const C2StreamInitDataInfo::output *csd,
1195 size_t *index,
1196 sp<MediaCodecBuffer> *clientBuffer) {
1197 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1198 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1199 *index = mImpl.assignSlot(newBuffer);
1200 *clientBuffer = newBuffer;
1201 return OK;
1202}
1203
1204bool FlexOutputBuffers::releaseBuffer(
1205 const sp<MediaCodecBuffer> &buffer,
1206 std::shared_ptr<C2Buffer> *c2buffer) {
1207 return mImpl.releaseSlot(buffer, c2buffer, true);
1208}
1209
1210void FlexOutputBuffers::flush(
1211 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1212 (void) flushedWork;
1213 // This is no-op by default unless we're in array mode where we need to keep
1214 // track of the flushed work.
1215}
1216
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001217std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001218 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001219 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001220 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1221 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001222 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001223}
1224
Wonsik Kim0487b782020-10-28 11:45:50 -07001225size_t FlexOutputBuffers::numActiveSlots() const {
1226 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001227}
1228
1229// LinearOutputBuffers
1230
1231void LinearOutputBuffers::flush(
1232 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1233 if (mSkipCutBuffer != nullptr) {
1234 mSkipCutBuffer->clear();
1235 }
1236 FlexOutputBuffers::flush(flushedWork);
1237}
1238
1239sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1240 if (buffer == nullptr) {
1241 ALOGV("[%s] using a dummy buffer", mName);
1242 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1243 }
1244 if (buffer->data().type() != C2BufferData::LINEAR) {
1245 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1246 // We expect linear output buffers from the component.
1247 return nullptr;
1248 }
1249 if (buffer->data().linearBlocks().size() != 1u) {
1250 ALOGV("[%s] no linear buffers", mName);
1251 // We expect one and only one linear block from the component.
1252 return nullptr;
1253 }
1254 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1255 if (clientBuffer == nullptr) {
1256 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1257 return nullptr;
1258 }
1259 submit(clientBuffer);
1260 return clientBuffer;
1261}
1262
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001263std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1264 return [format = mFormat]{
1265 // TODO: proper max output size
1266 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1267 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001268}
1269
1270// GraphicOutputBuffers
1271
1272sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1273 return new DummyContainerBuffer(mFormat, buffer);
1274}
1275
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001276std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1277 return [format = mFormat]{
1278 return new DummyContainerBuffer(format);
1279 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001280}
1281
1282// RawGraphicOutputBuffers
1283
1284RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001285 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001286 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001287 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001288
1289sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1290 if (buffer == nullptr) {
1291 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1292 mFormat,
1293 [lbp = mLocalBufferPool](size_t capacity) {
1294 return lbp->newBuffer(capacity);
1295 });
1296 if (c2buffer == nullptr) {
1297 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1298 return nullptr;
1299 }
1300 c2buffer->setRange(0, 0);
1301 return c2buffer;
1302 } else {
1303 return ConstGraphicBlockBuffer::Allocate(
1304 mFormat,
1305 buffer,
1306 [lbp = mLocalBufferPool](size_t capacity) {
1307 return lbp->newBuffer(capacity);
1308 });
1309 }
1310}
1311
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001312std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1313 return [format = mFormat, lbp = mLocalBufferPool]{
1314 return ConstGraphicBlockBuffer::AllocateEmpty(
1315 format,
1316 [lbp](size_t capacity) {
1317 return lbp->newBuffer(capacity);
1318 });
1319 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001320}
1321
1322} // namespace android