blob: 5ebd5bd3170963786e3fc1dffce83eeafa811f45 [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>
25
26#include "CCodecBuffers.h"
27
28namespace android {
29
30namespace {
31
32sp<GraphicBlockBuffer> AllocateGraphicBuffer(
33 const std::shared_ptr<C2BlockPool> &pool,
34 const sp<AMessage> &format,
35 uint32_t pixelFormat,
36 const C2MemoryUsage &usage,
37 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
38 int32_t width, height;
39 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
40 ALOGD("format lacks width or height");
41 return nullptr;
42 }
43
44 std::shared_ptr<C2GraphicBlock> block;
45 c2_status_t err = pool->fetchGraphicBlock(
46 width, height, pixelFormat, usage, &block);
47 if (err != C2_OK) {
48 ALOGD("fetch graphic block failed: %d", err);
49 return nullptr;
50 }
51
52 return GraphicBlockBuffer::Allocate(
53 format,
54 block,
55 [localBufferPool](size_t capacity) {
56 return localBufferPool->newBuffer(capacity);
57 });
58}
59
60} // namespace
61
62// CCodecBuffers
63
64void CCodecBuffers::setFormat(const sp<AMessage> &format) {
65 CHECK(format != nullptr);
66 mFormat = format;
67}
68
69sp<AMessage> CCodecBuffers::dupFormat() {
70 return mFormat != nullptr ? mFormat->dup() : nullptr;
71}
72
73void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
74 sp<ABuffer> imageDataCandidate = buffer->getImageData();
75 if (imageDataCandidate == nullptr) {
76 return;
77 }
78 sp<ABuffer> imageData;
79 if (!mFormat->findBuffer("image-data", &imageData)
80 || imageDataCandidate->size() != imageData->size()
81 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
82 ALOGD("[%s] updating image-data", mName);
83 sp<AMessage> newFormat = dupFormat();
84 newFormat->setBuffer("image-data", imageDataCandidate);
85 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
86 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
87 int32_t stride = img->mPlane[0].mRowInc;
88 newFormat->setInt32(KEY_STRIDE, stride);
89 ALOGD("[%s] updating stride = %d", mName, stride);
90 if (img->mNumPlanes > 1 && stride > 0) {
91 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
92 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
93 ALOGD("[%s] updating vstride = %d", mName, vstride);
94 }
95 }
96 setFormat(newFormat);
97 buffer->setFormat(newFormat);
98 }
99}
100
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700101// InputBuffers
102
103sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
104 sp<Codec2Buffer> copy = createNewBuffer();
105 if (copy == nullptr) {
106 return nullptr;
107 }
108 std::shared_ptr<C2Buffer> c2buffer;
109 if (!releaseBuffer(buffer, &c2buffer, true)) {
110 return nullptr;
111 }
112 if (!copy->canCopy(c2buffer)) {
113 return nullptr;
114 }
115 if (!copy->copy(c2buffer)) {
116 return nullptr;
117 }
118 return copy;
119}
120
Wonsik Kim469c8342019-04-11 16:46:09 -0700121// OutputBuffers
122
123void OutputBuffers::initSkipCutBuffer(
124 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
125 CHECK(mSkipCutBuffer == nullptr);
126 mDelay = delay;
127 mPadding = padding;
128 mSampleRate = sampleRate;
129 setSkipCutBuffer(delay, padding, channelCount);
130}
131
132void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
133 if (mSkipCutBuffer == nullptr) {
134 return;
135 }
136 int32_t delay = mDelay;
137 int32_t padding = mPadding;
138 if (sampleRate != mSampleRate) {
139 delay = ((int64_t)delay * sampleRate) / mSampleRate;
140 padding = ((int64_t)padding * sampleRate) / mSampleRate;
141 }
142 setSkipCutBuffer(delay, padding, channelCount);
143}
144
145void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
146 if (mSkipCutBuffer != nullptr) {
147 mSkipCutBuffer->submit(buffer);
148 }
149}
150
151void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
152 mSkipCutBuffer = scb;
153}
154
155void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
156 if (mSkipCutBuffer != nullptr) {
157 size_t prevSize = mSkipCutBuffer->size();
158 if (prevSize != 0u) {
159 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
160 }
161 }
162 mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
163}
164
165// LocalBufferPool
166
167std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
168 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
169}
170
171sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
172 Mutex::Autolock lock(mMutex);
173 auto it = std::find_if(
174 mPool.begin(), mPool.end(),
175 [capacity](const std::vector<uint8_t> &vec) {
176 return vec.capacity() >= capacity;
177 });
178 if (it != mPool.end()) {
179 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
180 mPool.erase(it);
181 return buffer;
182 }
183 if (mUsedSize + capacity > mPoolCapacity) {
184 while (!mPool.empty()) {
185 mUsedSize -= mPool.back().capacity();
186 mPool.pop_back();
187 }
188 if (mUsedSize + capacity > mPoolCapacity) {
189 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
190 mUsedSize, capacity, mPoolCapacity);
191 return nullptr;
192 }
193 }
194 std::vector<uint8_t> vec(capacity);
195 mUsedSize += vec.capacity();
196 return new VectorBuffer(std::move(vec), shared_from_this());
197}
198
199LocalBufferPool::VectorBuffer::VectorBuffer(
200 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
201 : ABuffer(vec.data(), vec.capacity()),
202 mVec(std::move(vec)),
203 mPool(pool) {
204}
205
206LocalBufferPool::VectorBuffer::~VectorBuffer() {
207 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
208 if (pool) {
209 // If pool is alive, return the vector back to the pool so that
210 // it can be recycled.
211 pool->returnVector(std::move(mVec));
212 }
213}
214
215void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
216 Mutex::Autolock lock(mMutex);
217 mPool.push_front(std::move(vec));
218}
219
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700220// FlexBuffersImpl
221
Wonsik Kim469c8342019-04-11 16:46:09 -0700222size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
223 for (size_t i = 0; i < mBuffers.size(); ++i) {
224 if (mBuffers[i].clientBuffer == nullptr
225 && mBuffers[i].compBuffer.expired()) {
226 mBuffers[i].clientBuffer = buffer;
227 return i;
228 }
229 }
230 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
231 return mBuffers.size() - 1;
232}
233
Wonsik Kim469c8342019-04-11 16:46:09 -0700234bool FlexBuffersImpl::releaseSlot(
235 const sp<MediaCodecBuffer> &buffer,
236 std::shared_ptr<C2Buffer> *c2buffer,
237 bool release) {
238 sp<Codec2Buffer> clientBuffer;
239 size_t index = mBuffers.size();
240 for (size_t i = 0; i < mBuffers.size(); ++i) {
241 if (mBuffers[i].clientBuffer == buffer) {
242 clientBuffer = mBuffers[i].clientBuffer;
243 if (release) {
244 mBuffers[i].clientBuffer.clear();
245 }
246 index = i;
247 break;
248 }
249 }
250 if (clientBuffer == nullptr) {
251 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
252 return false;
253 }
254 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
255 if (!result) {
256 result = clientBuffer->asC2Buffer();
257 mBuffers[index].compBuffer = result;
258 }
259 if (c2buffer) {
260 *c2buffer = result;
261 }
262 return true;
263}
264
265bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
266 for (size_t i = 0; i < mBuffers.size(); ++i) {
267 std::shared_ptr<C2Buffer> compBuffer =
268 mBuffers[i].compBuffer.lock();
269 if (!compBuffer || compBuffer != c2buffer) {
270 continue;
271 }
272 mBuffers[i].compBuffer.reset();
273 ALOGV("[%s] codec released buffer #%zu", mName, i);
274 return true;
275 }
276 ALOGV("[%s] codec released an unknown buffer", mName);
277 return false;
278}
279
280void FlexBuffersImpl::flush() {
281 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
282 mBuffers.clear();
283}
284
285size_t FlexBuffersImpl::numClientBuffers() const {
286 return std::count_if(
287 mBuffers.begin(), mBuffers.end(),
288 [](const Entry &entry) {
289 return (entry.clientBuffer != nullptr);
290 });
291}
292
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700293size_t FlexBuffersImpl::numComponentBuffers() const {
294 return std::count_if(
295 mBuffers.begin(), mBuffers.end(),
296 [](const Entry &entry) {
297 return !entry.compBuffer.expired();
298 });
299}
300
Wonsik Kim469c8342019-04-11 16:46:09 -0700301// BuffersArrayImpl
302
303void BuffersArrayImpl::initialize(
304 const FlexBuffersImpl &impl,
305 size_t minSize,
306 std::function<sp<Codec2Buffer>()> allocate) {
307 mImplName = impl.mImplName + "[N]";
308 mName = mImplName.c_str();
309 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
310 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
311 bool ownedByClient = (clientBuffer != nullptr);
312 if (!ownedByClient) {
313 clientBuffer = allocate();
314 }
315 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
316 }
317 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
318 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
319 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
320 }
321}
322
323status_t BuffersArrayImpl::grabBuffer(
324 size_t *index,
325 sp<Codec2Buffer> *buffer,
326 std::function<bool(const sp<Codec2Buffer> &)> match) {
327 // allBuffersDontMatch remains true if all buffers are available but
328 // match() returns false for every buffer.
329 bool allBuffersDontMatch = true;
330 for (size_t i = 0; i < mBuffers.size(); ++i) {
331 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
332 if (match(mBuffers[i].clientBuffer)) {
333 mBuffers[i].ownedByClient = true;
334 *buffer = mBuffers[i].clientBuffer;
335 (*buffer)->meta()->clear();
336 (*buffer)->setRange(0, (*buffer)->capacity());
337 *index = i;
338 return OK;
339 }
340 } else {
341 allBuffersDontMatch = false;
342 }
343 }
344 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
345}
346
347bool BuffersArrayImpl::returnBuffer(
348 const sp<MediaCodecBuffer> &buffer,
349 std::shared_ptr<C2Buffer> *c2buffer,
350 bool release) {
351 sp<Codec2Buffer> clientBuffer;
352 size_t index = mBuffers.size();
353 for (size_t i = 0; i < mBuffers.size(); ++i) {
354 if (mBuffers[i].clientBuffer == buffer) {
355 if (!mBuffers[i].ownedByClient) {
356 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
357 mName, i);
358 }
359 clientBuffer = mBuffers[i].clientBuffer;
360 if (release) {
361 mBuffers[i].ownedByClient = false;
362 }
363 index = i;
364 break;
365 }
366 }
367 if (clientBuffer == nullptr) {
368 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
369 return false;
370 }
371 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
372 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
373 if (!result) {
374 result = clientBuffer->asC2Buffer();
375 mBuffers[index].compBuffer = result;
376 }
377 if (c2buffer) {
378 *c2buffer = result;
379 }
380 return true;
381}
382
383bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
384 for (size_t i = 0; i < mBuffers.size(); ++i) {
385 std::shared_ptr<C2Buffer> compBuffer =
386 mBuffers[i].compBuffer.lock();
387 if (!compBuffer) {
388 continue;
389 }
390 if (c2buffer == compBuffer) {
391 if (mBuffers[i].ownedByClient) {
392 // This should not happen.
393 ALOGD("[%s] codec released a buffer owned by client "
394 "(index %zu)", mName, i);
395 }
396 mBuffers[i].compBuffer.reset();
397 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
398 return true;
399 }
400 }
401 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
402 return false;
403}
404
405void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
406 array->clear();
407 for (const Entry &entry : mBuffers) {
408 array->push(entry.clientBuffer);
409 }
410}
411
412void BuffersArrayImpl::flush() {
413 for (Entry &entry : mBuffers) {
414 entry.ownedByClient = false;
415 }
416}
417
418void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
419 size_t size = mBuffers.size();
420 mBuffers.clear();
421 for (size_t i = 0; i < size; ++i) {
422 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
423 }
424}
425
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700426void BuffersArrayImpl::grow(
427 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
428 CHECK_LT(mBuffers.size(), newSize);
429 while (mBuffers.size() < newSize) {
430 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
431 }
432}
433
Wonsik Kim469c8342019-04-11 16:46:09 -0700434size_t BuffersArrayImpl::numClientBuffers() const {
435 return std::count_if(
436 mBuffers.begin(), mBuffers.end(),
437 [](const Entry &entry) {
438 return entry.ownedByClient;
439 });
440}
441
442// InputBuffersArray
443
444void InputBuffersArray::initialize(
445 const FlexBuffersImpl &impl,
446 size_t minSize,
447 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700448 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700449 mImpl.initialize(impl, minSize, allocate);
450}
451
452void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
453 mImpl.getArray(array);
454}
455
456bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
457 sp<Codec2Buffer> c2Buffer;
458 status_t err = mImpl.grabBuffer(index, &c2Buffer);
459 if (err == OK) {
460 c2Buffer->setFormat(mFormat);
461 handleImageData(c2Buffer);
462 *buffer = c2Buffer;
463 return true;
464 }
465 return false;
466}
467
468bool InputBuffersArray::releaseBuffer(
469 const sp<MediaCodecBuffer> &buffer,
470 std::shared_ptr<C2Buffer> *c2buffer,
471 bool release) {
472 return mImpl.returnBuffer(buffer, c2buffer, release);
473}
474
475bool InputBuffersArray::expireComponentBuffer(
476 const std::shared_ptr<C2Buffer> &c2buffer) {
477 return mImpl.expireComponentBuffer(c2buffer);
478}
479
480void InputBuffersArray::flush() {
481 mImpl.flush();
482}
483
484size_t InputBuffersArray::numClientBuffers() const {
485 return mImpl.numClientBuffers();
486}
487
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700488sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
489 return mAllocate();
490}
491
Wonsik Kim469c8342019-04-11 16:46:09 -0700492// LinearInputBuffers
493
494bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700495 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700496 if (newBuffer == nullptr) {
497 return false;
498 }
499 *index = mImpl.assignSlot(newBuffer);
500 *buffer = newBuffer;
501 return true;
502}
503
504bool LinearInputBuffers::releaseBuffer(
505 const sp<MediaCodecBuffer> &buffer,
506 std::shared_ptr<C2Buffer> *c2buffer,
507 bool release) {
508 return mImpl.releaseSlot(buffer, c2buffer, release);
509}
510
511bool LinearInputBuffers::expireComponentBuffer(
512 const std::shared_ptr<C2Buffer> &c2buffer) {
513 return mImpl.expireComponentBuffer(c2buffer);
514}
515
516void LinearInputBuffers::flush() {
517 // This is no-op by default unless we're in array mode where we need to keep
518 // track of the flushed work.
519 mImpl.flush();
520}
521
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700522std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700523 std::unique_ptr<InputBuffersArray> array(
524 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
525 array->setPool(mPool);
526 array->setFormat(mFormat);
527 array->initialize(
528 mImpl,
529 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700530 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
531 return Alloc(pool, format);
532 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700533 return std::move(array);
534}
535
536size_t LinearInputBuffers::numClientBuffers() const {
537 return mImpl.numClientBuffers();
538}
539
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700540// static
541sp<Codec2Buffer> LinearInputBuffers::Alloc(
542 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
543 int32_t capacity = kLinearBufferSize;
544 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
545 if ((size_t)capacity > kMaxLinearBufferSize) {
546 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
547 capacity = kMaxLinearBufferSize;
548 }
549
550 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700551 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
552 std::shared_ptr<C2LinearBlock> block;
553
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700554 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700555 if (err != C2_OK) {
556 return nullptr;
557 }
558
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700559 return LinearBlockBuffer::Allocate(format, block);
560}
561
562sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
563 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700564}
565
566// EncryptedLinearInputBuffers
567
568EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
569 bool secure,
570 const sp<MemoryDealer> &dealer,
571 const sp<ICrypto> &crypto,
572 int32_t heapSeqNum,
573 size_t capacity,
574 size_t numInputSlots,
575 const char *componentName, const char *name)
576 : LinearInputBuffers(componentName, name),
577 mUsage({0, 0}),
578 mDealer(dealer),
579 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700580 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700581 if (secure) {
582 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
583 } else {
584 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
585 }
586 for (size_t i = 0; i < numInputSlots; ++i) {
587 sp<IMemory> memory = mDealer->allocate(capacity);
588 if (memory == nullptr) {
589 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
590 mName, i);
591 break;
592 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700593 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700594 }
595}
596
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700597std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
598 std::unique_ptr<InputBuffersArray> array(
599 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
600 array->setPool(mPool);
601 array->setFormat(mFormat);
602 array->initialize(
603 mImpl,
604 size,
605 [pool = mPool,
606 format = mFormat,
607 usage = mUsage,
608 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
609 return Alloc(pool, format, usage, memoryVector);
610 });
611 return std::move(array);
612}
613
614
615// static
616sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
617 const std::shared_ptr<C2BlockPool> &pool,
618 const sp<AMessage> &format,
619 C2MemoryUsage usage,
620 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
621 int32_t capacity = kLinearBufferSize;
622 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
623 if ((size_t)capacity > kMaxLinearBufferSize) {
624 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
625 capacity = kMaxLinearBufferSize;
626 }
627
Wonsik Kim469c8342019-04-11 16:46:09 -0700628 sp<IMemory> memory;
629 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700630 int32_t heapSeqNum = -1;
631 for (; slot < memoryVector->size(); ++slot) {
632 if (memoryVector->at(slot).block.expired()) {
633 memory = memoryVector->at(slot).memory;
634 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700635 break;
636 }
637 }
638 if (memory == nullptr) {
639 return nullptr;
640 }
641
642 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700643 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700644 if (err != C2_OK || block == nullptr) {
645 return nullptr;
646 }
647
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700648 memoryVector->at(slot).block = block;
649 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
650}
651
652sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
653 // TODO: android_2020
654 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700655}
656
657// GraphicMetadataInputBuffers
658
659GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
660 const char *componentName, const char *name)
661 : InputBuffers(componentName, name),
662 mImpl(mName),
663 mStore(GetCodec2PlatformAllocatorStore()) { }
664
665bool GraphicMetadataInputBuffers::requestNewBuffer(
666 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700667 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700668 if (newBuffer == nullptr) {
669 return false;
670 }
671 *index = mImpl.assignSlot(newBuffer);
672 *buffer = newBuffer;
673 return true;
674}
675
676bool GraphicMetadataInputBuffers::releaseBuffer(
677 const sp<MediaCodecBuffer> &buffer,
678 std::shared_ptr<C2Buffer> *c2buffer,
679 bool release) {
680 return mImpl.releaseSlot(buffer, c2buffer, release);
681}
682
683bool GraphicMetadataInputBuffers::expireComponentBuffer(
684 const std::shared_ptr<C2Buffer> &c2buffer) {
685 return mImpl.expireComponentBuffer(c2buffer);
686}
687
688void GraphicMetadataInputBuffers::flush() {
689 // This is no-op by default unless we're in array mode where we need to keep
690 // track of the flushed work.
691}
692
693std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
694 size_t size) {
695 std::shared_ptr<C2Allocator> alloc;
696 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
697 if (err != C2_OK) {
698 return nullptr;
699 }
700 std::unique_ptr<InputBuffersArray> array(
701 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
702 array->setPool(mPool);
703 array->setFormat(mFormat);
704 array->initialize(
705 mImpl,
706 size,
707 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
708 return new GraphicMetadataBuffer(format, alloc);
709 });
710 return std::move(array);
711}
712
713size_t GraphicMetadataInputBuffers::numClientBuffers() const {
714 return mImpl.numClientBuffers();
715}
716
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700717sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
718 std::shared_ptr<C2Allocator> alloc;
719 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
720 if (err != C2_OK) {
721 return nullptr;
722 }
723 return new GraphicMetadataBuffer(mFormat, alloc);
724}
725
Wonsik Kim469c8342019-04-11 16:46:09 -0700726// GraphicInputBuffers
727
728GraphicInputBuffers::GraphicInputBuffers(
729 size_t numInputSlots, const char *componentName, const char *name)
730 : InputBuffers(componentName, name),
731 mImpl(mName),
732 mLocalBufferPool(LocalBufferPool::Create(
733 kMaxLinearBufferSize * numInputSlots)) { }
734
735bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700736 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700737 if (newBuffer == nullptr) {
738 return false;
739 }
740 *index = mImpl.assignSlot(newBuffer);
741 handleImageData(newBuffer);
742 *buffer = newBuffer;
743 return true;
744}
745
746bool GraphicInputBuffers::releaseBuffer(
747 const sp<MediaCodecBuffer> &buffer,
748 std::shared_ptr<C2Buffer> *c2buffer,
749 bool release) {
750 return mImpl.releaseSlot(buffer, c2buffer, release);
751}
752
753bool GraphicInputBuffers::expireComponentBuffer(
754 const std::shared_ptr<C2Buffer> &c2buffer) {
755 return mImpl.expireComponentBuffer(c2buffer);
756}
757
758void GraphicInputBuffers::flush() {
759 // This is no-op by default unless we're in array mode where we need to keep
760 // track of the flushed work.
761}
762
763std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
764 std::unique_ptr<InputBuffersArray> array(
765 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
766 array->setPool(mPool);
767 array->setFormat(mFormat);
768 array->initialize(
769 mImpl,
770 size,
771 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
772 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
773 return AllocateGraphicBuffer(
774 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
775 });
776 return std::move(array);
777}
778
779size_t GraphicInputBuffers::numClientBuffers() const {
780 return mImpl.numClientBuffers();
781}
782
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700783sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
784 // TODO: read usage from intf
785 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
786 return AllocateGraphicBuffer(
787 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
788}
789
Wonsik Kim469c8342019-04-11 16:46:09 -0700790// OutputBuffersArray
791
792void OutputBuffersArray::initialize(
793 const FlexBuffersImpl &impl,
794 size_t minSize,
795 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700796 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700797 mImpl.initialize(impl, minSize, allocate);
798}
799
800status_t OutputBuffersArray::registerBuffer(
801 const std::shared_ptr<C2Buffer> &buffer,
802 size_t *index,
803 sp<MediaCodecBuffer> *clientBuffer) {
804 sp<Codec2Buffer> c2Buffer;
805 status_t err = mImpl.grabBuffer(
806 index,
807 &c2Buffer,
808 [buffer](const sp<Codec2Buffer> &clientBuffer) {
809 return clientBuffer->canCopy(buffer);
810 });
811 if (err == WOULD_BLOCK) {
812 ALOGV("[%s] buffers temporarily not available", mName);
813 return err;
814 } else if (err != OK) {
815 ALOGD("[%s] grabBuffer failed: %d", mName, err);
816 return err;
817 }
818 c2Buffer->setFormat(mFormat);
819 if (!c2Buffer->copy(buffer)) {
820 ALOGD("[%s] copy buffer failed", mName);
821 return WOULD_BLOCK;
822 }
823 submit(c2Buffer);
824 handleImageData(c2Buffer);
825 *clientBuffer = c2Buffer;
826 ALOGV("[%s] grabbed buffer %zu", mName, *index);
827 return OK;
828}
829
830status_t OutputBuffersArray::registerCsd(
831 const C2StreamInitDataInfo::output *csd,
832 size_t *index,
833 sp<MediaCodecBuffer> *clientBuffer) {
834 sp<Codec2Buffer> c2Buffer;
835 status_t err = mImpl.grabBuffer(
836 index,
837 &c2Buffer,
838 [csd](const sp<Codec2Buffer> &clientBuffer) {
839 return clientBuffer->base() != nullptr
840 && clientBuffer->capacity() >= csd->flexCount();
841 });
842 if (err != OK) {
843 return err;
844 }
845 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
846 c2Buffer->setRange(0, csd->flexCount());
847 c2Buffer->setFormat(mFormat);
848 *clientBuffer = c2Buffer;
849 return OK;
850}
851
852bool OutputBuffersArray::releaseBuffer(
853 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
854 return mImpl.returnBuffer(buffer, c2buffer, true);
855}
856
857void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
858 (void)flushedWork;
859 mImpl.flush();
860 if (mSkipCutBuffer != nullptr) {
861 mSkipCutBuffer->clear();
862 }
863}
864
865void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
866 mImpl.getArray(array);
867}
868
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700869size_t OutputBuffersArray::numClientBuffers() const {
870 return mImpl.numClientBuffers();
871}
872
Wonsik Kim469c8342019-04-11 16:46:09 -0700873void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700874 switch (c2buffer->data().type()) {
875 case C2BufferData::LINEAR: {
876 uint32_t size = kLinearBufferSize;
877 const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
878 if (block.size() < kMaxLinearBufferSize / 2) {
879 size = block.size() * 2;
880 } else {
881 size = kMaxLinearBufferSize;
882 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700883 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -0700884 return new LocalLinearBuffer(format, new ABuffer(size));
885 };
886 break;
887 }
888
889 // TODO: add support
890 case C2BufferData::GRAPHIC: [[fallthrough]];
891
892 case C2BufferData::INVALID: [[fallthrough]];
893 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
894 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
895 default:
896 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
897 return;
898 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700899 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700900}
901
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700902void OutputBuffersArray::grow(size_t newSize) {
903 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700904}
905
906// FlexOutputBuffers
907
908status_t FlexOutputBuffers::registerBuffer(
909 const std::shared_ptr<C2Buffer> &buffer,
910 size_t *index,
911 sp<MediaCodecBuffer> *clientBuffer) {
912 sp<Codec2Buffer> newBuffer = wrap(buffer);
913 if (newBuffer == nullptr) {
914 return NO_MEMORY;
915 }
916 newBuffer->setFormat(mFormat);
917 *index = mImpl.assignSlot(newBuffer);
918 handleImageData(newBuffer);
919 *clientBuffer = newBuffer;
920 ALOGV("[%s] registered buffer %zu", mName, *index);
921 return OK;
922}
923
924status_t FlexOutputBuffers::registerCsd(
925 const C2StreamInitDataInfo::output *csd,
926 size_t *index,
927 sp<MediaCodecBuffer> *clientBuffer) {
928 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
929 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
930 *index = mImpl.assignSlot(newBuffer);
931 *clientBuffer = newBuffer;
932 return OK;
933}
934
935bool FlexOutputBuffers::releaseBuffer(
936 const sp<MediaCodecBuffer> &buffer,
937 std::shared_ptr<C2Buffer> *c2buffer) {
938 return mImpl.releaseSlot(buffer, c2buffer, true);
939}
940
941void FlexOutputBuffers::flush(
942 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
943 (void) flushedWork;
944 // This is no-op by default unless we're in array mode where we need to keep
945 // track of the flushed work.
946}
947
948std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
949 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
950 array->setFormat(mFormat);
951 array->transferSkipCutBuffer(mSkipCutBuffer);
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700952 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
953 array->initialize(mImpl, size, alloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700954 return std::move(array);
955}
956
957size_t FlexOutputBuffers::numClientBuffers() const {
958 return mImpl.numClientBuffers();
959}
960
961// LinearOutputBuffers
962
963void LinearOutputBuffers::flush(
964 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
965 if (mSkipCutBuffer != nullptr) {
966 mSkipCutBuffer->clear();
967 }
968 FlexOutputBuffers::flush(flushedWork);
969}
970
971sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
972 if (buffer == nullptr) {
973 ALOGV("[%s] using a dummy buffer", mName);
974 return new LocalLinearBuffer(mFormat, new ABuffer(0));
975 }
976 if (buffer->data().type() != C2BufferData::LINEAR) {
977 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
978 // We expect linear output buffers from the component.
979 return nullptr;
980 }
981 if (buffer->data().linearBlocks().size() != 1u) {
982 ALOGV("[%s] no linear buffers", mName);
983 // We expect one and only one linear block from the component.
984 return nullptr;
985 }
986 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
987 if (clientBuffer == nullptr) {
988 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
989 return nullptr;
990 }
991 submit(clientBuffer);
992 return clientBuffer;
993}
994
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700995std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
996 return [format = mFormat]{
997 // TODO: proper max output size
998 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
999 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001000}
1001
1002// GraphicOutputBuffers
1003
1004sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1005 return new DummyContainerBuffer(mFormat, buffer);
1006}
1007
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001008std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1009 return [format = mFormat]{
1010 return new DummyContainerBuffer(format);
1011 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001012}
1013
1014// RawGraphicOutputBuffers
1015
1016RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1017 size_t numOutputSlots, const char *componentName, const char *name)
1018 : FlexOutputBuffers(componentName, name),
1019 mLocalBufferPool(LocalBufferPool::Create(
1020 kMaxLinearBufferSize * numOutputSlots)) { }
1021
1022sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1023 if (buffer == nullptr) {
1024 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1025 mFormat,
1026 [lbp = mLocalBufferPool](size_t capacity) {
1027 return lbp->newBuffer(capacity);
1028 });
1029 if (c2buffer == nullptr) {
1030 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1031 return nullptr;
1032 }
1033 c2buffer->setRange(0, 0);
1034 return c2buffer;
1035 } else {
1036 return ConstGraphicBlockBuffer::Allocate(
1037 mFormat,
1038 buffer,
1039 [lbp = mLocalBufferPool](size_t capacity) {
1040 return lbp->newBuffer(capacity);
1041 });
1042 }
1043}
1044
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001045std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1046 return [format = mFormat, lbp = mLocalBufferPool]{
1047 return ConstGraphicBlockBuffer::AllocateEmpty(
1048 format,
1049 [lbp](size_t capacity) {
1050 return lbp->newBuffer(capacity);
1051 });
1052 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001053}
1054
1055} // namespace android