blob: adcead4463db7dfa43c95807f0f21729276a9471 [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 Kim970bf0b2020-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 Kim970bf0b2020-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 Kim970bf0b2020-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 Kim970bf0b2020-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);
319 ALOGV("[%s] popFromStashAndRegister: "
320 "out buffer index = %zu [%p] => %p + %zu (%lld)",
321 mName, *index, outBuffer->get(),
322 (*outBuffer)->data(), (*outBuffer)->size(),
323 (long long)entry.timestamp);
324
325 // The front entry of mPending will be removed now that the registration
326 // succeeded.
327 mPending.pop_front();
328 return NOTIFY_CLIENT;
329}
330
331bool OutputBuffers::popPending(StashEntry *entry) {
332 if (mPending.empty()) {
333 return false;
334 }
335 *entry = mPending.front();
336 mPending.pop_front();
337 return true;
338}
339
340void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
341 mPending.push_front(entry);
342}
343
344bool OutputBuffers::hasPending() const {
345 return !mPending.empty();
346}
347
348bool OutputBuffers::less(
349 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
350 switch (mKey) {
351 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
352 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
353 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
354 default:
355 ALOGD("Unrecognized key; default to timestamp");
356 return o1.frameIndex < o2.frameIndex;
357 }
358}
359
Wonsik Kim469c8342019-04-11 16:46:09 -0700360// LocalBufferPool
361
Wonsik Kim41d83432020-04-27 16:40:49 -0700362constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
363constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
364
365std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
366 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700367}
368
369sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
370 Mutex::Autolock lock(mMutex);
371 auto it = std::find_if(
372 mPool.begin(), mPool.end(),
373 [capacity](const std::vector<uint8_t> &vec) {
374 return vec.capacity() >= capacity;
375 });
376 if (it != mPool.end()) {
377 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
378 mPool.erase(it);
379 return buffer;
380 }
381 if (mUsedSize + capacity > mPoolCapacity) {
382 while (!mPool.empty()) {
383 mUsedSize -= mPool.back().capacity();
384 mPool.pop_back();
385 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700386 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
387 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
388 mPoolCapacity, mPoolCapacity * 2);
389 mPoolCapacity *= 2;
390 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700391 if (mUsedSize + capacity > mPoolCapacity) {
392 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
393 mUsedSize, capacity, mPoolCapacity);
394 return nullptr;
395 }
396 }
397 std::vector<uint8_t> vec(capacity);
398 mUsedSize += vec.capacity();
399 return new VectorBuffer(std::move(vec), shared_from_this());
400}
401
402LocalBufferPool::VectorBuffer::VectorBuffer(
403 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
404 : ABuffer(vec.data(), vec.capacity()),
405 mVec(std::move(vec)),
406 mPool(pool) {
407}
408
409LocalBufferPool::VectorBuffer::~VectorBuffer() {
410 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
411 if (pool) {
412 // If pool is alive, return the vector back to the pool so that
413 // it can be recycled.
414 pool->returnVector(std::move(mVec));
415 }
416}
417
418void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
419 Mutex::Autolock lock(mMutex);
420 mPool.push_front(std::move(vec));
421}
422
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700423// FlexBuffersImpl
424
Wonsik Kim469c8342019-04-11 16:46:09 -0700425size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
426 for (size_t i = 0; i < mBuffers.size(); ++i) {
427 if (mBuffers[i].clientBuffer == nullptr
428 && mBuffers[i].compBuffer.expired()) {
429 mBuffers[i].clientBuffer = buffer;
430 return i;
431 }
432 }
433 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
434 return mBuffers.size() - 1;
435}
436
Wonsik Kim469c8342019-04-11 16:46:09 -0700437bool FlexBuffersImpl::releaseSlot(
438 const sp<MediaCodecBuffer> &buffer,
439 std::shared_ptr<C2Buffer> *c2buffer,
440 bool release) {
441 sp<Codec2Buffer> clientBuffer;
442 size_t index = mBuffers.size();
443 for (size_t i = 0; i < mBuffers.size(); ++i) {
444 if (mBuffers[i].clientBuffer == buffer) {
445 clientBuffer = mBuffers[i].clientBuffer;
446 if (release) {
447 mBuffers[i].clientBuffer.clear();
448 }
449 index = i;
450 break;
451 }
452 }
453 if (clientBuffer == nullptr) {
454 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
455 return false;
456 }
457 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
458 if (!result) {
459 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700460 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700461 mBuffers[index].compBuffer = result;
462 }
463 if (c2buffer) {
464 *c2buffer = result;
465 }
466 return true;
467}
468
469bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
470 for (size_t i = 0; i < mBuffers.size(); ++i) {
471 std::shared_ptr<C2Buffer> compBuffer =
472 mBuffers[i].compBuffer.lock();
473 if (!compBuffer || compBuffer != c2buffer) {
474 continue;
475 }
476 mBuffers[i].compBuffer.reset();
477 ALOGV("[%s] codec released buffer #%zu", mName, i);
478 return true;
479 }
480 ALOGV("[%s] codec released an unknown buffer", mName);
481 return false;
482}
483
484void FlexBuffersImpl::flush() {
485 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
486 mBuffers.clear();
487}
488
Wonsik Kim0487b782020-10-28 11:45:50 -0700489size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700490 return std::count_if(
491 mBuffers.begin(), mBuffers.end(),
492 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700493 return (entry.clientBuffer != nullptr
494 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700495 });
496}
497
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700498size_t FlexBuffersImpl::numComponentBuffers() const {
499 return std::count_if(
500 mBuffers.begin(), mBuffers.end(),
501 [](const Entry &entry) {
502 return !entry.compBuffer.expired();
503 });
504}
505
Wonsik Kim469c8342019-04-11 16:46:09 -0700506// BuffersArrayImpl
507
508void BuffersArrayImpl::initialize(
509 const FlexBuffersImpl &impl,
510 size_t minSize,
511 std::function<sp<Codec2Buffer>()> allocate) {
512 mImplName = impl.mImplName + "[N]";
513 mName = mImplName.c_str();
514 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
515 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
516 bool ownedByClient = (clientBuffer != nullptr);
517 if (!ownedByClient) {
518 clientBuffer = allocate();
519 }
520 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
521 }
522 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
523 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
524 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
525 }
526}
527
528status_t BuffersArrayImpl::grabBuffer(
529 size_t *index,
530 sp<Codec2Buffer> *buffer,
531 std::function<bool(const sp<Codec2Buffer> &)> match) {
532 // allBuffersDontMatch remains true if all buffers are available but
533 // match() returns false for every buffer.
534 bool allBuffersDontMatch = true;
535 for (size_t i = 0; i < mBuffers.size(); ++i) {
536 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
537 if (match(mBuffers[i].clientBuffer)) {
538 mBuffers[i].ownedByClient = true;
539 *buffer = mBuffers[i].clientBuffer;
540 (*buffer)->meta()->clear();
541 (*buffer)->setRange(0, (*buffer)->capacity());
542 *index = i;
543 return OK;
544 }
545 } else {
546 allBuffersDontMatch = false;
547 }
548 }
549 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
550}
551
552bool BuffersArrayImpl::returnBuffer(
553 const sp<MediaCodecBuffer> &buffer,
554 std::shared_ptr<C2Buffer> *c2buffer,
555 bool release) {
556 sp<Codec2Buffer> clientBuffer;
557 size_t index = mBuffers.size();
558 for (size_t i = 0; i < mBuffers.size(); ++i) {
559 if (mBuffers[i].clientBuffer == buffer) {
560 if (!mBuffers[i].ownedByClient) {
561 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
562 mName, i);
563 }
564 clientBuffer = mBuffers[i].clientBuffer;
565 if (release) {
566 mBuffers[i].ownedByClient = false;
567 }
568 index = i;
569 break;
570 }
571 }
572 if (clientBuffer == nullptr) {
573 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
574 return false;
575 }
576 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
577 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
578 if (!result) {
579 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700580 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700581 mBuffers[index].compBuffer = result;
582 }
583 if (c2buffer) {
584 *c2buffer = result;
585 }
586 return true;
587}
588
589bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
590 for (size_t i = 0; i < mBuffers.size(); ++i) {
591 std::shared_ptr<C2Buffer> compBuffer =
592 mBuffers[i].compBuffer.lock();
593 if (!compBuffer) {
594 continue;
595 }
596 if (c2buffer == compBuffer) {
597 if (mBuffers[i].ownedByClient) {
598 // This should not happen.
599 ALOGD("[%s] codec released a buffer owned by client "
600 "(index %zu)", mName, i);
601 }
602 mBuffers[i].compBuffer.reset();
603 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
604 return true;
605 }
606 }
607 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
608 return false;
609}
610
611void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
612 array->clear();
613 for (const Entry &entry : mBuffers) {
614 array->push(entry.clientBuffer);
615 }
616}
617
618void BuffersArrayImpl::flush() {
619 for (Entry &entry : mBuffers) {
620 entry.ownedByClient = false;
621 }
622}
623
624void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
625 size_t size = mBuffers.size();
626 mBuffers.clear();
627 for (size_t i = 0; i < size; ++i) {
628 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
629 }
630}
631
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700632void BuffersArrayImpl::grow(
633 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
634 CHECK_LT(mBuffers.size(), newSize);
635 while (mBuffers.size() < newSize) {
636 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
637 }
638}
639
Wonsik Kim0487b782020-10-28 11:45:50 -0700640size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700641 return std::count_if(
642 mBuffers.begin(), mBuffers.end(),
643 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700644 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700645 });
646}
647
Wonsik Kima39882b2019-06-20 16:13:56 -0700648size_t BuffersArrayImpl::arraySize() const {
649 return mBuffers.size();
650}
651
Wonsik Kim469c8342019-04-11 16:46:09 -0700652// InputBuffersArray
653
654void InputBuffersArray::initialize(
655 const FlexBuffersImpl &impl,
656 size_t minSize,
657 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700658 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700659 mImpl.initialize(impl, minSize, allocate);
660}
661
662void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
663 mImpl.getArray(array);
664}
665
666bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
667 sp<Codec2Buffer> c2Buffer;
668 status_t err = mImpl.grabBuffer(index, &c2Buffer);
669 if (err == OK) {
670 c2Buffer->setFormat(mFormat);
671 handleImageData(c2Buffer);
672 *buffer = c2Buffer;
673 return true;
674 }
675 return false;
676}
677
678bool InputBuffersArray::releaseBuffer(
679 const sp<MediaCodecBuffer> &buffer,
680 std::shared_ptr<C2Buffer> *c2buffer,
681 bool release) {
682 return mImpl.returnBuffer(buffer, c2buffer, release);
683}
684
685bool InputBuffersArray::expireComponentBuffer(
686 const std::shared_ptr<C2Buffer> &c2buffer) {
687 return mImpl.expireComponentBuffer(c2buffer);
688}
689
690void InputBuffersArray::flush() {
691 mImpl.flush();
692}
693
Wonsik Kim0487b782020-10-28 11:45:50 -0700694size_t InputBuffersArray::numActiveSlots() const {
695 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700696}
697
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700698sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
699 return mAllocate();
700}
701
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800702// SlotInputBuffers
703
704bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
705 sp<Codec2Buffer> newBuffer = createNewBuffer();
706 *index = mImpl.assignSlot(newBuffer);
707 *buffer = newBuffer;
708 return true;
709}
710
711bool SlotInputBuffers::releaseBuffer(
712 const sp<MediaCodecBuffer> &buffer,
713 std::shared_ptr<C2Buffer> *c2buffer,
714 bool release) {
715 return mImpl.releaseSlot(buffer, c2buffer, release);
716}
717
718bool SlotInputBuffers::expireComponentBuffer(
719 const std::shared_ptr<C2Buffer> &c2buffer) {
720 return mImpl.expireComponentBuffer(c2buffer);
721}
722
723void SlotInputBuffers::flush() {
724 mImpl.flush();
725}
726
727std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
728 TRESPASS("Array mode should not be called at non-legacy mode");
729 return nullptr;
730}
731
Wonsik Kim0487b782020-10-28 11:45:50 -0700732size_t SlotInputBuffers::numActiveSlots() const {
733 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800734}
735
736sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
737 return new DummyContainerBuffer{mFormat, nullptr};
738}
739
Wonsik Kim469c8342019-04-11 16:46:09 -0700740// LinearInputBuffers
741
742bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700743 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700744 if (newBuffer == nullptr) {
745 return false;
746 }
747 *index = mImpl.assignSlot(newBuffer);
748 *buffer = newBuffer;
749 return true;
750}
751
752bool LinearInputBuffers::releaseBuffer(
753 const sp<MediaCodecBuffer> &buffer,
754 std::shared_ptr<C2Buffer> *c2buffer,
755 bool release) {
756 return mImpl.releaseSlot(buffer, c2buffer, release);
757}
758
759bool LinearInputBuffers::expireComponentBuffer(
760 const std::shared_ptr<C2Buffer> &c2buffer) {
761 return mImpl.expireComponentBuffer(c2buffer);
762}
763
764void LinearInputBuffers::flush() {
765 // This is no-op by default unless we're in array mode where we need to keep
766 // track of the flushed work.
767 mImpl.flush();
768}
769
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700770std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700771 std::unique_ptr<InputBuffersArray> array(
772 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
773 array->setPool(mPool);
774 array->setFormat(mFormat);
775 array->initialize(
776 mImpl,
777 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700778 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
779 return Alloc(pool, format);
780 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700781 return std::move(array);
782}
783
Wonsik Kim0487b782020-10-28 11:45:50 -0700784size_t LinearInputBuffers::numActiveSlots() const {
785 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700786}
787
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700788// static
789sp<Codec2Buffer> LinearInputBuffers::Alloc(
790 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
791 int32_t capacity = kLinearBufferSize;
792 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
793 if ((size_t)capacity > kMaxLinearBufferSize) {
794 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
795 capacity = kMaxLinearBufferSize;
796 }
797
798 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700799 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
800 std::shared_ptr<C2LinearBlock> block;
801
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700802 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700803 if (err != C2_OK) {
804 return nullptr;
805 }
806
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700807 return LinearBlockBuffer::Allocate(format, block);
808}
809
810sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
811 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700812}
813
814// EncryptedLinearInputBuffers
815
816EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
817 bool secure,
818 const sp<MemoryDealer> &dealer,
819 const sp<ICrypto> &crypto,
820 int32_t heapSeqNum,
821 size_t capacity,
822 size_t numInputSlots,
823 const char *componentName, const char *name)
824 : LinearInputBuffers(componentName, name),
825 mUsage({0, 0}),
826 mDealer(dealer),
827 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700828 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700829 if (secure) {
830 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
831 } else {
832 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
833 }
834 for (size_t i = 0; i < numInputSlots; ++i) {
835 sp<IMemory> memory = mDealer->allocate(capacity);
836 if (memory == nullptr) {
837 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
838 mName, i);
839 break;
840 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700841 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700842 }
843}
844
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700845std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
846 std::unique_ptr<InputBuffersArray> array(
847 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
848 array->setPool(mPool);
849 array->setFormat(mFormat);
850 array->initialize(
851 mImpl,
852 size,
853 [pool = mPool,
854 format = mFormat,
855 usage = mUsage,
856 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
857 return Alloc(pool, format, usage, memoryVector);
858 });
859 return std::move(array);
860}
861
862
863// static
864sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
865 const std::shared_ptr<C2BlockPool> &pool,
866 const sp<AMessage> &format,
867 C2MemoryUsage usage,
868 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
869 int32_t capacity = kLinearBufferSize;
870 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
871 if ((size_t)capacity > kMaxLinearBufferSize) {
872 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
873 capacity = kMaxLinearBufferSize;
874 }
875
Wonsik Kim469c8342019-04-11 16:46:09 -0700876 sp<IMemory> memory;
877 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700878 int32_t heapSeqNum = -1;
879 for (; slot < memoryVector->size(); ++slot) {
880 if (memoryVector->at(slot).block.expired()) {
881 memory = memoryVector->at(slot).memory;
882 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700883 break;
884 }
885 }
886 if (memory == nullptr) {
887 return nullptr;
888 }
889
890 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700891 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700892 if (err != C2_OK || block == nullptr) {
893 return nullptr;
894 }
895
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700896 memoryVector->at(slot).block = block;
897 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
898}
899
900sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
901 // TODO: android_2020
902 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700903}
904
905// GraphicMetadataInputBuffers
906
907GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
908 const char *componentName, const char *name)
909 : InputBuffers(componentName, name),
910 mImpl(mName),
911 mStore(GetCodec2PlatformAllocatorStore()) { }
912
913bool GraphicMetadataInputBuffers::requestNewBuffer(
914 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700915 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700916 if (newBuffer == nullptr) {
917 return false;
918 }
919 *index = mImpl.assignSlot(newBuffer);
920 *buffer = newBuffer;
921 return true;
922}
923
924bool GraphicMetadataInputBuffers::releaseBuffer(
925 const sp<MediaCodecBuffer> &buffer,
926 std::shared_ptr<C2Buffer> *c2buffer,
927 bool release) {
928 return mImpl.releaseSlot(buffer, c2buffer, release);
929}
930
931bool GraphicMetadataInputBuffers::expireComponentBuffer(
932 const std::shared_ptr<C2Buffer> &c2buffer) {
933 return mImpl.expireComponentBuffer(c2buffer);
934}
935
936void GraphicMetadataInputBuffers::flush() {
937 // This is no-op by default unless we're in array mode where we need to keep
938 // track of the flushed work.
939}
940
941std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
942 size_t size) {
943 std::shared_ptr<C2Allocator> alloc;
944 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
945 if (err != C2_OK) {
946 return nullptr;
947 }
948 std::unique_ptr<InputBuffersArray> array(
949 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
950 array->setPool(mPool);
951 array->setFormat(mFormat);
952 array->initialize(
953 mImpl,
954 size,
955 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
956 return new GraphicMetadataBuffer(format, alloc);
957 });
958 return std::move(array);
959}
960
Wonsik Kim0487b782020-10-28 11:45:50 -0700961size_t GraphicMetadataInputBuffers::numActiveSlots() const {
962 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700963}
964
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700965sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
966 std::shared_ptr<C2Allocator> alloc;
967 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
968 if (err != C2_OK) {
969 return nullptr;
970 }
971 return new GraphicMetadataBuffer(mFormat, alloc);
972}
973
Wonsik Kim469c8342019-04-11 16:46:09 -0700974// GraphicInputBuffers
975
976GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700977 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700978 : InputBuffers(componentName, name),
979 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700980 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700981
982bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700983 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700984 if (newBuffer == nullptr) {
985 return false;
986 }
987 *index = mImpl.assignSlot(newBuffer);
988 handleImageData(newBuffer);
989 *buffer = newBuffer;
990 return true;
991}
992
993bool GraphicInputBuffers::releaseBuffer(
994 const sp<MediaCodecBuffer> &buffer,
995 std::shared_ptr<C2Buffer> *c2buffer,
996 bool release) {
997 return mImpl.releaseSlot(buffer, c2buffer, release);
998}
999
1000bool GraphicInputBuffers::expireComponentBuffer(
1001 const std::shared_ptr<C2Buffer> &c2buffer) {
1002 return mImpl.expireComponentBuffer(c2buffer);
1003}
1004
1005void GraphicInputBuffers::flush() {
1006 // This is no-op by default unless we're in array mode where we need to keep
1007 // track of the flushed work.
1008}
1009
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001010static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1011 int32_t frameworkColorFormat = 0;
1012 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1013 return PIXEL_FORMAT_UNKNOWN;
1014 }
1015 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1016 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1017 return pixelFormat;
1018 }
1019 return PIXEL_FORMAT_UNKNOWN;
1020}
1021
Wonsik Kim469c8342019-04-11 16:46:09 -07001022std::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);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001027 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001028 array->initialize(
1029 mImpl,
1030 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001031 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1032 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001033 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1034 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001035 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001036 });
1037 return std::move(array);
1038}
1039
Wonsik Kim0487b782020-10-28 11:45:50 -07001040size_t GraphicInputBuffers::numActiveSlots() const {
1041 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001042}
1043
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001044sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1045 // TODO: read usage from intf
1046 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1047 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001048 mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001049}
1050
Wonsik Kim469c8342019-04-11 16:46:09 -07001051// OutputBuffersArray
1052
1053void OutputBuffersArray::initialize(
1054 const FlexBuffersImpl &impl,
1055 size_t minSize,
1056 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001057 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001058 mImpl.initialize(impl, minSize, allocate);
1059}
1060
1061status_t OutputBuffersArray::registerBuffer(
1062 const std::shared_ptr<C2Buffer> &buffer,
1063 size_t *index,
1064 sp<MediaCodecBuffer> *clientBuffer) {
1065 sp<Codec2Buffer> c2Buffer;
1066 status_t err = mImpl.grabBuffer(
1067 index,
1068 &c2Buffer,
1069 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1070 return clientBuffer->canCopy(buffer);
1071 });
1072 if (err == WOULD_BLOCK) {
1073 ALOGV("[%s] buffers temporarily not available", mName);
1074 return err;
1075 } else if (err != OK) {
1076 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1077 return err;
1078 }
1079 c2Buffer->setFormat(mFormat);
1080 if (!c2Buffer->copy(buffer)) {
1081 ALOGD("[%s] copy buffer failed", mName);
1082 return WOULD_BLOCK;
1083 }
1084 submit(c2Buffer);
1085 handleImageData(c2Buffer);
1086 *clientBuffer = c2Buffer;
1087 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1088 return OK;
1089}
1090
1091status_t OutputBuffersArray::registerCsd(
1092 const C2StreamInitDataInfo::output *csd,
1093 size_t *index,
1094 sp<MediaCodecBuffer> *clientBuffer) {
1095 sp<Codec2Buffer> c2Buffer;
1096 status_t err = mImpl.grabBuffer(
1097 index,
1098 &c2Buffer,
1099 [csd](const sp<Codec2Buffer> &clientBuffer) {
1100 return clientBuffer->base() != nullptr
1101 && clientBuffer->capacity() >= csd->flexCount();
1102 });
1103 if (err != OK) {
1104 return err;
1105 }
1106 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1107 c2Buffer->setRange(0, csd->flexCount());
1108 c2Buffer->setFormat(mFormat);
1109 *clientBuffer = c2Buffer;
1110 return OK;
1111}
1112
1113bool OutputBuffersArray::releaseBuffer(
1114 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1115 return mImpl.returnBuffer(buffer, c2buffer, true);
1116}
1117
1118void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1119 (void)flushedWork;
1120 mImpl.flush();
1121 if (mSkipCutBuffer != nullptr) {
1122 mSkipCutBuffer->clear();
1123 }
1124}
1125
1126void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1127 mImpl.getArray(array);
1128}
1129
Wonsik Kim0487b782020-10-28 11:45:50 -07001130size_t OutputBuffersArray::numActiveSlots() const {
1131 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001132}
1133
Wonsik Kim469c8342019-04-11 16:46:09 -07001134void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001135 switch (c2buffer->data().type()) {
1136 case C2BufferData::LINEAR: {
1137 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001138 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1139 const uint32_t block_size = linear_blocks.front().size();
1140 if (block_size < kMaxLinearBufferSize / 2) {
1141 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001142 } else {
1143 size = kMaxLinearBufferSize;
1144 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001145 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001146 return new LocalLinearBuffer(format, new ABuffer(size));
1147 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001148 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001149 break;
1150 }
1151
Wonsik Kima39882b2019-06-20 16:13:56 -07001152 case C2BufferData::GRAPHIC: {
1153 // This is only called for RawGraphicOutputBuffers.
1154 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001155 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001156 return ConstGraphicBlockBuffer::AllocateEmpty(
1157 format,
1158 [lbp](size_t capacity) {
1159 return lbp->newBuffer(capacity);
1160 });
1161 };
1162 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1163 mName, mFormat->debugString().c_str());
1164 break;
1165 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001166
1167 case C2BufferData::INVALID: [[fallthrough]];
1168 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1169 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1170 default:
1171 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1172 return;
1173 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001174 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001175}
1176
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001177void OutputBuffersArray::grow(size_t newSize) {
1178 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001179}
1180
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001181void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1182 mFormat = source->mFormat;
1183 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001184 mPending = std::move(source->mPending);
1185 mReorderStash = std::move(source->mReorderStash);
1186 mDepth = source->mDepth;
1187 mKey = source->mKey;
1188}
1189
Wonsik Kim469c8342019-04-11 16:46:09 -07001190// FlexOutputBuffers
1191
1192status_t FlexOutputBuffers::registerBuffer(
1193 const std::shared_ptr<C2Buffer> &buffer,
1194 size_t *index,
1195 sp<MediaCodecBuffer> *clientBuffer) {
1196 sp<Codec2Buffer> newBuffer = wrap(buffer);
1197 if (newBuffer == nullptr) {
1198 return NO_MEMORY;
1199 }
1200 newBuffer->setFormat(mFormat);
1201 *index = mImpl.assignSlot(newBuffer);
1202 handleImageData(newBuffer);
1203 *clientBuffer = newBuffer;
1204 ALOGV("[%s] registered buffer %zu", mName, *index);
1205 return OK;
1206}
1207
1208status_t FlexOutputBuffers::registerCsd(
1209 const C2StreamInitDataInfo::output *csd,
1210 size_t *index,
1211 sp<MediaCodecBuffer> *clientBuffer) {
1212 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1213 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1214 *index = mImpl.assignSlot(newBuffer);
1215 *clientBuffer = newBuffer;
1216 return OK;
1217}
1218
1219bool FlexOutputBuffers::releaseBuffer(
1220 const sp<MediaCodecBuffer> &buffer,
1221 std::shared_ptr<C2Buffer> *c2buffer) {
1222 return mImpl.releaseSlot(buffer, c2buffer, true);
1223}
1224
1225void FlexOutputBuffers::flush(
1226 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1227 (void) flushedWork;
1228 // This is no-op by default unless we're in array mode where we need to keep
1229 // track of the flushed work.
1230}
1231
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001232std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001233 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001234 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001235 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1236 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001237 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001238}
1239
Wonsik Kim0487b782020-10-28 11:45:50 -07001240size_t FlexOutputBuffers::numActiveSlots() const {
1241 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001242}
1243
1244// LinearOutputBuffers
1245
1246void LinearOutputBuffers::flush(
1247 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1248 if (mSkipCutBuffer != nullptr) {
1249 mSkipCutBuffer->clear();
1250 }
1251 FlexOutputBuffers::flush(flushedWork);
1252}
1253
1254sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1255 if (buffer == nullptr) {
1256 ALOGV("[%s] using a dummy buffer", mName);
1257 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1258 }
1259 if (buffer->data().type() != C2BufferData::LINEAR) {
1260 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1261 // We expect linear output buffers from the component.
1262 return nullptr;
1263 }
1264 if (buffer->data().linearBlocks().size() != 1u) {
1265 ALOGV("[%s] no linear buffers", mName);
1266 // We expect one and only one linear block from the component.
1267 return nullptr;
1268 }
1269 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1270 if (clientBuffer == nullptr) {
1271 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1272 return nullptr;
1273 }
1274 submit(clientBuffer);
1275 return clientBuffer;
1276}
1277
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001278std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1279 return [format = mFormat]{
1280 // TODO: proper max output size
1281 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1282 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001283}
1284
1285// GraphicOutputBuffers
1286
1287sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1288 return new DummyContainerBuffer(mFormat, buffer);
1289}
1290
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001291std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1292 return [format = mFormat]{
1293 return new DummyContainerBuffer(format);
1294 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001295}
1296
1297// RawGraphicOutputBuffers
1298
1299RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001300 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001301 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001302 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001303
1304sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1305 if (buffer == nullptr) {
1306 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1307 mFormat,
1308 [lbp = mLocalBufferPool](size_t capacity) {
1309 return lbp->newBuffer(capacity);
1310 });
1311 if (c2buffer == nullptr) {
1312 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1313 return nullptr;
1314 }
1315 c2buffer->setRange(0, 0);
1316 return c2buffer;
1317 } else {
1318 return ConstGraphicBlockBuffer::Allocate(
1319 mFormat,
1320 buffer,
1321 [lbp = mLocalBufferPool](size_t capacity) {
1322 return lbp->newBuffer(capacity);
1323 });
1324 }
1325}
1326
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001327std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1328 return [format = mFormat, lbp = mLocalBufferPool]{
1329 return ConstGraphicBlockBuffer::AllocateEmpty(
1330 format,
1331 [lbp](size_t capacity) {
1332 return lbp->newBuffer(capacity);
1333 });
1334 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001335}
1336
1337} // namespace android