blob: 668f892017991027bb14a2da95543a1bc27e1204 [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();
264 mBuffers[index].compBuffer = result;
265 }
266 if (c2buffer) {
267 *c2buffer = result;
268 }
269 return true;
270}
271
272bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
273 for (size_t i = 0; i < mBuffers.size(); ++i) {
274 std::shared_ptr<C2Buffer> compBuffer =
275 mBuffers[i].compBuffer.lock();
276 if (!compBuffer || compBuffer != c2buffer) {
277 continue;
278 }
279 mBuffers[i].compBuffer.reset();
280 ALOGV("[%s] codec released buffer #%zu", mName, i);
281 return true;
282 }
283 ALOGV("[%s] codec released an unknown buffer", mName);
284 return false;
285}
286
287void FlexBuffersImpl::flush() {
288 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
289 mBuffers.clear();
290}
291
292size_t FlexBuffersImpl::numClientBuffers() const {
293 return std::count_if(
294 mBuffers.begin(), mBuffers.end(),
295 [](const Entry &entry) {
296 return (entry.clientBuffer != nullptr);
297 });
298}
299
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700300size_t FlexBuffersImpl::numComponentBuffers() const {
301 return std::count_if(
302 mBuffers.begin(), mBuffers.end(),
303 [](const Entry &entry) {
304 return !entry.compBuffer.expired();
305 });
306}
307
Wonsik Kim469c8342019-04-11 16:46:09 -0700308// BuffersArrayImpl
309
310void BuffersArrayImpl::initialize(
311 const FlexBuffersImpl &impl,
312 size_t minSize,
313 std::function<sp<Codec2Buffer>()> allocate) {
314 mImplName = impl.mImplName + "[N]";
315 mName = mImplName.c_str();
316 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
317 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
318 bool ownedByClient = (clientBuffer != nullptr);
319 if (!ownedByClient) {
320 clientBuffer = allocate();
321 }
322 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
323 }
324 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
325 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
326 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
327 }
328}
329
330status_t BuffersArrayImpl::grabBuffer(
331 size_t *index,
332 sp<Codec2Buffer> *buffer,
333 std::function<bool(const sp<Codec2Buffer> &)> match) {
334 // allBuffersDontMatch remains true if all buffers are available but
335 // match() returns false for every buffer.
336 bool allBuffersDontMatch = true;
337 for (size_t i = 0; i < mBuffers.size(); ++i) {
338 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
339 if (match(mBuffers[i].clientBuffer)) {
340 mBuffers[i].ownedByClient = true;
341 *buffer = mBuffers[i].clientBuffer;
342 (*buffer)->meta()->clear();
343 (*buffer)->setRange(0, (*buffer)->capacity());
344 *index = i;
345 return OK;
346 }
347 } else {
348 allBuffersDontMatch = false;
349 }
350 }
351 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
352}
353
354bool BuffersArrayImpl::returnBuffer(
355 const sp<MediaCodecBuffer> &buffer,
356 std::shared_ptr<C2Buffer> *c2buffer,
357 bool release) {
358 sp<Codec2Buffer> clientBuffer;
359 size_t index = mBuffers.size();
360 for (size_t i = 0; i < mBuffers.size(); ++i) {
361 if (mBuffers[i].clientBuffer == buffer) {
362 if (!mBuffers[i].ownedByClient) {
363 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
364 mName, i);
365 }
366 clientBuffer = mBuffers[i].clientBuffer;
367 if (release) {
368 mBuffers[i].ownedByClient = false;
369 }
370 index = i;
371 break;
372 }
373 }
374 if (clientBuffer == nullptr) {
375 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
376 return false;
377 }
378 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
379 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
380 if (!result) {
381 result = clientBuffer->asC2Buffer();
382 mBuffers[index].compBuffer = result;
383 }
384 if (c2buffer) {
385 *c2buffer = result;
386 }
387 return true;
388}
389
390bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
391 for (size_t i = 0; i < mBuffers.size(); ++i) {
392 std::shared_ptr<C2Buffer> compBuffer =
393 mBuffers[i].compBuffer.lock();
394 if (!compBuffer) {
395 continue;
396 }
397 if (c2buffer == compBuffer) {
398 if (mBuffers[i].ownedByClient) {
399 // This should not happen.
400 ALOGD("[%s] codec released a buffer owned by client "
401 "(index %zu)", mName, i);
402 }
403 mBuffers[i].compBuffer.reset();
404 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
405 return true;
406 }
407 }
408 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
409 return false;
410}
411
412void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
413 array->clear();
414 for (const Entry &entry : mBuffers) {
415 array->push(entry.clientBuffer);
416 }
417}
418
419void BuffersArrayImpl::flush() {
420 for (Entry &entry : mBuffers) {
421 entry.ownedByClient = false;
422 }
423}
424
425void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
426 size_t size = mBuffers.size();
427 mBuffers.clear();
428 for (size_t i = 0; i < size; ++i) {
429 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
430 }
431}
432
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700433void BuffersArrayImpl::grow(
434 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
435 CHECK_LT(mBuffers.size(), newSize);
436 while (mBuffers.size() < newSize) {
437 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
438 }
439}
440
Wonsik Kim469c8342019-04-11 16:46:09 -0700441size_t BuffersArrayImpl::numClientBuffers() const {
442 return std::count_if(
443 mBuffers.begin(), mBuffers.end(),
444 [](const Entry &entry) {
445 return entry.ownedByClient;
446 });
447}
448
Wonsik Kima39882b2019-06-20 16:13:56 -0700449size_t BuffersArrayImpl::arraySize() const {
450 return mBuffers.size();
451}
452
Wonsik Kim469c8342019-04-11 16:46:09 -0700453// InputBuffersArray
454
455void InputBuffersArray::initialize(
456 const FlexBuffersImpl &impl,
457 size_t minSize,
458 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700459 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700460 mImpl.initialize(impl, minSize, allocate);
461}
462
463void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
464 mImpl.getArray(array);
465}
466
467bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
468 sp<Codec2Buffer> c2Buffer;
469 status_t err = mImpl.grabBuffer(index, &c2Buffer);
470 if (err == OK) {
471 c2Buffer->setFormat(mFormat);
472 handleImageData(c2Buffer);
473 *buffer = c2Buffer;
474 return true;
475 }
476 return false;
477}
478
479bool InputBuffersArray::releaseBuffer(
480 const sp<MediaCodecBuffer> &buffer,
481 std::shared_ptr<C2Buffer> *c2buffer,
482 bool release) {
483 return mImpl.returnBuffer(buffer, c2buffer, release);
484}
485
486bool InputBuffersArray::expireComponentBuffer(
487 const std::shared_ptr<C2Buffer> &c2buffer) {
488 return mImpl.expireComponentBuffer(c2buffer);
489}
490
491void InputBuffersArray::flush() {
492 mImpl.flush();
493}
494
495size_t InputBuffersArray::numClientBuffers() const {
496 return mImpl.numClientBuffers();
497}
498
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700499sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
500 return mAllocate();
501}
502
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800503// SlotInputBuffers
504
505bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
506 sp<Codec2Buffer> newBuffer = createNewBuffer();
507 *index = mImpl.assignSlot(newBuffer);
508 *buffer = newBuffer;
509 return true;
510}
511
512bool SlotInputBuffers::releaseBuffer(
513 const sp<MediaCodecBuffer> &buffer,
514 std::shared_ptr<C2Buffer> *c2buffer,
515 bool release) {
516 return mImpl.releaseSlot(buffer, c2buffer, release);
517}
518
519bool SlotInputBuffers::expireComponentBuffer(
520 const std::shared_ptr<C2Buffer> &c2buffer) {
521 return mImpl.expireComponentBuffer(c2buffer);
522}
523
524void SlotInputBuffers::flush() {
525 mImpl.flush();
526}
527
528std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
529 TRESPASS("Array mode should not be called at non-legacy mode");
530 return nullptr;
531}
532
533size_t SlotInputBuffers::numClientBuffers() const {
534 return mImpl.numClientBuffers();
535}
536
537sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
538 return new DummyContainerBuffer{mFormat, nullptr};
539}
540
Wonsik Kim469c8342019-04-11 16:46:09 -0700541// LinearInputBuffers
542
543bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700544 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700545 if (newBuffer == nullptr) {
546 return false;
547 }
548 *index = mImpl.assignSlot(newBuffer);
549 *buffer = newBuffer;
550 return true;
551}
552
553bool LinearInputBuffers::releaseBuffer(
554 const sp<MediaCodecBuffer> &buffer,
555 std::shared_ptr<C2Buffer> *c2buffer,
556 bool release) {
557 return mImpl.releaseSlot(buffer, c2buffer, release);
558}
559
560bool LinearInputBuffers::expireComponentBuffer(
561 const std::shared_ptr<C2Buffer> &c2buffer) {
562 return mImpl.expireComponentBuffer(c2buffer);
563}
564
565void LinearInputBuffers::flush() {
566 // This is no-op by default unless we're in array mode where we need to keep
567 // track of the flushed work.
568 mImpl.flush();
569}
570
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700571std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700572 std::unique_ptr<InputBuffersArray> array(
573 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
574 array->setPool(mPool);
575 array->setFormat(mFormat);
576 array->initialize(
577 mImpl,
578 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700579 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
580 return Alloc(pool, format);
581 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700582 return std::move(array);
583}
584
585size_t LinearInputBuffers::numClientBuffers() const {
586 return mImpl.numClientBuffers();
587}
588
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700589// static
590sp<Codec2Buffer> LinearInputBuffers::Alloc(
591 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
592 int32_t capacity = kLinearBufferSize;
593 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
594 if ((size_t)capacity > kMaxLinearBufferSize) {
595 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
596 capacity = kMaxLinearBufferSize;
597 }
598
599 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700600 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
601 std::shared_ptr<C2LinearBlock> block;
602
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700603 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700604 if (err != C2_OK) {
605 return nullptr;
606 }
607
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700608 return LinearBlockBuffer::Allocate(format, block);
609}
610
611sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
612 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700613}
614
615// EncryptedLinearInputBuffers
616
617EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
618 bool secure,
619 const sp<MemoryDealer> &dealer,
620 const sp<ICrypto> &crypto,
621 int32_t heapSeqNum,
622 size_t capacity,
623 size_t numInputSlots,
624 const char *componentName, const char *name)
625 : LinearInputBuffers(componentName, name),
626 mUsage({0, 0}),
627 mDealer(dealer),
628 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700629 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700630 if (secure) {
631 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
632 } else {
633 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
634 }
635 for (size_t i = 0; i < numInputSlots; ++i) {
636 sp<IMemory> memory = mDealer->allocate(capacity);
637 if (memory == nullptr) {
638 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
639 mName, i);
640 break;
641 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700642 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700643 }
644}
645
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700646std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
647 std::unique_ptr<InputBuffersArray> array(
648 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
649 array->setPool(mPool);
650 array->setFormat(mFormat);
651 array->initialize(
652 mImpl,
653 size,
654 [pool = mPool,
655 format = mFormat,
656 usage = mUsage,
657 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
658 return Alloc(pool, format, usage, memoryVector);
659 });
660 return std::move(array);
661}
662
663
664// static
665sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
666 const std::shared_ptr<C2BlockPool> &pool,
667 const sp<AMessage> &format,
668 C2MemoryUsage usage,
669 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
670 int32_t capacity = kLinearBufferSize;
671 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
672 if ((size_t)capacity > kMaxLinearBufferSize) {
673 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
674 capacity = kMaxLinearBufferSize;
675 }
676
Wonsik Kim469c8342019-04-11 16:46:09 -0700677 sp<IMemory> memory;
678 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700679 int32_t heapSeqNum = -1;
680 for (; slot < memoryVector->size(); ++slot) {
681 if (memoryVector->at(slot).block.expired()) {
682 memory = memoryVector->at(slot).memory;
683 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700684 break;
685 }
686 }
687 if (memory == nullptr) {
688 return nullptr;
689 }
690
691 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700692 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700693 if (err != C2_OK || block == nullptr) {
694 return nullptr;
695 }
696
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700697 memoryVector->at(slot).block = block;
698 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
699}
700
701sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
702 // TODO: android_2020
703 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700704}
705
706// GraphicMetadataInputBuffers
707
708GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
709 const char *componentName, const char *name)
710 : InputBuffers(componentName, name),
711 mImpl(mName),
712 mStore(GetCodec2PlatformAllocatorStore()) { }
713
714bool GraphicMetadataInputBuffers::requestNewBuffer(
715 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700716 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700717 if (newBuffer == nullptr) {
718 return false;
719 }
720 *index = mImpl.assignSlot(newBuffer);
721 *buffer = newBuffer;
722 return true;
723}
724
725bool GraphicMetadataInputBuffers::releaseBuffer(
726 const sp<MediaCodecBuffer> &buffer,
727 std::shared_ptr<C2Buffer> *c2buffer,
728 bool release) {
729 return mImpl.releaseSlot(buffer, c2buffer, release);
730}
731
732bool GraphicMetadataInputBuffers::expireComponentBuffer(
733 const std::shared_ptr<C2Buffer> &c2buffer) {
734 return mImpl.expireComponentBuffer(c2buffer);
735}
736
737void GraphicMetadataInputBuffers::flush() {
738 // This is no-op by default unless we're in array mode where we need to keep
739 // track of the flushed work.
740}
741
742std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
743 size_t size) {
744 std::shared_ptr<C2Allocator> alloc;
745 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
746 if (err != C2_OK) {
747 return nullptr;
748 }
749 std::unique_ptr<InputBuffersArray> array(
750 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
751 array->setPool(mPool);
752 array->setFormat(mFormat);
753 array->initialize(
754 mImpl,
755 size,
756 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
757 return new GraphicMetadataBuffer(format, alloc);
758 });
759 return std::move(array);
760}
761
762size_t GraphicMetadataInputBuffers::numClientBuffers() const {
763 return mImpl.numClientBuffers();
764}
765
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700766sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
767 std::shared_ptr<C2Allocator> alloc;
768 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
769 if (err != C2_OK) {
770 return nullptr;
771 }
772 return new GraphicMetadataBuffer(mFormat, alloc);
773}
774
Wonsik Kim469c8342019-04-11 16:46:09 -0700775// GraphicInputBuffers
776
777GraphicInputBuffers::GraphicInputBuffers(
778 size_t numInputSlots, const char *componentName, const char *name)
779 : InputBuffers(componentName, name),
780 mImpl(mName),
781 mLocalBufferPool(LocalBufferPool::Create(
782 kMaxLinearBufferSize * numInputSlots)) { }
783
784bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700785 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700786 if (newBuffer == nullptr) {
787 return false;
788 }
789 *index = mImpl.assignSlot(newBuffer);
790 handleImageData(newBuffer);
791 *buffer = newBuffer;
792 return true;
793}
794
795bool GraphicInputBuffers::releaseBuffer(
796 const sp<MediaCodecBuffer> &buffer,
797 std::shared_ptr<C2Buffer> *c2buffer,
798 bool release) {
799 return mImpl.releaseSlot(buffer, c2buffer, release);
800}
801
802bool GraphicInputBuffers::expireComponentBuffer(
803 const std::shared_ptr<C2Buffer> &c2buffer) {
804 return mImpl.expireComponentBuffer(c2buffer);
805}
806
807void GraphicInputBuffers::flush() {
808 // This is no-op by default unless we're in array mode where we need to keep
809 // track of the flushed work.
810}
811
812std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
813 std::unique_ptr<InputBuffersArray> array(
814 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
815 array->setPool(mPool);
816 array->setFormat(mFormat);
817 array->initialize(
818 mImpl,
819 size,
820 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
821 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
822 return AllocateGraphicBuffer(
823 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
824 });
825 return std::move(array);
826}
827
828size_t GraphicInputBuffers::numClientBuffers() const {
829 return mImpl.numClientBuffers();
830}
831
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700832sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
833 // TODO: read usage from intf
834 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
835 return AllocateGraphicBuffer(
836 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
837}
838
Wonsik Kim469c8342019-04-11 16:46:09 -0700839// OutputBuffersArray
840
841void OutputBuffersArray::initialize(
842 const FlexBuffersImpl &impl,
843 size_t minSize,
844 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700845 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700846 mImpl.initialize(impl, minSize, allocate);
847}
848
849status_t OutputBuffersArray::registerBuffer(
850 const std::shared_ptr<C2Buffer> &buffer,
851 size_t *index,
852 sp<MediaCodecBuffer> *clientBuffer) {
853 sp<Codec2Buffer> c2Buffer;
854 status_t err = mImpl.grabBuffer(
855 index,
856 &c2Buffer,
857 [buffer](const sp<Codec2Buffer> &clientBuffer) {
858 return clientBuffer->canCopy(buffer);
859 });
860 if (err == WOULD_BLOCK) {
861 ALOGV("[%s] buffers temporarily not available", mName);
862 return err;
863 } else if (err != OK) {
864 ALOGD("[%s] grabBuffer failed: %d", mName, err);
865 return err;
866 }
867 c2Buffer->setFormat(mFormat);
868 if (!c2Buffer->copy(buffer)) {
869 ALOGD("[%s] copy buffer failed", mName);
870 return WOULD_BLOCK;
871 }
872 submit(c2Buffer);
873 handleImageData(c2Buffer);
874 *clientBuffer = c2Buffer;
875 ALOGV("[%s] grabbed buffer %zu", mName, *index);
876 return OK;
877}
878
879status_t OutputBuffersArray::registerCsd(
880 const C2StreamInitDataInfo::output *csd,
881 size_t *index,
882 sp<MediaCodecBuffer> *clientBuffer) {
883 sp<Codec2Buffer> c2Buffer;
884 status_t err = mImpl.grabBuffer(
885 index,
886 &c2Buffer,
887 [csd](const sp<Codec2Buffer> &clientBuffer) {
888 return clientBuffer->base() != nullptr
889 && clientBuffer->capacity() >= csd->flexCount();
890 });
891 if (err != OK) {
892 return err;
893 }
894 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
895 c2Buffer->setRange(0, csd->flexCount());
896 c2Buffer->setFormat(mFormat);
897 *clientBuffer = c2Buffer;
898 return OK;
899}
900
901bool OutputBuffersArray::releaseBuffer(
902 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
903 return mImpl.returnBuffer(buffer, c2buffer, true);
904}
905
906void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
907 (void)flushedWork;
908 mImpl.flush();
909 if (mSkipCutBuffer != nullptr) {
910 mSkipCutBuffer->clear();
911 }
912}
913
914void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
915 mImpl.getArray(array);
916}
917
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700918size_t OutputBuffersArray::numClientBuffers() const {
919 return mImpl.numClientBuffers();
920}
921
Wonsik Kim469c8342019-04-11 16:46:09 -0700922void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700923 switch (c2buffer->data().type()) {
924 case C2BufferData::LINEAR: {
925 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -0700926 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
927 const uint32_t block_size = linear_blocks.front().size();
928 if (block_size < kMaxLinearBufferSize / 2) {
929 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -0700930 } else {
931 size = kMaxLinearBufferSize;
932 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700933 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -0700934 return new LocalLinearBuffer(format, new ABuffer(size));
935 };
Wonsik Kima39882b2019-06-20 16:13:56 -0700936 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -0700937 break;
938 }
939
Wonsik Kima39882b2019-06-20 16:13:56 -0700940 case C2BufferData::GRAPHIC: {
941 // This is only called for RawGraphicOutputBuffers.
942 mAlloc = [format = mFormat,
943 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
944 return ConstGraphicBlockBuffer::AllocateEmpty(
945 format,
946 [lbp](size_t capacity) {
947 return lbp->newBuffer(capacity);
948 });
949 };
950 ALOGD("[%s] reallocating with graphic buffer: format = %s",
951 mName, mFormat->debugString().c_str());
952 break;
953 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700954
955 case C2BufferData::INVALID: [[fallthrough]];
956 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
957 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
958 default:
959 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
960 return;
961 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700962 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700963}
964
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700965void OutputBuffersArray::grow(size_t newSize) {
966 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700967}
968
969// FlexOutputBuffers
970
971status_t FlexOutputBuffers::registerBuffer(
972 const std::shared_ptr<C2Buffer> &buffer,
973 size_t *index,
974 sp<MediaCodecBuffer> *clientBuffer) {
975 sp<Codec2Buffer> newBuffer = wrap(buffer);
976 if (newBuffer == nullptr) {
977 return NO_MEMORY;
978 }
979 newBuffer->setFormat(mFormat);
980 *index = mImpl.assignSlot(newBuffer);
981 handleImageData(newBuffer);
982 *clientBuffer = newBuffer;
983 ALOGV("[%s] registered buffer %zu", mName, *index);
984 return OK;
985}
986
987status_t FlexOutputBuffers::registerCsd(
988 const C2StreamInitDataInfo::output *csd,
989 size_t *index,
990 sp<MediaCodecBuffer> *clientBuffer) {
991 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
992 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
993 *index = mImpl.assignSlot(newBuffer);
994 *clientBuffer = newBuffer;
995 return OK;
996}
997
998bool FlexOutputBuffers::releaseBuffer(
999 const sp<MediaCodecBuffer> &buffer,
1000 std::shared_ptr<C2Buffer> *c2buffer) {
1001 return mImpl.releaseSlot(buffer, c2buffer, true);
1002}
1003
1004void FlexOutputBuffers::flush(
1005 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1006 (void) flushedWork;
1007 // This is no-op by default unless we're in array mode where we need to keep
1008 // track of the flushed work.
1009}
1010
1011std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
1012 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1013 array->setFormat(mFormat);
1014 array->transferSkipCutBuffer(mSkipCutBuffer);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001015 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1016 array->initialize(mImpl, size, alloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001017 return std::move(array);
1018}
1019
1020size_t FlexOutputBuffers::numClientBuffers() const {
1021 return mImpl.numClientBuffers();
1022}
1023
1024// LinearOutputBuffers
1025
1026void LinearOutputBuffers::flush(
1027 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1028 if (mSkipCutBuffer != nullptr) {
1029 mSkipCutBuffer->clear();
1030 }
1031 FlexOutputBuffers::flush(flushedWork);
1032}
1033
1034sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1035 if (buffer == nullptr) {
1036 ALOGV("[%s] using a dummy buffer", mName);
1037 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1038 }
1039 if (buffer->data().type() != C2BufferData::LINEAR) {
1040 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1041 // We expect linear output buffers from the component.
1042 return nullptr;
1043 }
1044 if (buffer->data().linearBlocks().size() != 1u) {
1045 ALOGV("[%s] no linear buffers", mName);
1046 // We expect one and only one linear block from the component.
1047 return nullptr;
1048 }
1049 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1050 if (clientBuffer == nullptr) {
1051 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1052 return nullptr;
1053 }
1054 submit(clientBuffer);
1055 return clientBuffer;
1056}
1057
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001058std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1059 return [format = mFormat]{
1060 // TODO: proper max output size
1061 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1062 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001063}
1064
1065// GraphicOutputBuffers
1066
1067sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1068 return new DummyContainerBuffer(mFormat, buffer);
1069}
1070
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001071std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1072 return [format = mFormat]{
1073 return new DummyContainerBuffer(format);
1074 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001075}
1076
1077// RawGraphicOutputBuffers
1078
1079RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1080 size_t numOutputSlots, const char *componentName, const char *name)
1081 : FlexOutputBuffers(componentName, name),
1082 mLocalBufferPool(LocalBufferPool::Create(
1083 kMaxLinearBufferSize * numOutputSlots)) { }
1084
1085sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1086 if (buffer == nullptr) {
1087 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1088 mFormat,
1089 [lbp = mLocalBufferPool](size_t capacity) {
1090 return lbp->newBuffer(capacity);
1091 });
1092 if (c2buffer == nullptr) {
1093 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1094 return nullptr;
1095 }
1096 c2buffer->setRange(0, 0);
1097 return c2buffer;
1098 } else {
1099 return ConstGraphicBlockBuffer::Allocate(
1100 mFormat,
1101 buffer,
1102 [lbp = mLocalBufferPool](size_t capacity) {
1103 return lbp->newBuffer(capacity);
1104 });
1105 }
1106}
1107
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001108std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1109 return [format = mFormat, lbp = mLocalBufferPool]{
1110 return ConstGraphicBlockBuffer::AllocateEmpty(
1111 format,
1112 [lbp](size_t capacity) {
1113 return lbp->newBuffer(capacity);
1114 });
1115 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001116}
1117
1118} // namespace android