blob: fb0efce45d91c8343eb562fee53286022b983584 [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
101// OutputBuffers
102
103void OutputBuffers::initSkipCutBuffer(
104 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
105 CHECK(mSkipCutBuffer == nullptr);
106 mDelay = delay;
107 mPadding = padding;
108 mSampleRate = sampleRate;
109 setSkipCutBuffer(delay, padding, channelCount);
110}
111
112void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
113 if (mSkipCutBuffer == nullptr) {
114 return;
115 }
116 int32_t delay = mDelay;
117 int32_t padding = mPadding;
118 if (sampleRate != mSampleRate) {
119 delay = ((int64_t)delay * sampleRate) / mSampleRate;
120 padding = ((int64_t)padding * sampleRate) / mSampleRate;
121 }
122 setSkipCutBuffer(delay, padding, channelCount);
123}
124
125void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
126 if (mSkipCutBuffer != nullptr) {
127 mSkipCutBuffer->submit(buffer);
128 }
129}
130
131void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
132 mSkipCutBuffer = scb;
133}
134
135void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
136 if (mSkipCutBuffer != nullptr) {
137 size_t prevSize = mSkipCutBuffer->size();
138 if (prevSize != 0u) {
139 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
140 }
141 }
142 mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
143}
144
145// LocalBufferPool
146
147std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
148 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
149}
150
151sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
152 Mutex::Autolock lock(mMutex);
153 auto it = std::find_if(
154 mPool.begin(), mPool.end(),
155 [capacity](const std::vector<uint8_t> &vec) {
156 return vec.capacity() >= capacity;
157 });
158 if (it != mPool.end()) {
159 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
160 mPool.erase(it);
161 return buffer;
162 }
163 if (mUsedSize + capacity > mPoolCapacity) {
164 while (!mPool.empty()) {
165 mUsedSize -= mPool.back().capacity();
166 mPool.pop_back();
167 }
168 if (mUsedSize + capacity > mPoolCapacity) {
169 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
170 mUsedSize, capacity, mPoolCapacity);
171 return nullptr;
172 }
173 }
174 std::vector<uint8_t> vec(capacity);
175 mUsedSize += vec.capacity();
176 return new VectorBuffer(std::move(vec), shared_from_this());
177}
178
179LocalBufferPool::VectorBuffer::VectorBuffer(
180 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
181 : ABuffer(vec.data(), vec.capacity()),
182 mVec(std::move(vec)),
183 mPool(pool) {
184}
185
186LocalBufferPool::VectorBuffer::~VectorBuffer() {
187 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
188 if (pool) {
189 // If pool is alive, return the vector back to the pool so that
190 // it can be recycled.
191 pool->returnVector(std::move(mVec));
192 }
193}
194
195void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
196 Mutex::Autolock lock(mMutex);
197 mPool.push_front(std::move(vec));
198}
199
200size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
201 for (size_t i = 0; i < mBuffers.size(); ++i) {
202 if (mBuffers[i].clientBuffer == nullptr
203 && mBuffers[i].compBuffer.expired()) {
204 mBuffers[i].clientBuffer = buffer;
205 return i;
206 }
207 }
208 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
209 return mBuffers.size() - 1;
210}
211
212// FlexBuffersImpl
213
214bool FlexBuffersImpl::releaseSlot(
215 const sp<MediaCodecBuffer> &buffer,
216 std::shared_ptr<C2Buffer> *c2buffer,
217 bool release) {
218 sp<Codec2Buffer> clientBuffer;
219 size_t index = mBuffers.size();
220 for (size_t i = 0; i < mBuffers.size(); ++i) {
221 if (mBuffers[i].clientBuffer == buffer) {
222 clientBuffer = mBuffers[i].clientBuffer;
223 if (release) {
224 mBuffers[i].clientBuffer.clear();
225 }
226 index = i;
227 break;
228 }
229 }
230 if (clientBuffer == nullptr) {
231 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
232 return false;
233 }
234 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
235 if (!result) {
236 result = clientBuffer->asC2Buffer();
237 mBuffers[index].compBuffer = result;
238 }
239 if (c2buffer) {
240 *c2buffer = result;
241 }
242 return true;
243}
244
245bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
246 for (size_t i = 0; i < mBuffers.size(); ++i) {
247 std::shared_ptr<C2Buffer> compBuffer =
248 mBuffers[i].compBuffer.lock();
249 if (!compBuffer || compBuffer != c2buffer) {
250 continue;
251 }
252 mBuffers[i].compBuffer.reset();
253 ALOGV("[%s] codec released buffer #%zu", mName, i);
254 return true;
255 }
256 ALOGV("[%s] codec released an unknown buffer", mName);
257 return false;
258}
259
260void FlexBuffersImpl::flush() {
261 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
262 mBuffers.clear();
263}
264
265size_t FlexBuffersImpl::numClientBuffers() const {
266 return std::count_if(
267 mBuffers.begin(), mBuffers.end(),
268 [](const Entry &entry) {
269 return (entry.clientBuffer != nullptr);
270 });
271}
272
273// BuffersArrayImpl
274
275void BuffersArrayImpl::initialize(
276 const FlexBuffersImpl &impl,
277 size_t minSize,
278 std::function<sp<Codec2Buffer>()> allocate) {
279 mImplName = impl.mImplName + "[N]";
280 mName = mImplName.c_str();
281 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
282 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
283 bool ownedByClient = (clientBuffer != nullptr);
284 if (!ownedByClient) {
285 clientBuffer = allocate();
286 }
287 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
288 }
289 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
290 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
291 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
292 }
293}
294
295status_t BuffersArrayImpl::grabBuffer(
296 size_t *index,
297 sp<Codec2Buffer> *buffer,
298 std::function<bool(const sp<Codec2Buffer> &)> match) {
299 // allBuffersDontMatch remains true if all buffers are available but
300 // match() returns false for every buffer.
301 bool allBuffersDontMatch = true;
302 for (size_t i = 0; i < mBuffers.size(); ++i) {
303 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
304 if (match(mBuffers[i].clientBuffer)) {
305 mBuffers[i].ownedByClient = true;
306 *buffer = mBuffers[i].clientBuffer;
307 (*buffer)->meta()->clear();
308 (*buffer)->setRange(0, (*buffer)->capacity());
309 *index = i;
310 return OK;
311 }
312 } else {
313 allBuffersDontMatch = false;
314 }
315 }
316 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
317}
318
319bool BuffersArrayImpl::returnBuffer(
320 const sp<MediaCodecBuffer> &buffer,
321 std::shared_ptr<C2Buffer> *c2buffer,
322 bool release) {
323 sp<Codec2Buffer> clientBuffer;
324 size_t index = mBuffers.size();
325 for (size_t i = 0; i < mBuffers.size(); ++i) {
326 if (mBuffers[i].clientBuffer == buffer) {
327 if (!mBuffers[i].ownedByClient) {
328 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
329 mName, i);
330 }
331 clientBuffer = mBuffers[i].clientBuffer;
332 if (release) {
333 mBuffers[i].ownedByClient = false;
334 }
335 index = i;
336 break;
337 }
338 }
339 if (clientBuffer == nullptr) {
340 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
341 return false;
342 }
343 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
344 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
345 if (!result) {
346 result = clientBuffer->asC2Buffer();
347 mBuffers[index].compBuffer = result;
348 }
349 if (c2buffer) {
350 *c2buffer = result;
351 }
352 return true;
353}
354
355bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
356 for (size_t i = 0; i < mBuffers.size(); ++i) {
357 std::shared_ptr<C2Buffer> compBuffer =
358 mBuffers[i].compBuffer.lock();
359 if (!compBuffer) {
360 continue;
361 }
362 if (c2buffer == compBuffer) {
363 if (mBuffers[i].ownedByClient) {
364 // This should not happen.
365 ALOGD("[%s] codec released a buffer owned by client "
366 "(index %zu)", mName, i);
367 }
368 mBuffers[i].compBuffer.reset();
369 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
370 return true;
371 }
372 }
373 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
374 return false;
375}
376
377void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
378 array->clear();
379 for (const Entry &entry : mBuffers) {
380 array->push(entry.clientBuffer);
381 }
382}
383
384void BuffersArrayImpl::flush() {
385 for (Entry &entry : mBuffers) {
386 entry.ownedByClient = false;
387 }
388}
389
390void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
391 size_t size = mBuffers.size();
392 mBuffers.clear();
393 for (size_t i = 0; i < size; ++i) {
394 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
395 }
396}
397
398size_t BuffersArrayImpl::numClientBuffers() const {
399 return std::count_if(
400 mBuffers.begin(), mBuffers.end(),
401 [](const Entry &entry) {
402 return entry.ownedByClient;
403 });
404}
405
406// InputBuffersArray
407
408void InputBuffersArray::initialize(
409 const FlexBuffersImpl &impl,
410 size_t minSize,
411 std::function<sp<Codec2Buffer>()> allocate) {
412 mImpl.initialize(impl, minSize, allocate);
413}
414
415void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
416 mImpl.getArray(array);
417}
418
419bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
420 sp<Codec2Buffer> c2Buffer;
421 status_t err = mImpl.grabBuffer(index, &c2Buffer);
422 if (err == OK) {
423 c2Buffer->setFormat(mFormat);
424 handleImageData(c2Buffer);
425 *buffer = c2Buffer;
426 return true;
427 }
428 return false;
429}
430
431bool InputBuffersArray::releaseBuffer(
432 const sp<MediaCodecBuffer> &buffer,
433 std::shared_ptr<C2Buffer> *c2buffer,
434 bool release) {
435 return mImpl.returnBuffer(buffer, c2buffer, release);
436}
437
438bool InputBuffersArray::expireComponentBuffer(
439 const std::shared_ptr<C2Buffer> &c2buffer) {
440 return mImpl.expireComponentBuffer(c2buffer);
441}
442
443void InputBuffersArray::flush() {
444 mImpl.flush();
445}
446
447size_t InputBuffersArray::numClientBuffers() const {
448 return mImpl.numClientBuffers();
449}
450
451// LinearInputBuffers
452
453bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
454 int32_t capacity = kLinearBufferSize;
455 (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
456 if ((size_t)capacity > kMaxLinearBufferSize) {
457 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
458 capacity = kMaxLinearBufferSize;
459 }
460 // TODO: proper max input size
461 // TODO: read usage from intf
462 sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
463 if (newBuffer == nullptr) {
464 return false;
465 }
466 *index = mImpl.assignSlot(newBuffer);
467 *buffer = newBuffer;
468 return true;
469}
470
471bool LinearInputBuffers::releaseBuffer(
472 const sp<MediaCodecBuffer> &buffer,
473 std::shared_ptr<C2Buffer> *c2buffer,
474 bool release) {
475 return mImpl.releaseSlot(buffer, c2buffer, release);
476}
477
478bool LinearInputBuffers::expireComponentBuffer(
479 const std::shared_ptr<C2Buffer> &c2buffer) {
480 return mImpl.expireComponentBuffer(c2buffer);
481}
482
483void LinearInputBuffers::flush() {
484 // This is no-op by default unless we're in array mode where we need to keep
485 // track of the flushed work.
486 mImpl.flush();
487}
488
489std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(
490 size_t size) {
491 int32_t capacity = kLinearBufferSize;
492 (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
493 if ((size_t)capacity > kMaxLinearBufferSize) {
494 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
495 capacity = kMaxLinearBufferSize;
496 }
497 // TODO: proper max input size
498 // TODO: read usage from intf
499 std::unique_ptr<InputBuffersArray> array(
500 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
501 array->setPool(mPool);
502 array->setFormat(mFormat);
503 array->initialize(
504 mImpl,
505 size,
506 [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
507 return std::move(array);
508}
509
510size_t LinearInputBuffers::numClientBuffers() const {
511 return mImpl.numClientBuffers();
512}
513
514sp<Codec2Buffer> LinearInputBuffers::alloc(size_t size) {
515 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
516 std::shared_ptr<C2LinearBlock> block;
517
518 c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
519 if (err != C2_OK) {
520 return nullptr;
521 }
522
523 return LinearBlockBuffer::Allocate(mFormat, block);
524}
525
526// EncryptedLinearInputBuffers
527
528EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
529 bool secure,
530 const sp<MemoryDealer> &dealer,
531 const sp<ICrypto> &crypto,
532 int32_t heapSeqNum,
533 size_t capacity,
534 size_t numInputSlots,
535 const char *componentName, const char *name)
536 : LinearInputBuffers(componentName, name),
537 mUsage({0, 0}),
538 mDealer(dealer),
539 mCrypto(crypto),
540 mHeapSeqNum(heapSeqNum) {
541 if (secure) {
542 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
543 } else {
544 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
545 }
546 for (size_t i = 0; i < numInputSlots; ++i) {
547 sp<IMemory> memory = mDealer->allocate(capacity);
548 if (memory == nullptr) {
549 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
550 mName, i);
551 break;
552 }
553 mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
554 }
555}
556
557sp<Codec2Buffer> EncryptedLinearInputBuffers::alloc(size_t size) {
558 sp<IMemory> memory;
559 size_t slot = 0;
560 for (; slot < mMemoryVector.size(); ++slot) {
561 if (mMemoryVector[slot].block.expired()) {
562 memory = mMemoryVector[slot].memory;
563 break;
564 }
565 }
566 if (memory == nullptr) {
567 return nullptr;
568 }
569
570 std::shared_ptr<C2LinearBlock> block;
571 c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
572 if (err != C2_OK || block == nullptr) {
573 return nullptr;
574 }
575
576 mMemoryVector[slot].block = block;
577 return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
578}
579
580// GraphicMetadataInputBuffers
581
582GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
583 const char *componentName, const char *name)
584 : InputBuffers(componentName, name),
585 mImpl(mName),
586 mStore(GetCodec2PlatformAllocatorStore()) { }
587
588bool GraphicMetadataInputBuffers::requestNewBuffer(
589 size_t *index, sp<MediaCodecBuffer> *buffer) {
590 std::shared_ptr<C2Allocator> alloc;
591 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
592 if (err != C2_OK) {
593 return false;
594 }
595 sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
596 if (newBuffer == nullptr) {
597 return false;
598 }
599 *index = mImpl.assignSlot(newBuffer);
600 *buffer = newBuffer;
601 return true;
602}
603
604bool GraphicMetadataInputBuffers::releaseBuffer(
605 const sp<MediaCodecBuffer> &buffer,
606 std::shared_ptr<C2Buffer> *c2buffer,
607 bool release) {
608 return mImpl.releaseSlot(buffer, c2buffer, release);
609}
610
611bool GraphicMetadataInputBuffers::expireComponentBuffer(
612 const std::shared_ptr<C2Buffer> &c2buffer) {
613 return mImpl.expireComponentBuffer(c2buffer);
614}
615
616void GraphicMetadataInputBuffers::flush() {
617 // This is no-op by default unless we're in array mode where we need to keep
618 // track of the flushed work.
619}
620
621std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
622 size_t size) {
623 std::shared_ptr<C2Allocator> alloc;
624 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
625 if (err != C2_OK) {
626 return nullptr;
627 }
628 std::unique_ptr<InputBuffersArray> array(
629 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
630 array->setPool(mPool);
631 array->setFormat(mFormat);
632 array->initialize(
633 mImpl,
634 size,
635 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
636 return new GraphicMetadataBuffer(format, alloc);
637 });
638 return std::move(array);
639}
640
641size_t GraphicMetadataInputBuffers::numClientBuffers() const {
642 return mImpl.numClientBuffers();
643}
644
645// GraphicInputBuffers
646
647GraphicInputBuffers::GraphicInputBuffers(
648 size_t numInputSlots, const char *componentName, const char *name)
649 : InputBuffers(componentName, name),
650 mImpl(mName),
651 mLocalBufferPool(LocalBufferPool::Create(
652 kMaxLinearBufferSize * numInputSlots)) { }
653
654bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
655 // TODO: proper max input size
656 // TODO: read usage from intf
657 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
658 sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
659 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
660 if (newBuffer == nullptr) {
661 return false;
662 }
663 *index = mImpl.assignSlot(newBuffer);
664 handleImageData(newBuffer);
665 *buffer = newBuffer;
666 return true;
667}
668
669bool GraphicInputBuffers::releaseBuffer(
670 const sp<MediaCodecBuffer> &buffer,
671 std::shared_ptr<C2Buffer> *c2buffer,
672 bool release) {
673 return mImpl.releaseSlot(buffer, c2buffer, release);
674}
675
676bool GraphicInputBuffers::expireComponentBuffer(
677 const std::shared_ptr<C2Buffer> &c2buffer) {
678 return mImpl.expireComponentBuffer(c2buffer);
679}
680
681void GraphicInputBuffers::flush() {
682 // This is no-op by default unless we're in array mode where we need to keep
683 // track of the flushed work.
684}
685
686std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
687 std::unique_ptr<InputBuffersArray> array(
688 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
689 array->setPool(mPool);
690 array->setFormat(mFormat);
691 array->initialize(
692 mImpl,
693 size,
694 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
695 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
696 return AllocateGraphicBuffer(
697 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
698 });
699 return std::move(array);
700}
701
702size_t GraphicInputBuffers::numClientBuffers() const {
703 return mImpl.numClientBuffers();
704}
705
706// OutputBuffersArray
707
708void OutputBuffersArray::initialize(
709 const FlexBuffersImpl &impl,
710 size_t minSize,
711 std::function<sp<Codec2Buffer>()> allocate) {
712 mImpl.initialize(impl, minSize, allocate);
713}
714
715status_t OutputBuffersArray::registerBuffer(
716 const std::shared_ptr<C2Buffer> &buffer,
717 size_t *index,
718 sp<MediaCodecBuffer> *clientBuffer) {
719 sp<Codec2Buffer> c2Buffer;
720 status_t err = mImpl.grabBuffer(
721 index,
722 &c2Buffer,
723 [buffer](const sp<Codec2Buffer> &clientBuffer) {
724 return clientBuffer->canCopy(buffer);
725 });
726 if (err == WOULD_BLOCK) {
727 ALOGV("[%s] buffers temporarily not available", mName);
728 return err;
729 } else if (err != OK) {
730 ALOGD("[%s] grabBuffer failed: %d", mName, err);
731 return err;
732 }
733 c2Buffer->setFormat(mFormat);
734 if (!c2Buffer->copy(buffer)) {
735 ALOGD("[%s] copy buffer failed", mName);
736 return WOULD_BLOCK;
737 }
738 submit(c2Buffer);
739 handleImageData(c2Buffer);
740 *clientBuffer = c2Buffer;
741 ALOGV("[%s] grabbed buffer %zu", mName, *index);
742 return OK;
743}
744
745status_t OutputBuffersArray::registerCsd(
746 const C2StreamInitDataInfo::output *csd,
747 size_t *index,
748 sp<MediaCodecBuffer> *clientBuffer) {
749 sp<Codec2Buffer> c2Buffer;
750 status_t err = mImpl.grabBuffer(
751 index,
752 &c2Buffer,
753 [csd](const sp<Codec2Buffer> &clientBuffer) {
754 return clientBuffer->base() != nullptr
755 && clientBuffer->capacity() >= csd->flexCount();
756 });
757 if (err != OK) {
758 return err;
759 }
760 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
761 c2Buffer->setRange(0, csd->flexCount());
762 c2Buffer->setFormat(mFormat);
763 *clientBuffer = c2Buffer;
764 return OK;
765}
766
767bool OutputBuffersArray::releaseBuffer(
768 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
769 return mImpl.returnBuffer(buffer, c2buffer, true);
770}
771
772void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
773 (void)flushedWork;
774 mImpl.flush();
775 if (mSkipCutBuffer != nullptr) {
776 mSkipCutBuffer->clear();
777 }
778}
779
780void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
781 mImpl.getArray(array);
782}
783
784void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
785 std::function<sp<Codec2Buffer>()> alloc;
786 switch (c2buffer->data().type()) {
787 case C2BufferData::LINEAR: {
788 uint32_t size = kLinearBufferSize;
789 const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
790 if (block.size() < kMaxLinearBufferSize / 2) {
791 size = block.size() * 2;
792 } else {
793 size = kMaxLinearBufferSize;
794 }
795 alloc = [format = mFormat, size] {
796 return new LocalLinearBuffer(format, new ABuffer(size));
797 };
798 break;
799 }
800
801 // TODO: add support
802 case C2BufferData::GRAPHIC: [[fallthrough]];
803
804 case C2BufferData::INVALID: [[fallthrough]];
805 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
806 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
807 default:
808 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
809 return;
810 }
811 mImpl.realloc(alloc);
812}
813
814size_t OutputBuffersArray::numClientBuffers() const {
815 return mImpl.numClientBuffers();
816}
817
818// FlexOutputBuffers
819
820status_t FlexOutputBuffers::registerBuffer(
821 const std::shared_ptr<C2Buffer> &buffer,
822 size_t *index,
823 sp<MediaCodecBuffer> *clientBuffer) {
824 sp<Codec2Buffer> newBuffer = wrap(buffer);
825 if (newBuffer == nullptr) {
826 return NO_MEMORY;
827 }
828 newBuffer->setFormat(mFormat);
829 *index = mImpl.assignSlot(newBuffer);
830 handleImageData(newBuffer);
831 *clientBuffer = newBuffer;
832 ALOGV("[%s] registered buffer %zu", mName, *index);
833 return OK;
834}
835
836status_t FlexOutputBuffers::registerCsd(
837 const C2StreamInitDataInfo::output *csd,
838 size_t *index,
839 sp<MediaCodecBuffer> *clientBuffer) {
840 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
841 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
842 *index = mImpl.assignSlot(newBuffer);
843 *clientBuffer = newBuffer;
844 return OK;
845}
846
847bool FlexOutputBuffers::releaseBuffer(
848 const sp<MediaCodecBuffer> &buffer,
849 std::shared_ptr<C2Buffer> *c2buffer) {
850 return mImpl.releaseSlot(buffer, c2buffer, true);
851}
852
853void FlexOutputBuffers::flush(
854 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
855 (void) flushedWork;
856 // This is no-op by default unless we're in array mode where we need to keep
857 // track of the flushed work.
858}
859
860std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
861 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
862 array->setFormat(mFormat);
863 array->transferSkipCutBuffer(mSkipCutBuffer);
864 array->initialize(
865 mImpl,
866 size,
867 [this]() { return allocateArrayBuffer(); });
868 return std::move(array);
869}
870
871size_t FlexOutputBuffers::numClientBuffers() const {
872 return mImpl.numClientBuffers();
873}
874
875// LinearOutputBuffers
876
877void LinearOutputBuffers::flush(
878 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
879 if (mSkipCutBuffer != nullptr) {
880 mSkipCutBuffer->clear();
881 }
882 FlexOutputBuffers::flush(flushedWork);
883}
884
885sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
886 if (buffer == nullptr) {
887 ALOGV("[%s] using a dummy buffer", mName);
888 return new LocalLinearBuffer(mFormat, new ABuffer(0));
889 }
890 if (buffer->data().type() != C2BufferData::LINEAR) {
891 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
892 // We expect linear output buffers from the component.
893 return nullptr;
894 }
895 if (buffer->data().linearBlocks().size() != 1u) {
896 ALOGV("[%s] no linear buffers", mName);
897 // We expect one and only one linear block from the component.
898 return nullptr;
899 }
900 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
901 if (clientBuffer == nullptr) {
902 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
903 return nullptr;
904 }
905 submit(clientBuffer);
906 return clientBuffer;
907}
908
909sp<Codec2Buffer> LinearOutputBuffers::allocateArrayBuffer() {
910 // TODO: proper max output size
911 return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
912}
913
914// GraphicOutputBuffers
915
916sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
917 return new DummyContainerBuffer(mFormat, buffer);
918}
919
920sp<Codec2Buffer> GraphicOutputBuffers::allocateArrayBuffer() {
921 return new DummyContainerBuffer(mFormat);
922}
923
924// RawGraphicOutputBuffers
925
926RawGraphicOutputBuffers::RawGraphicOutputBuffers(
927 size_t numOutputSlots, const char *componentName, const char *name)
928 : FlexOutputBuffers(componentName, name),
929 mLocalBufferPool(LocalBufferPool::Create(
930 kMaxLinearBufferSize * numOutputSlots)) { }
931
932sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
933 if (buffer == nullptr) {
934 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
935 mFormat,
936 [lbp = mLocalBufferPool](size_t capacity) {
937 return lbp->newBuffer(capacity);
938 });
939 if (c2buffer == nullptr) {
940 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
941 return nullptr;
942 }
943 c2buffer->setRange(0, 0);
944 return c2buffer;
945 } else {
946 return ConstGraphicBlockBuffer::Allocate(
947 mFormat,
948 buffer,
949 [lbp = mLocalBufferPool](size_t capacity) {
950 return lbp->newBuffer(capacity);
951 });
952 }
953}
954
955sp<Codec2Buffer> RawGraphicOutputBuffers::allocateArrayBuffer() {
956 return ConstGraphicBlockBuffer::AllocateEmpty(
957 mFormat,
958 [lbp = mLocalBufferPool](size_t capacity) {
959 return lbp->newBuffer(capacity);
960 });
961}
962
963} // namespace android