blob: 689e3bb10d5e71782a35551ebb4a042e38a8862f [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) {
277 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
278 mName, outputFormat->debugString().c_str());
279 updateSkipCutBuffer(outputFormat, entry.notify);
280 }
281
282 if (entry.notify) {
283 if (outputFormat) {
284 setFormat(outputFormat);
285 } else if (mUnreportedFormat) {
286 outputFormat = mUnreportedFormat;
287 setFormat(outputFormat);
288 }
289 mUnreportedFormat = nullptr;
290 } else {
291 if (outputFormat) {
292 mUnreportedFormat = outputFormat;
293 } else if (!mUnreportedFormat) {
294 mUnreportedFormat = mFormat;
295 }
296 }
297
298 // Flushing mReorderStash because no other buffers should come after output
299 // EOS.
300 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
301 // Flush reorder stash
302 setReorderDepth(0);
303 }
304
305 if (!entry.notify) {
306 mPending.pop_front();
307 return DISCARD;
308 }
309
310 // Try to register the buffer.
311 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
312 if (err != OK) {
313 if (err != WOULD_BLOCK) {
314 return REALLOCATE;
315 }
316 return RETRY;
317 }
318
319 // Append information from the front stash entry to outBuffer.
320 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
321 (*outBuffer)->meta()->setInt32("flags", entry.flags);
322 ALOGV("[%s] popFromStashAndRegister: "
323 "out buffer index = %zu [%p] => %p + %zu (%lld)",
324 mName, *index, outBuffer->get(),
325 (*outBuffer)->data(), (*outBuffer)->size(),
326 (long long)entry.timestamp);
327
328 // The front entry of mPending will be removed now that the registration
329 // succeeded.
330 mPending.pop_front();
331 return NOTIFY_CLIENT;
332}
333
334bool OutputBuffers::popPending(StashEntry *entry) {
335 if (mPending.empty()) {
336 return false;
337 }
338 *entry = mPending.front();
339 mPending.pop_front();
340 return true;
341}
342
343void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
344 mPending.push_front(entry);
345}
346
347bool OutputBuffers::hasPending() const {
348 return !mPending.empty();
349}
350
351bool OutputBuffers::less(
352 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
353 switch (mKey) {
354 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
355 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
356 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
357 default:
358 ALOGD("Unrecognized key; default to timestamp");
359 return o1.frameIndex < o2.frameIndex;
360 }
361}
362
Wonsik Kim469c8342019-04-11 16:46:09 -0700363// LocalBufferPool
364
Wonsik Kim41d83432020-04-27 16:40:49 -0700365constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
366constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
367
368std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
369 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700370}
371
372sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
373 Mutex::Autolock lock(mMutex);
374 auto it = std::find_if(
375 mPool.begin(), mPool.end(),
376 [capacity](const std::vector<uint8_t> &vec) {
377 return vec.capacity() >= capacity;
378 });
379 if (it != mPool.end()) {
380 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
381 mPool.erase(it);
382 return buffer;
383 }
384 if (mUsedSize + capacity > mPoolCapacity) {
385 while (!mPool.empty()) {
386 mUsedSize -= mPool.back().capacity();
387 mPool.pop_back();
388 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700389 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
390 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
391 mPoolCapacity, mPoolCapacity * 2);
392 mPoolCapacity *= 2;
393 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700394 if (mUsedSize + capacity > mPoolCapacity) {
395 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
396 mUsedSize, capacity, mPoolCapacity);
397 return nullptr;
398 }
399 }
400 std::vector<uint8_t> vec(capacity);
401 mUsedSize += vec.capacity();
402 return new VectorBuffer(std::move(vec), shared_from_this());
403}
404
405LocalBufferPool::VectorBuffer::VectorBuffer(
406 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
407 : ABuffer(vec.data(), vec.capacity()),
408 mVec(std::move(vec)),
409 mPool(pool) {
410}
411
412LocalBufferPool::VectorBuffer::~VectorBuffer() {
413 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
414 if (pool) {
415 // If pool is alive, return the vector back to the pool so that
416 // it can be recycled.
417 pool->returnVector(std::move(mVec));
418 }
419}
420
421void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
422 Mutex::Autolock lock(mMutex);
423 mPool.push_front(std::move(vec));
424}
425
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700426// FlexBuffersImpl
427
Wonsik Kim469c8342019-04-11 16:46:09 -0700428size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
429 for (size_t i = 0; i < mBuffers.size(); ++i) {
430 if (mBuffers[i].clientBuffer == nullptr
431 && mBuffers[i].compBuffer.expired()) {
432 mBuffers[i].clientBuffer = buffer;
433 return i;
434 }
435 }
436 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
437 return mBuffers.size() - 1;
438}
439
Wonsik Kim469c8342019-04-11 16:46:09 -0700440bool FlexBuffersImpl::releaseSlot(
441 const sp<MediaCodecBuffer> &buffer,
442 std::shared_ptr<C2Buffer> *c2buffer,
443 bool release) {
444 sp<Codec2Buffer> clientBuffer;
445 size_t index = mBuffers.size();
446 for (size_t i = 0; i < mBuffers.size(); ++i) {
447 if (mBuffers[i].clientBuffer == buffer) {
448 clientBuffer = mBuffers[i].clientBuffer;
449 if (release) {
450 mBuffers[i].clientBuffer.clear();
451 }
452 index = i;
453 break;
454 }
455 }
456 if (clientBuffer == nullptr) {
457 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
458 return false;
459 }
460 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
461 if (!result) {
462 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700463 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700464 mBuffers[index].compBuffer = result;
465 }
466 if (c2buffer) {
467 *c2buffer = result;
468 }
469 return true;
470}
471
472bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
473 for (size_t i = 0; i < mBuffers.size(); ++i) {
474 std::shared_ptr<C2Buffer> compBuffer =
475 mBuffers[i].compBuffer.lock();
476 if (!compBuffer || compBuffer != c2buffer) {
477 continue;
478 }
479 mBuffers[i].compBuffer.reset();
480 ALOGV("[%s] codec released buffer #%zu", mName, i);
481 return true;
482 }
483 ALOGV("[%s] codec released an unknown buffer", mName);
484 return false;
485}
486
487void FlexBuffersImpl::flush() {
488 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
489 mBuffers.clear();
490}
491
Wonsik Kim0487b782020-10-28 11:45:50 -0700492size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700493 return std::count_if(
494 mBuffers.begin(), mBuffers.end(),
495 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700496 return (entry.clientBuffer != nullptr
497 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700498 });
499}
500
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700501size_t FlexBuffersImpl::numComponentBuffers() const {
502 return std::count_if(
503 mBuffers.begin(), mBuffers.end(),
504 [](const Entry &entry) {
505 return !entry.compBuffer.expired();
506 });
507}
508
Wonsik Kim469c8342019-04-11 16:46:09 -0700509// BuffersArrayImpl
510
511void BuffersArrayImpl::initialize(
512 const FlexBuffersImpl &impl,
513 size_t minSize,
514 std::function<sp<Codec2Buffer>()> allocate) {
515 mImplName = impl.mImplName + "[N]";
516 mName = mImplName.c_str();
517 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
518 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
519 bool ownedByClient = (clientBuffer != nullptr);
520 if (!ownedByClient) {
521 clientBuffer = allocate();
522 }
523 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
524 }
525 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
526 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
527 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
528 }
529}
530
531status_t BuffersArrayImpl::grabBuffer(
532 size_t *index,
533 sp<Codec2Buffer> *buffer,
534 std::function<bool(const sp<Codec2Buffer> &)> match) {
535 // allBuffersDontMatch remains true if all buffers are available but
536 // match() returns false for every buffer.
537 bool allBuffersDontMatch = true;
538 for (size_t i = 0; i < mBuffers.size(); ++i) {
539 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
540 if (match(mBuffers[i].clientBuffer)) {
541 mBuffers[i].ownedByClient = true;
542 *buffer = mBuffers[i].clientBuffer;
543 (*buffer)->meta()->clear();
544 (*buffer)->setRange(0, (*buffer)->capacity());
545 *index = i;
546 return OK;
547 }
548 } else {
549 allBuffersDontMatch = false;
550 }
551 }
552 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
553}
554
555bool BuffersArrayImpl::returnBuffer(
556 const sp<MediaCodecBuffer> &buffer,
557 std::shared_ptr<C2Buffer> *c2buffer,
558 bool release) {
559 sp<Codec2Buffer> clientBuffer;
560 size_t index = mBuffers.size();
561 for (size_t i = 0; i < mBuffers.size(); ++i) {
562 if (mBuffers[i].clientBuffer == buffer) {
563 if (!mBuffers[i].ownedByClient) {
564 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
565 mName, i);
566 }
567 clientBuffer = mBuffers[i].clientBuffer;
568 if (release) {
569 mBuffers[i].ownedByClient = false;
570 }
571 index = i;
572 break;
573 }
574 }
575 if (clientBuffer == nullptr) {
576 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
577 return false;
578 }
579 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
580 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
581 if (!result) {
582 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700583 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700584 mBuffers[index].compBuffer = result;
585 }
586 if (c2buffer) {
587 *c2buffer = result;
588 }
589 return true;
590}
591
592bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
593 for (size_t i = 0; i < mBuffers.size(); ++i) {
594 std::shared_ptr<C2Buffer> compBuffer =
595 mBuffers[i].compBuffer.lock();
596 if (!compBuffer) {
597 continue;
598 }
599 if (c2buffer == compBuffer) {
600 if (mBuffers[i].ownedByClient) {
601 // This should not happen.
602 ALOGD("[%s] codec released a buffer owned by client "
603 "(index %zu)", mName, i);
604 }
605 mBuffers[i].compBuffer.reset();
606 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
607 return true;
608 }
609 }
610 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
611 return false;
612}
613
614void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
615 array->clear();
616 for (const Entry &entry : mBuffers) {
617 array->push(entry.clientBuffer);
618 }
619}
620
621void BuffersArrayImpl::flush() {
622 for (Entry &entry : mBuffers) {
623 entry.ownedByClient = false;
624 }
625}
626
627void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
628 size_t size = mBuffers.size();
629 mBuffers.clear();
630 for (size_t i = 0; i < size; ++i) {
631 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
632 }
633}
634
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700635void BuffersArrayImpl::grow(
636 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
637 CHECK_LT(mBuffers.size(), newSize);
638 while (mBuffers.size() < newSize) {
639 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
640 }
641}
642
Wonsik Kim0487b782020-10-28 11:45:50 -0700643size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700644 return std::count_if(
645 mBuffers.begin(), mBuffers.end(),
646 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700647 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700648 });
649}
650
Wonsik Kima39882b2019-06-20 16:13:56 -0700651size_t BuffersArrayImpl::arraySize() const {
652 return mBuffers.size();
653}
654
Wonsik Kim469c8342019-04-11 16:46:09 -0700655// InputBuffersArray
656
657void InputBuffersArray::initialize(
658 const FlexBuffersImpl &impl,
659 size_t minSize,
660 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700661 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700662 mImpl.initialize(impl, minSize, allocate);
663}
664
665void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
666 mImpl.getArray(array);
667}
668
669bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
670 sp<Codec2Buffer> c2Buffer;
671 status_t err = mImpl.grabBuffer(index, &c2Buffer);
672 if (err == OK) {
673 c2Buffer->setFormat(mFormat);
674 handleImageData(c2Buffer);
675 *buffer = c2Buffer;
676 return true;
677 }
678 return false;
679}
680
681bool InputBuffersArray::releaseBuffer(
682 const sp<MediaCodecBuffer> &buffer,
683 std::shared_ptr<C2Buffer> *c2buffer,
684 bool release) {
685 return mImpl.returnBuffer(buffer, c2buffer, release);
686}
687
688bool InputBuffersArray::expireComponentBuffer(
689 const std::shared_ptr<C2Buffer> &c2buffer) {
690 return mImpl.expireComponentBuffer(c2buffer);
691}
692
693void InputBuffersArray::flush() {
694 mImpl.flush();
695}
696
Wonsik Kim0487b782020-10-28 11:45:50 -0700697size_t InputBuffersArray::numActiveSlots() const {
698 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700699}
700
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700701sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
702 return mAllocate();
703}
704
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800705// SlotInputBuffers
706
707bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
708 sp<Codec2Buffer> newBuffer = createNewBuffer();
709 *index = mImpl.assignSlot(newBuffer);
710 *buffer = newBuffer;
711 return true;
712}
713
714bool SlotInputBuffers::releaseBuffer(
715 const sp<MediaCodecBuffer> &buffer,
716 std::shared_ptr<C2Buffer> *c2buffer,
717 bool release) {
718 return mImpl.releaseSlot(buffer, c2buffer, release);
719}
720
721bool SlotInputBuffers::expireComponentBuffer(
722 const std::shared_ptr<C2Buffer> &c2buffer) {
723 return mImpl.expireComponentBuffer(c2buffer);
724}
725
726void SlotInputBuffers::flush() {
727 mImpl.flush();
728}
729
730std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
731 TRESPASS("Array mode should not be called at non-legacy mode");
732 return nullptr;
733}
734
Wonsik Kim0487b782020-10-28 11:45:50 -0700735size_t SlotInputBuffers::numActiveSlots() const {
736 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800737}
738
739sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
740 return new DummyContainerBuffer{mFormat, nullptr};
741}
742
Wonsik Kim469c8342019-04-11 16:46:09 -0700743// LinearInputBuffers
744
745bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700746 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700747 if (newBuffer == nullptr) {
748 return false;
749 }
750 *index = mImpl.assignSlot(newBuffer);
751 *buffer = newBuffer;
752 return true;
753}
754
755bool LinearInputBuffers::releaseBuffer(
756 const sp<MediaCodecBuffer> &buffer,
757 std::shared_ptr<C2Buffer> *c2buffer,
758 bool release) {
759 return mImpl.releaseSlot(buffer, c2buffer, release);
760}
761
762bool LinearInputBuffers::expireComponentBuffer(
763 const std::shared_ptr<C2Buffer> &c2buffer) {
764 return mImpl.expireComponentBuffer(c2buffer);
765}
766
767void LinearInputBuffers::flush() {
768 // This is no-op by default unless we're in array mode where we need to keep
769 // track of the flushed work.
770 mImpl.flush();
771}
772
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700773std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700774 std::unique_ptr<InputBuffersArray> array(
775 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
776 array->setPool(mPool);
777 array->setFormat(mFormat);
778 array->initialize(
779 mImpl,
780 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700781 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
782 return Alloc(pool, format);
783 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700784 return std::move(array);
785}
786
Wonsik Kim0487b782020-10-28 11:45:50 -0700787size_t LinearInputBuffers::numActiveSlots() const {
788 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700789}
790
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700791// static
792sp<Codec2Buffer> LinearInputBuffers::Alloc(
793 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
794 int32_t capacity = kLinearBufferSize;
795 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
796 if ((size_t)capacity > kMaxLinearBufferSize) {
797 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
798 capacity = kMaxLinearBufferSize;
799 }
800
801 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700802 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
803 std::shared_ptr<C2LinearBlock> block;
804
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700805 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700806 if (err != C2_OK) {
807 return nullptr;
808 }
809
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700810 return LinearBlockBuffer::Allocate(format, block);
811}
812
813sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
814 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700815}
816
817// EncryptedLinearInputBuffers
818
819EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
820 bool secure,
821 const sp<MemoryDealer> &dealer,
822 const sp<ICrypto> &crypto,
823 int32_t heapSeqNum,
824 size_t capacity,
825 size_t numInputSlots,
826 const char *componentName, const char *name)
827 : LinearInputBuffers(componentName, name),
828 mUsage({0, 0}),
829 mDealer(dealer),
830 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700831 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700832 if (secure) {
833 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
834 } else {
835 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
836 }
837 for (size_t i = 0; i < numInputSlots; ++i) {
838 sp<IMemory> memory = mDealer->allocate(capacity);
839 if (memory == nullptr) {
840 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
841 mName, i);
842 break;
843 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700844 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700845 }
846}
847
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700848std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
849 std::unique_ptr<InputBuffersArray> array(
850 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
851 array->setPool(mPool);
852 array->setFormat(mFormat);
853 array->initialize(
854 mImpl,
855 size,
856 [pool = mPool,
857 format = mFormat,
858 usage = mUsage,
859 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
860 return Alloc(pool, format, usage, memoryVector);
861 });
862 return std::move(array);
863}
864
865
866// static
867sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
868 const std::shared_ptr<C2BlockPool> &pool,
869 const sp<AMessage> &format,
870 C2MemoryUsage usage,
871 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
872 int32_t capacity = kLinearBufferSize;
873 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
874 if ((size_t)capacity > kMaxLinearBufferSize) {
875 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
876 capacity = kMaxLinearBufferSize;
877 }
878
Wonsik Kim469c8342019-04-11 16:46:09 -0700879 sp<IMemory> memory;
880 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700881 int32_t heapSeqNum = -1;
882 for (; slot < memoryVector->size(); ++slot) {
883 if (memoryVector->at(slot).block.expired()) {
884 memory = memoryVector->at(slot).memory;
885 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700886 break;
887 }
888 }
889 if (memory == nullptr) {
890 return nullptr;
891 }
892
893 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700894 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700895 if (err != C2_OK || block == nullptr) {
896 return nullptr;
897 }
898
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700899 memoryVector->at(slot).block = block;
900 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
901}
902
903sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
904 // TODO: android_2020
905 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700906}
907
908// GraphicMetadataInputBuffers
909
910GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
911 const char *componentName, const char *name)
912 : InputBuffers(componentName, name),
913 mImpl(mName),
914 mStore(GetCodec2PlatformAllocatorStore()) { }
915
916bool GraphicMetadataInputBuffers::requestNewBuffer(
917 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700918 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700919 if (newBuffer == nullptr) {
920 return false;
921 }
922 *index = mImpl.assignSlot(newBuffer);
923 *buffer = newBuffer;
924 return true;
925}
926
927bool GraphicMetadataInputBuffers::releaseBuffer(
928 const sp<MediaCodecBuffer> &buffer,
929 std::shared_ptr<C2Buffer> *c2buffer,
930 bool release) {
931 return mImpl.releaseSlot(buffer, c2buffer, release);
932}
933
934bool GraphicMetadataInputBuffers::expireComponentBuffer(
935 const std::shared_ptr<C2Buffer> &c2buffer) {
936 return mImpl.expireComponentBuffer(c2buffer);
937}
938
939void GraphicMetadataInputBuffers::flush() {
940 // This is no-op by default unless we're in array mode where we need to keep
941 // track of the flushed work.
942}
943
944std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
945 size_t size) {
946 std::shared_ptr<C2Allocator> alloc;
947 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
948 if (err != C2_OK) {
949 return nullptr;
950 }
951 std::unique_ptr<InputBuffersArray> array(
952 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
953 array->setPool(mPool);
954 array->setFormat(mFormat);
955 array->initialize(
956 mImpl,
957 size,
958 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
959 return new GraphicMetadataBuffer(format, alloc);
960 });
961 return std::move(array);
962}
963
Wonsik Kim0487b782020-10-28 11:45:50 -0700964size_t GraphicMetadataInputBuffers::numActiveSlots() const {
965 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700966}
967
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700968sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
969 std::shared_ptr<C2Allocator> alloc;
970 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
971 if (err != C2_OK) {
972 return nullptr;
973 }
974 return new GraphicMetadataBuffer(mFormat, alloc);
975}
976
Wonsik Kim469c8342019-04-11 16:46:09 -0700977// GraphicInputBuffers
978
979GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700980 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700981 : InputBuffers(componentName, name),
982 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700983 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700984
985bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700986 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700987 if (newBuffer == nullptr) {
988 return false;
989 }
990 *index = mImpl.assignSlot(newBuffer);
991 handleImageData(newBuffer);
992 *buffer = newBuffer;
993 return true;
994}
995
996bool GraphicInputBuffers::releaseBuffer(
997 const sp<MediaCodecBuffer> &buffer,
998 std::shared_ptr<C2Buffer> *c2buffer,
999 bool release) {
1000 return mImpl.releaseSlot(buffer, c2buffer, release);
1001}
1002
1003bool GraphicInputBuffers::expireComponentBuffer(
1004 const std::shared_ptr<C2Buffer> &c2buffer) {
1005 return mImpl.expireComponentBuffer(c2buffer);
1006}
1007
1008void GraphicInputBuffers::flush() {
1009 // This is no-op by default unless we're in array mode where we need to keep
1010 // track of the flushed work.
1011}
1012
1013std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1014 std::unique_ptr<InputBuffersArray> array(
1015 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1016 array->setPool(mPool);
1017 array->setFormat(mFormat);
1018 array->initialize(
1019 mImpl,
1020 size,
1021 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1022 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1023 return AllocateGraphicBuffer(
1024 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1025 });
1026 return std::move(array);
1027}
1028
Wonsik Kim0487b782020-10-28 11:45:50 -07001029size_t GraphicInputBuffers::numActiveSlots() const {
1030 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001031}
1032
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001033sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1034 // TODO: read usage from intf
1035 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1036 return AllocateGraphicBuffer(
1037 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1038}
1039
Wonsik Kim469c8342019-04-11 16:46:09 -07001040// OutputBuffersArray
1041
1042void OutputBuffersArray::initialize(
1043 const FlexBuffersImpl &impl,
1044 size_t minSize,
1045 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001046 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001047 mImpl.initialize(impl, minSize, allocate);
1048}
1049
1050status_t OutputBuffersArray::registerBuffer(
1051 const std::shared_ptr<C2Buffer> &buffer,
1052 size_t *index,
1053 sp<MediaCodecBuffer> *clientBuffer) {
1054 sp<Codec2Buffer> c2Buffer;
1055 status_t err = mImpl.grabBuffer(
1056 index,
1057 &c2Buffer,
1058 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1059 return clientBuffer->canCopy(buffer);
1060 });
1061 if (err == WOULD_BLOCK) {
1062 ALOGV("[%s] buffers temporarily not available", mName);
1063 return err;
1064 } else if (err != OK) {
1065 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1066 return err;
1067 }
1068 c2Buffer->setFormat(mFormat);
1069 if (!c2Buffer->copy(buffer)) {
1070 ALOGD("[%s] copy buffer failed", mName);
1071 return WOULD_BLOCK;
1072 }
1073 submit(c2Buffer);
1074 handleImageData(c2Buffer);
1075 *clientBuffer = c2Buffer;
1076 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1077 return OK;
1078}
1079
1080status_t OutputBuffersArray::registerCsd(
1081 const C2StreamInitDataInfo::output *csd,
1082 size_t *index,
1083 sp<MediaCodecBuffer> *clientBuffer) {
1084 sp<Codec2Buffer> c2Buffer;
1085 status_t err = mImpl.grabBuffer(
1086 index,
1087 &c2Buffer,
1088 [csd](const sp<Codec2Buffer> &clientBuffer) {
1089 return clientBuffer->base() != nullptr
1090 && clientBuffer->capacity() >= csd->flexCount();
1091 });
1092 if (err != OK) {
1093 return err;
1094 }
1095 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1096 c2Buffer->setRange(0, csd->flexCount());
1097 c2Buffer->setFormat(mFormat);
1098 *clientBuffer = c2Buffer;
1099 return OK;
1100}
1101
1102bool OutputBuffersArray::releaseBuffer(
1103 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1104 return mImpl.returnBuffer(buffer, c2buffer, true);
1105}
1106
1107void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1108 (void)flushedWork;
1109 mImpl.flush();
1110 if (mSkipCutBuffer != nullptr) {
1111 mSkipCutBuffer->clear();
1112 }
1113}
1114
1115void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1116 mImpl.getArray(array);
1117}
1118
Wonsik Kim0487b782020-10-28 11:45:50 -07001119size_t OutputBuffersArray::numActiveSlots() const {
1120 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001121}
1122
Wonsik Kim469c8342019-04-11 16:46:09 -07001123void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001124 switch (c2buffer->data().type()) {
1125 case C2BufferData::LINEAR: {
1126 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001127 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1128 const uint32_t block_size = linear_blocks.front().size();
1129 if (block_size < kMaxLinearBufferSize / 2) {
1130 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001131 } else {
1132 size = kMaxLinearBufferSize;
1133 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001134 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001135 return new LocalLinearBuffer(format, new ABuffer(size));
1136 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001137 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001138 break;
1139 }
1140
Wonsik Kima39882b2019-06-20 16:13:56 -07001141 case C2BufferData::GRAPHIC: {
1142 // This is only called for RawGraphicOutputBuffers.
1143 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001144 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001145 return ConstGraphicBlockBuffer::AllocateEmpty(
1146 format,
1147 [lbp](size_t capacity) {
1148 return lbp->newBuffer(capacity);
1149 });
1150 };
1151 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1152 mName, mFormat->debugString().c_str());
1153 break;
1154 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001155
1156 case C2BufferData::INVALID: [[fallthrough]];
1157 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1158 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1159 default:
1160 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1161 return;
1162 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001163 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001164}
1165
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001166void OutputBuffersArray::grow(size_t newSize) {
1167 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001168}
1169
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001170void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1171 mFormat = source->mFormat;
1172 mSkipCutBuffer = source->mSkipCutBuffer;
1173 mUnreportedFormat = source->mUnreportedFormat;
1174 mPending = std::move(source->mPending);
1175 mReorderStash = std::move(source->mReorderStash);
1176 mDepth = source->mDepth;
1177 mKey = source->mKey;
1178}
1179
Wonsik Kim469c8342019-04-11 16:46:09 -07001180// FlexOutputBuffers
1181
1182status_t FlexOutputBuffers::registerBuffer(
1183 const std::shared_ptr<C2Buffer> &buffer,
1184 size_t *index,
1185 sp<MediaCodecBuffer> *clientBuffer) {
1186 sp<Codec2Buffer> newBuffer = wrap(buffer);
1187 if (newBuffer == nullptr) {
1188 return NO_MEMORY;
1189 }
1190 newBuffer->setFormat(mFormat);
1191 *index = mImpl.assignSlot(newBuffer);
1192 handleImageData(newBuffer);
1193 *clientBuffer = newBuffer;
1194 ALOGV("[%s] registered buffer %zu", mName, *index);
1195 return OK;
1196}
1197
1198status_t FlexOutputBuffers::registerCsd(
1199 const C2StreamInitDataInfo::output *csd,
1200 size_t *index,
1201 sp<MediaCodecBuffer> *clientBuffer) {
1202 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1203 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1204 *index = mImpl.assignSlot(newBuffer);
1205 *clientBuffer = newBuffer;
1206 return OK;
1207}
1208
1209bool FlexOutputBuffers::releaseBuffer(
1210 const sp<MediaCodecBuffer> &buffer,
1211 std::shared_ptr<C2Buffer> *c2buffer) {
1212 return mImpl.releaseSlot(buffer, c2buffer, true);
1213}
1214
1215void FlexOutputBuffers::flush(
1216 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1217 (void) flushedWork;
1218 // This is no-op by default unless we're in array mode where we need to keep
1219 // track of the flushed work.
1220}
1221
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001222std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001223 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001224 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001225 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1226 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001227 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001228}
1229
Wonsik Kim0487b782020-10-28 11:45:50 -07001230size_t FlexOutputBuffers::numActiveSlots() const {
1231 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001232}
1233
1234// LinearOutputBuffers
1235
1236void LinearOutputBuffers::flush(
1237 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1238 if (mSkipCutBuffer != nullptr) {
1239 mSkipCutBuffer->clear();
1240 }
1241 FlexOutputBuffers::flush(flushedWork);
1242}
1243
1244sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1245 if (buffer == nullptr) {
1246 ALOGV("[%s] using a dummy buffer", mName);
1247 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1248 }
1249 if (buffer->data().type() != C2BufferData::LINEAR) {
1250 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1251 // We expect linear output buffers from the component.
1252 return nullptr;
1253 }
1254 if (buffer->data().linearBlocks().size() != 1u) {
1255 ALOGV("[%s] no linear buffers", mName);
1256 // We expect one and only one linear block from the component.
1257 return nullptr;
1258 }
1259 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1260 if (clientBuffer == nullptr) {
1261 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1262 return nullptr;
1263 }
1264 submit(clientBuffer);
1265 return clientBuffer;
1266}
1267
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001268std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1269 return [format = mFormat]{
1270 // TODO: proper max output size
1271 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1272 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001273}
1274
1275// GraphicOutputBuffers
1276
1277sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1278 return new DummyContainerBuffer(mFormat, buffer);
1279}
1280
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001281std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1282 return [format = mFormat]{
1283 return new DummyContainerBuffer(format);
1284 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001285}
1286
1287// RawGraphicOutputBuffers
1288
1289RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001290 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001291 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001292 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001293
1294sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1295 if (buffer == nullptr) {
1296 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1297 mFormat,
1298 [lbp = mLocalBufferPool](size_t capacity) {
1299 return lbp->newBuffer(capacity);
1300 });
1301 if (c2buffer == nullptr) {
1302 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1303 return nullptr;
1304 }
1305 c2buffer->setRange(0, 0);
1306 return c2buffer;
1307 } else {
1308 return ConstGraphicBlockBuffer::Allocate(
1309 mFormat,
1310 buffer,
1311 [lbp = mLocalBufferPool](size_t capacity) {
1312 return lbp->newBuffer(capacity);
1313 });
1314 }
1315}
1316
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001317std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1318 return [format = mFormat, lbp = mLocalBufferPool]{
1319 return ConstGraphicBlockBuffer::AllocateEmpty(
1320 format,
1321 [lbp](size_t capacity) {
1322 return lbp->newBuffer(capacity);
1323 });
1324 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001325}
1326
1327} // namespace android