blob: 692da584ce3b778ec3265e19c091bee00fda0fa1 [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);
99 }
100 }
101 setFormat(newFormat);
102 buffer->setFormat(newFormat);
103 }
104}
105
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700106// InputBuffers
107
108sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
109 sp<Codec2Buffer> copy = createNewBuffer();
110 if (copy == nullptr) {
111 return nullptr;
112 }
113 std::shared_ptr<C2Buffer> c2buffer;
114 if (!releaseBuffer(buffer, &c2buffer, true)) {
115 return nullptr;
116 }
117 if (!copy->canCopy(c2buffer)) {
118 return nullptr;
119 }
120 if (!copy->copy(c2buffer)) {
121 return nullptr;
122 }
123 return copy;
124}
125
Wonsik Kim469c8342019-04-11 16:46:09 -0700126// OutputBuffers
127
Wonsik Kim41d83432020-04-27 16:40:49 -0700128OutputBuffers::OutputBuffers(const char *componentName, const char *name)
129 : CCodecBuffers(componentName, name) { }
130
131OutputBuffers::~OutputBuffers() = default;
132
Wonsik Kim469c8342019-04-11 16:46:09 -0700133void OutputBuffers::initSkipCutBuffer(
134 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
135 CHECK(mSkipCutBuffer == nullptr);
136 mDelay = delay;
137 mPadding = padding;
138 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700139 mChannelCount = channelCount;
140 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700141}
142
143void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
144 if (mSkipCutBuffer == nullptr) {
145 return;
146 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700147 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
148 return;
149 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700150 int32_t delay = mDelay;
151 int32_t padding = mPadding;
152 if (sampleRate != mSampleRate) {
153 delay = ((int64_t)delay * sampleRate) / mSampleRate;
154 padding = ((int64_t)padding * sampleRate) / mSampleRate;
155 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700156 mSampleRate = sampleRate;
157 mChannelCount = channelCount;
158 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700159}
160
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800161void OutputBuffers::updateSkipCutBuffer(
162 const sp<AMessage> &format, bool notify) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700163 AString mediaType;
164 if (format->findString(KEY_MIME, &mediaType)
165 && mediaType == MIMETYPE_AUDIO_RAW) {
166 int32_t channelCount;
167 int32_t sampleRate;
168 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
169 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
170 updateSkipCutBuffer(sampleRate, channelCount);
171 }
172 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800173 if (notify) {
174 mUnreportedFormat = nullptr;
175 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700176}
177
Wonsik Kim469c8342019-04-11 16:46:09 -0700178void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
179 if (mSkipCutBuffer != nullptr) {
180 mSkipCutBuffer->submit(buffer);
181 }
182}
183
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700184void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700185 if (mSkipCutBuffer != nullptr) {
186 size_t prevSize = mSkipCutBuffer->size();
187 if (prevSize != 0u) {
188 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
189 }
190 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700191 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700192}
193
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700194void OutputBuffers::clearStash() {
195 mPending.clear();
196 mReorderStash.clear();
197 mDepth = 0;
198 mKey = C2Config::ORDINAL;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800199 mUnreportedFormat = nullptr;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700200}
201
202void OutputBuffers::flushStash() {
203 for (StashEntry& e : mPending) {
204 e.notify = false;
205 }
206 for (StashEntry& e : mReorderStash) {
207 e.notify = false;
208 }
209}
210
211uint32_t OutputBuffers::getReorderDepth() const {
212 return mDepth;
213}
214
215void OutputBuffers::setReorderDepth(uint32_t depth) {
216 mPending.splice(mPending.end(), mReorderStash);
217 mDepth = depth;
218}
219
220void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
221 mPending.splice(mPending.end(), mReorderStash);
222 mKey = key;
223}
224
225void OutputBuffers::pushToStash(
226 const std::shared_ptr<C2Buffer>& buffer,
227 bool notify,
228 int64_t timestamp,
229 int32_t flags,
230 const sp<AMessage>& format,
231 const C2WorkOrdinalStruct& ordinal) {
232 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
233 if (!buffer && eos) {
234 // TRICKY: we may be violating ordering of the stash here. Because we
235 // don't expect any more emplace() calls after this, the ordering should
236 // not matter.
237 mReorderStash.emplace_back(
238 buffer, notify, timestamp, flags, format, ordinal);
239 } else {
240 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
241 auto it = mReorderStash.begin();
242 for (; it != mReorderStash.end(); ++it) {
243 if (less(ordinal, it->ordinal)) {
244 break;
245 }
246 }
247 mReorderStash.emplace(it,
248 buffer, notify, timestamp, flags, format, ordinal);
249 if (eos) {
250 mReorderStash.back().flags =
251 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
252 }
253 }
254 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
255 mPending.push_back(mReorderStash.front());
256 mReorderStash.pop_front();
257 }
258 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
259}
260
261OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
262 std::shared_ptr<C2Buffer>* c2Buffer,
263 size_t* index,
264 sp<MediaCodecBuffer>* outBuffer) {
265 if (mPending.empty()) {
266 return SKIP;
267 }
268
269 // Retrieve the first entry.
270 StashEntry &entry = mPending.front();
271
272 *c2Buffer = entry.buffer;
273 sp<AMessage> outputFormat = entry.format;
274
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800275 // The output format can be processed without a registered slot.
276 if (outputFormat) {
277 updateSkipCutBuffer(outputFormat, entry.notify);
278 }
279
280 if (entry.notify) {
281 if (outputFormat) {
282 setFormat(outputFormat);
283 } else if (mUnreportedFormat) {
284 outputFormat = mUnreportedFormat;
285 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700286 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800287 mUnreportedFormat = nullptr;
288 } else {
289 if (outputFormat) {
290 mUnreportedFormat = outputFormat;
291 } else if (!mUnreportedFormat) {
292 mUnreportedFormat = mFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700293 }
294 }
295
296 // Flushing mReorderStash because no other buffers should come after output
297 // EOS.
298 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
299 // Flush reorder stash
300 setReorderDepth(0);
301 }
302
303 if (!entry.notify) {
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800304 if (outputFormat) {
305 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
306 mName, outputFormat->debugString().c_str());
307 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700308 mPending.pop_front();
309 return DISCARD;
310 }
311
312 // Try to register the buffer.
313 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
314 if (err != OK) {
315 if (err != WOULD_BLOCK) {
316 return REALLOCATE;
317 }
318 return RETRY;
319 }
320
321 // Append information from the front stash entry to outBuffer.
322 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
323 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800324 if (outputFormat) {
325 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
326 mName, outputFormat->debugString().c_str());
327 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700328 ALOGV("[%s] popFromStashAndRegister: "
329 "out buffer index = %zu [%p] => %p + %zu (%lld)",
330 mName, *index, outBuffer->get(),
331 (*outBuffer)->data(), (*outBuffer)->size(),
332 (long long)entry.timestamp);
333
334 // The front entry of mPending will be removed now that the registration
335 // succeeded.
336 mPending.pop_front();
337 return NOTIFY_CLIENT;
338}
339
340bool OutputBuffers::popPending(StashEntry *entry) {
341 if (mPending.empty()) {
342 return false;
343 }
344 *entry = mPending.front();
345 mPending.pop_front();
346 return true;
347}
348
349void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
350 mPending.push_front(entry);
351}
352
353bool OutputBuffers::hasPending() const {
354 return !mPending.empty();
355}
356
357bool OutputBuffers::less(
358 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
359 switch (mKey) {
360 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
361 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
362 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
363 default:
364 ALOGD("Unrecognized key; default to timestamp");
365 return o1.frameIndex < o2.frameIndex;
366 }
367}
368
Wonsik Kim469c8342019-04-11 16:46:09 -0700369// LocalBufferPool
370
Wonsik Kim41d83432020-04-27 16:40:49 -0700371constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
372constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
373
374std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
375 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700376}
377
378sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
379 Mutex::Autolock lock(mMutex);
380 auto it = std::find_if(
381 mPool.begin(), mPool.end(),
382 [capacity](const std::vector<uint8_t> &vec) {
383 return vec.capacity() >= capacity;
384 });
385 if (it != mPool.end()) {
386 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
387 mPool.erase(it);
388 return buffer;
389 }
390 if (mUsedSize + capacity > mPoolCapacity) {
391 while (!mPool.empty()) {
392 mUsedSize -= mPool.back().capacity();
393 mPool.pop_back();
394 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700395 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
396 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
397 mPoolCapacity, mPoolCapacity * 2);
398 mPoolCapacity *= 2;
399 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700400 if (mUsedSize + capacity > mPoolCapacity) {
401 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
402 mUsedSize, capacity, mPoolCapacity);
403 return nullptr;
404 }
405 }
406 std::vector<uint8_t> vec(capacity);
407 mUsedSize += vec.capacity();
408 return new VectorBuffer(std::move(vec), shared_from_this());
409}
410
411LocalBufferPool::VectorBuffer::VectorBuffer(
412 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
413 : ABuffer(vec.data(), vec.capacity()),
414 mVec(std::move(vec)),
415 mPool(pool) {
416}
417
418LocalBufferPool::VectorBuffer::~VectorBuffer() {
419 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
420 if (pool) {
421 // If pool is alive, return the vector back to the pool so that
422 // it can be recycled.
423 pool->returnVector(std::move(mVec));
424 }
425}
426
427void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
428 Mutex::Autolock lock(mMutex);
429 mPool.push_front(std::move(vec));
430}
431
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700432// FlexBuffersImpl
433
Wonsik Kim469c8342019-04-11 16:46:09 -0700434size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
435 for (size_t i = 0; i < mBuffers.size(); ++i) {
436 if (mBuffers[i].clientBuffer == nullptr
437 && mBuffers[i].compBuffer.expired()) {
438 mBuffers[i].clientBuffer = buffer;
439 return i;
440 }
441 }
442 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
443 return mBuffers.size() - 1;
444}
445
Wonsik Kim469c8342019-04-11 16:46:09 -0700446bool FlexBuffersImpl::releaseSlot(
447 const sp<MediaCodecBuffer> &buffer,
448 std::shared_ptr<C2Buffer> *c2buffer,
449 bool release) {
450 sp<Codec2Buffer> clientBuffer;
451 size_t index = mBuffers.size();
452 for (size_t i = 0; i < mBuffers.size(); ++i) {
453 if (mBuffers[i].clientBuffer == buffer) {
454 clientBuffer = mBuffers[i].clientBuffer;
455 if (release) {
456 mBuffers[i].clientBuffer.clear();
457 }
458 index = i;
459 break;
460 }
461 }
462 if (clientBuffer == nullptr) {
463 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
464 return false;
465 }
466 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
467 if (!result) {
468 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700469 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700470 mBuffers[index].compBuffer = result;
471 }
472 if (c2buffer) {
473 *c2buffer = result;
474 }
475 return true;
476}
477
478bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
479 for (size_t i = 0; i < mBuffers.size(); ++i) {
480 std::shared_ptr<C2Buffer> compBuffer =
481 mBuffers[i].compBuffer.lock();
482 if (!compBuffer || compBuffer != c2buffer) {
483 continue;
484 }
485 mBuffers[i].compBuffer.reset();
486 ALOGV("[%s] codec released buffer #%zu", mName, i);
487 return true;
488 }
489 ALOGV("[%s] codec released an unknown buffer", mName);
490 return false;
491}
492
493void FlexBuffersImpl::flush() {
494 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
495 mBuffers.clear();
496}
497
Wonsik Kim0487b782020-10-28 11:45:50 -0700498size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700499 return std::count_if(
500 mBuffers.begin(), mBuffers.end(),
501 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700502 return (entry.clientBuffer != nullptr
503 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700504 });
505}
506
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700507size_t FlexBuffersImpl::numComponentBuffers() const {
508 return std::count_if(
509 mBuffers.begin(), mBuffers.end(),
510 [](const Entry &entry) {
511 return !entry.compBuffer.expired();
512 });
513}
514
Wonsik Kim469c8342019-04-11 16:46:09 -0700515// BuffersArrayImpl
516
517void BuffersArrayImpl::initialize(
518 const FlexBuffersImpl &impl,
519 size_t minSize,
520 std::function<sp<Codec2Buffer>()> allocate) {
521 mImplName = impl.mImplName + "[N]";
522 mName = mImplName.c_str();
523 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
524 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
525 bool ownedByClient = (clientBuffer != nullptr);
526 if (!ownedByClient) {
527 clientBuffer = allocate();
528 }
529 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
530 }
531 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
532 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
533 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
534 }
535}
536
537status_t BuffersArrayImpl::grabBuffer(
538 size_t *index,
539 sp<Codec2Buffer> *buffer,
540 std::function<bool(const sp<Codec2Buffer> &)> match) {
541 // allBuffersDontMatch remains true if all buffers are available but
542 // match() returns false for every buffer.
543 bool allBuffersDontMatch = true;
544 for (size_t i = 0; i < mBuffers.size(); ++i) {
545 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
546 if (match(mBuffers[i].clientBuffer)) {
547 mBuffers[i].ownedByClient = true;
548 *buffer = mBuffers[i].clientBuffer;
549 (*buffer)->meta()->clear();
550 (*buffer)->setRange(0, (*buffer)->capacity());
551 *index = i;
552 return OK;
553 }
554 } else {
555 allBuffersDontMatch = false;
556 }
557 }
558 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
559}
560
561bool BuffersArrayImpl::returnBuffer(
562 const sp<MediaCodecBuffer> &buffer,
563 std::shared_ptr<C2Buffer> *c2buffer,
564 bool release) {
565 sp<Codec2Buffer> clientBuffer;
566 size_t index = mBuffers.size();
567 for (size_t i = 0; i < mBuffers.size(); ++i) {
568 if (mBuffers[i].clientBuffer == buffer) {
569 if (!mBuffers[i].ownedByClient) {
570 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
571 mName, i);
572 }
573 clientBuffer = mBuffers[i].clientBuffer;
574 if (release) {
575 mBuffers[i].ownedByClient = false;
576 }
577 index = i;
578 break;
579 }
580 }
581 if (clientBuffer == nullptr) {
582 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
583 return false;
584 }
585 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
586 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
587 if (!result) {
588 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700589 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700590 mBuffers[index].compBuffer = result;
591 }
592 if (c2buffer) {
593 *c2buffer = result;
594 }
595 return true;
596}
597
598bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
599 for (size_t i = 0; i < mBuffers.size(); ++i) {
600 std::shared_ptr<C2Buffer> compBuffer =
601 mBuffers[i].compBuffer.lock();
602 if (!compBuffer) {
603 continue;
604 }
605 if (c2buffer == compBuffer) {
606 if (mBuffers[i].ownedByClient) {
607 // This should not happen.
608 ALOGD("[%s] codec released a buffer owned by client "
609 "(index %zu)", mName, i);
610 }
611 mBuffers[i].compBuffer.reset();
612 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
613 return true;
614 }
615 }
616 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
617 return false;
618}
619
620void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
621 array->clear();
622 for (const Entry &entry : mBuffers) {
623 array->push(entry.clientBuffer);
624 }
625}
626
627void BuffersArrayImpl::flush() {
628 for (Entry &entry : mBuffers) {
629 entry.ownedByClient = false;
630 }
631}
632
633void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
634 size_t size = mBuffers.size();
635 mBuffers.clear();
636 for (size_t i = 0; i < size; ++i) {
637 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
638 }
639}
640
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700641void BuffersArrayImpl::grow(
642 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
643 CHECK_LT(mBuffers.size(), newSize);
644 while (mBuffers.size() < newSize) {
645 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
646 }
647}
648
Wonsik Kim0487b782020-10-28 11:45:50 -0700649size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700650 return std::count_if(
651 mBuffers.begin(), mBuffers.end(),
652 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700653 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700654 });
655}
656
Wonsik Kima39882b2019-06-20 16:13:56 -0700657size_t BuffersArrayImpl::arraySize() const {
658 return mBuffers.size();
659}
660
Wonsik Kim469c8342019-04-11 16:46:09 -0700661// InputBuffersArray
662
663void InputBuffersArray::initialize(
664 const FlexBuffersImpl &impl,
665 size_t minSize,
666 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700667 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700668 mImpl.initialize(impl, minSize, allocate);
669}
670
671void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
672 mImpl.getArray(array);
673}
674
675bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
676 sp<Codec2Buffer> c2Buffer;
677 status_t err = mImpl.grabBuffer(index, &c2Buffer);
678 if (err == OK) {
679 c2Buffer->setFormat(mFormat);
680 handleImageData(c2Buffer);
681 *buffer = c2Buffer;
682 return true;
683 }
684 return false;
685}
686
687bool InputBuffersArray::releaseBuffer(
688 const sp<MediaCodecBuffer> &buffer,
689 std::shared_ptr<C2Buffer> *c2buffer,
690 bool release) {
691 return mImpl.returnBuffer(buffer, c2buffer, release);
692}
693
694bool InputBuffersArray::expireComponentBuffer(
695 const std::shared_ptr<C2Buffer> &c2buffer) {
696 return mImpl.expireComponentBuffer(c2buffer);
697}
698
699void InputBuffersArray::flush() {
700 mImpl.flush();
701}
702
Wonsik Kim0487b782020-10-28 11:45:50 -0700703size_t InputBuffersArray::numActiveSlots() const {
704 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700705}
706
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700707sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
708 return mAllocate();
709}
710
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800711// SlotInputBuffers
712
713bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
714 sp<Codec2Buffer> newBuffer = createNewBuffer();
715 *index = mImpl.assignSlot(newBuffer);
716 *buffer = newBuffer;
717 return true;
718}
719
720bool SlotInputBuffers::releaseBuffer(
721 const sp<MediaCodecBuffer> &buffer,
722 std::shared_ptr<C2Buffer> *c2buffer,
723 bool release) {
724 return mImpl.releaseSlot(buffer, c2buffer, release);
725}
726
727bool SlotInputBuffers::expireComponentBuffer(
728 const std::shared_ptr<C2Buffer> &c2buffer) {
729 return mImpl.expireComponentBuffer(c2buffer);
730}
731
732void SlotInputBuffers::flush() {
733 mImpl.flush();
734}
735
736std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
737 TRESPASS("Array mode should not be called at non-legacy mode");
738 return nullptr;
739}
740
Wonsik Kim0487b782020-10-28 11:45:50 -0700741size_t SlotInputBuffers::numActiveSlots() const {
742 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800743}
744
745sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
746 return new DummyContainerBuffer{mFormat, nullptr};
747}
748
Wonsik Kim469c8342019-04-11 16:46:09 -0700749// LinearInputBuffers
750
751bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700752 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700753 if (newBuffer == nullptr) {
754 return false;
755 }
756 *index = mImpl.assignSlot(newBuffer);
757 *buffer = newBuffer;
758 return true;
759}
760
761bool LinearInputBuffers::releaseBuffer(
762 const sp<MediaCodecBuffer> &buffer,
763 std::shared_ptr<C2Buffer> *c2buffer,
764 bool release) {
765 return mImpl.releaseSlot(buffer, c2buffer, release);
766}
767
768bool LinearInputBuffers::expireComponentBuffer(
769 const std::shared_ptr<C2Buffer> &c2buffer) {
770 return mImpl.expireComponentBuffer(c2buffer);
771}
772
773void LinearInputBuffers::flush() {
774 // This is no-op by default unless we're in array mode where we need to keep
775 // track of the flushed work.
776 mImpl.flush();
777}
778
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700779std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700780 std::unique_ptr<InputBuffersArray> array(
781 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
782 array->setPool(mPool);
783 array->setFormat(mFormat);
784 array->initialize(
785 mImpl,
786 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700787 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
788 return Alloc(pool, format);
789 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700790 return std::move(array);
791}
792
Wonsik Kim0487b782020-10-28 11:45:50 -0700793size_t LinearInputBuffers::numActiveSlots() const {
794 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700795}
796
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700797// static
798sp<Codec2Buffer> LinearInputBuffers::Alloc(
799 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
800 int32_t capacity = kLinearBufferSize;
801 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
802 if ((size_t)capacity > kMaxLinearBufferSize) {
803 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
804 capacity = kMaxLinearBufferSize;
805 }
806
807 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700808 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
809 std::shared_ptr<C2LinearBlock> block;
810
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700811 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700812 if (err != C2_OK) {
813 return nullptr;
814 }
815
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700816 return LinearBlockBuffer::Allocate(format, block);
817}
818
819sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
820 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700821}
822
823// EncryptedLinearInputBuffers
824
825EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
826 bool secure,
827 const sp<MemoryDealer> &dealer,
828 const sp<ICrypto> &crypto,
829 int32_t heapSeqNum,
830 size_t capacity,
831 size_t numInputSlots,
832 const char *componentName, const char *name)
833 : LinearInputBuffers(componentName, name),
834 mUsage({0, 0}),
835 mDealer(dealer),
836 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700837 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700838 if (secure) {
839 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
840 } else {
841 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
842 }
843 for (size_t i = 0; i < numInputSlots; ++i) {
844 sp<IMemory> memory = mDealer->allocate(capacity);
845 if (memory == nullptr) {
846 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
847 mName, i);
848 break;
849 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700850 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700851 }
852}
853
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700854std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
855 std::unique_ptr<InputBuffersArray> array(
856 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
857 array->setPool(mPool);
858 array->setFormat(mFormat);
859 array->initialize(
860 mImpl,
861 size,
862 [pool = mPool,
863 format = mFormat,
864 usage = mUsage,
865 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
866 return Alloc(pool, format, usage, memoryVector);
867 });
868 return std::move(array);
869}
870
871
872// static
873sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
874 const std::shared_ptr<C2BlockPool> &pool,
875 const sp<AMessage> &format,
876 C2MemoryUsage usage,
877 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
878 int32_t capacity = kLinearBufferSize;
879 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
880 if ((size_t)capacity > kMaxLinearBufferSize) {
881 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
882 capacity = kMaxLinearBufferSize;
883 }
884
Wonsik Kim469c8342019-04-11 16:46:09 -0700885 sp<IMemory> memory;
886 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700887 int32_t heapSeqNum = -1;
888 for (; slot < memoryVector->size(); ++slot) {
889 if (memoryVector->at(slot).block.expired()) {
890 memory = memoryVector->at(slot).memory;
891 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700892 break;
893 }
894 }
895 if (memory == nullptr) {
896 return nullptr;
897 }
898
899 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700900 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700901 if (err != C2_OK || block == nullptr) {
902 return nullptr;
903 }
904
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700905 memoryVector->at(slot).block = block;
906 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
907}
908
909sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
910 // TODO: android_2020
911 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700912}
913
914// GraphicMetadataInputBuffers
915
916GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
917 const char *componentName, const char *name)
918 : InputBuffers(componentName, name),
919 mImpl(mName),
920 mStore(GetCodec2PlatformAllocatorStore()) { }
921
922bool GraphicMetadataInputBuffers::requestNewBuffer(
923 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700924 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700925 if (newBuffer == nullptr) {
926 return false;
927 }
928 *index = mImpl.assignSlot(newBuffer);
929 *buffer = newBuffer;
930 return true;
931}
932
933bool GraphicMetadataInputBuffers::releaseBuffer(
934 const sp<MediaCodecBuffer> &buffer,
935 std::shared_ptr<C2Buffer> *c2buffer,
936 bool release) {
937 return mImpl.releaseSlot(buffer, c2buffer, release);
938}
939
940bool GraphicMetadataInputBuffers::expireComponentBuffer(
941 const std::shared_ptr<C2Buffer> &c2buffer) {
942 return mImpl.expireComponentBuffer(c2buffer);
943}
944
945void GraphicMetadataInputBuffers::flush() {
946 // This is no-op by default unless we're in array mode where we need to keep
947 // track of the flushed work.
948}
949
950std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
951 size_t size) {
952 std::shared_ptr<C2Allocator> alloc;
953 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
954 if (err != C2_OK) {
955 return nullptr;
956 }
957 std::unique_ptr<InputBuffersArray> array(
958 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
959 array->setPool(mPool);
960 array->setFormat(mFormat);
961 array->initialize(
962 mImpl,
963 size,
964 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
965 return new GraphicMetadataBuffer(format, alloc);
966 });
967 return std::move(array);
968}
969
Wonsik Kim0487b782020-10-28 11:45:50 -0700970size_t GraphicMetadataInputBuffers::numActiveSlots() const {
971 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700972}
973
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700974sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
975 std::shared_ptr<C2Allocator> alloc;
976 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
977 if (err != C2_OK) {
978 return nullptr;
979 }
980 return new GraphicMetadataBuffer(mFormat, alloc);
981}
982
Wonsik Kim469c8342019-04-11 16:46:09 -0700983// GraphicInputBuffers
984
985GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700986 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700987 : InputBuffers(componentName, name),
988 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700989 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700990
991bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700992 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700993 if (newBuffer == nullptr) {
994 return false;
995 }
996 *index = mImpl.assignSlot(newBuffer);
997 handleImageData(newBuffer);
998 *buffer = newBuffer;
999 return true;
1000}
1001
1002bool GraphicInputBuffers::releaseBuffer(
1003 const sp<MediaCodecBuffer> &buffer,
1004 std::shared_ptr<C2Buffer> *c2buffer,
1005 bool release) {
1006 return mImpl.releaseSlot(buffer, c2buffer, release);
1007}
1008
1009bool GraphicInputBuffers::expireComponentBuffer(
1010 const std::shared_ptr<C2Buffer> &c2buffer) {
1011 return mImpl.expireComponentBuffer(c2buffer);
1012}
1013
1014void GraphicInputBuffers::flush() {
1015 // This is no-op by default unless we're in array mode where we need to keep
1016 // track of the flushed work.
1017}
1018
1019std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1020 std::unique_ptr<InputBuffersArray> array(
1021 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1022 array->setPool(mPool);
1023 array->setFormat(mFormat);
1024 array->initialize(
1025 mImpl,
1026 size,
1027 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1028 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1029 return AllocateGraphicBuffer(
1030 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1031 });
1032 return std::move(array);
1033}
1034
Wonsik Kim0487b782020-10-28 11:45:50 -07001035size_t GraphicInputBuffers::numActiveSlots() const {
1036 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001037}
1038
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001039sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1040 // TODO: read usage from intf
1041 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1042 return AllocateGraphicBuffer(
1043 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1044}
1045
Wonsik Kim469c8342019-04-11 16:46:09 -07001046// OutputBuffersArray
1047
1048void OutputBuffersArray::initialize(
1049 const FlexBuffersImpl &impl,
1050 size_t minSize,
1051 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001052 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001053 mImpl.initialize(impl, minSize, allocate);
1054}
1055
1056status_t OutputBuffersArray::registerBuffer(
1057 const std::shared_ptr<C2Buffer> &buffer,
1058 size_t *index,
1059 sp<MediaCodecBuffer> *clientBuffer) {
1060 sp<Codec2Buffer> c2Buffer;
1061 status_t err = mImpl.grabBuffer(
1062 index,
1063 &c2Buffer,
1064 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1065 return clientBuffer->canCopy(buffer);
1066 });
1067 if (err == WOULD_BLOCK) {
1068 ALOGV("[%s] buffers temporarily not available", mName);
1069 return err;
1070 } else if (err != OK) {
1071 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1072 return err;
1073 }
1074 c2Buffer->setFormat(mFormat);
1075 if (!c2Buffer->copy(buffer)) {
1076 ALOGD("[%s] copy buffer failed", mName);
1077 return WOULD_BLOCK;
1078 }
1079 submit(c2Buffer);
1080 handleImageData(c2Buffer);
1081 *clientBuffer = c2Buffer;
1082 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1083 return OK;
1084}
1085
1086status_t OutputBuffersArray::registerCsd(
1087 const C2StreamInitDataInfo::output *csd,
1088 size_t *index,
1089 sp<MediaCodecBuffer> *clientBuffer) {
1090 sp<Codec2Buffer> c2Buffer;
1091 status_t err = mImpl.grabBuffer(
1092 index,
1093 &c2Buffer,
1094 [csd](const sp<Codec2Buffer> &clientBuffer) {
1095 return clientBuffer->base() != nullptr
1096 && clientBuffer->capacity() >= csd->flexCount();
1097 });
1098 if (err != OK) {
1099 return err;
1100 }
1101 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1102 c2Buffer->setRange(0, csd->flexCount());
1103 c2Buffer->setFormat(mFormat);
1104 *clientBuffer = c2Buffer;
1105 return OK;
1106}
1107
1108bool OutputBuffersArray::releaseBuffer(
1109 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1110 return mImpl.returnBuffer(buffer, c2buffer, true);
1111}
1112
1113void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1114 (void)flushedWork;
1115 mImpl.flush();
1116 if (mSkipCutBuffer != nullptr) {
1117 mSkipCutBuffer->clear();
1118 }
1119}
1120
1121void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1122 mImpl.getArray(array);
1123}
1124
Wonsik Kim0487b782020-10-28 11:45:50 -07001125size_t OutputBuffersArray::numActiveSlots() const {
1126 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001127}
1128
Wonsik Kim469c8342019-04-11 16:46:09 -07001129void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001130 switch (c2buffer->data().type()) {
1131 case C2BufferData::LINEAR: {
1132 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001133 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1134 const uint32_t block_size = linear_blocks.front().size();
1135 if (block_size < kMaxLinearBufferSize / 2) {
1136 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001137 } else {
1138 size = kMaxLinearBufferSize;
1139 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001140 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001141 return new LocalLinearBuffer(format, new ABuffer(size));
1142 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001143 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001144 break;
1145 }
1146
Wonsik Kima39882b2019-06-20 16:13:56 -07001147 case C2BufferData::GRAPHIC: {
1148 // This is only called for RawGraphicOutputBuffers.
1149 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001150 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001151 return ConstGraphicBlockBuffer::AllocateEmpty(
1152 format,
1153 [lbp](size_t capacity) {
1154 return lbp->newBuffer(capacity);
1155 });
1156 };
1157 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1158 mName, mFormat->debugString().c_str());
1159 break;
1160 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001161
1162 case C2BufferData::INVALID: [[fallthrough]];
1163 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1164 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1165 default:
1166 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1167 return;
1168 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001169 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001170}
1171
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001172void OutputBuffersArray::grow(size_t newSize) {
1173 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001174}
1175
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001176void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1177 mFormat = source->mFormat;
1178 mSkipCutBuffer = source->mSkipCutBuffer;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -08001179 mUnreportedFormat = source->mUnreportedFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001180 mPending = std::move(source->mPending);
1181 mReorderStash = std::move(source->mReorderStash);
1182 mDepth = source->mDepth;
1183 mKey = source->mKey;
1184}
1185
Wonsik Kim469c8342019-04-11 16:46:09 -07001186// FlexOutputBuffers
1187
1188status_t FlexOutputBuffers::registerBuffer(
1189 const std::shared_ptr<C2Buffer> &buffer,
1190 size_t *index,
1191 sp<MediaCodecBuffer> *clientBuffer) {
1192 sp<Codec2Buffer> newBuffer = wrap(buffer);
1193 if (newBuffer == nullptr) {
1194 return NO_MEMORY;
1195 }
1196 newBuffer->setFormat(mFormat);
1197 *index = mImpl.assignSlot(newBuffer);
1198 handleImageData(newBuffer);
1199 *clientBuffer = newBuffer;
1200 ALOGV("[%s] registered buffer %zu", mName, *index);
1201 return OK;
1202}
1203
1204status_t FlexOutputBuffers::registerCsd(
1205 const C2StreamInitDataInfo::output *csd,
1206 size_t *index,
1207 sp<MediaCodecBuffer> *clientBuffer) {
1208 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1209 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1210 *index = mImpl.assignSlot(newBuffer);
1211 *clientBuffer = newBuffer;
1212 return OK;
1213}
1214
1215bool FlexOutputBuffers::releaseBuffer(
1216 const sp<MediaCodecBuffer> &buffer,
1217 std::shared_ptr<C2Buffer> *c2buffer) {
1218 return mImpl.releaseSlot(buffer, c2buffer, true);
1219}
1220
1221void FlexOutputBuffers::flush(
1222 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1223 (void) flushedWork;
1224 // This is no-op by default unless we're in array mode where we need to keep
1225 // track of the flushed work.
1226}
1227
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001228std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001229 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001230 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001231 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1232 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001233 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001234}
1235
Wonsik Kim0487b782020-10-28 11:45:50 -07001236size_t FlexOutputBuffers::numActiveSlots() const {
1237 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001238}
1239
1240// LinearOutputBuffers
1241
1242void LinearOutputBuffers::flush(
1243 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1244 if (mSkipCutBuffer != nullptr) {
1245 mSkipCutBuffer->clear();
1246 }
1247 FlexOutputBuffers::flush(flushedWork);
1248}
1249
1250sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1251 if (buffer == nullptr) {
1252 ALOGV("[%s] using a dummy buffer", mName);
1253 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1254 }
1255 if (buffer->data().type() != C2BufferData::LINEAR) {
1256 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1257 // We expect linear output buffers from the component.
1258 return nullptr;
1259 }
1260 if (buffer->data().linearBlocks().size() != 1u) {
1261 ALOGV("[%s] no linear buffers", mName);
1262 // We expect one and only one linear block from the component.
1263 return nullptr;
1264 }
1265 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1266 if (clientBuffer == nullptr) {
1267 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1268 return nullptr;
1269 }
1270 submit(clientBuffer);
1271 return clientBuffer;
1272}
1273
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001274std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1275 return [format = mFormat]{
1276 // TODO: proper max output size
1277 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1278 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001279}
1280
1281// GraphicOutputBuffers
1282
1283sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1284 return new DummyContainerBuffer(mFormat, buffer);
1285}
1286
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001287std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1288 return [format = mFormat]{
1289 return new DummyContainerBuffer(format);
1290 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001291}
1292
1293// RawGraphicOutputBuffers
1294
1295RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001296 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001297 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001298 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001299
1300sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1301 if (buffer == nullptr) {
1302 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1303 mFormat,
1304 [lbp = mLocalBufferPool](size_t capacity) {
1305 return lbp->newBuffer(capacity);
1306 });
1307 if (c2buffer == nullptr) {
1308 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1309 return nullptr;
1310 }
1311 c2buffer->setRange(0, 0);
1312 return c2buffer;
1313 } else {
1314 return ConstGraphicBlockBuffer::Allocate(
1315 mFormat,
1316 buffer,
1317 [lbp = mLocalBufferPool](size_t capacity) {
1318 return lbp->newBuffer(capacity);
1319 });
1320 }
1321}
1322
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001323std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1324 return [format = mFormat, lbp = mLocalBufferPool]{
1325 return ConstGraphicBlockBuffer::AllocateEmpty(
1326 format,
1327 [lbp](size_t capacity) {
1328 return lbp->newBuffer(capacity);
1329 });
1330 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001331}
1332
1333} // namespace android