blob: c49a16cc366e67b10c5fc38782b158de38d749bf [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) {
94 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
95 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
96 ALOGD("[%s] updating vstride = %d", mName, vstride);
97 }
98 }
99 setFormat(newFormat);
100 buffer->setFormat(newFormat);
101 }
102}
103
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700104// InputBuffers
105
106sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
107 sp<Codec2Buffer> copy = createNewBuffer();
108 if (copy == nullptr) {
109 return nullptr;
110 }
111 std::shared_ptr<C2Buffer> c2buffer;
112 if (!releaseBuffer(buffer, &c2buffer, true)) {
113 return nullptr;
114 }
115 if (!copy->canCopy(c2buffer)) {
116 return nullptr;
117 }
118 if (!copy->copy(c2buffer)) {
119 return nullptr;
120 }
121 return copy;
122}
123
Wonsik Kim469c8342019-04-11 16:46:09 -0700124// OutputBuffers
125
Wonsik Kim41d83432020-04-27 16:40:49 -0700126OutputBuffers::OutputBuffers(const char *componentName, const char *name)
127 : CCodecBuffers(componentName, name) { }
128
129OutputBuffers::~OutputBuffers() = default;
130
Wonsik Kim469c8342019-04-11 16:46:09 -0700131void OutputBuffers::initSkipCutBuffer(
132 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
133 CHECK(mSkipCutBuffer == nullptr);
134 mDelay = delay;
135 mPadding = padding;
136 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700137 mChannelCount = channelCount;
138 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700139}
140
141void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
142 if (mSkipCutBuffer == nullptr) {
143 return;
144 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700145 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
146 return;
147 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700148 int32_t delay = mDelay;
149 int32_t padding = mPadding;
150 if (sampleRate != mSampleRate) {
151 delay = ((int64_t)delay * sampleRate) / mSampleRate;
152 padding = ((int64_t)padding * sampleRate) / mSampleRate;
153 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700154 mSampleRate = sampleRate;
155 mChannelCount = channelCount;
156 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700157}
158
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700159void OutputBuffers::updateSkipCutBuffer(
160 const sp<AMessage> &format, bool notify) {
161 AString mediaType;
162 if (format->findString(KEY_MIME, &mediaType)
163 && mediaType == MIMETYPE_AUDIO_RAW) {
164 int32_t channelCount;
165 int32_t sampleRate;
166 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
167 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
168 updateSkipCutBuffer(sampleRate, channelCount);
169 }
170 }
171 if (notify) {
172 mUnreportedFormat = nullptr;
173 }
174}
175
Wonsik Kim469c8342019-04-11 16:46:09 -0700176void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
177 if (mSkipCutBuffer != nullptr) {
178 mSkipCutBuffer->submit(buffer);
179 }
180}
181
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700182void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700183 if (mSkipCutBuffer != nullptr) {
184 size_t prevSize = mSkipCutBuffer->size();
185 if (prevSize != 0u) {
186 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
187 }
188 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700189 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700190}
191
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700192void OutputBuffers::clearStash() {
193 mPending.clear();
194 mReorderStash.clear();
195 mDepth = 0;
196 mKey = C2Config::ORDINAL;
197 mUnreportedFormat = nullptr;
198}
199
200void OutputBuffers::flushStash() {
201 for (StashEntry& e : mPending) {
202 e.notify = false;
203 }
204 for (StashEntry& e : mReorderStash) {
205 e.notify = false;
206 }
207}
208
209uint32_t OutputBuffers::getReorderDepth() const {
210 return mDepth;
211}
212
213void OutputBuffers::setReorderDepth(uint32_t depth) {
214 mPending.splice(mPending.end(), mReorderStash);
215 mDepth = depth;
216}
217
218void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
219 mPending.splice(mPending.end(), mReorderStash);
220 mKey = key;
221}
222
223void OutputBuffers::pushToStash(
224 const std::shared_ptr<C2Buffer>& buffer,
225 bool notify,
226 int64_t timestamp,
227 int32_t flags,
228 const sp<AMessage>& format,
229 const C2WorkOrdinalStruct& ordinal) {
230 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
231 if (!buffer && eos) {
232 // TRICKY: we may be violating ordering of the stash here. Because we
233 // don't expect any more emplace() calls after this, the ordering should
234 // not matter.
235 mReorderStash.emplace_back(
236 buffer, notify, timestamp, flags, format, ordinal);
237 } else {
238 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
239 auto it = mReorderStash.begin();
240 for (; it != mReorderStash.end(); ++it) {
241 if (less(ordinal, it->ordinal)) {
242 break;
243 }
244 }
245 mReorderStash.emplace(it,
246 buffer, notify, timestamp, flags, format, ordinal);
247 if (eos) {
248 mReorderStash.back().flags =
249 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
250 }
251 }
252 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
253 mPending.push_back(mReorderStash.front());
254 mReorderStash.pop_front();
255 }
256 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
257}
258
259OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
260 std::shared_ptr<C2Buffer>* c2Buffer,
261 size_t* index,
262 sp<MediaCodecBuffer>* outBuffer) {
263 if (mPending.empty()) {
264 return SKIP;
265 }
266
267 // Retrieve the first entry.
268 StashEntry &entry = mPending.front();
269
270 *c2Buffer = entry.buffer;
271 sp<AMessage> outputFormat = entry.format;
272
273 // The output format can be processed without a registered slot.
274 if (outputFormat) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700275 updateSkipCutBuffer(outputFormat, entry.notify);
276 }
277
278 if (entry.notify) {
279 if (outputFormat) {
280 setFormat(outputFormat);
281 } else if (mUnreportedFormat) {
282 outputFormat = mUnreportedFormat;
283 setFormat(outputFormat);
284 }
285 mUnreportedFormat = nullptr;
286 } else {
287 if (outputFormat) {
288 mUnreportedFormat = outputFormat;
289 } else if (!mUnreportedFormat) {
290 mUnreportedFormat = mFormat;
291 }
292 }
293
294 // Flushing mReorderStash because no other buffers should come after output
295 // EOS.
296 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
297 // Flush reorder stash
298 setReorderDepth(0);
299 }
300
301 if (!entry.notify) {
Wonsik Kim4a868842020-08-18 14:06:03 -0700302 if (outputFormat) {
303 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
304 mName, outputFormat->debugString().c_str());
305 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700306 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);
Wonsik Kim4a868842020-08-18 14:06:03 -0700322 if (outputFormat) {
323 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
324 mName, outputFormat->debugString().c_str());
325 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700326 ALOGV("[%s] popFromStashAndRegister: "
327 "out buffer index = %zu [%p] => %p + %zu (%lld)",
328 mName, *index, outBuffer->get(),
329 (*outBuffer)->data(), (*outBuffer)->size(),
330 (long long)entry.timestamp);
331
332 // The front entry of mPending will be removed now that the registration
333 // succeeded.
334 mPending.pop_front();
335 return NOTIFY_CLIENT;
336}
337
338bool OutputBuffers::popPending(StashEntry *entry) {
339 if (mPending.empty()) {
340 return false;
341 }
342 *entry = mPending.front();
343 mPending.pop_front();
344 return true;
345}
346
347void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
348 mPending.push_front(entry);
349}
350
351bool OutputBuffers::hasPending() const {
352 return !mPending.empty();
353}
354
355bool OutputBuffers::less(
356 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
357 switch (mKey) {
358 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
359 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
360 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
361 default:
362 ALOGD("Unrecognized key; default to timestamp");
363 return o1.frameIndex < o2.frameIndex;
364 }
365}
366
Wonsik Kim469c8342019-04-11 16:46:09 -0700367// LocalBufferPool
368
Wonsik Kim41d83432020-04-27 16:40:49 -0700369constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
370constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
371
372std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
373 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700374}
375
376sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
377 Mutex::Autolock lock(mMutex);
378 auto it = std::find_if(
379 mPool.begin(), mPool.end(),
380 [capacity](const std::vector<uint8_t> &vec) {
381 return vec.capacity() >= capacity;
382 });
383 if (it != mPool.end()) {
384 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
385 mPool.erase(it);
386 return buffer;
387 }
388 if (mUsedSize + capacity > mPoolCapacity) {
389 while (!mPool.empty()) {
390 mUsedSize -= mPool.back().capacity();
391 mPool.pop_back();
392 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700393 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
394 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
395 mPoolCapacity, mPoolCapacity * 2);
396 mPoolCapacity *= 2;
397 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700398 if (mUsedSize + capacity > mPoolCapacity) {
399 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
400 mUsedSize, capacity, mPoolCapacity);
401 return nullptr;
402 }
403 }
404 std::vector<uint8_t> vec(capacity);
405 mUsedSize += vec.capacity();
406 return new VectorBuffer(std::move(vec), shared_from_this());
407}
408
409LocalBufferPool::VectorBuffer::VectorBuffer(
410 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
411 : ABuffer(vec.data(), vec.capacity()),
412 mVec(std::move(vec)),
413 mPool(pool) {
414}
415
416LocalBufferPool::VectorBuffer::~VectorBuffer() {
417 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
418 if (pool) {
419 // If pool is alive, return the vector back to the pool so that
420 // it can be recycled.
421 pool->returnVector(std::move(mVec));
422 }
423}
424
425void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
426 Mutex::Autolock lock(mMutex);
427 mPool.push_front(std::move(vec));
428}
429
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700430// FlexBuffersImpl
431
Wonsik Kim469c8342019-04-11 16:46:09 -0700432size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
433 for (size_t i = 0; i < mBuffers.size(); ++i) {
434 if (mBuffers[i].clientBuffer == nullptr
435 && mBuffers[i].compBuffer.expired()) {
436 mBuffers[i].clientBuffer = buffer;
437 return i;
438 }
439 }
440 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
441 return mBuffers.size() - 1;
442}
443
Wonsik Kim469c8342019-04-11 16:46:09 -0700444bool FlexBuffersImpl::releaseSlot(
445 const sp<MediaCodecBuffer> &buffer,
446 std::shared_ptr<C2Buffer> *c2buffer,
447 bool release) {
448 sp<Codec2Buffer> clientBuffer;
449 size_t index = mBuffers.size();
450 for (size_t i = 0; i < mBuffers.size(); ++i) {
451 if (mBuffers[i].clientBuffer == buffer) {
452 clientBuffer = mBuffers[i].clientBuffer;
453 if (release) {
454 mBuffers[i].clientBuffer.clear();
455 }
456 index = i;
457 break;
458 }
459 }
460 if (clientBuffer == nullptr) {
461 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
462 return false;
463 }
464 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
465 if (!result) {
466 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700467 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700468 mBuffers[index].compBuffer = result;
469 }
470 if (c2buffer) {
471 *c2buffer = result;
472 }
473 return true;
474}
475
476bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
477 for (size_t i = 0; i < mBuffers.size(); ++i) {
478 std::shared_ptr<C2Buffer> compBuffer =
479 mBuffers[i].compBuffer.lock();
480 if (!compBuffer || compBuffer != c2buffer) {
481 continue;
482 }
483 mBuffers[i].compBuffer.reset();
484 ALOGV("[%s] codec released buffer #%zu", mName, i);
485 return true;
486 }
487 ALOGV("[%s] codec released an unknown buffer", mName);
488 return false;
489}
490
491void FlexBuffersImpl::flush() {
492 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
493 mBuffers.clear();
494}
495
496size_t FlexBuffersImpl::numClientBuffers() const {
497 return std::count_if(
498 mBuffers.begin(), mBuffers.end(),
499 [](const Entry &entry) {
500 return (entry.clientBuffer != nullptr);
501 });
502}
503
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700504size_t FlexBuffersImpl::numComponentBuffers() const {
505 return std::count_if(
506 mBuffers.begin(), mBuffers.end(),
507 [](const Entry &entry) {
508 return !entry.compBuffer.expired();
509 });
510}
511
Wonsik Kim469c8342019-04-11 16:46:09 -0700512// BuffersArrayImpl
513
514void BuffersArrayImpl::initialize(
515 const FlexBuffersImpl &impl,
516 size_t minSize,
517 std::function<sp<Codec2Buffer>()> allocate) {
518 mImplName = impl.mImplName + "[N]";
519 mName = mImplName.c_str();
520 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
521 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
522 bool ownedByClient = (clientBuffer != nullptr);
523 if (!ownedByClient) {
524 clientBuffer = allocate();
525 }
526 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
527 }
528 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
529 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
530 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
531 }
532}
533
534status_t BuffersArrayImpl::grabBuffer(
535 size_t *index,
536 sp<Codec2Buffer> *buffer,
537 std::function<bool(const sp<Codec2Buffer> &)> match) {
538 // allBuffersDontMatch remains true if all buffers are available but
539 // match() returns false for every buffer.
540 bool allBuffersDontMatch = true;
541 for (size_t i = 0; i < mBuffers.size(); ++i) {
542 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
543 if (match(mBuffers[i].clientBuffer)) {
544 mBuffers[i].ownedByClient = true;
545 *buffer = mBuffers[i].clientBuffer;
546 (*buffer)->meta()->clear();
547 (*buffer)->setRange(0, (*buffer)->capacity());
548 *index = i;
549 return OK;
550 }
551 } else {
552 allBuffersDontMatch = false;
553 }
554 }
555 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
556}
557
558bool BuffersArrayImpl::returnBuffer(
559 const sp<MediaCodecBuffer> &buffer,
560 std::shared_ptr<C2Buffer> *c2buffer,
561 bool release) {
562 sp<Codec2Buffer> clientBuffer;
563 size_t index = mBuffers.size();
564 for (size_t i = 0; i < mBuffers.size(); ++i) {
565 if (mBuffers[i].clientBuffer == buffer) {
566 if (!mBuffers[i].ownedByClient) {
567 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
568 mName, i);
569 }
570 clientBuffer = mBuffers[i].clientBuffer;
571 if (release) {
572 mBuffers[i].ownedByClient = false;
573 }
574 index = i;
575 break;
576 }
577 }
578 if (clientBuffer == nullptr) {
579 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
580 return false;
581 }
582 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
583 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
584 if (!result) {
585 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700586 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700587 mBuffers[index].compBuffer = result;
588 }
589 if (c2buffer) {
590 *c2buffer = result;
591 }
592 return true;
593}
594
595bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
596 for (size_t i = 0; i < mBuffers.size(); ++i) {
597 std::shared_ptr<C2Buffer> compBuffer =
598 mBuffers[i].compBuffer.lock();
599 if (!compBuffer) {
600 continue;
601 }
602 if (c2buffer == compBuffer) {
603 if (mBuffers[i].ownedByClient) {
604 // This should not happen.
605 ALOGD("[%s] codec released a buffer owned by client "
606 "(index %zu)", mName, i);
607 }
608 mBuffers[i].compBuffer.reset();
609 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
610 return true;
611 }
612 }
613 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
614 return false;
615}
616
617void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
618 array->clear();
619 for (const Entry &entry : mBuffers) {
620 array->push(entry.clientBuffer);
621 }
622}
623
624void BuffersArrayImpl::flush() {
625 for (Entry &entry : mBuffers) {
626 entry.ownedByClient = false;
627 }
628}
629
630void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
631 size_t size = mBuffers.size();
632 mBuffers.clear();
633 for (size_t i = 0; i < size; ++i) {
634 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
635 }
636}
637
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700638void BuffersArrayImpl::grow(
639 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
640 CHECK_LT(mBuffers.size(), newSize);
641 while (mBuffers.size() < newSize) {
642 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
643 }
644}
645
Wonsik Kim469c8342019-04-11 16:46:09 -0700646size_t BuffersArrayImpl::numClientBuffers() const {
647 return std::count_if(
648 mBuffers.begin(), mBuffers.end(),
649 [](const Entry &entry) {
650 return entry.ownedByClient;
651 });
652}
653
Wonsik Kima39882b2019-06-20 16:13:56 -0700654size_t BuffersArrayImpl::arraySize() const {
655 return mBuffers.size();
656}
657
Wonsik Kim469c8342019-04-11 16:46:09 -0700658// InputBuffersArray
659
660void InputBuffersArray::initialize(
661 const FlexBuffersImpl &impl,
662 size_t minSize,
663 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700664 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700665 mImpl.initialize(impl, minSize, allocate);
666}
667
668void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
669 mImpl.getArray(array);
670}
671
672bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
673 sp<Codec2Buffer> c2Buffer;
674 status_t err = mImpl.grabBuffer(index, &c2Buffer);
675 if (err == OK) {
676 c2Buffer->setFormat(mFormat);
677 handleImageData(c2Buffer);
678 *buffer = c2Buffer;
679 return true;
680 }
681 return false;
682}
683
684bool InputBuffersArray::releaseBuffer(
685 const sp<MediaCodecBuffer> &buffer,
686 std::shared_ptr<C2Buffer> *c2buffer,
687 bool release) {
688 return mImpl.returnBuffer(buffer, c2buffer, release);
689}
690
691bool InputBuffersArray::expireComponentBuffer(
692 const std::shared_ptr<C2Buffer> &c2buffer) {
693 return mImpl.expireComponentBuffer(c2buffer);
694}
695
696void InputBuffersArray::flush() {
697 mImpl.flush();
698}
699
700size_t InputBuffersArray::numClientBuffers() const {
701 return mImpl.numClientBuffers();
702}
703
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700704sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
705 return mAllocate();
706}
707
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800708// SlotInputBuffers
709
710bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
711 sp<Codec2Buffer> newBuffer = createNewBuffer();
712 *index = mImpl.assignSlot(newBuffer);
713 *buffer = newBuffer;
714 return true;
715}
716
717bool SlotInputBuffers::releaseBuffer(
718 const sp<MediaCodecBuffer> &buffer,
719 std::shared_ptr<C2Buffer> *c2buffer,
720 bool release) {
721 return mImpl.releaseSlot(buffer, c2buffer, release);
722}
723
724bool SlotInputBuffers::expireComponentBuffer(
725 const std::shared_ptr<C2Buffer> &c2buffer) {
726 return mImpl.expireComponentBuffer(c2buffer);
727}
728
729void SlotInputBuffers::flush() {
730 mImpl.flush();
731}
732
733std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
734 TRESPASS("Array mode should not be called at non-legacy mode");
735 return nullptr;
736}
737
738size_t SlotInputBuffers::numClientBuffers() const {
739 return mImpl.numClientBuffers();
740}
741
742sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
743 return new DummyContainerBuffer{mFormat, nullptr};
744}
745
Wonsik Kim469c8342019-04-11 16:46:09 -0700746// LinearInputBuffers
747
748bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700749 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700750 if (newBuffer == nullptr) {
751 return false;
752 }
753 *index = mImpl.assignSlot(newBuffer);
754 *buffer = newBuffer;
755 return true;
756}
757
758bool LinearInputBuffers::releaseBuffer(
759 const sp<MediaCodecBuffer> &buffer,
760 std::shared_ptr<C2Buffer> *c2buffer,
761 bool release) {
762 return mImpl.releaseSlot(buffer, c2buffer, release);
763}
764
765bool LinearInputBuffers::expireComponentBuffer(
766 const std::shared_ptr<C2Buffer> &c2buffer) {
767 return mImpl.expireComponentBuffer(c2buffer);
768}
769
770void LinearInputBuffers::flush() {
771 // This is no-op by default unless we're in array mode where we need to keep
772 // track of the flushed work.
773 mImpl.flush();
774}
775
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700776std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700777 std::unique_ptr<InputBuffersArray> array(
778 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
779 array->setPool(mPool);
780 array->setFormat(mFormat);
781 array->initialize(
782 mImpl,
783 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700784 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
785 return Alloc(pool, format);
786 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700787 return std::move(array);
788}
789
790size_t LinearInputBuffers::numClientBuffers() const {
791 return mImpl.numClientBuffers();
792}
793
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700794// static
795sp<Codec2Buffer> LinearInputBuffers::Alloc(
796 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
797 int32_t capacity = kLinearBufferSize;
798 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
799 if ((size_t)capacity > kMaxLinearBufferSize) {
800 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
801 capacity = kMaxLinearBufferSize;
802 }
803
804 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700805 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
806 std::shared_ptr<C2LinearBlock> block;
807
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700808 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700809 if (err != C2_OK) {
810 return nullptr;
811 }
812
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700813 return LinearBlockBuffer::Allocate(format, block);
814}
815
816sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
817 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700818}
819
820// EncryptedLinearInputBuffers
821
822EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
823 bool secure,
824 const sp<MemoryDealer> &dealer,
825 const sp<ICrypto> &crypto,
826 int32_t heapSeqNum,
827 size_t capacity,
828 size_t numInputSlots,
829 const char *componentName, const char *name)
830 : LinearInputBuffers(componentName, name),
831 mUsage({0, 0}),
832 mDealer(dealer),
833 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700834 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700835 if (secure) {
836 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
837 } else {
838 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
839 }
840 for (size_t i = 0; i < numInputSlots; ++i) {
841 sp<IMemory> memory = mDealer->allocate(capacity);
842 if (memory == nullptr) {
843 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
844 mName, i);
845 break;
846 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700847 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700848 }
849}
850
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700851std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
852 std::unique_ptr<InputBuffersArray> array(
853 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
854 array->setPool(mPool);
855 array->setFormat(mFormat);
856 array->initialize(
857 mImpl,
858 size,
859 [pool = mPool,
860 format = mFormat,
861 usage = mUsage,
862 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
863 return Alloc(pool, format, usage, memoryVector);
864 });
865 return std::move(array);
866}
867
868
869// static
870sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
871 const std::shared_ptr<C2BlockPool> &pool,
872 const sp<AMessage> &format,
873 C2MemoryUsage usage,
874 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
875 int32_t capacity = kLinearBufferSize;
876 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
877 if ((size_t)capacity > kMaxLinearBufferSize) {
878 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
879 capacity = kMaxLinearBufferSize;
880 }
881
Wonsik Kim469c8342019-04-11 16:46:09 -0700882 sp<IMemory> memory;
883 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700884 int32_t heapSeqNum = -1;
885 for (; slot < memoryVector->size(); ++slot) {
886 if (memoryVector->at(slot).block.expired()) {
887 memory = memoryVector->at(slot).memory;
888 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700889 break;
890 }
891 }
892 if (memory == nullptr) {
893 return nullptr;
894 }
895
896 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700897 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700898 if (err != C2_OK || block == nullptr) {
899 return nullptr;
900 }
901
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700902 memoryVector->at(slot).block = block;
903 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
904}
905
906sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
907 // TODO: android_2020
908 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700909}
910
911// GraphicMetadataInputBuffers
912
913GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
914 const char *componentName, const char *name)
915 : InputBuffers(componentName, name),
916 mImpl(mName),
917 mStore(GetCodec2PlatformAllocatorStore()) { }
918
919bool GraphicMetadataInputBuffers::requestNewBuffer(
920 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700921 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700922 if (newBuffer == nullptr) {
923 return false;
924 }
925 *index = mImpl.assignSlot(newBuffer);
926 *buffer = newBuffer;
927 return true;
928}
929
930bool GraphicMetadataInputBuffers::releaseBuffer(
931 const sp<MediaCodecBuffer> &buffer,
932 std::shared_ptr<C2Buffer> *c2buffer,
933 bool release) {
934 return mImpl.releaseSlot(buffer, c2buffer, release);
935}
936
937bool GraphicMetadataInputBuffers::expireComponentBuffer(
938 const std::shared_ptr<C2Buffer> &c2buffer) {
939 return mImpl.expireComponentBuffer(c2buffer);
940}
941
942void GraphicMetadataInputBuffers::flush() {
943 // This is no-op by default unless we're in array mode where we need to keep
944 // track of the flushed work.
945}
946
947std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
948 size_t size) {
949 std::shared_ptr<C2Allocator> alloc;
950 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
951 if (err != C2_OK) {
952 return nullptr;
953 }
954 std::unique_ptr<InputBuffersArray> array(
955 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
956 array->setPool(mPool);
957 array->setFormat(mFormat);
958 array->initialize(
959 mImpl,
960 size,
961 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
962 return new GraphicMetadataBuffer(format, alloc);
963 });
964 return std::move(array);
965}
966
967size_t GraphicMetadataInputBuffers::numClientBuffers() const {
968 return mImpl.numClientBuffers();
969}
970
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700971sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
972 std::shared_ptr<C2Allocator> alloc;
973 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
974 if (err != C2_OK) {
975 return nullptr;
976 }
977 return new GraphicMetadataBuffer(mFormat, alloc);
978}
979
Wonsik Kim469c8342019-04-11 16:46:09 -0700980// GraphicInputBuffers
981
982GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -0700983 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -0700984 : InputBuffers(componentName, name),
985 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -0700986 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -0700987
988bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700989 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700990 if (newBuffer == nullptr) {
991 return false;
992 }
993 *index = mImpl.assignSlot(newBuffer);
994 handleImageData(newBuffer);
995 *buffer = newBuffer;
996 return true;
997}
998
999bool GraphicInputBuffers::releaseBuffer(
1000 const sp<MediaCodecBuffer> &buffer,
1001 std::shared_ptr<C2Buffer> *c2buffer,
1002 bool release) {
1003 return mImpl.releaseSlot(buffer, c2buffer, release);
1004}
1005
1006bool GraphicInputBuffers::expireComponentBuffer(
1007 const std::shared_ptr<C2Buffer> &c2buffer) {
1008 return mImpl.expireComponentBuffer(c2buffer);
1009}
1010
1011void GraphicInputBuffers::flush() {
1012 // This is no-op by default unless we're in array mode where we need to keep
1013 // track of the flushed work.
1014}
1015
1016std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1017 std::unique_ptr<InputBuffersArray> array(
1018 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1019 array->setPool(mPool);
1020 array->setFormat(mFormat);
1021 array->initialize(
1022 mImpl,
1023 size,
1024 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1025 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1026 return AllocateGraphicBuffer(
1027 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1028 });
1029 return std::move(array);
1030}
1031
1032size_t GraphicInputBuffers::numClientBuffers() const {
1033 return mImpl.numClientBuffers();
1034}
1035
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001036sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1037 // TODO: read usage from intf
1038 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1039 return AllocateGraphicBuffer(
1040 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1041}
1042
Wonsik Kim469c8342019-04-11 16:46:09 -07001043// OutputBuffersArray
1044
1045void OutputBuffersArray::initialize(
1046 const FlexBuffersImpl &impl,
1047 size_t minSize,
1048 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001049 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001050 mImpl.initialize(impl, minSize, allocate);
1051}
1052
1053status_t OutputBuffersArray::registerBuffer(
1054 const std::shared_ptr<C2Buffer> &buffer,
1055 size_t *index,
1056 sp<MediaCodecBuffer> *clientBuffer) {
1057 sp<Codec2Buffer> c2Buffer;
1058 status_t err = mImpl.grabBuffer(
1059 index,
1060 &c2Buffer,
1061 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1062 return clientBuffer->canCopy(buffer);
1063 });
1064 if (err == WOULD_BLOCK) {
1065 ALOGV("[%s] buffers temporarily not available", mName);
1066 return err;
1067 } else if (err != OK) {
1068 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1069 return err;
1070 }
1071 c2Buffer->setFormat(mFormat);
1072 if (!c2Buffer->copy(buffer)) {
1073 ALOGD("[%s] copy buffer failed", mName);
1074 return WOULD_BLOCK;
1075 }
1076 submit(c2Buffer);
1077 handleImageData(c2Buffer);
1078 *clientBuffer = c2Buffer;
1079 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1080 return OK;
1081}
1082
1083status_t OutputBuffersArray::registerCsd(
1084 const C2StreamInitDataInfo::output *csd,
1085 size_t *index,
1086 sp<MediaCodecBuffer> *clientBuffer) {
1087 sp<Codec2Buffer> c2Buffer;
1088 status_t err = mImpl.grabBuffer(
1089 index,
1090 &c2Buffer,
1091 [csd](const sp<Codec2Buffer> &clientBuffer) {
1092 return clientBuffer->base() != nullptr
1093 && clientBuffer->capacity() >= csd->flexCount();
1094 });
1095 if (err != OK) {
1096 return err;
1097 }
1098 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1099 c2Buffer->setRange(0, csd->flexCount());
1100 c2Buffer->setFormat(mFormat);
1101 *clientBuffer = c2Buffer;
1102 return OK;
1103}
1104
1105bool OutputBuffersArray::releaseBuffer(
1106 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1107 return mImpl.returnBuffer(buffer, c2buffer, true);
1108}
1109
1110void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1111 (void)flushedWork;
1112 mImpl.flush();
1113 if (mSkipCutBuffer != nullptr) {
1114 mSkipCutBuffer->clear();
1115 }
1116}
1117
1118void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1119 mImpl.getArray(array);
1120}
1121
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001122size_t OutputBuffersArray::numClientBuffers() const {
1123 return mImpl.numClientBuffers();
1124}
1125
Wonsik Kim469c8342019-04-11 16:46:09 -07001126void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001127 switch (c2buffer->data().type()) {
1128 case C2BufferData::LINEAR: {
1129 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001130 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1131 const uint32_t block_size = linear_blocks.front().size();
1132 if (block_size < kMaxLinearBufferSize / 2) {
1133 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001134 } else {
1135 size = kMaxLinearBufferSize;
1136 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001137 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001138 return new LocalLinearBuffer(format, new ABuffer(size));
1139 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001140 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001141 break;
1142 }
1143
Wonsik Kima39882b2019-06-20 16:13:56 -07001144 case C2BufferData::GRAPHIC: {
1145 // This is only called for RawGraphicOutputBuffers.
1146 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001147 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001148 return ConstGraphicBlockBuffer::AllocateEmpty(
1149 format,
1150 [lbp](size_t capacity) {
1151 return lbp->newBuffer(capacity);
1152 });
1153 };
1154 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1155 mName, mFormat->debugString().c_str());
1156 break;
1157 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001158
1159 case C2BufferData::INVALID: [[fallthrough]];
1160 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1161 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1162 default:
1163 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1164 return;
1165 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001166 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001167}
1168
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001169void OutputBuffersArray::grow(size_t newSize) {
1170 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001171}
1172
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001173void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1174 mFormat = source->mFormat;
1175 mSkipCutBuffer = source->mSkipCutBuffer;
1176 mUnreportedFormat = source->mUnreportedFormat;
1177 mPending = std::move(source->mPending);
1178 mReorderStash = std::move(source->mReorderStash);
1179 mDepth = source->mDepth;
1180 mKey = source->mKey;
1181}
1182
Wonsik Kim469c8342019-04-11 16:46:09 -07001183// FlexOutputBuffers
1184
1185status_t FlexOutputBuffers::registerBuffer(
1186 const std::shared_ptr<C2Buffer> &buffer,
1187 size_t *index,
1188 sp<MediaCodecBuffer> *clientBuffer) {
1189 sp<Codec2Buffer> newBuffer = wrap(buffer);
1190 if (newBuffer == nullptr) {
1191 return NO_MEMORY;
1192 }
1193 newBuffer->setFormat(mFormat);
1194 *index = mImpl.assignSlot(newBuffer);
1195 handleImageData(newBuffer);
1196 *clientBuffer = newBuffer;
1197 ALOGV("[%s] registered buffer %zu", mName, *index);
1198 return OK;
1199}
1200
1201status_t FlexOutputBuffers::registerCsd(
1202 const C2StreamInitDataInfo::output *csd,
1203 size_t *index,
1204 sp<MediaCodecBuffer> *clientBuffer) {
1205 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1206 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1207 *index = mImpl.assignSlot(newBuffer);
1208 *clientBuffer = newBuffer;
1209 return OK;
1210}
1211
1212bool FlexOutputBuffers::releaseBuffer(
1213 const sp<MediaCodecBuffer> &buffer,
1214 std::shared_ptr<C2Buffer> *c2buffer) {
1215 return mImpl.releaseSlot(buffer, c2buffer, true);
1216}
1217
1218void FlexOutputBuffers::flush(
1219 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1220 (void) flushedWork;
1221 // This is no-op by default unless we're in array mode where we need to keep
1222 // track of the flushed work.
1223}
1224
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001225std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001226 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001227 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001228 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1229 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001230 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001231}
1232
1233size_t FlexOutputBuffers::numClientBuffers() const {
1234 return mImpl.numClientBuffers();
1235}
1236
1237// LinearOutputBuffers
1238
1239void LinearOutputBuffers::flush(
1240 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1241 if (mSkipCutBuffer != nullptr) {
1242 mSkipCutBuffer->clear();
1243 }
1244 FlexOutputBuffers::flush(flushedWork);
1245}
1246
1247sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1248 if (buffer == nullptr) {
1249 ALOGV("[%s] using a dummy buffer", mName);
1250 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1251 }
1252 if (buffer->data().type() != C2BufferData::LINEAR) {
1253 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1254 // We expect linear output buffers from the component.
1255 return nullptr;
1256 }
1257 if (buffer->data().linearBlocks().size() != 1u) {
1258 ALOGV("[%s] no linear buffers", mName);
1259 // We expect one and only one linear block from the component.
1260 return nullptr;
1261 }
1262 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1263 if (clientBuffer == nullptr) {
1264 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1265 return nullptr;
1266 }
1267 submit(clientBuffer);
1268 return clientBuffer;
1269}
1270
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001271std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1272 return [format = mFormat]{
1273 // TODO: proper max output size
1274 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1275 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001276}
1277
1278// GraphicOutputBuffers
1279
1280sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1281 return new DummyContainerBuffer(mFormat, buffer);
1282}
1283
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001284std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1285 return [format = mFormat]{
1286 return new DummyContainerBuffer(format);
1287 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001288}
1289
1290// RawGraphicOutputBuffers
1291
1292RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001293 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001294 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001295 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001296
1297sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1298 if (buffer == nullptr) {
1299 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1300 mFormat,
1301 [lbp = mLocalBufferPool](size_t capacity) {
1302 return lbp->newBuffer(capacity);
1303 });
1304 if (c2buffer == nullptr) {
1305 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1306 return nullptr;
1307 }
1308 c2buffer->setRange(0, 0);
1309 return c2buffer;
1310 } else {
1311 return ConstGraphicBlockBuffer::Allocate(
1312 mFormat,
1313 buffer,
1314 [lbp = mLocalBufferPool](size_t capacity) {
1315 return lbp->newBuffer(capacity);
1316 });
1317 }
1318}
1319
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001320std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1321 return [format = mFormat, lbp = mLocalBufferPool]{
1322 return ConstGraphicBlockBuffer::AllocateEmpty(
1323 format,
1324 [lbp](size_t capacity) {
1325 return lbp->newBuffer(capacity);
1326 });
1327 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001328}
1329
1330} // namespace android