blob: 566a18fbee75dcd70e93633617c6f64a5ed87061 [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 Kim8ec93ab2020-11-13 16:17:04 -0800164void OutputBuffers::updateSkipCutBuffer(
165 const sp<AMessage> &format, bool notify) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700166 AString mediaType;
167 if (format->findString(KEY_MIME, &mediaType)
168 && mediaType == MIMETYPE_AUDIO_RAW) {
169 int32_t channelCount;
170 int32_t sampleRate;
171 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
172 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
173 updateSkipCutBuffer(sampleRate, channelCount);
174 }
175 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800176 if (notify) {
177 mUnreportedFormat = nullptr;
178 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700179}
180
Wonsik Kim469c8342019-04-11 16:46:09 -0700181void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
182 if (mSkipCutBuffer != nullptr) {
183 mSkipCutBuffer->submit(buffer);
184 }
185}
186
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700187void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700188 if (mSkipCutBuffer != nullptr) {
189 size_t prevSize = mSkipCutBuffer->size();
190 if (prevSize != 0u) {
191 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
192 }
193 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700194 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700195}
196
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700197void OutputBuffers::clearStash() {
198 mPending.clear();
199 mReorderStash.clear();
200 mDepth = 0;
201 mKey = C2Config::ORDINAL;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800202 mUnreportedFormat = nullptr;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700203}
204
205void OutputBuffers::flushStash() {
206 for (StashEntry& e : mPending) {
207 e.notify = false;
208 }
209 for (StashEntry& e : mReorderStash) {
210 e.notify = false;
211 }
212}
213
214uint32_t OutputBuffers::getReorderDepth() const {
215 return mDepth;
216}
217
218void OutputBuffers::setReorderDepth(uint32_t depth) {
219 mPending.splice(mPending.end(), mReorderStash);
220 mDepth = depth;
221}
222
223void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
224 mPending.splice(mPending.end(), mReorderStash);
225 mKey = key;
226}
227
228void OutputBuffers::pushToStash(
229 const std::shared_ptr<C2Buffer>& buffer,
230 bool notify,
231 int64_t timestamp,
232 int32_t flags,
233 const sp<AMessage>& format,
234 const C2WorkOrdinalStruct& ordinal) {
235 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
236 if (!buffer && eos) {
237 // TRICKY: we may be violating ordering of the stash here. Because we
238 // don't expect any more emplace() calls after this, the ordering should
239 // not matter.
240 mReorderStash.emplace_back(
241 buffer, notify, timestamp, flags, format, ordinal);
242 } else {
243 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
244 auto it = mReorderStash.begin();
245 for (; it != mReorderStash.end(); ++it) {
246 if (less(ordinal, it->ordinal)) {
247 break;
248 }
249 }
250 mReorderStash.emplace(it,
251 buffer, notify, timestamp, flags, format, ordinal);
252 if (eos) {
253 mReorderStash.back().flags =
254 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
255 }
256 }
257 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
258 mPending.push_back(mReorderStash.front());
259 mReorderStash.pop_front();
260 }
261 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
262}
263
264OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
265 std::shared_ptr<C2Buffer>* c2Buffer,
266 size_t* index,
267 sp<MediaCodecBuffer>* outBuffer) {
268 if (mPending.empty()) {
269 return SKIP;
270 }
271
272 // Retrieve the first entry.
273 StashEntry &entry = mPending.front();
274
275 *c2Buffer = entry.buffer;
276 sp<AMessage> outputFormat = entry.format;
277
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800278 // The output format can be processed without a registered slot.
279 if (outputFormat) {
280 updateSkipCutBuffer(outputFormat, entry.notify);
281 }
282
283 if (entry.notify) {
284 if (outputFormat) {
285 setFormat(outputFormat);
286 } else if (mUnreportedFormat) {
287 outputFormat = mUnreportedFormat;
288 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700289 }
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800290 mUnreportedFormat = nullptr;
291 } else {
292 if (outputFormat) {
293 mUnreportedFormat = outputFormat;
294 } else if (!mUnreportedFormat) {
295 mUnreportedFormat = mFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700296 }
297 }
298
299 // Flushing mReorderStash because no other buffers should come after output
300 // EOS.
301 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
302 // Flush reorder stash
303 setReorderDepth(0);
304 }
305
306 if (!entry.notify) {
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800307 if (outputFormat) {
308 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
309 mName, outputFormat->debugString().c_str());
310 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700311 mPending.pop_front();
312 return DISCARD;
313 }
314
315 // Try to register the buffer.
316 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
317 if (err != OK) {
318 if (err != WOULD_BLOCK) {
319 return REALLOCATE;
320 }
321 return RETRY;
322 }
323
324 // Append information from the front stash entry to outBuffer.
325 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
326 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Wonsik Kim8ec93ab2020-11-13 16:17:04 -0800327 if (outputFormat) {
328 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
329 mName, outputFormat->debugString().c_str());
330 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700331 ALOGV("[%s] popFromStashAndRegister: "
332 "out buffer index = %zu [%p] => %p + %zu (%lld)",
333 mName, *index, outBuffer->get(),
334 (*outBuffer)->data(), (*outBuffer)->size(),
335 (long long)entry.timestamp);
336
337 // The front entry of mPending will be removed now that the registration
338 // succeeded.
339 mPending.pop_front();
340 return NOTIFY_CLIENT;
341}
342
343bool OutputBuffers::popPending(StashEntry *entry) {
344 if (mPending.empty()) {
345 return false;
346 }
347 *entry = mPending.front();
348 mPending.pop_front();
349 return true;
350}
351
352void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
353 mPending.push_front(entry);
354}
355
356bool OutputBuffers::hasPending() const {
357 return !mPending.empty();
358}
359
360bool OutputBuffers::less(
361 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
362 switch (mKey) {
363 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
364 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
365 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
366 default:
367 ALOGD("Unrecognized key; default to timestamp");
368 return o1.frameIndex < o2.frameIndex;
369 }
370}
371
Wonsik Kim469c8342019-04-11 16:46:09 -0700372// LocalBufferPool
373
Wonsik Kim41d83432020-04-27 16:40:49 -0700374constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
375constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
376
377std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
378 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700379}
380
381sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
382 Mutex::Autolock lock(mMutex);
383 auto it = std::find_if(
384 mPool.begin(), mPool.end(),
385 [capacity](const std::vector<uint8_t> &vec) {
386 return vec.capacity() >= capacity;
387 });
388 if (it != mPool.end()) {
389 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
390 mPool.erase(it);
391 return buffer;
392 }
393 if (mUsedSize + capacity > mPoolCapacity) {
394 while (!mPool.empty()) {
395 mUsedSize -= mPool.back().capacity();
396 mPool.pop_back();
397 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700398 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
399 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
400 mPoolCapacity, mPoolCapacity * 2);
401 mPoolCapacity *= 2;
402 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700403 if (mUsedSize + capacity > mPoolCapacity) {
404 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
405 mUsedSize, capacity, mPoolCapacity);
406 return nullptr;
407 }
408 }
409 std::vector<uint8_t> vec(capacity);
410 mUsedSize += vec.capacity();
411 return new VectorBuffer(std::move(vec), shared_from_this());
412}
413
414LocalBufferPool::VectorBuffer::VectorBuffer(
415 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
416 : ABuffer(vec.data(), vec.capacity()),
417 mVec(std::move(vec)),
418 mPool(pool) {
419}
420
421LocalBufferPool::VectorBuffer::~VectorBuffer() {
422 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
423 if (pool) {
424 // If pool is alive, return the vector back to the pool so that
425 // it can be recycled.
426 pool->returnVector(std::move(mVec));
427 }
428}
429
430void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
431 Mutex::Autolock lock(mMutex);
432 mPool.push_front(std::move(vec));
433}
434
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700435// FlexBuffersImpl
436
Wonsik Kim469c8342019-04-11 16:46:09 -0700437size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
438 for (size_t i = 0; i < mBuffers.size(); ++i) {
439 if (mBuffers[i].clientBuffer == nullptr
440 && mBuffers[i].compBuffer.expired()) {
441 mBuffers[i].clientBuffer = buffer;
442 return i;
443 }
444 }
445 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
446 return mBuffers.size() - 1;
447}
448
Wonsik Kim469c8342019-04-11 16:46:09 -0700449bool FlexBuffersImpl::releaseSlot(
450 const sp<MediaCodecBuffer> &buffer,
451 std::shared_ptr<C2Buffer> *c2buffer,
452 bool release) {
453 sp<Codec2Buffer> clientBuffer;
454 size_t index = mBuffers.size();
455 for (size_t i = 0; i < mBuffers.size(); ++i) {
456 if (mBuffers[i].clientBuffer == buffer) {
457 clientBuffer = mBuffers[i].clientBuffer;
458 if (release) {
459 mBuffers[i].clientBuffer.clear();
460 }
461 index = i;
462 break;
463 }
464 }
465 if (clientBuffer == nullptr) {
466 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
467 return false;
468 }
469 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
470 if (!result) {
471 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700472 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700473 mBuffers[index].compBuffer = result;
474 }
475 if (c2buffer) {
476 *c2buffer = result;
477 }
478 return true;
479}
480
481bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
482 for (size_t i = 0; i < mBuffers.size(); ++i) {
483 std::shared_ptr<C2Buffer> compBuffer =
484 mBuffers[i].compBuffer.lock();
485 if (!compBuffer || compBuffer != c2buffer) {
486 continue;
487 }
488 mBuffers[i].compBuffer.reset();
489 ALOGV("[%s] codec released buffer #%zu", mName, i);
490 return true;
491 }
492 ALOGV("[%s] codec released an unknown buffer", mName);
493 return false;
494}
495
496void FlexBuffersImpl::flush() {
497 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
498 mBuffers.clear();
499}
500
Wonsik Kim0487b782020-10-28 11:45:50 -0700501size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700502 return std::count_if(
503 mBuffers.begin(), mBuffers.end(),
504 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700505 return (entry.clientBuffer != nullptr
506 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700507 });
508}
509
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700510size_t FlexBuffersImpl::numComponentBuffers() const {
511 return std::count_if(
512 mBuffers.begin(), mBuffers.end(),
513 [](const Entry &entry) {
514 return !entry.compBuffer.expired();
515 });
516}
517
Wonsik Kim469c8342019-04-11 16:46:09 -0700518// BuffersArrayImpl
519
520void BuffersArrayImpl::initialize(
521 const FlexBuffersImpl &impl,
522 size_t minSize,
523 std::function<sp<Codec2Buffer>()> allocate) {
524 mImplName = impl.mImplName + "[N]";
525 mName = mImplName.c_str();
526 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
527 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
528 bool ownedByClient = (clientBuffer != nullptr);
529 if (!ownedByClient) {
530 clientBuffer = allocate();
531 }
532 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
533 }
534 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
535 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
536 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
537 }
538}
539
540status_t BuffersArrayImpl::grabBuffer(
541 size_t *index,
542 sp<Codec2Buffer> *buffer,
543 std::function<bool(const sp<Codec2Buffer> &)> match) {
544 // allBuffersDontMatch remains true if all buffers are available but
545 // match() returns false for every buffer.
546 bool allBuffersDontMatch = true;
547 for (size_t i = 0; i < mBuffers.size(); ++i) {
548 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
549 if (match(mBuffers[i].clientBuffer)) {
550 mBuffers[i].ownedByClient = true;
551 *buffer = mBuffers[i].clientBuffer;
552 (*buffer)->meta()->clear();
553 (*buffer)->setRange(0, (*buffer)->capacity());
554 *index = i;
555 return OK;
556 }
557 } else {
558 allBuffersDontMatch = false;
559 }
560 }
561 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
562}
563
564bool BuffersArrayImpl::returnBuffer(
565 const sp<MediaCodecBuffer> &buffer,
566 std::shared_ptr<C2Buffer> *c2buffer,
567 bool release) {
568 sp<Codec2Buffer> clientBuffer;
569 size_t index = mBuffers.size();
570 for (size_t i = 0; i < mBuffers.size(); ++i) {
571 if (mBuffers[i].clientBuffer == buffer) {
572 if (!mBuffers[i].ownedByClient) {
573 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
574 mName, i);
575 }
576 clientBuffer = mBuffers[i].clientBuffer;
577 if (release) {
578 mBuffers[i].ownedByClient = false;
579 }
580 index = i;
581 break;
582 }
583 }
584 if (clientBuffer == nullptr) {
585 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
586 return false;
587 }
588 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
589 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
590 if (!result) {
591 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700592 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700593 mBuffers[index].compBuffer = result;
594 }
595 if (c2buffer) {
596 *c2buffer = result;
597 }
598 return true;
599}
600
601bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
602 for (size_t i = 0; i < mBuffers.size(); ++i) {
603 std::shared_ptr<C2Buffer> compBuffer =
604 mBuffers[i].compBuffer.lock();
605 if (!compBuffer) {
606 continue;
607 }
608 if (c2buffer == compBuffer) {
609 if (mBuffers[i].ownedByClient) {
610 // This should not happen.
611 ALOGD("[%s] codec released a buffer owned by client "
612 "(index %zu)", mName, i);
613 }
614 mBuffers[i].compBuffer.reset();
615 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
616 return true;
617 }
618 }
619 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
620 return false;
621}
622
623void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
624 array->clear();
625 for (const Entry &entry : mBuffers) {
626 array->push(entry.clientBuffer);
627 }
628}
629
630void BuffersArrayImpl::flush() {
631 for (Entry &entry : mBuffers) {
632 entry.ownedByClient = false;
633 }
634}
635
636void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
637 size_t size = mBuffers.size();
638 mBuffers.clear();
639 for (size_t i = 0; i < size; ++i) {
640 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
641 }
642}
643
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700644void BuffersArrayImpl::grow(
645 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
646 CHECK_LT(mBuffers.size(), newSize);
647 while (mBuffers.size() < newSize) {
648 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
649 }
650}
651
Wonsik Kim0487b782020-10-28 11:45:50 -0700652size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700653 return std::count_if(
654 mBuffers.begin(), mBuffers.end(),
655 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700656 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700657 });
658}
659
Wonsik Kima39882b2019-06-20 16:13:56 -0700660size_t BuffersArrayImpl::arraySize() const {
661 return mBuffers.size();
662}
663
Wonsik Kim469c8342019-04-11 16:46:09 -0700664// InputBuffersArray
665
666void InputBuffersArray::initialize(
667 const FlexBuffersImpl &impl,
668 size_t minSize,
669 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700670 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700671 mImpl.initialize(impl, minSize, allocate);
672}
673
674void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
675 mImpl.getArray(array);
676}
677
678bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
679 sp<Codec2Buffer> c2Buffer;
680 status_t err = mImpl.grabBuffer(index, &c2Buffer);
681 if (err == OK) {
682 c2Buffer->setFormat(mFormat);
683 handleImageData(c2Buffer);
684 *buffer = c2Buffer;
685 return true;
686 }
687 return false;
688}
689
690bool InputBuffersArray::releaseBuffer(
691 const sp<MediaCodecBuffer> &buffer,
692 std::shared_ptr<C2Buffer> *c2buffer,
693 bool release) {
694 return mImpl.returnBuffer(buffer, c2buffer, release);
695}
696
697bool InputBuffersArray::expireComponentBuffer(
698 const std::shared_ptr<C2Buffer> &c2buffer) {
699 return mImpl.expireComponentBuffer(c2buffer);
700}
701
702void InputBuffersArray::flush() {
703 mImpl.flush();
704}
705
Wonsik Kim0487b782020-10-28 11:45:50 -0700706size_t InputBuffersArray::numActiveSlots() const {
707 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700708}
709
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700710sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
711 return mAllocate();
712}
713
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800714// SlotInputBuffers
715
716bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
717 sp<Codec2Buffer> newBuffer = createNewBuffer();
718 *index = mImpl.assignSlot(newBuffer);
719 *buffer = newBuffer;
720 return true;
721}
722
723bool SlotInputBuffers::releaseBuffer(
724 const sp<MediaCodecBuffer> &buffer,
725 std::shared_ptr<C2Buffer> *c2buffer,
726 bool release) {
727 return mImpl.releaseSlot(buffer, c2buffer, release);
728}
729
730bool SlotInputBuffers::expireComponentBuffer(
731 const std::shared_ptr<C2Buffer> &c2buffer) {
732 return mImpl.expireComponentBuffer(c2buffer);
733}
734
735void SlotInputBuffers::flush() {
736 mImpl.flush();
737}
738
739std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
740 TRESPASS("Array mode should not be called at non-legacy mode");
741 return nullptr;
742}
743
Wonsik Kim0487b782020-10-28 11:45:50 -0700744size_t SlotInputBuffers::numActiveSlots() const {
745 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800746}
747
748sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
749 return new DummyContainerBuffer{mFormat, nullptr};
750}
751
Wonsik Kim469c8342019-04-11 16:46:09 -0700752// LinearInputBuffers
753
754bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700755 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700756 if (newBuffer == nullptr) {
757 return false;
758 }
759 *index = mImpl.assignSlot(newBuffer);
760 *buffer = newBuffer;
761 return true;
762}
763
764bool LinearInputBuffers::releaseBuffer(
765 const sp<MediaCodecBuffer> &buffer,
766 std::shared_ptr<C2Buffer> *c2buffer,
767 bool release) {
768 return mImpl.releaseSlot(buffer, c2buffer, release);
769}
770
771bool LinearInputBuffers::expireComponentBuffer(
772 const std::shared_ptr<C2Buffer> &c2buffer) {
773 return mImpl.expireComponentBuffer(c2buffer);
774}
775
776void LinearInputBuffers::flush() {
777 // This is no-op by default unless we're in array mode where we need to keep
778 // track of the flushed work.
779 mImpl.flush();
780}
781
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700782std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700783 std::unique_ptr<InputBuffersArray> array(
784 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
785 array->setPool(mPool);
786 array->setFormat(mFormat);
787 array->initialize(
788 mImpl,
789 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700790 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
791 return Alloc(pool, format);
792 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700793 return std::move(array);
794}
795
Wonsik Kim0487b782020-10-28 11:45:50 -0700796size_t LinearInputBuffers::numActiveSlots() const {
797 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700798}
799
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700800// static
801sp<Codec2Buffer> LinearInputBuffers::Alloc(
802 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
803 int32_t capacity = kLinearBufferSize;
804 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
805 if ((size_t)capacity > kMaxLinearBufferSize) {
806 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
807 capacity = kMaxLinearBufferSize;
808 }
809
810 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700811 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
812 std::shared_ptr<C2LinearBlock> block;
813
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700814 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700815 if (err != C2_OK) {
816 return nullptr;
817 }
818
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700819 return LinearBlockBuffer::Allocate(format, block);
820}
821
822sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
823 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700824}
825
826// EncryptedLinearInputBuffers
827
828EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
829 bool secure,
830 const sp<MemoryDealer> &dealer,
831 const sp<ICrypto> &crypto,
832 int32_t heapSeqNum,
833 size_t capacity,
834 size_t numInputSlots,
835 const char *componentName, const char *name)
836 : LinearInputBuffers(componentName, name),
837 mUsage({0, 0}),
838 mDealer(dealer),
839 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700840 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700841 if (secure) {
842 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
843 } else {
844 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
845 }
846 for (size_t i = 0; i < numInputSlots; ++i) {
847 sp<IMemory> memory = mDealer->allocate(capacity);
848 if (memory == nullptr) {
849 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
850 mName, i);
851 break;
852 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700853 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700854 }
855}
856
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700857std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
858 std::unique_ptr<InputBuffersArray> array(
859 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
860 array->setPool(mPool);
861 array->setFormat(mFormat);
862 array->initialize(
863 mImpl,
864 size,
865 [pool = mPool,
866 format = mFormat,
867 usage = mUsage,
868 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
869 return Alloc(pool, format, usage, memoryVector);
870 });
871 return std::move(array);
872}
873
874
875// static
876sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
877 const std::shared_ptr<C2BlockPool> &pool,
878 const sp<AMessage> &format,
879 C2MemoryUsage usage,
880 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
881 int32_t capacity = kLinearBufferSize;
882 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
883 if ((size_t)capacity > kMaxLinearBufferSize) {
884 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
885 capacity = kMaxLinearBufferSize;
886 }
887
Wonsik Kim469c8342019-04-11 16:46:09 -0700888 sp<IMemory> memory;
889 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700890 int32_t heapSeqNum = -1;
891 for (; slot < memoryVector->size(); ++slot) {
892 if (memoryVector->at(slot).block.expired()) {
893 memory = memoryVector->at(slot).memory;
894 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700895 break;
896 }
897 }
898 if (memory == nullptr) {
899 return nullptr;
900 }
901
902 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700903 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700904 if (err != C2_OK || block == nullptr) {
905 return nullptr;
906 }
907
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700908 memoryVector->at(slot).block = block;
909 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
910}
911
912sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
913 // TODO: android_2020
914 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700915}
916
917// GraphicMetadataInputBuffers
918
919GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
920 const char *componentName, const char *name)
921 : InputBuffers(componentName, name),
922 mImpl(mName),
923 mStore(GetCodec2PlatformAllocatorStore()) { }
924
925bool GraphicMetadataInputBuffers::requestNewBuffer(
926 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700927 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700928 if (newBuffer == nullptr) {
929 return false;
930 }
931 *index = mImpl.assignSlot(newBuffer);
932 *buffer = newBuffer;
933 return true;
934}
935
936bool GraphicMetadataInputBuffers::releaseBuffer(
937 const sp<MediaCodecBuffer> &buffer,
938 std::shared_ptr<C2Buffer> *c2buffer,
939 bool release) {
940 return mImpl.releaseSlot(buffer, c2buffer, release);
941}
942
943bool GraphicMetadataInputBuffers::expireComponentBuffer(
944 const std::shared_ptr<C2Buffer> &c2buffer) {
945 return mImpl.expireComponentBuffer(c2buffer);
946}
947
948void GraphicMetadataInputBuffers::flush() {
949 // This is no-op by default unless we're in array mode where we need to keep
950 // track of the flushed work.
951}
952
953std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
954 size_t size) {
955 std::shared_ptr<C2Allocator> alloc;
956 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
957 if (err != C2_OK) {
958 return nullptr;
959 }
960 std::unique_ptr<InputBuffersArray> array(
961 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
962 array->setPool(mPool);
963 array->setFormat(mFormat);
964 array->initialize(
965 mImpl,
966 size,
967 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
968 return new GraphicMetadataBuffer(format, alloc);
969 });
970 return std::move(array);
971}
972
Wonsik Kim0487b782020-10-28 11:45:50 -0700973size_t GraphicMetadataInputBuffers::numActiveSlots() const {
974 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700975}
976
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700977sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
978 std::shared_ptr<C2Allocator> alloc;
979 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
980 if (err != C2_OK) {
981 return nullptr;
982 }
983 return new GraphicMetadataBuffer(mFormat, alloc);
984}
985
Wonsik Kim469c8342019-04-11 16:46:09 -0700986// GraphicInputBuffers
987
988GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700989 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700990 : InputBuffers(componentName, name),
991 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700992 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700993
994bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700995 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700996 if (newBuffer == nullptr) {
997 return false;
998 }
999 *index = mImpl.assignSlot(newBuffer);
1000 handleImageData(newBuffer);
1001 *buffer = newBuffer;
1002 return true;
1003}
1004
1005bool GraphicInputBuffers::releaseBuffer(
1006 const sp<MediaCodecBuffer> &buffer,
1007 std::shared_ptr<C2Buffer> *c2buffer,
1008 bool release) {
1009 return mImpl.releaseSlot(buffer, c2buffer, release);
1010}
1011
1012bool GraphicInputBuffers::expireComponentBuffer(
1013 const std::shared_ptr<C2Buffer> &c2buffer) {
1014 return mImpl.expireComponentBuffer(c2buffer);
1015}
1016
1017void GraphicInputBuffers::flush() {
1018 // This is no-op by default unless we're in array mode where we need to keep
1019 // track of the flushed work.
1020}
1021
1022std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1023 std::unique_ptr<InputBuffersArray> array(
1024 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1025 array->setPool(mPool);
1026 array->setFormat(mFormat);
1027 array->initialize(
1028 mImpl,
1029 size,
1030 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1031 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1032 return AllocateGraphicBuffer(
1033 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1034 });
1035 return std::move(array);
1036}
1037
Wonsik Kim0487b782020-10-28 11:45:50 -07001038size_t GraphicInputBuffers::numActiveSlots() const {
1039 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001040}
1041
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001042sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1043 // TODO: read usage from intf
1044 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1045 return AllocateGraphicBuffer(
1046 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1047}
1048
Wonsik Kim469c8342019-04-11 16:46:09 -07001049// OutputBuffersArray
1050
1051void OutputBuffersArray::initialize(
1052 const FlexBuffersImpl &impl,
1053 size_t minSize,
1054 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001055 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001056 mImpl.initialize(impl, minSize, allocate);
1057}
1058
1059status_t OutputBuffersArray::registerBuffer(
1060 const std::shared_ptr<C2Buffer> &buffer,
1061 size_t *index,
1062 sp<MediaCodecBuffer> *clientBuffer) {
1063 sp<Codec2Buffer> c2Buffer;
1064 status_t err = mImpl.grabBuffer(
1065 index,
1066 &c2Buffer,
1067 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1068 return clientBuffer->canCopy(buffer);
1069 });
1070 if (err == WOULD_BLOCK) {
1071 ALOGV("[%s] buffers temporarily not available", mName);
1072 return err;
1073 } else if (err != OK) {
1074 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1075 return err;
1076 }
1077 c2Buffer->setFormat(mFormat);
1078 if (!c2Buffer->copy(buffer)) {
1079 ALOGD("[%s] copy buffer failed", mName);
1080 return WOULD_BLOCK;
1081 }
1082 submit(c2Buffer);
1083 handleImageData(c2Buffer);
1084 *clientBuffer = c2Buffer;
1085 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1086 return OK;
1087}
1088
1089status_t OutputBuffersArray::registerCsd(
1090 const C2StreamInitDataInfo::output *csd,
1091 size_t *index,
1092 sp<MediaCodecBuffer> *clientBuffer) {
1093 sp<Codec2Buffer> c2Buffer;
1094 status_t err = mImpl.grabBuffer(
1095 index,
1096 &c2Buffer,
1097 [csd](const sp<Codec2Buffer> &clientBuffer) {
1098 return clientBuffer->base() != nullptr
1099 && clientBuffer->capacity() >= csd->flexCount();
1100 });
1101 if (err != OK) {
1102 return err;
1103 }
1104 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1105 c2Buffer->setRange(0, csd->flexCount());
1106 c2Buffer->setFormat(mFormat);
1107 *clientBuffer = c2Buffer;
1108 return OK;
1109}
1110
1111bool OutputBuffersArray::releaseBuffer(
1112 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1113 return mImpl.returnBuffer(buffer, c2buffer, true);
1114}
1115
1116void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1117 (void)flushedWork;
1118 mImpl.flush();
1119 if (mSkipCutBuffer != nullptr) {
1120 mSkipCutBuffer->clear();
1121 }
1122}
1123
1124void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1125 mImpl.getArray(array);
1126}
1127
Wonsik Kim0487b782020-10-28 11:45:50 -07001128size_t OutputBuffersArray::numActiveSlots() const {
1129 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001130}
1131
Wonsik Kim469c8342019-04-11 16:46:09 -07001132void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001133 switch (c2buffer->data().type()) {
1134 case C2BufferData::LINEAR: {
1135 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001136 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1137 const uint32_t block_size = linear_blocks.front().size();
1138 if (block_size < kMaxLinearBufferSize / 2) {
1139 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001140 } else {
1141 size = kMaxLinearBufferSize;
1142 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001143 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001144 return new LocalLinearBuffer(format, new ABuffer(size));
1145 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001146 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001147 break;
1148 }
1149
Wonsik Kima39882b2019-06-20 16:13:56 -07001150 case C2BufferData::GRAPHIC: {
1151 // This is only called for RawGraphicOutputBuffers.
1152 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001153 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001154 return ConstGraphicBlockBuffer::AllocateEmpty(
1155 format,
1156 [lbp](size_t capacity) {
1157 return lbp->newBuffer(capacity);
1158 });
1159 };
1160 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1161 mName, mFormat->debugString().c_str());
1162 break;
1163 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001164
1165 case C2BufferData::INVALID: [[fallthrough]];
1166 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1167 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1168 default:
1169 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1170 return;
1171 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001172 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001173}
1174
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001175void OutputBuffersArray::grow(size_t newSize) {
1176 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001177}
1178
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001179void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1180 mFormat = source->mFormat;
1181 mSkipCutBuffer = source->mSkipCutBuffer;
Wonsik Kim8ec93ab2020-11-13 16:17:04 -08001182 mUnreportedFormat = source->mUnreportedFormat;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001183 mPending = std::move(source->mPending);
1184 mReorderStash = std::move(source->mReorderStash);
1185 mDepth = source->mDepth;
1186 mKey = source->mKey;
1187}
1188
Wonsik Kim469c8342019-04-11 16:46:09 -07001189// FlexOutputBuffers
1190
1191status_t FlexOutputBuffers::registerBuffer(
1192 const std::shared_ptr<C2Buffer> &buffer,
1193 size_t *index,
1194 sp<MediaCodecBuffer> *clientBuffer) {
1195 sp<Codec2Buffer> newBuffer = wrap(buffer);
1196 if (newBuffer == nullptr) {
1197 return NO_MEMORY;
1198 }
1199 newBuffer->setFormat(mFormat);
1200 *index = mImpl.assignSlot(newBuffer);
1201 handleImageData(newBuffer);
1202 *clientBuffer = newBuffer;
1203 ALOGV("[%s] registered buffer %zu", mName, *index);
1204 return OK;
1205}
1206
1207status_t FlexOutputBuffers::registerCsd(
1208 const C2StreamInitDataInfo::output *csd,
1209 size_t *index,
1210 sp<MediaCodecBuffer> *clientBuffer) {
1211 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1212 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1213 *index = mImpl.assignSlot(newBuffer);
1214 *clientBuffer = newBuffer;
1215 return OK;
1216}
1217
1218bool FlexOutputBuffers::releaseBuffer(
1219 const sp<MediaCodecBuffer> &buffer,
1220 std::shared_ptr<C2Buffer> *c2buffer) {
1221 return mImpl.releaseSlot(buffer, c2buffer, true);
1222}
1223
1224void FlexOutputBuffers::flush(
1225 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1226 (void) flushedWork;
1227 // This is no-op by default unless we're in array mode where we need to keep
1228 // track of the flushed work.
1229}
1230
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001231std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001232 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001233 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001234 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1235 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001236 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001237}
1238
Wonsik Kim0487b782020-10-28 11:45:50 -07001239size_t FlexOutputBuffers::numActiveSlots() const {
1240 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001241}
1242
1243// LinearOutputBuffers
1244
1245void LinearOutputBuffers::flush(
1246 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1247 if (mSkipCutBuffer != nullptr) {
1248 mSkipCutBuffer->clear();
1249 }
1250 FlexOutputBuffers::flush(flushedWork);
1251}
1252
1253sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1254 if (buffer == nullptr) {
1255 ALOGV("[%s] using a dummy buffer", mName);
1256 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1257 }
1258 if (buffer->data().type() != C2BufferData::LINEAR) {
1259 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1260 // We expect linear output buffers from the component.
1261 return nullptr;
1262 }
1263 if (buffer->data().linearBlocks().size() != 1u) {
1264 ALOGV("[%s] no linear buffers", mName);
1265 // We expect one and only one linear block from the component.
1266 return nullptr;
1267 }
1268 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1269 if (clientBuffer == nullptr) {
1270 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1271 return nullptr;
1272 }
1273 submit(clientBuffer);
1274 return clientBuffer;
1275}
1276
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001277std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1278 return [format = mFormat]{
1279 // TODO: proper max output size
1280 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1281 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001282}
1283
1284// GraphicOutputBuffers
1285
1286sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1287 return new DummyContainerBuffer(mFormat, buffer);
1288}
1289
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001290std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1291 return [format = mFormat]{
1292 return new DummyContainerBuffer(format);
1293 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001294}
1295
1296// RawGraphicOutputBuffers
1297
1298RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001299 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001300 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001301 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001302
1303sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1304 if (buffer == nullptr) {
1305 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1306 mFormat,
1307 [lbp = mLocalBufferPool](size_t capacity) {
1308 return lbp->newBuffer(capacity);
1309 });
1310 if (c2buffer == nullptr) {
1311 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1312 return nullptr;
1313 }
1314 c2buffer->setRange(0, 0);
1315 return c2buffer;
1316 } else {
1317 return ConstGraphicBlockBuffer::Allocate(
1318 mFormat,
1319 buffer,
1320 [lbp = mLocalBufferPool](size_t capacity) {
1321 return lbp->newBuffer(capacity);
1322 });
1323 }
1324}
1325
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001326std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1327 return [format = mFormat, lbp = mLocalBufferPool]{
1328 return ConstGraphicBlockBuffer::AllocateEmpty(
1329 format,
1330 [lbp](size_t capacity) {
1331 return lbp->newBuffer(capacity);
1332 });
1333 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001334}
1335
1336} // namespace android