blob: 2025da2b1e1d0167e6337bc69d6c11215f2c8b7c [file] [log] [blame]
Wonsik Kim469c8342019-04-11 16:46:09 -07001/*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CCodecBuffers"
19#include <utils/Log.h>
20
21#include <C2PlatformSupport.h>
22
23#include <media/stagefright/foundation/ADebug.h>
Pawin Vongmasa9b906982020-04-11 05:07:15 -070024#include <media/stagefright/MediaCodec.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070025#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070026#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070027#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070028
29#include "CCodecBuffers.h"
Wonsik Kimd79ee1f2020-08-27 17:41:56 -070030#include "Codec2Mapper.h"
Wonsik Kim469c8342019-04-11 16:46:09 -070031
32namespace android {
33
34namespace {
35
36sp<GraphicBlockBuffer> AllocateGraphicBuffer(
37 const std::shared_ptr<C2BlockPool> &pool,
38 const sp<AMessage> &format,
39 uint32_t pixelFormat,
40 const C2MemoryUsage &usage,
41 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
42 int32_t width, height;
43 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
44 ALOGD("format lacks width or height");
45 return nullptr;
46 }
47
48 std::shared_ptr<C2GraphicBlock> block;
49 c2_status_t err = pool->fetchGraphicBlock(
50 width, height, pixelFormat, usage, &block);
51 if (err != C2_OK) {
52 ALOGD("fetch graphic block failed: %d", err);
53 return nullptr;
54 }
55
56 return GraphicBlockBuffer::Allocate(
57 format,
58 block,
59 [localBufferPool](size_t capacity) {
60 return localBufferPool->newBuffer(capacity);
61 });
62}
63
64} // namespace
65
66// CCodecBuffers
67
68void CCodecBuffers::setFormat(const sp<AMessage> &format) {
69 CHECK(format != nullptr);
70 mFormat = format;
71}
72
73sp<AMessage> CCodecBuffers::dupFormat() {
74 return mFormat != nullptr ? mFormat->dup() : nullptr;
75}
76
77void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
78 sp<ABuffer> imageDataCandidate = buffer->getImageData();
79 if (imageDataCandidate == nullptr) {
80 return;
81 }
82 sp<ABuffer> imageData;
83 if (!mFormat->findBuffer("image-data", &imageData)
84 || imageDataCandidate->size() != imageData->size()
85 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
86 ALOGD("[%s] updating image-data", mName);
87 sp<AMessage> newFormat = dupFormat();
88 newFormat->setBuffer("image-data", imageDataCandidate);
89 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
90 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
91 int32_t stride = img->mPlane[0].mRowInc;
92 newFormat->setInt32(KEY_STRIDE, stride);
93 ALOGD("[%s] updating stride = %d", mName, stride);
94 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +090095 int64_t offsetDelta =
96 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
97 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim469c8342019-04-11 16:46:09 -070098 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
99 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800100 buffer->setRange(
101 img->mPlane[0].mOffset,
102 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700103 }
104 }
105 setFormat(newFormat);
106 buffer->setFormat(newFormat);
107 }
108}
109
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700110// InputBuffers
111
112sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
113 sp<Codec2Buffer> copy = createNewBuffer();
114 if (copy == nullptr) {
115 return nullptr;
116 }
117 std::shared_ptr<C2Buffer> c2buffer;
118 if (!releaseBuffer(buffer, &c2buffer, true)) {
119 return nullptr;
120 }
121 if (!copy->canCopy(c2buffer)) {
122 return nullptr;
123 }
124 if (!copy->copy(c2buffer)) {
125 return nullptr;
126 }
127 return copy;
128}
129
Wonsik Kim469c8342019-04-11 16:46:09 -0700130// OutputBuffers
131
Wonsik Kim41d83432020-04-27 16:40:49 -0700132OutputBuffers::OutputBuffers(const char *componentName, const char *name)
133 : CCodecBuffers(componentName, name) { }
134
135OutputBuffers::~OutputBuffers() = default;
136
Wonsik Kim469c8342019-04-11 16:46:09 -0700137void OutputBuffers::initSkipCutBuffer(
138 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
139 CHECK(mSkipCutBuffer == nullptr);
140 mDelay = delay;
141 mPadding = padding;
142 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700143 mChannelCount = channelCount;
144 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700145}
146
147void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
148 if (mSkipCutBuffer == nullptr) {
149 return;
150 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700151 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
152 return;
153 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700154 int32_t delay = mDelay;
155 int32_t padding = mPadding;
156 if (sampleRate != mSampleRate) {
157 delay = ((int64_t)delay * sampleRate) / mSampleRate;
158 padding = ((int64_t)padding * sampleRate) / mSampleRate;
159 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700160 mSampleRate = sampleRate;
161 mChannelCount = channelCount;
162 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700163}
164
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800165void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
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 }
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;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700199}
200
201void OutputBuffers::flushStash() {
202 for (StashEntry& e : mPending) {
203 e.notify = false;
204 }
205 for (StashEntry& e : mReorderStash) {
206 e.notify = false;
207 }
208}
209
210uint32_t OutputBuffers::getReorderDepth() const {
211 return mDepth;
212}
213
214void OutputBuffers::setReorderDepth(uint32_t depth) {
215 mPending.splice(mPending.end(), mReorderStash);
216 mDepth = depth;
217}
218
219void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
220 mPending.splice(mPending.end(), mReorderStash);
221 mKey = key;
222}
223
224void OutputBuffers::pushToStash(
225 const std::shared_ptr<C2Buffer>& buffer,
226 bool notify,
227 int64_t timestamp,
228 int32_t flags,
229 const sp<AMessage>& format,
230 const C2WorkOrdinalStruct& ordinal) {
231 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
232 if (!buffer && eos) {
233 // TRICKY: we may be violating ordering of the stash here. Because we
234 // don't expect any more emplace() calls after this, the ordering should
235 // not matter.
236 mReorderStash.emplace_back(
237 buffer, notify, timestamp, flags, format, ordinal);
238 } else {
239 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
240 auto it = mReorderStash.begin();
241 for (; it != mReorderStash.end(); ++it) {
242 if (less(ordinal, it->ordinal)) {
243 break;
244 }
245 }
246 mReorderStash.emplace(it,
247 buffer, notify, timestamp, flags, format, ordinal);
248 if (eos) {
249 mReorderStash.back().flags =
250 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
251 }
252 }
253 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
254 mPending.push_back(mReorderStash.front());
255 mReorderStash.pop_front();
256 }
257 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
258}
259
260OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
261 std::shared_ptr<C2Buffer>* c2Buffer,
262 size_t* index,
263 sp<MediaCodecBuffer>* outBuffer) {
264 if (mPending.empty()) {
265 return SKIP;
266 }
267
268 // Retrieve the first entry.
269 StashEntry &entry = mPending.front();
270
271 *c2Buffer = entry.buffer;
272 sp<AMessage> outputFormat = entry.format;
273
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800274 if (entry.notify && mFormat != outputFormat) {
275 updateSkipCutBuffer(outputFormat);
276 sp<ABuffer> imageData;
277 if (mFormat->findBuffer("image-data", &imageData)) {
278 outputFormat->setBuffer("image-data", imageData);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700279 }
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800280 int32_t stride;
281 if (mFormat->findInt32(KEY_STRIDE, &stride)) {
282 outputFormat->setInt32(KEY_STRIDE, stride);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700283 }
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800284 int32_t sliceHeight;
285 if (mFormat->findInt32(KEY_SLICE_HEIGHT, &sliceHeight)) {
286 outputFormat->setInt32(KEY_SLICE_HEIGHT, sliceHeight);
287 }
288 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
289 mName, mFormat.get(), outputFormat.get());
290 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
291 mName, outputFormat->debugString().c_str());
292 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700293 }
294
295 // Flushing mReorderStash because no other buffers should come after output
296 // EOS.
297 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
298 // Flush reorder stash
299 setReorderDepth(0);
300 }
301
302 if (!entry.notify) {
303 mPending.pop_front();
304 return DISCARD;
305 }
306
307 // Try to register the buffer.
308 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
309 if (err != OK) {
310 if (err != WOULD_BLOCK) {
311 return REALLOCATE;
312 }
313 return RETRY;
314 }
315
316 // Append information from the front stash entry to outBuffer.
317 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
318 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park2eef13e2020-06-12 17:24:21 +0900319 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700320 ALOGV("[%s] popFromStashAndRegister: "
321 "out buffer index = %zu [%p] => %p + %zu (%lld)",
322 mName, *index, outBuffer->get(),
323 (*outBuffer)->data(), (*outBuffer)->size(),
324 (long long)entry.timestamp);
325
326 // The front entry of mPending will be removed now that the registration
327 // succeeded.
328 mPending.pop_front();
329 return NOTIFY_CLIENT;
330}
331
332bool OutputBuffers::popPending(StashEntry *entry) {
333 if (mPending.empty()) {
334 return false;
335 }
336 *entry = mPending.front();
337 mPending.pop_front();
338 return true;
339}
340
341void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
342 mPending.push_front(entry);
343}
344
345bool OutputBuffers::hasPending() const {
346 return !mPending.empty();
347}
348
349bool OutputBuffers::less(
350 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
351 switch (mKey) {
352 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
353 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
354 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
355 default:
356 ALOGD("Unrecognized key; default to timestamp");
357 return o1.frameIndex < o2.frameIndex;
358 }
359}
360
Wonsik Kim469c8342019-04-11 16:46:09 -0700361// LocalBufferPool
362
Wonsik Kim41d83432020-04-27 16:40:49 -0700363constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
364constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
365
366std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
367 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700368}
369
370sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
371 Mutex::Autolock lock(mMutex);
372 auto it = std::find_if(
373 mPool.begin(), mPool.end(),
374 [capacity](const std::vector<uint8_t> &vec) {
375 return vec.capacity() >= capacity;
376 });
377 if (it != mPool.end()) {
378 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
379 mPool.erase(it);
380 return buffer;
381 }
382 if (mUsedSize + capacity > mPoolCapacity) {
383 while (!mPool.empty()) {
384 mUsedSize -= mPool.back().capacity();
385 mPool.pop_back();
386 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700387 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
388 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
389 mPoolCapacity, mPoolCapacity * 2);
390 mPoolCapacity *= 2;
391 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700392 if (mUsedSize + capacity > mPoolCapacity) {
393 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
394 mUsedSize, capacity, mPoolCapacity);
395 return nullptr;
396 }
397 }
398 std::vector<uint8_t> vec(capacity);
399 mUsedSize += vec.capacity();
400 return new VectorBuffer(std::move(vec), shared_from_this());
401}
402
403LocalBufferPool::VectorBuffer::VectorBuffer(
404 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
405 : ABuffer(vec.data(), vec.capacity()),
406 mVec(std::move(vec)),
407 mPool(pool) {
408}
409
410LocalBufferPool::VectorBuffer::~VectorBuffer() {
411 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
412 if (pool) {
413 // If pool is alive, return the vector back to the pool so that
414 // it can be recycled.
415 pool->returnVector(std::move(mVec));
416 }
417}
418
419void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
420 Mutex::Autolock lock(mMutex);
421 mPool.push_front(std::move(vec));
422}
423
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700424// FlexBuffersImpl
425
Wonsik Kim469c8342019-04-11 16:46:09 -0700426size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
427 for (size_t i = 0; i < mBuffers.size(); ++i) {
428 if (mBuffers[i].clientBuffer == nullptr
429 && mBuffers[i].compBuffer.expired()) {
430 mBuffers[i].clientBuffer = buffer;
431 return i;
432 }
433 }
434 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
435 return mBuffers.size() - 1;
436}
437
Wonsik Kim469c8342019-04-11 16:46:09 -0700438bool FlexBuffersImpl::releaseSlot(
439 const sp<MediaCodecBuffer> &buffer,
440 std::shared_ptr<C2Buffer> *c2buffer,
441 bool release) {
442 sp<Codec2Buffer> clientBuffer;
443 size_t index = mBuffers.size();
444 for (size_t i = 0; i < mBuffers.size(); ++i) {
445 if (mBuffers[i].clientBuffer == buffer) {
446 clientBuffer = mBuffers[i].clientBuffer;
447 if (release) {
448 mBuffers[i].clientBuffer.clear();
449 }
450 index = i;
451 break;
452 }
453 }
454 if (clientBuffer == nullptr) {
455 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
456 return false;
457 }
458 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
459 if (!result) {
460 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700461 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700462 mBuffers[index].compBuffer = result;
463 }
464 if (c2buffer) {
465 *c2buffer = result;
466 }
467 return true;
468}
469
470bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
471 for (size_t i = 0; i < mBuffers.size(); ++i) {
472 std::shared_ptr<C2Buffer> compBuffer =
473 mBuffers[i].compBuffer.lock();
474 if (!compBuffer || compBuffer != c2buffer) {
475 continue;
476 }
477 mBuffers[i].compBuffer.reset();
478 ALOGV("[%s] codec released buffer #%zu", mName, i);
479 return true;
480 }
481 ALOGV("[%s] codec released an unknown buffer", mName);
482 return false;
483}
484
485void FlexBuffersImpl::flush() {
486 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
487 mBuffers.clear();
488}
489
Wonsik Kim0487b782020-10-28 11:45:50 -0700490size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700491 return std::count_if(
492 mBuffers.begin(), mBuffers.end(),
493 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700494 return (entry.clientBuffer != nullptr
495 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700496 });
497}
498
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700499size_t FlexBuffersImpl::numComponentBuffers() const {
500 return std::count_if(
501 mBuffers.begin(), mBuffers.end(),
502 [](const Entry &entry) {
503 return !entry.compBuffer.expired();
504 });
505}
506
Wonsik Kim469c8342019-04-11 16:46:09 -0700507// BuffersArrayImpl
508
509void BuffersArrayImpl::initialize(
510 const FlexBuffersImpl &impl,
511 size_t minSize,
512 std::function<sp<Codec2Buffer>()> allocate) {
513 mImplName = impl.mImplName + "[N]";
514 mName = mImplName.c_str();
515 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
516 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
517 bool ownedByClient = (clientBuffer != nullptr);
518 if (!ownedByClient) {
519 clientBuffer = allocate();
520 }
521 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
522 }
523 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
524 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
525 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
526 }
527}
528
529status_t BuffersArrayImpl::grabBuffer(
530 size_t *index,
531 sp<Codec2Buffer> *buffer,
532 std::function<bool(const sp<Codec2Buffer> &)> match) {
533 // allBuffersDontMatch remains true if all buffers are available but
534 // match() returns false for every buffer.
535 bool allBuffersDontMatch = true;
536 for (size_t i = 0; i < mBuffers.size(); ++i) {
537 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
538 if (match(mBuffers[i].clientBuffer)) {
539 mBuffers[i].ownedByClient = true;
540 *buffer = mBuffers[i].clientBuffer;
541 (*buffer)->meta()->clear();
542 (*buffer)->setRange(0, (*buffer)->capacity());
543 *index = i;
544 return OK;
545 }
546 } else {
547 allBuffersDontMatch = false;
548 }
549 }
550 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
551}
552
553bool BuffersArrayImpl::returnBuffer(
554 const sp<MediaCodecBuffer> &buffer,
555 std::shared_ptr<C2Buffer> *c2buffer,
556 bool release) {
557 sp<Codec2Buffer> clientBuffer;
558 size_t index = mBuffers.size();
559 for (size_t i = 0; i < mBuffers.size(); ++i) {
560 if (mBuffers[i].clientBuffer == buffer) {
561 if (!mBuffers[i].ownedByClient) {
562 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
563 mName, i);
564 }
565 clientBuffer = mBuffers[i].clientBuffer;
566 if (release) {
567 mBuffers[i].ownedByClient = false;
568 }
569 index = i;
570 break;
571 }
572 }
573 if (clientBuffer == nullptr) {
574 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
575 return false;
576 }
577 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
578 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
579 if (!result) {
580 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700581 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700582 mBuffers[index].compBuffer = result;
583 }
584 if (c2buffer) {
585 *c2buffer = result;
586 }
587 return true;
588}
589
590bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
591 for (size_t i = 0; i < mBuffers.size(); ++i) {
592 std::shared_ptr<C2Buffer> compBuffer =
593 mBuffers[i].compBuffer.lock();
594 if (!compBuffer) {
595 continue;
596 }
597 if (c2buffer == compBuffer) {
598 if (mBuffers[i].ownedByClient) {
599 // This should not happen.
600 ALOGD("[%s] codec released a buffer owned by client "
601 "(index %zu)", mName, i);
602 }
603 mBuffers[i].compBuffer.reset();
604 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
605 return true;
606 }
607 }
608 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
609 return false;
610}
611
612void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
613 array->clear();
614 for (const Entry &entry : mBuffers) {
615 array->push(entry.clientBuffer);
616 }
617}
618
619void BuffersArrayImpl::flush() {
620 for (Entry &entry : mBuffers) {
621 entry.ownedByClient = false;
622 }
623}
624
625void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
626 size_t size = mBuffers.size();
627 mBuffers.clear();
628 for (size_t i = 0; i < size; ++i) {
629 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
630 }
631}
632
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700633void BuffersArrayImpl::grow(
634 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
635 CHECK_LT(mBuffers.size(), newSize);
636 while (mBuffers.size() < newSize) {
637 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
638 }
639}
640
Wonsik Kim0487b782020-10-28 11:45:50 -0700641size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700642 return std::count_if(
643 mBuffers.begin(), mBuffers.end(),
644 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700645 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700646 });
647}
648
Wonsik Kima39882b2019-06-20 16:13:56 -0700649size_t BuffersArrayImpl::arraySize() const {
650 return mBuffers.size();
651}
652
Wonsik Kim469c8342019-04-11 16:46:09 -0700653// InputBuffersArray
654
655void InputBuffersArray::initialize(
656 const FlexBuffersImpl &impl,
657 size_t minSize,
658 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700659 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700660 mImpl.initialize(impl, minSize, allocate);
661}
662
663void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
664 mImpl.getArray(array);
665}
666
667bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
668 sp<Codec2Buffer> c2Buffer;
669 status_t err = mImpl.grabBuffer(index, &c2Buffer);
670 if (err == OK) {
671 c2Buffer->setFormat(mFormat);
672 handleImageData(c2Buffer);
673 *buffer = c2Buffer;
674 return true;
675 }
676 return false;
677}
678
679bool InputBuffersArray::releaseBuffer(
680 const sp<MediaCodecBuffer> &buffer,
681 std::shared_ptr<C2Buffer> *c2buffer,
682 bool release) {
683 return mImpl.returnBuffer(buffer, c2buffer, release);
684}
685
686bool InputBuffersArray::expireComponentBuffer(
687 const std::shared_ptr<C2Buffer> &c2buffer) {
688 return mImpl.expireComponentBuffer(c2buffer);
689}
690
691void InputBuffersArray::flush() {
692 mImpl.flush();
693}
694
Wonsik Kim0487b782020-10-28 11:45:50 -0700695size_t InputBuffersArray::numActiveSlots() const {
696 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700697}
698
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700699sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
700 return mAllocate();
701}
702
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800703// SlotInputBuffers
704
705bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
706 sp<Codec2Buffer> newBuffer = createNewBuffer();
707 *index = mImpl.assignSlot(newBuffer);
708 *buffer = newBuffer;
709 return true;
710}
711
712bool SlotInputBuffers::releaseBuffer(
713 const sp<MediaCodecBuffer> &buffer,
714 std::shared_ptr<C2Buffer> *c2buffer,
715 bool release) {
716 return mImpl.releaseSlot(buffer, c2buffer, release);
717}
718
719bool SlotInputBuffers::expireComponentBuffer(
720 const std::shared_ptr<C2Buffer> &c2buffer) {
721 return mImpl.expireComponentBuffer(c2buffer);
722}
723
724void SlotInputBuffers::flush() {
725 mImpl.flush();
726}
727
728std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
729 TRESPASS("Array mode should not be called at non-legacy mode");
730 return nullptr;
731}
732
Wonsik Kim0487b782020-10-28 11:45:50 -0700733size_t SlotInputBuffers::numActiveSlots() const {
734 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800735}
736
737sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
738 return new DummyContainerBuffer{mFormat, nullptr};
739}
740
Wonsik Kim469c8342019-04-11 16:46:09 -0700741// LinearInputBuffers
742
743bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700744 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700745 if (newBuffer == nullptr) {
746 return false;
747 }
748 *index = mImpl.assignSlot(newBuffer);
749 *buffer = newBuffer;
750 return true;
751}
752
753bool LinearInputBuffers::releaseBuffer(
754 const sp<MediaCodecBuffer> &buffer,
755 std::shared_ptr<C2Buffer> *c2buffer,
756 bool release) {
757 return mImpl.releaseSlot(buffer, c2buffer, release);
758}
759
760bool LinearInputBuffers::expireComponentBuffer(
761 const std::shared_ptr<C2Buffer> &c2buffer) {
762 return mImpl.expireComponentBuffer(c2buffer);
763}
764
765void LinearInputBuffers::flush() {
766 // This is no-op by default unless we're in array mode where we need to keep
767 // track of the flushed work.
768 mImpl.flush();
769}
770
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700771std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700772 std::unique_ptr<InputBuffersArray> array(
773 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
774 array->setPool(mPool);
775 array->setFormat(mFormat);
776 array->initialize(
777 mImpl,
778 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700779 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
780 return Alloc(pool, format);
781 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700782 return std::move(array);
783}
784
Wonsik Kim0487b782020-10-28 11:45:50 -0700785size_t LinearInputBuffers::numActiveSlots() const {
786 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700787}
788
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700789// static
790sp<Codec2Buffer> LinearInputBuffers::Alloc(
791 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
792 int32_t capacity = kLinearBufferSize;
793 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
794 if ((size_t)capacity > kMaxLinearBufferSize) {
795 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
796 capacity = kMaxLinearBufferSize;
797 }
798
Wonsik Kim666604a2020-05-14 16:57:49 -0700799 int64_t usageValue = 0;
800 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
801 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -0700802 std::shared_ptr<C2LinearBlock> block;
803
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700804 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700805 if (err != C2_OK) {
806 return nullptr;
807 }
808
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700809 return LinearBlockBuffer::Allocate(format, block);
810}
811
812sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
813 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700814}
815
816// EncryptedLinearInputBuffers
817
818EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
819 bool secure,
820 const sp<MemoryDealer> &dealer,
821 const sp<ICrypto> &crypto,
822 int32_t heapSeqNum,
823 size_t capacity,
824 size_t numInputSlots,
825 const char *componentName, const char *name)
826 : LinearInputBuffers(componentName, name),
827 mUsage({0, 0}),
828 mDealer(dealer),
829 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700830 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700831 if (secure) {
832 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
833 } else {
834 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
835 }
836 for (size_t i = 0; i < numInputSlots; ++i) {
837 sp<IMemory> memory = mDealer->allocate(capacity);
838 if (memory == nullptr) {
839 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
840 mName, i);
841 break;
842 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700843 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700844 }
845}
846
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700847std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
848 std::unique_ptr<InputBuffersArray> array(
849 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
850 array->setPool(mPool);
851 array->setFormat(mFormat);
852 array->initialize(
853 mImpl,
854 size,
855 [pool = mPool,
856 format = mFormat,
857 usage = mUsage,
858 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
859 return Alloc(pool, format, usage, memoryVector);
860 });
861 return std::move(array);
862}
863
864
865// static
866sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
867 const std::shared_ptr<C2BlockPool> &pool,
868 const sp<AMessage> &format,
869 C2MemoryUsage usage,
870 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
871 int32_t capacity = kLinearBufferSize;
872 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
873 if ((size_t)capacity > kMaxLinearBufferSize) {
874 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
875 capacity = kMaxLinearBufferSize;
876 }
877
Wonsik Kim469c8342019-04-11 16:46:09 -0700878 sp<IMemory> memory;
879 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700880 int32_t heapSeqNum = -1;
881 for (; slot < memoryVector->size(); ++slot) {
882 if (memoryVector->at(slot).block.expired()) {
883 memory = memoryVector->at(slot).memory;
884 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700885 break;
886 }
887 }
888 if (memory == nullptr) {
889 return nullptr;
890 }
891
892 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700893 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700894 if (err != C2_OK || block == nullptr) {
895 return nullptr;
896 }
897
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700898 memoryVector->at(slot).block = block;
899 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
900}
901
902sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
903 // TODO: android_2020
904 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700905}
906
907// GraphicMetadataInputBuffers
908
909GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
910 const char *componentName, const char *name)
911 : InputBuffers(componentName, name),
912 mImpl(mName),
913 mStore(GetCodec2PlatformAllocatorStore()) { }
914
915bool GraphicMetadataInputBuffers::requestNewBuffer(
916 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700917 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700918 if (newBuffer == nullptr) {
919 return false;
920 }
921 *index = mImpl.assignSlot(newBuffer);
922 *buffer = newBuffer;
923 return true;
924}
925
926bool GraphicMetadataInputBuffers::releaseBuffer(
927 const sp<MediaCodecBuffer> &buffer,
928 std::shared_ptr<C2Buffer> *c2buffer,
929 bool release) {
930 return mImpl.releaseSlot(buffer, c2buffer, release);
931}
932
933bool GraphicMetadataInputBuffers::expireComponentBuffer(
934 const std::shared_ptr<C2Buffer> &c2buffer) {
935 return mImpl.expireComponentBuffer(c2buffer);
936}
937
938void GraphicMetadataInputBuffers::flush() {
939 // This is no-op by default unless we're in array mode where we need to keep
940 // track of the flushed work.
941}
942
943std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
944 size_t size) {
945 std::shared_ptr<C2Allocator> alloc;
946 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
947 if (err != C2_OK) {
948 return nullptr;
949 }
950 std::unique_ptr<InputBuffersArray> array(
951 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
952 array->setPool(mPool);
953 array->setFormat(mFormat);
954 array->initialize(
955 mImpl,
956 size,
957 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
958 return new GraphicMetadataBuffer(format, alloc);
959 });
960 return std::move(array);
961}
962
Wonsik Kim0487b782020-10-28 11:45:50 -0700963size_t GraphicMetadataInputBuffers::numActiveSlots() const {
964 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700965}
966
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700967sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
968 std::shared_ptr<C2Allocator> alloc;
969 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
970 if (err != C2_OK) {
971 return nullptr;
972 }
973 return new GraphicMetadataBuffer(mFormat, alloc);
974}
975
Wonsik Kim469c8342019-04-11 16:46:09 -0700976// GraphicInputBuffers
977
978GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700979 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700980 : InputBuffers(componentName, name),
981 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700982 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700983
984bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700985 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700986 if (newBuffer == nullptr) {
987 return false;
988 }
989 *index = mImpl.assignSlot(newBuffer);
990 handleImageData(newBuffer);
991 *buffer = newBuffer;
992 return true;
993}
994
995bool GraphicInputBuffers::releaseBuffer(
996 const sp<MediaCodecBuffer> &buffer,
997 std::shared_ptr<C2Buffer> *c2buffer,
998 bool release) {
999 return mImpl.releaseSlot(buffer, c2buffer, release);
1000}
1001
1002bool GraphicInputBuffers::expireComponentBuffer(
1003 const std::shared_ptr<C2Buffer> &c2buffer) {
1004 return mImpl.expireComponentBuffer(c2buffer);
1005}
1006
1007void GraphicInputBuffers::flush() {
1008 // This is no-op by default unless we're in array mode where we need to keep
1009 // track of the flushed work.
1010}
1011
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001012static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1013 int32_t frameworkColorFormat = 0;
1014 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1015 return PIXEL_FORMAT_UNKNOWN;
1016 }
1017 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1018 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1019 return pixelFormat;
1020 }
1021 return PIXEL_FORMAT_UNKNOWN;
1022}
1023
Wonsik Kim469c8342019-04-11 16:46:09 -07001024std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1025 std::unique_ptr<InputBuffersArray> array(
1026 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1027 array->setPool(mPool);
1028 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001029 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001030 array->initialize(
1031 mImpl,
1032 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001033 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1034 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001035 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1036 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001037 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001038 });
1039 return std::move(array);
1040}
1041
Wonsik Kim0487b782020-10-28 11:45:50 -07001042size_t GraphicInputBuffers::numActiveSlots() const {
1043 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001044}
1045
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001046sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
Wonsik Kim666604a2020-05-14 16:57:49 -07001047 int64_t usageValue = 0;
1048 (void)mFormat->findInt64("android._C2MemoryUsage", &usageValue);
1049 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001050 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001051 mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001052}
1053
Wonsik Kim469c8342019-04-11 16:46:09 -07001054// OutputBuffersArray
1055
1056void OutputBuffersArray::initialize(
1057 const FlexBuffersImpl &impl,
1058 size_t minSize,
1059 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001060 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001061 mImpl.initialize(impl, minSize, allocate);
1062}
1063
1064status_t OutputBuffersArray::registerBuffer(
1065 const std::shared_ptr<C2Buffer> &buffer,
1066 size_t *index,
1067 sp<MediaCodecBuffer> *clientBuffer) {
1068 sp<Codec2Buffer> c2Buffer;
1069 status_t err = mImpl.grabBuffer(
1070 index,
1071 &c2Buffer,
1072 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1073 return clientBuffer->canCopy(buffer);
1074 });
1075 if (err == WOULD_BLOCK) {
1076 ALOGV("[%s] buffers temporarily not available", mName);
1077 return err;
1078 } else if (err != OK) {
1079 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1080 return err;
1081 }
1082 c2Buffer->setFormat(mFormat);
1083 if (!c2Buffer->copy(buffer)) {
1084 ALOGD("[%s] copy buffer failed", mName);
1085 return WOULD_BLOCK;
1086 }
1087 submit(c2Buffer);
1088 handleImageData(c2Buffer);
1089 *clientBuffer = c2Buffer;
1090 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1091 return OK;
1092}
1093
1094status_t OutputBuffersArray::registerCsd(
1095 const C2StreamInitDataInfo::output *csd,
1096 size_t *index,
1097 sp<MediaCodecBuffer> *clientBuffer) {
1098 sp<Codec2Buffer> c2Buffer;
1099 status_t err = mImpl.grabBuffer(
1100 index,
1101 &c2Buffer,
1102 [csd](const sp<Codec2Buffer> &clientBuffer) {
1103 return clientBuffer->base() != nullptr
1104 && clientBuffer->capacity() >= csd->flexCount();
1105 });
1106 if (err != OK) {
1107 return err;
1108 }
1109 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1110 c2Buffer->setRange(0, csd->flexCount());
1111 c2Buffer->setFormat(mFormat);
1112 *clientBuffer = c2Buffer;
1113 return OK;
1114}
1115
1116bool OutputBuffersArray::releaseBuffer(
1117 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1118 return mImpl.returnBuffer(buffer, c2buffer, true);
1119}
1120
1121void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1122 (void)flushedWork;
1123 mImpl.flush();
1124 if (mSkipCutBuffer != nullptr) {
1125 mSkipCutBuffer->clear();
1126 }
1127}
1128
1129void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1130 mImpl.getArray(array);
1131}
1132
Wonsik Kim0487b782020-10-28 11:45:50 -07001133size_t OutputBuffersArray::numActiveSlots() const {
1134 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001135}
1136
Wonsik Kim469c8342019-04-11 16:46:09 -07001137void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001138 switch (c2buffer->data().type()) {
1139 case C2BufferData::LINEAR: {
1140 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001141 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1142 const uint32_t block_size = linear_blocks.front().size();
1143 if (block_size < kMaxLinearBufferSize / 2) {
1144 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001145 } else {
1146 size = kMaxLinearBufferSize;
1147 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001148 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001149 return new LocalLinearBuffer(format, new ABuffer(size));
1150 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001151 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001152 break;
1153 }
1154
Wonsik Kima39882b2019-06-20 16:13:56 -07001155 case C2BufferData::GRAPHIC: {
1156 // This is only called for RawGraphicOutputBuffers.
1157 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001158 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001159 return ConstGraphicBlockBuffer::AllocateEmpty(
1160 format,
1161 [lbp](size_t capacity) {
1162 return lbp->newBuffer(capacity);
1163 });
1164 };
1165 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1166 mName, mFormat->debugString().c_str());
1167 break;
1168 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001169
1170 case C2BufferData::INVALID: [[fallthrough]];
1171 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1172 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1173 default:
1174 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1175 return;
1176 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001177 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001178}
1179
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001180void OutputBuffersArray::grow(size_t newSize) {
1181 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001182}
1183
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001184void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1185 mFormat = source->mFormat;
1186 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001187 mPending = std::move(source->mPending);
1188 mReorderStash = std::move(source->mReorderStash);
1189 mDepth = source->mDepth;
1190 mKey = source->mKey;
1191}
1192
Wonsik Kim469c8342019-04-11 16:46:09 -07001193// FlexOutputBuffers
1194
1195status_t FlexOutputBuffers::registerBuffer(
1196 const std::shared_ptr<C2Buffer> &buffer,
1197 size_t *index,
1198 sp<MediaCodecBuffer> *clientBuffer) {
1199 sp<Codec2Buffer> newBuffer = wrap(buffer);
1200 if (newBuffer == nullptr) {
1201 return NO_MEMORY;
1202 }
1203 newBuffer->setFormat(mFormat);
1204 *index = mImpl.assignSlot(newBuffer);
1205 handleImageData(newBuffer);
1206 *clientBuffer = newBuffer;
1207 ALOGV("[%s] registered buffer %zu", mName, *index);
1208 return OK;
1209}
1210
1211status_t FlexOutputBuffers::registerCsd(
1212 const C2StreamInitDataInfo::output *csd,
1213 size_t *index,
1214 sp<MediaCodecBuffer> *clientBuffer) {
1215 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1216 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1217 *index = mImpl.assignSlot(newBuffer);
1218 *clientBuffer = newBuffer;
1219 return OK;
1220}
1221
1222bool FlexOutputBuffers::releaseBuffer(
1223 const sp<MediaCodecBuffer> &buffer,
1224 std::shared_ptr<C2Buffer> *c2buffer) {
1225 return mImpl.releaseSlot(buffer, c2buffer, true);
1226}
1227
1228void FlexOutputBuffers::flush(
1229 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1230 (void) flushedWork;
1231 // This is no-op by default unless we're in array mode where we need to keep
1232 // track of the flushed work.
1233}
1234
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001235std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001236 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001237 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001238 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1239 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001240 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001241}
1242
Wonsik Kim0487b782020-10-28 11:45:50 -07001243size_t FlexOutputBuffers::numActiveSlots() const {
1244 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001245}
1246
1247// LinearOutputBuffers
1248
1249void LinearOutputBuffers::flush(
1250 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1251 if (mSkipCutBuffer != nullptr) {
1252 mSkipCutBuffer->clear();
1253 }
1254 FlexOutputBuffers::flush(flushedWork);
1255}
1256
1257sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1258 if (buffer == nullptr) {
1259 ALOGV("[%s] using a dummy buffer", mName);
1260 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1261 }
1262 if (buffer->data().type() != C2BufferData::LINEAR) {
1263 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1264 // We expect linear output buffers from the component.
1265 return nullptr;
1266 }
1267 if (buffer->data().linearBlocks().size() != 1u) {
1268 ALOGV("[%s] no linear buffers", mName);
1269 // We expect one and only one linear block from the component.
1270 return nullptr;
1271 }
1272 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1273 if (clientBuffer == nullptr) {
1274 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1275 return nullptr;
1276 }
1277 submit(clientBuffer);
1278 return clientBuffer;
1279}
1280
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001281std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1282 return [format = mFormat]{
1283 // TODO: proper max output size
1284 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1285 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001286}
1287
1288// GraphicOutputBuffers
1289
1290sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1291 return new DummyContainerBuffer(mFormat, buffer);
1292}
1293
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001294std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1295 return [format = mFormat]{
1296 return new DummyContainerBuffer(format);
1297 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001298}
1299
1300// RawGraphicOutputBuffers
1301
1302RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001303 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001304 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001305 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001306
1307sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1308 if (buffer == nullptr) {
1309 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1310 mFormat,
1311 [lbp = mLocalBufferPool](size_t capacity) {
1312 return lbp->newBuffer(capacity);
1313 });
1314 if (c2buffer == nullptr) {
1315 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1316 return nullptr;
1317 }
1318 c2buffer->setRange(0, 0);
1319 return c2buffer;
1320 } else {
1321 return ConstGraphicBlockBuffer::Allocate(
1322 mFormat,
1323 buffer,
1324 [lbp = mLocalBufferPool](size_t capacity) {
1325 return lbp->newBuffer(capacity);
1326 });
1327 }
1328}
1329
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001330std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1331 return [format = mFormat, lbp = mLocalBufferPool]{
1332 return ConstGraphicBlockBuffer::AllocateEmpty(
1333 format,
1334 [lbp](size_t capacity) {
1335 return lbp->newBuffer(capacity);
1336 });
1337 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001338}
1339
1340} // namespace android