blob: 3c99bf63d215975494b4d190b0650eaa104dd433 [file] [log] [blame]
Wonsik Kim469c8342019-04-11 16:46:09 -07001/*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CCodecBuffers"
19#include <utils/Log.h>
20
21#include <C2PlatformSupport.h>
22
23#include <media/stagefright/foundation/ADebug.h>
Pawin Vongmasa9b906982020-04-11 05:07:15 -070024#include <media/stagefright/MediaCodec.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070025#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070026#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070027#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070028
29#include "CCodecBuffers.h"
30
31namespace android {
32
33namespace {
34
35sp<GraphicBlockBuffer> AllocateGraphicBuffer(
36 const std::shared_ptr<C2BlockPool> &pool,
37 const sp<AMessage> &format,
38 uint32_t pixelFormat,
39 const C2MemoryUsage &usage,
40 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
41 int32_t width, height;
42 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
43 ALOGD("format lacks width or height");
44 return nullptr;
45 }
46
47 std::shared_ptr<C2GraphicBlock> block;
48 c2_status_t err = pool->fetchGraphicBlock(
49 width, height, pixelFormat, usage, &block);
50 if (err != C2_OK) {
51 ALOGD("fetch graphic block failed: %d", err);
52 return nullptr;
53 }
54
55 return GraphicBlockBuffer::Allocate(
56 format,
57 block,
58 [localBufferPool](size_t capacity) {
59 return localBufferPool->newBuffer(capacity);
60 });
61}
62
63} // namespace
64
65// CCodecBuffers
66
67void CCodecBuffers::setFormat(const sp<AMessage> &format) {
68 CHECK(format != nullptr);
69 mFormat = format;
70}
71
72sp<AMessage> CCodecBuffers::dupFormat() {
73 return mFormat != nullptr ? mFormat->dup() : nullptr;
74}
75
76void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
77 sp<ABuffer> imageDataCandidate = buffer->getImageData();
78 if (imageDataCandidate == nullptr) {
79 return;
80 }
81 sp<ABuffer> imageData;
82 if (!mFormat->findBuffer("image-data", &imageData)
83 || imageDataCandidate->size() != imageData->size()
84 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
85 ALOGD("[%s] updating image-data", mName);
86 sp<AMessage> newFormat = dupFormat();
87 newFormat->setBuffer("image-data", imageDataCandidate);
88 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
89 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
90 int32_t stride = img->mPlane[0].mRowInc;
91 newFormat->setInt32(KEY_STRIDE, stride);
92 ALOGD("[%s] updating stride = %d", mName, stride);
93 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +090094 int64_t offsetDelta =
95 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
96 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim469c8342019-04-11 16:46:09 -070097 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
98 ALOGD("[%s] updating vstride = %d", mName, vstride);
99 }
100 }
101 setFormat(newFormat);
102 buffer->setFormat(newFormat);
103 }
104}
105
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700106// InputBuffers
107
108sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
109 sp<Codec2Buffer> copy = createNewBuffer();
110 if (copy == nullptr) {
111 return nullptr;
112 }
113 std::shared_ptr<C2Buffer> c2buffer;
114 if (!releaseBuffer(buffer, &c2buffer, true)) {
115 return nullptr;
116 }
117 if (!copy->canCopy(c2buffer)) {
118 return nullptr;
119 }
120 if (!copy->copy(c2buffer)) {
121 return nullptr;
122 }
123 return copy;
124}
125
Wonsik Kim469c8342019-04-11 16:46:09 -0700126// OutputBuffers
127
Wonsik Kim41d83432020-04-27 16:40:49 -0700128OutputBuffers::OutputBuffers(const char *componentName, const char *name)
129 : CCodecBuffers(componentName, name) { }
130
131OutputBuffers::~OutputBuffers() = default;
132
Wonsik Kim469c8342019-04-11 16:46:09 -0700133void OutputBuffers::initSkipCutBuffer(
134 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
135 CHECK(mSkipCutBuffer == nullptr);
136 mDelay = delay;
137 mPadding = padding;
138 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700139 mChannelCount = channelCount;
140 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700141}
142
143void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
144 if (mSkipCutBuffer == nullptr) {
145 return;
146 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700147 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
148 return;
149 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700150 int32_t delay = mDelay;
151 int32_t padding = mPadding;
152 if (sampleRate != mSampleRate) {
153 delay = ((int64_t)delay * sampleRate) / mSampleRate;
154 padding = ((int64_t)padding * sampleRate) / mSampleRate;
155 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700156 mSampleRate = sampleRate;
157 mChannelCount = channelCount;
158 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700159}
160
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700161void OutputBuffers::updateSkipCutBuffer(
162 const sp<AMessage> &format, bool notify) {
163 AString mediaType;
164 if (format->findString(KEY_MIME, &mediaType)
165 && mediaType == MIMETYPE_AUDIO_RAW) {
166 int32_t channelCount;
167 int32_t sampleRate;
168 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
169 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
170 updateSkipCutBuffer(sampleRate, channelCount);
171 }
172 }
173 if (notify) {
174 mUnreportedFormat = nullptr;
175 }
176}
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;
199 mUnreportedFormat = nullptr;
200}
201
202void OutputBuffers::flushStash() {
203 for (StashEntry& e : mPending) {
204 e.notify = false;
205 }
206 for (StashEntry& e : mReorderStash) {
207 e.notify = false;
208 }
209}
210
211uint32_t OutputBuffers::getReorderDepth() const {
212 return mDepth;
213}
214
215void OutputBuffers::setReorderDepth(uint32_t depth) {
216 mPending.splice(mPending.end(), mReorderStash);
217 mDepth = depth;
218}
219
220void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
221 mPending.splice(mPending.end(), mReorderStash);
222 mKey = key;
223}
224
225void OutputBuffers::pushToStash(
226 const std::shared_ptr<C2Buffer>& buffer,
227 bool notify,
228 int64_t timestamp,
229 int32_t flags,
230 const sp<AMessage>& format,
231 const C2WorkOrdinalStruct& ordinal) {
232 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
233 if (!buffer && eos) {
234 // TRICKY: we may be violating ordering of the stash here. Because we
235 // don't expect any more emplace() calls after this, the ordering should
236 // not matter.
237 mReorderStash.emplace_back(
238 buffer, notify, timestamp, flags, format, ordinal);
239 } else {
240 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
241 auto it = mReorderStash.begin();
242 for (; it != mReorderStash.end(); ++it) {
243 if (less(ordinal, it->ordinal)) {
244 break;
245 }
246 }
247 mReorderStash.emplace(it,
248 buffer, notify, timestamp, flags, format, ordinal);
249 if (eos) {
250 mReorderStash.back().flags =
251 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
252 }
253 }
254 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
255 mPending.push_back(mReorderStash.front());
256 mReorderStash.pop_front();
257 }
258 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
259}
260
261OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
262 std::shared_ptr<C2Buffer>* c2Buffer,
263 size_t* index,
264 sp<MediaCodecBuffer>* outBuffer) {
265 if (mPending.empty()) {
266 return SKIP;
267 }
268
269 // Retrieve the first entry.
270 StashEntry &entry = mPending.front();
271
272 *c2Buffer = entry.buffer;
273 sp<AMessage> outputFormat = entry.format;
274
275 // The output format can be processed without a registered slot.
276 if (outputFormat) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700277 updateSkipCutBuffer(outputFormat, entry.notify);
278 }
279
280 if (entry.notify) {
281 if (outputFormat) {
282 setFormat(outputFormat);
283 } else if (mUnreportedFormat) {
284 outputFormat = mUnreportedFormat;
285 setFormat(outputFormat);
286 }
287 mUnreportedFormat = nullptr;
288 } else {
289 if (outputFormat) {
290 mUnreportedFormat = outputFormat;
291 } else if (!mUnreportedFormat) {
292 mUnreportedFormat = mFormat;
293 }
294 }
295
296 // Flushing mReorderStash because no other buffers should come after output
297 // EOS.
298 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
299 // Flush reorder stash
300 setReorderDepth(0);
301 }
302
303 if (!entry.notify) {
Wonsik Kim7633b162020-08-18 14:06:03 -0700304 if (outputFormat) {
305 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
306 mName, outputFormat->debugString().c_str());
307 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700308 mPending.pop_front();
309 return DISCARD;
310 }
311
312 // Try to register the buffer.
313 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
314 if (err != OK) {
315 if (err != WOULD_BLOCK) {
316 return REALLOCATE;
317 }
318 return RETRY;
319 }
320
321 // Append information from the front stash entry to outBuffer.
322 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
323 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Wonsik Kim7633b162020-08-18 14:06:03 -0700324 if (outputFormat) {
325 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
326 mName, outputFormat->debugString().c_str());
327 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700328 ALOGV("[%s] popFromStashAndRegister: "
329 "out buffer index = %zu [%p] => %p + %zu (%lld)",
330 mName, *index, outBuffer->get(),
331 (*outBuffer)->data(), (*outBuffer)->size(),
332 (long long)entry.timestamp);
333
334 // The front entry of mPending will be removed now that the registration
335 // succeeded.
336 mPending.pop_front();
337 return NOTIFY_CLIENT;
338}
339
340bool OutputBuffers::popPending(StashEntry *entry) {
341 if (mPending.empty()) {
342 return false;
343 }
344 *entry = mPending.front();
345 mPending.pop_front();
346 return true;
347}
348
349void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
350 mPending.push_front(entry);
351}
352
353bool OutputBuffers::hasPending() const {
354 return !mPending.empty();
355}
356
357bool OutputBuffers::less(
358 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
359 switch (mKey) {
360 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
361 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
362 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
363 default:
364 ALOGD("Unrecognized key; default to timestamp");
365 return o1.frameIndex < o2.frameIndex;
366 }
367}
368
Wonsik Kim469c8342019-04-11 16:46:09 -0700369// LocalBufferPool
370
Wonsik Kim41d83432020-04-27 16:40:49 -0700371constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
372constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
373
374std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
375 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700376}
377
378sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
379 Mutex::Autolock lock(mMutex);
380 auto it = std::find_if(
381 mPool.begin(), mPool.end(),
382 [capacity](const std::vector<uint8_t> &vec) {
383 return vec.capacity() >= capacity;
384 });
385 if (it != mPool.end()) {
386 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
387 mPool.erase(it);
388 return buffer;
389 }
390 if (mUsedSize + capacity > mPoolCapacity) {
391 while (!mPool.empty()) {
392 mUsedSize -= mPool.back().capacity();
393 mPool.pop_back();
394 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700395 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
396 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
397 mPoolCapacity, mPoolCapacity * 2);
398 mPoolCapacity *= 2;
399 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700400 if (mUsedSize + capacity > mPoolCapacity) {
401 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
402 mUsedSize, capacity, mPoolCapacity);
403 return nullptr;
404 }
405 }
406 std::vector<uint8_t> vec(capacity);
407 mUsedSize += vec.capacity();
408 return new VectorBuffer(std::move(vec), shared_from_this());
409}
410
411LocalBufferPool::VectorBuffer::VectorBuffer(
412 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
413 : ABuffer(vec.data(), vec.capacity()),
414 mVec(std::move(vec)),
415 mPool(pool) {
416}
417
418LocalBufferPool::VectorBuffer::~VectorBuffer() {
419 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
420 if (pool) {
421 // If pool is alive, return the vector back to the pool so that
422 // it can be recycled.
423 pool->returnVector(std::move(mVec));
424 }
425}
426
427void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
428 Mutex::Autolock lock(mMutex);
429 mPool.push_front(std::move(vec));
430}
431
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700432// FlexBuffersImpl
433
Wonsik Kim469c8342019-04-11 16:46:09 -0700434size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
435 for (size_t i = 0; i < mBuffers.size(); ++i) {
436 if (mBuffers[i].clientBuffer == nullptr
437 && mBuffers[i].compBuffer.expired()) {
438 mBuffers[i].clientBuffer = buffer;
439 return i;
440 }
441 }
442 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
443 return mBuffers.size() - 1;
444}
445
Wonsik Kim469c8342019-04-11 16:46:09 -0700446bool FlexBuffersImpl::releaseSlot(
447 const sp<MediaCodecBuffer> &buffer,
448 std::shared_ptr<C2Buffer> *c2buffer,
449 bool release) {
450 sp<Codec2Buffer> clientBuffer;
451 size_t index = mBuffers.size();
452 for (size_t i = 0; i < mBuffers.size(); ++i) {
453 if (mBuffers[i].clientBuffer == buffer) {
454 clientBuffer = mBuffers[i].clientBuffer;
455 if (release) {
456 mBuffers[i].clientBuffer.clear();
457 }
458 index = i;
459 break;
460 }
461 }
462 if (clientBuffer == nullptr) {
463 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
464 return false;
465 }
466 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
467 if (!result) {
468 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700469 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700470 mBuffers[index].compBuffer = result;
471 }
472 if (c2buffer) {
473 *c2buffer = result;
474 }
475 return true;
476}
477
478bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
479 for (size_t i = 0; i < mBuffers.size(); ++i) {
480 std::shared_ptr<C2Buffer> compBuffer =
481 mBuffers[i].compBuffer.lock();
482 if (!compBuffer || compBuffer != c2buffer) {
483 continue;
484 }
485 mBuffers[i].compBuffer.reset();
486 ALOGV("[%s] codec released buffer #%zu", mName, i);
487 return true;
488 }
489 ALOGV("[%s] codec released an unknown buffer", mName);
490 return false;
491}
492
493void FlexBuffersImpl::flush() {
494 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
495 mBuffers.clear();
496}
497
498size_t FlexBuffersImpl::numClientBuffers() const {
499 return std::count_if(
500 mBuffers.begin(), mBuffers.end(),
501 [](const Entry &entry) {
502 return (entry.clientBuffer != nullptr);
503 });
504}
505
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700506size_t FlexBuffersImpl::numComponentBuffers() const {
507 return std::count_if(
508 mBuffers.begin(), mBuffers.end(),
509 [](const Entry &entry) {
510 return !entry.compBuffer.expired();
511 });
512}
513
Wonsik Kim469c8342019-04-11 16:46:09 -0700514// BuffersArrayImpl
515
516void BuffersArrayImpl::initialize(
517 const FlexBuffersImpl &impl,
518 size_t minSize,
519 std::function<sp<Codec2Buffer>()> allocate) {
520 mImplName = impl.mImplName + "[N]";
521 mName = mImplName.c_str();
522 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
523 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
524 bool ownedByClient = (clientBuffer != nullptr);
525 if (!ownedByClient) {
526 clientBuffer = allocate();
527 }
528 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
529 }
530 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
531 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
532 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
533 }
534}
535
536status_t BuffersArrayImpl::grabBuffer(
537 size_t *index,
538 sp<Codec2Buffer> *buffer,
539 std::function<bool(const sp<Codec2Buffer> &)> match) {
540 // allBuffersDontMatch remains true if all buffers are available but
541 // match() returns false for every buffer.
542 bool allBuffersDontMatch = true;
543 for (size_t i = 0; i < mBuffers.size(); ++i) {
544 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
545 if (match(mBuffers[i].clientBuffer)) {
546 mBuffers[i].ownedByClient = true;
547 *buffer = mBuffers[i].clientBuffer;
548 (*buffer)->meta()->clear();
549 (*buffer)->setRange(0, (*buffer)->capacity());
550 *index = i;
551 return OK;
552 }
553 } else {
554 allBuffersDontMatch = false;
555 }
556 }
557 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
558}
559
560bool BuffersArrayImpl::returnBuffer(
561 const sp<MediaCodecBuffer> &buffer,
562 std::shared_ptr<C2Buffer> *c2buffer,
563 bool release) {
564 sp<Codec2Buffer> clientBuffer;
565 size_t index = mBuffers.size();
566 for (size_t i = 0; i < mBuffers.size(); ++i) {
567 if (mBuffers[i].clientBuffer == buffer) {
568 if (!mBuffers[i].ownedByClient) {
569 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
570 mName, i);
571 }
572 clientBuffer = mBuffers[i].clientBuffer;
573 if (release) {
574 mBuffers[i].ownedByClient = false;
575 }
576 index = i;
577 break;
578 }
579 }
580 if (clientBuffer == nullptr) {
581 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
582 return false;
583 }
584 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
585 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
586 if (!result) {
587 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700588 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700589 mBuffers[index].compBuffer = result;
590 }
591 if (c2buffer) {
592 *c2buffer = result;
593 }
594 return true;
595}
596
597bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
598 for (size_t i = 0; i < mBuffers.size(); ++i) {
599 std::shared_ptr<C2Buffer> compBuffer =
600 mBuffers[i].compBuffer.lock();
601 if (!compBuffer) {
602 continue;
603 }
604 if (c2buffer == compBuffer) {
605 if (mBuffers[i].ownedByClient) {
606 // This should not happen.
607 ALOGD("[%s] codec released a buffer owned by client "
608 "(index %zu)", mName, i);
609 }
610 mBuffers[i].compBuffer.reset();
611 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
612 return true;
613 }
614 }
615 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
616 return false;
617}
618
619void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
620 array->clear();
621 for (const Entry &entry : mBuffers) {
622 array->push(entry.clientBuffer);
623 }
624}
625
626void BuffersArrayImpl::flush() {
627 for (Entry &entry : mBuffers) {
628 entry.ownedByClient = false;
629 }
630}
631
632void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
633 size_t size = mBuffers.size();
634 mBuffers.clear();
635 for (size_t i = 0; i < size; ++i) {
636 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
637 }
638}
639
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700640void BuffersArrayImpl::grow(
641 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
642 CHECK_LT(mBuffers.size(), newSize);
643 while (mBuffers.size() < newSize) {
644 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
645 }
646}
647
Wonsik Kim469c8342019-04-11 16:46:09 -0700648size_t BuffersArrayImpl::numClientBuffers() const {
649 return std::count_if(
650 mBuffers.begin(), mBuffers.end(),
651 [](const Entry &entry) {
652 return entry.ownedByClient;
653 });
654}
655
Wonsik Kima39882b2019-06-20 16:13:56 -0700656size_t BuffersArrayImpl::arraySize() const {
657 return mBuffers.size();
658}
659
Wonsik Kim469c8342019-04-11 16:46:09 -0700660// InputBuffersArray
661
662void InputBuffersArray::initialize(
663 const FlexBuffersImpl &impl,
664 size_t minSize,
665 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700666 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700667 mImpl.initialize(impl, minSize, allocate);
668}
669
670void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
671 mImpl.getArray(array);
672}
673
674bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
675 sp<Codec2Buffer> c2Buffer;
676 status_t err = mImpl.grabBuffer(index, &c2Buffer);
677 if (err == OK) {
678 c2Buffer->setFormat(mFormat);
679 handleImageData(c2Buffer);
680 *buffer = c2Buffer;
681 return true;
682 }
683 return false;
684}
685
686bool InputBuffersArray::releaseBuffer(
687 const sp<MediaCodecBuffer> &buffer,
688 std::shared_ptr<C2Buffer> *c2buffer,
689 bool release) {
690 return mImpl.returnBuffer(buffer, c2buffer, release);
691}
692
693bool InputBuffersArray::expireComponentBuffer(
694 const std::shared_ptr<C2Buffer> &c2buffer) {
695 return mImpl.expireComponentBuffer(c2buffer);
696}
697
698void InputBuffersArray::flush() {
699 mImpl.flush();
700}
701
702size_t InputBuffersArray::numClientBuffers() const {
703 return mImpl.numClientBuffers();
704}
705
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700706sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
707 return mAllocate();
708}
709
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800710// SlotInputBuffers
711
712bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
713 sp<Codec2Buffer> newBuffer = createNewBuffer();
714 *index = mImpl.assignSlot(newBuffer);
715 *buffer = newBuffer;
716 return true;
717}
718
719bool SlotInputBuffers::releaseBuffer(
720 const sp<MediaCodecBuffer> &buffer,
721 std::shared_ptr<C2Buffer> *c2buffer,
722 bool release) {
723 return mImpl.releaseSlot(buffer, c2buffer, release);
724}
725
726bool SlotInputBuffers::expireComponentBuffer(
727 const std::shared_ptr<C2Buffer> &c2buffer) {
728 return mImpl.expireComponentBuffer(c2buffer);
729}
730
731void SlotInputBuffers::flush() {
732 mImpl.flush();
733}
734
735std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
736 TRESPASS("Array mode should not be called at non-legacy mode");
737 return nullptr;
738}
739
740size_t SlotInputBuffers::numClientBuffers() const {
741 return mImpl.numClientBuffers();
742}
743
744sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
745 return new DummyContainerBuffer{mFormat, nullptr};
746}
747
Wonsik Kim469c8342019-04-11 16:46:09 -0700748// LinearInputBuffers
749
750bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700751 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700752 if (newBuffer == nullptr) {
753 return false;
754 }
755 *index = mImpl.assignSlot(newBuffer);
756 *buffer = newBuffer;
757 return true;
758}
759
760bool LinearInputBuffers::releaseBuffer(
761 const sp<MediaCodecBuffer> &buffer,
762 std::shared_ptr<C2Buffer> *c2buffer,
763 bool release) {
764 return mImpl.releaseSlot(buffer, c2buffer, release);
765}
766
767bool LinearInputBuffers::expireComponentBuffer(
768 const std::shared_ptr<C2Buffer> &c2buffer) {
769 return mImpl.expireComponentBuffer(c2buffer);
770}
771
772void LinearInputBuffers::flush() {
773 // This is no-op by default unless we're in array mode where we need to keep
774 // track of the flushed work.
775 mImpl.flush();
776}
777
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700778std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700779 std::unique_ptr<InputBuffersArray> array(
780 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
781 array->setPool(mPool);
782 array->setFormat(mFormat);
783 array->initialize(
784 mImpl,
785 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700786 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
787 return Alloc(pool, format);
788 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700789 return std::move(array);
790}
791
792size_t LinearInputBuffers::numClientBuffers() const {
793 return mImpl.numClientBuffers();
794}
795
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700796// static
797sp<Codec2Buffer> LinearInputBuffers::Alloc(
798 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
799 int32_t capacity = kLinearBufferSize;
800 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
801 if ((size_t)capacity > kMaxLinearBufferSize) {
802 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
803 capacity = kMaxLinearBufferSize;
804 }
805
806 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700807 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
808 std::shared_ptr<C2LinearBlock> block;
809
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700810 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700811 if (err != C2_OK) {
812 return nullptr;
813 }
814
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700815 return LinearBlockBuffer::Allocate(format, block);
816}
817
818sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
819 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700820}
821
822// EncryptedLinearInputBuffers
823
824EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
825 bool secure,
826 const sp<MemoryDealer> &dealer,
827 const sp<ICrypto> &crypto,
828 int32_t heapSeqNum,
829 size_t capacity,
830 size_t numInputSlots,
831 const char *componentName, const char *name)
832 : LinearInputBuffers(componentName, name),
833 mUsage({0, 0}),
834 mDealer(dealer),
835 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700836 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700837 if (secure) {
838 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
839 } else {
840 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
841 }
842 for (size_t i = 0; i < numInputSlots; ++i) {
843 sp<IMemory> memory = mDealer->allocate(capacity);
844 if (memory == nullptr) {
845 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
846 mName, i);
847 break;
848 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700849 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700850 }
851}
852
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700853std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
854 std::unique_ptr<InputBuffersArray> array(
855 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
856 array->setPool(mPool);
857 array->setFormat(mFormat);
858 array->initialize(
859 mImpl,
860 size,
861 [pool = mPool,
862 format = mFormat,
863 usage = mUsage,
864 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
865 return Alloc(pool, format, usage, memoryVector);
866 });
867 return std::move(array);
868}
869
870
871// static
872sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
873 const std::shared_ptr<C2BlockPool> &pool,
874 const sp<AMessage> &format,
875 C2MemoryUsage usage,
876 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
877 int32_t capacity = kLinearBufferSize;
878 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
879 if ((size_t)capacity > kMaxLinearBufferSize) {
880 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
881 capacity = kMaxLinearBufferSize;
882 }
883
Wonsik Kim469c8342019-04-11 16:46:09 -0700884 sp<IMemory> memory;
885 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700886 int32_t heapSeqNum = -1;
887 for (; slot < memoryVector->size(); ++slot) {
888 if (memoryVector->at(slot).block.expired()) {
889 memory = memoryVector->at(slot).memory;
890 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700891 break;
892 }
893 }
894 if (memory == nullptr) {
895 return nullptr;
896 }
897
898 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700899 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700900 if (err != C2_OK || block == nullptr) {
901 return nullptr;
902 }
903
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700904 memoryVector->at(slot).block = block;
905 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
906}
907
908sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
909 // TODO: android_2020
910 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700911}
912
913// GraphicMetadataInputBuffers
914
915GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
916 const char *componentName, const char *name)
917 : InputBuffers(componentName, name),
918 mImpl(mName),
919 mStore(GetCodec2PlatformAllocatorStore()) { }
920
921bool GraphicMetadataInputBuffers::requestNewBuffer(
922 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700923 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700924 if (newBuffer == nullptr) {
925 return false;
926 }
927 *index = mImpl.assignSlot(newBuffer);
928 *buffer = newBuffer;
929 return true;
930}
931
932bool GraphicMetadataInputBuffers::releaseBuffer(
933 const sp<MediaCodecBuffer> &buffer,
934 std::shared_ptr<C2Buffer> *c2buffer,
935 bool release) {
936 return mImpl.releaseSlot(buffer, c2buffer, release);
937}
938
939bool GraphicMetadataInputBuffers::expireComponentBuffer(
940 const std::shared_ptr<C2Buffer> &c2buffer) {
941 return mImpl.expireComponentBuffer(c2buffer);
942}
943
944void GraphicMetadataInputBuffers::flush() {
945 // This is no-op by default unless we're in array mode where we need to keep
946 // track of the flushed work.
947}
948
949std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
950 size_t size) {
951 std::shared_ptr<C2Allocator> alloc;
952 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
953 if (err != C2_OK) {
954 return nullptr;
955 }
956 std::unique_ptr<InputBuffersArray> array(
957 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
958 array->setPool(mPool);
959 array->setFormat(mFormat);
960 array->initialize(
961 mImpl,
962 size,
963 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
964 return new GraphicMetadataBuffer(format, alloc);
965 });
966 return std::move(array);
967}
968
969size_t GraphicMetadataInputBuffers::numClientBuffers() const {
970 return mImpl.numClientBuffers();
971}
972
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700973sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
974 std::shared_ptr<C2Allocator> alloc;
975 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
976 if (err != C2_OK) {
977 return nullptr;
978 }
979 return new GraphicMetadataBuffer(mFormat, alloc);
980}
981
Wonsik Kim469c8342019-04-11 16:46:09 -0700982// GraphicInputBuffers
983
984GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700985 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700986 : InputBuffers(componentName, name),
987 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700988 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700989
990bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700991 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700992 if (newBuffer == nullptr) {
993 return false;
994 }
995 *index = mImpl.assignSlot(newBuffer);
996 handleImageData(newBuffer);
997 *buffer = newBuffer;
998 return true;
999}
1000
1001bool GraphicInputBuffers::releaseBuffer(
1002 const sp<MediaCodecBuffer> &buffer,
1003 std::shared_ptr<C2Buffer> *c2buffer,
1004 bool release) {
1005 return mImpl.releaseSlot(buffer, c2buffer, release);
1006}
1007
1008bool GraphicInputBuffers::expireComponentBuffer(
1009 const std::shared_ptr<C2Buffer> &c2buffer) {
1010 return mImpl.expireComponentBuffer(c2buffer);
1011}
1012
1013void GraphicInputBuffers::flush() {
1014 // This is no-op by default unless we're in array mode where we need to keep
1015 // track of the flushed work.
1016}
1017
1018std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1019 std::unique_ptr<InputBuffersArray> array(
1020 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1021 array->setPool(mPool);
1022 array->setFormat(mFormat);
1023 array->initialize(
1024 mImpl,
1025 size,
1026 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1027 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1028 return AllocateGraphicBuffer(
1029 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1030 });
1031 return std::move(array);
1032}
1033
1034size_t GraphicInputBuffers::numClientBuffers() const {
1035 return mImpl.numClientBuffers();
1036}
1037
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001038sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1039 // TODO: read usage from intf
1040 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1041 return AllocateGraphicBuffer(
1042 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1043}
1044
Wonsik Kim469c8342019-04-11 16:46:09 -07001045// OutputBuffersArray
1046
1047void OutputBuffersArray::initialize(
1048 const FlexBuffersImpl &impl,
1049 size_t minSize,
1050 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001051 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001052 mImpl.initialize(impl, minSize, allocate);
1053}
1054
1055status_t OutputBuffersArray::registerBuffer(
1056 const std::shared_ptr<C2Buffer> &buffer,
1057 size_t *index,
1058 sp<MediaCodecBuffer> *clientBuffer) {
1059 sp<Codec2Buffer> c2Buffer;
1060 status_t err = mImpl.grabBuffer(
1061 index,
1062 &c2Buffer,
1063 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1064 return clientBuffer->canCopy(buffer);
1065 });
1066 if (err == WOULD_BLOCK) {
1067 ALOGV("[%s] buffers temporarily not available", mName);
1068 return err;
1069 } else if (err != OK) {
1070 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1071 return err;
1072 }
1073 c2Buffer->setFormat(mFormat);
1074 if (!c2Buffer->copy(buffer)) {
1075 ALOGD("[%s] copy buffer failed", mName);
1076 return WOULD_BLOCK;
1077 }
1078 submit(c2Buffer);
1079 handleImageData(c2Buffer);
1080 *clientBuffer = c2Buffer;
1081 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1082 return OK;
1083}
1084
1085status_t OutputBuffersArray::registerCsd(
1086 const C2StreamInitDataInfo::output *csd,
1087 size_t *index,
1088 sp<MediaCodecBuffer> *clientBuffer) {
1089 sp<Codec2Buffer> c2Buffer;
1090 status_t err = mImpl.grabBuffer(
1091 index,
1092 &c2Buffer,
1093 [csd](const sp<Codec2Buffer> &clientBuffer) {
1094 return clientBuffer->base() != nullptr
1095 && clientBuffer->capacity() >= csd->flexCount();
1096 });
1097 if (err != OK) {
1098 return err;
1099 }
1100 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1101 c2Buffer->setRange(0, csd->flexCount());
1102 c2Buffer->setFormat(mFormat);
1103 *clientBuffer = c2Buffer;
1104 return OK;
1105}
1106
1107bool OutputBuffersArray::releaseBuffer(
1108 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1109 return mImpl.returnBuffer(buffer, c2buffer, true);
1110}
1111
1112void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1113 (void)flushedWork;
1114 mImpl.flush();
1115 if (mSkipCutBuffer != nullptr) {
1116 mSkipCutBuffer->clear();
1117 }
1118}
1119
1120void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1121 mImpl.getArray(array);
1122}
1123
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001124size_t OutputBuffersArray::numClientBuffers() const {
1125 return mImpl.numClientBuffers();
1126}
1127
Wonsik Kim469c8342019-04-11 16:46:09 -07001128void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001129 switch (c2buffer->data().type()) {
1130 case C2BufferData::LINEAR: {
1131 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001132 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1133 const uint32_t block_size = linear_blocks.front().size();
1134 if (block_size < kMaxLinearBufferSize / 2) {
1135 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001136 } else {
1137 size = kMaxLinearBufferSize;
1138 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001139 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001140 return new LocalLinearBuffer(format, new ABuffer(size));
1141 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001142 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001143 break;
1144 }
1145
Wonsik Kima39882b2019-06-20 16:13:56 -07001146 case C2BufferData::GRAPHIC: {
1147 // This is only called for RawGraphicOutputBuffers.
1148 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001149 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001150 return ConstGraphicBlockBuffer::AllocateEmpty(
1151 format,
1152 [lbp](size_t capacity) {
1153 return lbp->newBuffer(capacity);
1154 });
1155 };
1156 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1157 mName, mFormat->debugString().c_str());
1158 break;
1159 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001160
1161 case C2BufferData::INVALID: [[fallthrough]];
1162 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1163 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1164 default:
1165 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1166 return;
1167 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001168 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001169}
1170
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001171void OutputBuffersArray::grow(size_t newSize) {
1172 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001173}
1174
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001175void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1176 mFormat = source->mFormat;
1177 mSkipCutBuffer = source->mSkipCutBuffer;
1178 mUnreportedFormat = source->mUnreportedFormat;
1179 mPending = std::move(source->mPending);
1180 mReorderStash = std::move(source->mReorderStash);
1181 mDepth = source->mDepth;
1182 mKey = source->mKey;
1183}
1184
Wonsik Kim469c8342019-04-11 16:46:09 -07001185// FlexOutputBuffers
1186
1187status_t FlexOutputBuffers::registerBuffer(
1188 const std::shared_ptr<C2Buffer> &buffer,
1189 size_t *index,
1190 sp<MediaCodecBuffer> *clientBuffer) {
1191 sp<Codec2Buffer> newBuffer = wrap(buffer);
1192 if (newBuffer == nullptr) {
1193 return NO_MEMORY;
1194 }
1195 newBuffer->setFormat(mFormat);
1196 *index = mImpl.assignSlot(newBuffer);
1197 handleImageData(newBuffer);
1198 *clientBuffer = newBuffer;
1199 ALOGV("[%s] registered buffer %zu", mName, *index);
1200 return OK;
1201}
1202
1203status_t FlexOutputBuffers::registerCsd(
1204 const C2StreamInitDataInfo::output *csd,
1205 size_t *index,
1206 sp<MediaCodecBuffer> *clientBuffer) {
1207 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1208 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1209 *index = mImpl.assignSlot(newBuffer);
1210 *clientBuffer = newBuffer;
1211 return OK;
1212}
1213
1214bool FlexOutputBuffers::releaseBuffer(
1215 const sp<MediaCodecBuffer> &buffer,
1216 std::shared_ptr<C2Buffer> *c2buffer) {
1217 return mImpl.releaseSlot(buffer, c2buffer, true);
1218}
1219
1220void FlexOutputBuffers::flush(
1221 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1222 (void) flushedWork;
1223 // This is no-op by default unless we're in array mode where we need to keep
1224 // track of the flushed work.
1225}
1226
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001227std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001228 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001229 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001230 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1231 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001232 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001233}
1234
1235size_t FlexOutputBuffers::numClientBuffers() const {
1236 return mImpl.numClientBuffers();
1237}
1238
1239// LinearOutputBuffers
1240
1241void LinearOutputBuffers::flush(
1242 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1243 if (mSkipCutBuffer != nullptr) {
1244 mSkipCutBuffer->clear();
1245 }
1246 FlexOutputBuffers::flush(flushedWork);
1247}
1248
1249sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1250 if (buffer == nullptr) {
1251 ALOGV("[%s] using a dummy buffer", mName);
1252 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1253 }
1254 if (buffer->data().type() != C2BufferData::LINEAR) {
1255 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1256 // We expect linear output buffers from the component.
1257 return nullptr;
1258 }
1259 if (buffer->data().linearBlocks().size() != 1u) {
1260 ALOGV("[%s] no linear buffers", mName);
1261 // We expect one and only one linear block from the component.
1262 return nullptr;
1263 }
1264 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1265 if (clientBuffer == nullptr) {
1266 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1267 return nullptr;
1268 }
1269 submit(clientBuffer);
1270 return clientBuffer;
1271}
1272
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001273std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1274 return [format = mFormat]{
1275 // TODO: proper max output size
1276 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1277 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001278}
1279
1280// GraphicOutputBuffers
1281
1282sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1283 return new DummyContainerBuffer(mFormat, buffer);
1284}
1285
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001286std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1287 return [format = mFormat]{
1288 return new DummyContainerBuffer(format);
1289 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001290}
1291
1292// RawGraphicOutputBuffers
1293
1294RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001295 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001296 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001297 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001298
1299sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1300 if (buffer == nullptr) {
1301 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1302 mFormat,
1303 [lbp = mLocalBufferPool](size_t capacity) {
1304 return lbp->newBuffer(capacity);
1305 });
1306 if (c2buffer == nullptr) {
1307 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1308 return nullptr;
1309 }
1310 c2buffer->setRange(0, 0);
1311 return c2buffer;
1312 } else {
1313 return ConstGraphicBlockBuffer::Allocate(
1314 mFormat,
1315 buffer,
1316 [lbp = mLocalBufferPool](size_t capacity) {
1317 return lbp->newBuffer(capacity);
1318 });
1319 }
1320}
1321
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001322std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1323 return [format = mFormat, lbp = mLocalBufferPool]{
1324 return ConstGraphicBlockBuffer::AllocateEmpty(
1325 format,
1326 [lbp](size_t capacity) {
1327 return lbp->newBuffer(capacity);
1328 });
1329 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001330}
1331
1332} // namespace android