blob: d7cc175aea2f490e63197ab5ce128db2ca6d8291 [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>
24#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070025#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070026
27#include "CCodecBuffers.h"
28
29namespace android {
30
31namespace {
32
33sp<GraphicBlockBuffer> AllocateGraphicBuffer(
34 const std::shared_ptr<C2BlockPool> &pool,
35 const sp<AMessage> &format,
36 uint32_t pixelFormat,
37 const C2MemoryUsage &usage,
38 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
39 int32_t width, height;
40 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
41 ALOGD("format lacks width or height");
42 return nullptr;
43 }
44
45 std::shared_ptr<C2GraphicBlock> block;
46 c2_status_t err = pool->fetchGraphicBlock(
47 width, height, pixelFormat, usage, &block);
48 if (err != C2_OK) {
49 ALOGD("fetch graphic block failed: %d", err);
50 return nullptr;
51 }
52
53 return GraphicBlockBuffer::Allocate(
54 format,
55 block,
56 [localBufferPool](size_t capacity) {
57 return localBufferPool->newBuffer(capacity);
58 });
59}
60
61} // namespace
62
63// CCodecBuffers
64
65void CCodecBuffers::setFormat(const sp<AMessage> &format) {
66 CHECK(format != nullptr);
67 mFormat = format;
68}
69
70sp<AMessage> CCodecBuffers::dupFormat() {
71 return mFormat != nullptr ? mFormat->dup() : nullptr;
72}
73
74void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
75 sp<ABuffer> imageDataCandidate = buffer->getImageData();
76 if (imageDataCandidate == nullptr) {
77 return;
78 }
79 sp<ABuffer> imageData;
80 if (!mFormat->findBuffer("image-data", &imageData)
81 || imageDataCandidate->size() != imageData->size()
82 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
83 ALOGD("[%s] updating image-data", mName);
84 sp<AMessage> newFormat = dupFormat();
85 newFormat->setBuffer("image-data", imageDataCandidate);
86 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
87 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
88 int32_t stride = img->mPlane[0].mRowInc;
89 newFormat->setInt32(KEY_STRIDE, stride);
90 ALOGD("[%s] updating stride = %d", mName, stride);
91 if (img->mNumPlanes > 1 && stride > 0) {
92 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
93 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
94 ALOGD("[%s] updating vstride = %d", mName, vstride);
95 }
96 }
97 setFormat(newFormat);
98 buffer->setFormat(newFormat);
99 }
100}
101
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700102// InputBuffers
103
104sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
105 sp<Codec2Buffer> copy = createNewBuffer();
106 if (copy == nullptr) {
107 return nullptr;
108 }
109 std::shared_ptr<C2Buffer> c2buffer;
110 if (!releaseBuffer(buffer, &c2buffer, true)) {
111 return nullptr;
112 }
113 if (!copy->canCopy(c2buffer)) {
114 return nullptr;
115 }
116 if (!copy->copy(c2buffer)) {
117 return nullptr;
118 }
119 return copy;
120}
121
Wonsik Kim469c8342019-04-11 16:46:09 -0700122// OutputBuffers
123
124void OutputBuffers::initSkipCutBuffer(
125 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
126 CHECK(mSkipCutBuffer == nullptr);
127 mDelay = delay;
128 mPadding = padding;
129 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700130 mChannelCount = channelCount;
131 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700132}
133
134void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
135 if (mSkipCutBuffer == nullptr) {
136 return;
137 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700138 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
139 return;
140 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700141 int32_t delay = mDelay;
142 int32_t padding = mPadding;
143 if (sampleRate != mSampleRate) {
144 delay = ((int64_t)delay * sampleRate) / mSampleRate;
145 padding = ((int64_t)padding * sampleRate) / mSampleRate;
146 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700147 mSampleRate = sampleRate;
148 mChannelCount = channelCount;
149 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700150}
151
152void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
153 if (mSkipCutBuffer != nullptr) {
154 mSkipCutBuffer->submit(buffer);
155 }
156}
157
158void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
159 mSkipCutBuffer = scb;
160}
161
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700162void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700163 if (mSkipCutBuffer != nullptr) {
164 size_t prevSize = mSkipCutBuffer->size();
165 if (prevSize != 0u) {
166 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
167 }
168 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700169 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700170}
171
172// LocalBufferPool
173
174std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
175 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
176}
177
178sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
179 Mutex::Autolock lock(mMutex);
180 auto it = std::find_if(
181 mPool.begin(), mPool.end(),
182 [capacity](const std::vector<uint8_t> &vec) {
183 return vec.capacity() >= capacity;
184 });
185 if (it != mPool.end()) {
186 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
187 mPool.erase(it);
188 return buffer;
189 }
190 if (mUsedSize + capacity > mPoolCapacity) {
191 while (!mPool.empty()) {
192 mUsedSize -= mPool.back().capacity();
193 mPool.pop_back();
194 }
195 if (mUsedSize + capacity > mPoolCapacity) {
196 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
197 mUsedSize, capacity, mPoolCapacity);
198 return nullptr;
199 }
200 }
201 std::vector<uint8_t> vec(capacity);
202 mUsedSize += vec.capacity();
203 return new VectorBuffer(std::move(vec), shared_from_this());
204}
205
206LocalBufferPool::VectorBuffer::VectorBuffer(
207 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
208 : ABuffer(vec.data(), vec.capacity()),
209 mVec(std::move(vec)),
210 mPool(pool) {
211}
212
213LocalBufferPool::VectorBuffer::~VectorBuffer() {
214 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
215 if (pool) {
216 // If pool is alive, return the vector back to the pool so that
217 // it can be recycled.
218 pool->returnVector(std::move(mVec));
219 }
220}
221
222void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
223 Mutex::Autolock lock(mMutex);
224 mPool.push_front(std::move(vec));
225}
226
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700227// FlexBuffersImpl
228
Wonsik Kim469c8342019-04-11 16:46:09 -0700229size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
230 for (size_t i = 0; i < mBuffers.size(); ++i) {
231 if (mBuffers[i].clientBuffer == nullptr
232 && mBuffers[i].compBuffer.expired()) {
233 mBuffers[i].clientBuffer = buffer;
234 return i;
235 }
236 }
237 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
238 return mBuffers.size() - 1;
239}
240
Wonsik Kim469c8342019-04-11 16:46:09 -0700241bool FlexBuffersImpl::releaseSlot(
242 const sp<MediaCodecBuffer> &buffer,
243 std::shared_ptr<C2Buffer> *c2buffer,
244 bool release) {
245 sp<Codec2Buffer> clientBuffer;
246 size_t index = mBuffers.size();
247 for (size_t i = 0; i < mBuffers.size(); ++i) {
248 if (mBuffers[i].clientBuffer == buffer) {
249 clientBuffer = mBuffers[i].clientBuffer;
250 if (release) {
251 mBuffers[i].clientBuffer.clear();
252 }
253 index = i;
254 break;
255 }
256 }
257 if (clientBuffer == nullptr) {
258 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
259 return false;
260 }
261 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
262 if (!result) {
263 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700264 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700265 mBuffers[index].compBuffer = result;
266 }
267 if (c2buffer) {
268 *c2buffer = result;
269 }
270 return true;
271}
272
273bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
274 for (size_t i = 0; i < mBuffers.size(); ++i) {
275 std::shared_ptr<C2Buffer> compBuffer =
276 mBuffers[i].compBuffer.lock();
277 if (!compBuffer || compBuffer != c2buffer) {
278 continue;
279 }
280 mBuffers[i].compBuffer.reset();
281 ALOGV("[%s] codec released buffer #%zu", mName, i);
282 return true;
283 }
284 ALOGV("[%s] codec released an unknown buffer", mName);
285 return false;
286}
287
288void FlexBuffersImpl::flush() {
289 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
290 mBuffers.clear();
291}
292
293size_t FlexBuffersImpl::numClientBuffers() const {
294 return std::count_if(
295 mBuffers.begin(), mBuffers.end(),
296 [](const Entry &entry) {
297 return (entry.clientBuffer != nullptr);
298 });
299}
300
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700301size_t FlexBuffersImpl::numComponentBuffers() const {
302 return std::count_if(
303 mBuffers.begin(), mBuffers.end(),
304 [](const Entry &entry) {
305 return !entry.compBuffer.expired();
306 });
307}
308
Wonsik Kim469c8342019-04-11 16:46:09 -0700309// BuffersArrayImpl
310
311void BuffersArrayImpl::initialize(
312 const FlexBuffersImpl &impl,
313 size_t minSize,
314 std::function<sp<Codec2Buffer>()> allocate) {
315 mImplName = impl.mImplName + "[N]";
316 mName = mImplName.c_str();
317 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
318 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
319 bool ownedByClient = (clientBuffer != nullptr);
320 if (!ownedByClient) {
321 clientBuffer = allocate();
322 }
323 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
324 }
325 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
326 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
327 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
328 }
329}
330
331status_t BuffersArrayImpl::grabBuffer(
332 size_t *index,
333 sp<Codec2Buffer> *buffer,
334 std::function<bool(const sp<Codec2Buffer> &)> match) {
335 // allBuffersDontMatch remains true if all buffers are available but
336 // match() returns false for every buffer.
337 bool allBuffersDontMatch = true;
338 for (size_t i = 0; i < mBuffers.size(); ++i) {
339 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
340 if (match(mBuffers[i].clientBuffer)) {
341 mBuffers[i].ownedByClient = true;
342 *buffer = mBuffers[i].clientBuffer;
343 (*buffer)->meta()->clear();
344 (*buffer)->setRange(0, (*buffer)->capacity());
345 *index = i;
346 return OK;
347 }
348 } else {
349 allBuffersDontMatch = false;
350 }
351 }
352 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
353}
354
355bool BuffersArrayImpl::returnBuffer(
356 const sp<MediaCodecBuffer> &buffer,
357 std::shared_ptr<C2Buffer> *c2buffer,
358 bool release) {
359 sp<Codec2Buffer> clientBuffer;
360 size_t index = mBuffers.size();
361 for (size_t i = 0; i < mBuffers.size(); ++i) {
362 if (mBuffers[i].clientBuffer == buffer) {
363 if (!mBuffers[i].ownedByClient) {
364 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
365 mName, i);
366 }
367 clientBuffer = mBuffers[i].clientBuffer;
368 if (release) {
369 mBuffers[i].ownedByClient = false;
370 }
371 index = i;
372 break;
373 }
374 }
375 if (clientBuffer == nullptr) {
376 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
377 return false;
378 }
379 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
380 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
381 if (!result) {
382 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700383 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700384 mBuffers[index].compBuffer = result;
385 }
386 if (c2buffer) {
387 *c2buffer = result;
388 }
389 return true;
390}
391
392bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
393 for (size_t i = 0; i < mBuffers.size(); ++i) {
394 std::shared_ptr<C2Buffer> compBuffer =
395 mBuffers[i].compBuffer.lock();
396 if (!compBuffer) {
397 continue;
398 }
399 if (c2buffer == compBuffer) {
400 if (mBuffers[i].ownedByClient) {
401 // This should not happen.
402 ALOGD("[%s] codec released a buffer owned by client "
403 "(index %zu)", mName, i);
404 }
405 mBuffers[i].compBuffer.reset();
406 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
407 return true;
408 }
409 }
410 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
411 return false;
412}
413
414void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
415 array->clear();
416 for (const Entry &entry : mBuffers) {
417 array->push(entry.clientBuffer);
418 }
419}
420
421void BuffersArrayImpl::flush() {
422 for (Entry &entry : mBuffers) {
423 entry.ownedByClient = false;
424 }
425}
426
427void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
428 size_t size = mBuffers.size();
429 mBuffers.clear();
430 for (size_t i = 0; i < size; ++i) {
431 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
432 }
433}
434
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700435void BuffersArrayImpl::grow(
436 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
437 CHECK_LT(mBuffers.size(), newSize);
438 while (mBuffers.size() < newSize) {
439 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
440 }
441}
442
Wonsik Kim469c8342019-04-11 16:46:09 -0700443size_t BuffersArrayImpl::numClientBuffers() const {
444 return std::count_if(
445 mBuffers.begin(), mBuffers.end(),
446 [](const Entry &entry) {
447 return entry.ownedByClient;
448 });
449}
450
Wonsik Kima39882b2019-06-20 16:13:56 -0700451size_t BuffersArrayImpl::arraySize() const {
452 return mBuffers.size();
453}
454
Wonsik Kim469c8342019-04-11 16:46:09 -0700455// InputBuffersArray
456
457void InputBuffersArray::initialize(
458 const FlexBuffersImpl &impl,
459 size_t minSize,
460 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700461 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700462 mImpl.initialize(impl, minSize, allocate);
463}
464
465void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
466 mImpl.getArray(array);
467}
468
469bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
470 sp<Codec2Buffer> c2Buffer;
471 status_t err = mImpl.grabBuffer(index, &c2Buffer);
472 if (err == OK) {
473 c2Buffer->setFormat(mFormat);
474 handleImageData(c2Buffer);
475 *buffer = c2Buffer;
476 return true;
477 }
478 return false;
479}
480
481bool InputBuffersArray::releaseBuffer(
482 const sp<MediaCodecBuffer> &buffer,
483 std::shared_ptr<C2Buffer> *c2buffer,
484 bool release) {
485 return mImpl.returnBuffer(buffer, c2buffer, release);
486}
487
488bool InputBuffersArray::expireComponentBuffer(
489 const std::shared_ptr<C2Buffer> &c2buffer) {
490 return mImpl.expireComponentBuffer(c2buffer);
491}
492
493void InputBuffersArray::flush() {
494 mImpl.flush();
495}
496
497size_t InputBuffersArray::numClientBuffers() const {
498 return mImpl.numClientBuffers();
499}
500
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700501sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
502 return mAllocate();
503}
504
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800505// SlotInputBuffers
506
507bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
508 sp<Codec2Buffer> newBuffer = createNewBuffer();
509 *index = mImpl.assignSlot(newBuffer);
510 *buffer = newBuffer;
511 return true;
512}
513
514bool SlotInputBuffers::releaseBuffer(
515 const sp<MediaCodecBuffer> &buffer,
516 std::shared_ptr<C2Buffer> *c2buffer,
517 bool release) {
518 return mImpl.releaseSlot(buffer, c2buffer, release);
519}
520
521bool SlotInputBuffers::expireComponentBuffer(
522 const std::shared_ptr<C2Buffer> &c2buffer) {
523 return mImpl.expireComponentBuffer(c2buffer);
524}
525
526void SlotInputBuffers::flush() {
527 mImpl.flush();
528}
529
530std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
531 TRESPASS("Array mode should not be called at non-legacy mode");
532 return nullptr;
533}
534
535size_t SlotInputBuffers::numClientBuffers() const {
536 return mImpl.numClientBuffers();
537}
538
539sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
540 return new DummyContainerBuffer{mFormat, nullptr};
541}
542
Wonsik Kim469c8342019-04-11 16:46:09 -0700543// LinearInputBuffers
544
545bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700546 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700547 if (newBuffer == nullptr) {
548 return false;
549 }
550 *index = mImpl.assignSlot(newBuffer);
551 *buffer = newBuffer;
552 return true;
553}
554
555bool LinearInputBuffers::releaseBuffer(
556 const sp<MediaCodecBuffer> &buffer,
557 std::shared_ptr<C2Buffer> *c2buffer,
558 bool release) {
559 return mImpl.releaseSlot(buffer, c2buffer, release);
560}
561
562bool LinearInputBuffers::expireComponentBuffer(
563 const std::shared_ptr<C2Buffer> &c2buffer) {
564 return mImpl.expireComponentBuffer(c2buffer);
565}
566
567void LinearInputBuffers::flush() {
568 // This is no-op by default unless we're in array mode where we need to keep
569 // track of the flushed work.
570 mImpl.flush();
571}
572
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700573std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700574 std::unique_ptr<InputBuffersArray> array(
575 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
576 array->setPool(mPool);
577 array->setFormat(mFormat);
578 array->initialize(
579 mImpl,
580 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700581 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
582 return Alloc(pool, format);
583 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700584 return std::move(array);
585}
586
587size_t LinearInputBuffers::numClientBuffers() const {
588 return mImpl.numClientBuffers();
589}
590
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700591// static
592sp<Codec2Buffer> LinearInputBuffers::Alloc(
593 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
594 int32_t capacity = kLinearBufferSize;
595 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
596 if ((size_t)capacity > kMaxLinearBufferSize) {
597 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
598 capacity = kMaxLinearBufferSize;
599 }
600
601 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700602 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
603 std::shared_ptr<C2LinearBlock> block;
604
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700605 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700606 if (err != C2_OK) {
607 return nullptr;
608 }
609
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700610 return LinearBlockBuffer::Allocate(format, block);
611}
612
613sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
614 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700615}
616
617// EncryptedLinearInputBuffers
618
619EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
620 bool secure,
621 const sp<MemoryDealer> &dealer,
622 const sp<ICrypto> &crypto,
623 int32_t heapSeqNum,
624 size_t capacity,
625 size_t numInputSlots,
626 const char *componentName, const char *name)
627 : LinearInputBuffers(componentName, name),
628 mUsage({0, 0}),
629 mDealer(dealer),
630 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700631 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700632 if (secure) {
633 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
634 } else {
635 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
636 }
637 for (size_t i = 0; i < numInputSlots; ++i) {
638 sp<IMemory> memory = mDealer->allocate(capacity);
639 if (memory == nullptr) {
640 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
641 mName, i);
642 break;
643 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700644 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700645 }
646}
647
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700648std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
649 std::unique_ptr<InputBuffersArray> array(
650 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
651 array->setPool(mPool);
652 array->setFormat(mFormat);
653 array->initialize(
654 mImpl,
655 size,
656 [pool = mPool,
657 format = mFormat,
658 usage = mUsage,
659 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
660 return Alloc(pool, format, usage, memoryVector);
661 });
662 return std::move(array);
663}
664
665
666// static
667sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
668 const std::shared_ptr<C2BlockPool> &pool,
669 const sp<AMessage> &format,
670 C2MemoryUsage usage,
671 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
672 int32_t capacity = kLinearBufferSize;
673 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
674 if ((size_t)capacity > kMaxLinearBufferSize) {
675 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
676 capacity = kMaxLinearBufferSize;
677 }
678
Wonsik Kim469c8342019-04-11 16:46:09 -0700679 sp<IMemory> memory;
680 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700681 int32_t heapSeqNum = -1;
682 for (; slot < memoryVector->size(); ++slot) {
683 if (memoryVector->at(slot).block.expired()) {
684 memory = memoryVector->at(slot).memory;
685 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700686 break;
687 }
688 }
689 if (memory == nullptr) {
690 return nullptr;
691 }
692
693 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700694 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700695 if (err != C2_OK || block == nullptr) {
696 return nullptr;
697 }
698
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700699 memoryVector->at(slot).block = block;
700 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
701}
702
703sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
704 // TODO: android_2020
705 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700706}
707
708// GraphicMetadataInputBuffers
709
710GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
711 const char *componentName, const char *name)
712 : InputBuffers(componentName, name),
713 mImpl(mName),
714 mStore(GetCodec2PlatformAllocatorStore()) { }
715
716bool GraphicMetadataInputBuffers::requestNewBuffer(
717 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700718 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700719 if (newBuffer == nullptr) {
720 return false;
721 }
722 *index = mImpl.assignSlot(newBuffer);
723 *buffer = newBuffer;
724 return true;
725}
726
727bool GraphicMetadataInputBuffers::releaseBuffer(
728 const sp<MediaCodecBuffer> &buffer,
729 std::shared_ptr<C2Buffer> *c2buffer,
730 bool release) {
731 return mImpl.releaseSlot(buffer, c2buffer, release);
732}
733
734bool GraphicMetadataInputBuffers::expireComponentBuffer(
735 const std::shared_ptr<C2Buffer> &c2buffer) {
736 return mImpl.expireComponentBuffer(c2buffer);
737}
738
739void GraphicMetadataInputBuffers::flush() {
740 // This is no-op by default unless we're in array mode where we need to keep
741 // track of the flushed work.
742}
743
744std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
745 size_t size) {
746 std::shared_ptr<C2Allocator> alloc;
747 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
748 if (err != C2_OK) {
749 return nullptr;
750 }
751 std::unique_ptr<InputBuffersArray> array(
752 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
753 array->setPool(mPool);
754 array->setFormat(mFormat);
755 array->initialize(
756 mImpl,
757 size,
758 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
759 return new GraphicMetadataBuffer(format, alloc);
760 });
761 return std::move(array);
762}
763
764size_t GraphicMetadataInputBuffers::numClientBuffers() const {
765 return mImpl.numClientBuffers();
766}
767
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700768sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
769 std::shared_ptr<C2Allocator> alloc;
770 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
771 if (err != C2_OK) {
772 return nullptr;
773 }
774 return new GraphicMetadataBuffer(mFormat, alloc);
775}
776
Wonsik Kim469c8342019-04-11 16:46:09 -0700777// GraphicInputBuffers
778
779GraphicInputBuffers::GraphicInputBuffers(
780 size_t numInputSlots, const char *componentName, const char *name)
781 : InputBuffers(componentName, name),
782 mImpl(mName),
783 mLocalBufferPool(LocalBufferPool::Create(
784 kMaxLinearBufferSize * numInputSlots)) { }
785
786bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700787 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700788 if (newBuffer == nullptr) {
789 return false;
790 }
791 *index = mImpl.assignSlot(newBuffer);
792 handleImageData(newBuffer);
793 *buffer = newBuffer;
794 return true;
795}
796
797bool GraphicInputBuffers::releaseBuffer(
798 const sp<MediaCodecBuffer> &buffer,
799 std::shared_ptr<C2Buffer> *c2buffer,
800 bool release) {
801 return mImpl.releaseSlot(buffer, c2buffer, release);
802}
803
804bool GraphicInputBuffers::expireComponentBuffer(
805 const std::shared_ptr<C2Buffer> &c2buffer) {
806 return mImpl.expireComponentBuffer(c2buffer);
807}
808
809void GraphicInputBuffers::flush() {
810 // This is no-op by default unless we're in array mode where we need to keep
811 // track of the flushed work.
812}
813
814std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
815 std::unique_ptr<InputBuffersArray> array(
816 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
817 array->setPool(mPool);
818 array->setFormat(mFormat);
819 array->initialize(
820 mImpl,
821 size,
822 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
823 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
824 return AllocateGraphicBuffer(
825 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
826 });
827 return std::move(array);
828}
829
830size_t GraphicInputBuffers::numClientBuffers() const {
831 return mImpl.numClientBuffers();
832}
833
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700834sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
835 // TODO: read usage from intf
836 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
837 return AllocateGraphicBuffer(
838 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
839}
840
Wonsik Kim469c8342019-04-11 16:46:09 -0700841// OutputBuffersArray
842
843void OutputBuffersArray::initialize(
844 const FlexBuffersImpl &impl,
845 size_t minSize,
846 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700847 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700848 mImpl.initialize(impl, minSize, allocate);
849}
850
851status_t OutputBuffersArray::registerBuffer(
852 const std::shared_ptr<C2Buffer> &buffer,
853 size_t *index,
854 sp<MediaCodecBuffer> *clientBuffer) {
855 sp<Codec2Buffer> c2Buffer;
856 status_t err = mImpl.grabBuffer(
857 index,
858 &c2Buffer,
859 [buffer](const sp<Codec2Buffer> &clientBuffer) {
860 return clientBuffer->canCopy(buffer);
861 });
862 if (err == WOULD_BLOCK) {
863 ALOGV("[%s] buffers temporarily not available", mName);
864 return err;
865 } else if (err != OK) {
866 ALOGD("[%s] grabBuffer failed: %d", mName, err);
867 return err;
868 }
869 c2Buffer->setFormat(mFormat);
870 if (!c2Buffer->copy(buffer)) {
871 ALOGD("[%s] copy buffer failed", mName);
872 return WOULD_BLOCK;
873 }
874 submit(c2Buffer);
875 handleImageData(c2Buffer);
876 *clientBuffer = c2Buffer;
877 ALOGV("[%s] grabbed buffer %zu", mName, *index);
878 return OK;
879}
880
881status_t OutputBuffersArray::registerCsd(
882 const C2StreamInitDataInfo::output *csd,
883 size_t *index,
884 sp<MediaCodecBuffer> *clientBuffer) {
885 sp<Codec2Buffer> c2Buffer;
886 status_t err = mImpl.grabBuffer(
887 index,
888 &c2Buffer,
889 [csd](const sp<Codec2Buffer> &clientBuffer) {
890 return clientBuffer->base() != nullptr
891 && clientBuffer->capacity() >= csd->flexCount();
892 });
893 if (err != OK) {
894 return err;
895 }
896 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
897 c2Buffer->setRange(0, csd->flexCount());
898 c2Buffer->setFormat(mFormat);
899 *clientBuffer = c2Buffer;
900 return OK;
901}
902
903bool OutputBuffersArray::releaseBuffer(
904 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
905 return mImpl.returnBuffer(buffer, c2buffer, true);
906}
907
908void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
909 (void)flushedWork;
910 mImpl.flush();
911 if (mSkipCutBuffer != nullptr) {
912 mSkipCutBuffer->clear();
913 }
914}
915
916void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
917 mImpl.getArray(array);
918}
919
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700920size_t OutputBuffersArray::numClientBuffers() const {
921 return mImpl.numClientBuffers();
922}
923
Wonsik Kim469c8342019-04-11 16:46:09 -0700924void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700925 switch (c2buffer->data().type()) {
926 case C2BufferData::LINEAR: {
927 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -0700928 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
929 const uint32_t block_size = linear_blocks.front().size();
930 if (block_size < kMaxLinearBufferSize / 2) {
931 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -0700932 } else {
933 size = kMaxLinearBufferSize;
934 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700935 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -0700936 return new LocalLinearBuffer(format, new ABuffer(size));
937 };
Wonsik Kima39882b2019-06-20 16:13:56 -0700938 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -0700939 break;
940 }
941
Wonsik Kima39882b2019-06-20 16:13:56 -0700942 case C2BufferData::GRAPHIC: {
943 // This is only called for RawGraphicOutputBuffers.
944 mAlloc = [format = mFormat,
945 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
946 return ConstGraphicBlockBuffer::AllocateEmpty(
947 format,
948 [lbp](size_t capacity) {
949 return lbp->newBuffer(capacity);
950 });
951 };
952 ALOGD("[%s] reallocating with graphic buffer: format = %s",
953 mName, mFormat->debugString().c_str());
954 break;
955 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700956
957 case C2BufferData::INVALID: [[fallthrough]];
958 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
959 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
960 default:
961 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
962 return;
963 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700964 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700965}
966
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700967void OutputBuffersArray::grow(size_t newSize) {
968 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700969}
970
971// FlexOutputBuffers
972
973status_t FlexOutputBuffers::registerBuffer(
974 const std::shared_ptr<C2Buffer> &buffer,
975 size_t *index,
976 sp<MediaCodecBuffer> *clientBuffer) {
977 sp<Codec2Buffer> newBuffer = wrap(buffer);
978 if (newBuffer == nullptr) {
979 return NO_MEMORY;
980 }
981 newBuffer->setFormat(mFormat);
982 *index = mImpl.assignSlot(newBuffer);
983 handleImageData(newBuffer);
984 *clientBuffer = newBuffer;
985 ALOGV("[%s] registered buffer %zu", mName, *index);
986 return OK;
987}
988
989status_t FlexOutputBuffers::registerCsd(
990 const C2StreamInitDataInfo::output *csd,
991 size_t *index,
992 sp<MediaCodecBuffer> *clientBuffer) {
993 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
994 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
995 *index = mImpl.assignSlot(newBuffer);
996 *clientBuffer = newBuffer;
997 return OK;
998}
999
1000bool FlexOutputBuffers::releaseBuffer(
1001 const sp<MediaCodecBuffer> &buffer,
1002 std::shared_ptr<C2Buffer> *c2buffer) {
1003 return mImpl.releaseSlot(buffer, c2buffer, true);
1004}
1005
1006void FlexOutputBuffers::flush(
1007 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1008 (void) flushedWork;
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<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
1014 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1015 array->setFormat(mFormat);
1016 array->transferSkipCutBuffer(mSkipCutBuffer);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001017 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1018 array->initialize(mImpl, size, alloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001019 return std::move(array);
1020}
1021
1022size_t FlexOutputBuffers::numClientBuffers() const {
1023 return mImpl.numClientBuffers();
1024}
1025
1026// LinearOutputBuffers
1027
1028void LinearOutputBuffers::flush(
1029 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1030 if (mSkipCutBuffer != nullptr) {
1031 mSkipCutBuffer->clear();
1032 }
1033 FlexOutputBuffers::flush(flushedWork);
1034}
1035
1036sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1037 if (buffer == nullptr) {
1038 ALOGV("[%s] using a dummy buffer", mName);
1039 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1040 }
1041 if (buffer->data().type() != C2BufferData::LINEAR) {
1042 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1043 // We expect linear output buffers from the component.
1044 return nullptr;
1045 }
1046 if (buffer->data().linearBlocks().size() != 1u) {
1047 ALOGV("[%s] no linear buffers", mName);
1048 // We expect one and only one linear block from the component.
1049 return nullptr;
1050 }
1051 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1052 if (clientBuffer == nullptr) {
1053 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1054 return nullptr;
1055 }
1056 submit(clientBuffer);
1057 return clientBuffer;
1058}
1059
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001060std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1061 return [format = mFormat]{
1062 // TODO: proper max output size
1063 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1064 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001065}
1066
1067// GraphicOutputBuffers
1068
1069sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1070 return new DummyContainerBuffer(mFormat, buffer);
1071}
1072
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001073std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1074 return [format = mFormat]{
1075 return new DummyContainerBuffer(format);
1076 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001077}
1078
1079// RawGraphicOutputBuffers
1080
1081RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1082 size_t numOutputSlots, const char *componentName, const char *name)
1083 : FlexOutputBuffers(componentName, name),
1084 mLocalBufferPool(LocalBufferPool::Create(
1085 kMaxLinearBufferSize * numOutputSlots)) { }
1086
1087sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1088 if (buffer == nullptr) {
1089 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1090 mFormat,
1091 [lbp = mLocalBufferPool](size_t capacity) {
1092 return lbp->newBuffer(capacity);
1093 });
1094 if (c2buffer == nullptr) {
1095 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1096 return nullptr;
1097 }
1098 c2buffer->setRange(0, 0);
1099 return c2buffer;
1100 } else {
1101 return ConstGraphicBlockBuffer::Allocate(
1102 mFormat,
1103 buffer,
1104 [lbp = mLocalBufferPool](size_t capacity) {
1105 return lbp->newBuffer(capacity);
1106 });
1107 }
1108}
1109
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001110std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1111 return [format = mFormat, lbp = mLocalBufferPool]{
1112 return ConstGraphicBlockBuffer::AllocateEmpty(
1113 format,
1114 [lbp](size_t capacity) {
1115 return lbp->newBuffer(capacity);
1116 });
1117 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001118}
1119
1120} // namespace android