blob: 265eeb7731f98778e59c2f8d87439fe279723567 [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;
130 setSkipCutBuffer(delay, padding, channelCount);
131}
132
133void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
134 if (mSkipCutBuffer == nullptr) {
135 return;
136 }
137 int32_t delay = mDelay;
138 int32_t padding = mPadding;
139 if (sampleRate != mSampleRate) {
140 delay = ((int64_t)delay * sampleRate) / mSampleRate;
141 padding = ((int64_t)padding * sampleRate) / mSampleRate;
142 }
143 setSkipCutBuffer(delay, padding, channelCount);
144}
145
146void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
147 if (mSkipCutBuffer != nullptr) {
148 mSkipCutBuffer->submit(buffer);
149 }
150}
151
152void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
153 mSkipCutBuffer = scb;
154}
155
156void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
157 if (mSkipCutBuffer != nullptr) {
158 size_t prevSize = mSkipCutBuffer->size();
159 if (prevSize != 0u) {
160 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
161 }
162 }
163 mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
164}
165
166// LocalBufferPool
167
168std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
169 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
170}
171
172sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
173 Mutex::Autolock lock(mMutex);
174 auto it = std::find_if(
175 mPool.begin(), mPool.end(),
176 [capacity](const std::vector<uint8_t> &vec) {
177 return vec.capacity() >= capacity;
178 });
179 if (it != mPool.end()) {
180 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
181 mPool.erase(it);
182 return buffer;
183 }
184 if (mUsedSize + capacity > mPoolCapacity) {
185 while (!mPool.empty()) {
186 mUsedSize -= mPool.back().capacity();
187 mPool.pop_back();
188 }
189 if (mUsedSize + capacity > mPoolCapacity) {
190 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
191 mUsedSize, capacity, mPoolCapacity);
192 return nullptr;
193 }
194 }
195 std::vector<uint8_t> vec(capacity);
196 mUsedSize += vec.capacity();
197 return new VectorBuffer(std::move(vec), shared_from_this());
198}
199
200LocalBufferPool::VectorBuffer::VectorBuffer(
201 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
202 : ABuffer(vec.data(), vec.capacity()),
203 mVec(std::move(vec)),
204 mPool(pool) {
205}
206
207LocalBufferPool::VectorBuffer::~VectorBuffer() {
208 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
209 if (pool) {
210 // If pool is alive, return the vector back to the pool so that
211 // it can be recycled.
212 pool->returnVector(std::move(mVec));
213 }
214}
215
216void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
217 Mutex::Autolock lock(mMutex);
218 mPool.push_front(std::move(vec));
219}
220
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700221// FlexBuffersImpl
222
Wonsik Kim469c8342019-04-11 16:46:09 -0700223size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
224 for (size_t i = 0; i < mBuffers.size(); ++i) {
225 if (mBuffers[i].clientBuffer == nullptr
226 && mBuffers[i].compBuffer.expired()) {
227 mBuffers[i].clientBuffer = buffer;
228 return i;
229 }
230 }
231 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
232 return mBuffers.size() - 1;
233}
234
Wonsik Kim469c8342019-04-11 16:46:09 -0700235bool FlexBuffersImpl::releaseSlot(
236 const sp<MediaCodecBuffer> &buffer,
237 std::shared_ptr<C2Buffer> *c2buffer,
238 bool release) {
239 sp<Codec2Buffer> clientBuffer;
240 size_t index = mBuffers.size();
241 for (size_t i = 0; i < mBuffers.size(); ++i) {
242 if (mBuffers[i].clientBuffer == buffer) {
243 clientBuffer = mBuffers[i].clientBuffer;
244 if (release) {
245 mBuffers[i].clientBuffer.clear();
246 }
247 index = i;
248 break;
249 }
250 }
251 if (clientBuffer == nullptr) {
252 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
253 return false;
254 }
255 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
256 if (!result) {
257 result = clientBuffer->asC2Buffer();
258 mBuffers[index].compBuffer = result;
259 }
260 if (c2buffer) {
261 *c2buffer = result;
262 }
263 return true;
264}
265
266bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
267 for (size_t i = 0; i < mBuffers.size(); ++i) {
268 std::shared_ptr<C2Buffer> compBuffer =
269 mBuffers[i].compBuffer.lock();
270 if (!compBuffer || compBuffer != c2buffer) {
271 continue;
272 }
273 mBuffers[i].compBuffer.reset();
274 ALOGV("[%s] codec released buffer #%zu", mName, i);
275 return true;
276 }
277 ALOGV("[%s] codec released an unknown buffer", mName);
278 return false;
279}
280
281void FlexBuffersImpl::flush() {
282 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
283 mBuffers.clear();
284}
285
286size_t FlexBuffersImpl::numClientBuffers() const {
287 return std::count_if(
288 mBuffers.begin(), mBuffers.end(),
289 [](const Entry &entry) {
290 return (entry.clientBuffer != nullptr);
291 });
292}
293
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700294size_t FlexBuffersImpl::numComponentBuffers() const {
295 return std::count_if(
296 mBuffers.begin(), mBuffers.end(),
297 [](const Entry &entry) {
298 return !entry.compBuffer.expired();
299 });
300}
301
Wonsik Kim469c8342019-04-11 16:46:09 -0700302// BuffersArrayImpl
303
304void BuffersArrayImpl::initialize(
305 const FlexBuffersImpl &impl,
306 size_t minSize,
307 std::function<sp<Codec2Buffer>()> allocate) {
308 mImplName = impl.mImplName + "[N]";
309 mName = mImplName.c_str();
310 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
311 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
312 bool ownedByClient = (clientBuffer != nullptr);
313 if (!ownedByClient) {
314 clientBuffer = allocate();
315 }
316 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
317 }
318 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
319 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
320 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
321 }
322}
323
324status_t BuffersArrayImpl::grabBuffer(
325 size_t *index,
326 sp<Codec2Buffer> *buffer,
327 std::function<bool(const sp<Codec2Buffer> &)> match) {
328 // allBuffersDontMatch remains true if all buffers are available but
329 // match() returns false for every buffer.
330 bool allBuffersDontMatch = true;
331 for (size_t i = 0; i < mBuffers.size(); ++i) {
332 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
333 if (match(mBuffers[i].clientBuffer)) {
334 mBuffers[i].ownedByClient = true;
335 *buffer = mBuffers[i].clientBuffer;
336 (*buffer)->meta()->clear();
337 (*buffer)->setRange(0, (*buffer)->capacity());
338 *index = i;
339 return OK;
340 }
341 } else {
342 allBuffersDontMatch = false;
343 }
344 }
345 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
346}
347
348bool BuffersArrayImpl::returnBuffer(
349 const sp<MediaCodecBuffer> &buffer,
350 std::shared_ptr<C2Buffer> *c2buffer,
351 bool release) {
352 sp<Codec2Buffer> clientBuffer;
353 size_t index = mBuffers.size();
354 for (size_t i = 0; i < mBuffers.size(); ++i) {
355 if (mBuffers[i].clientBuffer == buffer) {
356 if (!mBuffers[i].ownedByClient) {
357 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
358 mName, i);
359 }
360 clientBuffer = mBuffers[i].clientBuffer;
361 if (release) {
362 mBuffers[i].ownedByClient = false;
363 }
364 index = i;
365 break;
366 }
367 }
368 if (clientBuffer == nullptr) {
369 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
370 return false;
371 }
372 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
373 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
374 if (!result) {
375 result = clientBuffer->asC2Buffer();
376 mBuffers[index].compBuffer = result;
377 }
378 if (c2buffer) {
379 *c2buffer = result;
380 }
381 return true;
382}
383
384bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
385 for (size_t i = 0; i < mBuffers.size(); ++i) {
386 std::shared_ptr<C2Buffer> compBuffer =
387 mBuffers[i].compBuffer.lock();
388 if (!compBuffer) {
389 continue;
390 }
391 if (c2buffer == compBuffer) {
392 if (mBuffers[i].ownedByClient) {
393 // This should not happen.
394 ALOGD("[%s] codec released a buffer owned by client "
395 "(index %zu)", mName, i);
396 }
397 mBuffers[i].compBuffer.reset();
398 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
399 return true;
400 }
401 }
402 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
403 return false;
404}
405
406void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
407 array->clear();
408 for (const Entry &entry : mBuffers) {
409 array->push(entry.clientBuffer);
410 }
411}
412
413void BuffersArrayImpl::flush() {
414 for (Entry &entry : mBuffers) {
415 entry.ownedByClient = false;
416 }
417}
418
419void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
420 size_t size = mBuffers.size();
421 mBuffers.clear();
422 for (size_t i = 0; i < size; ++i) {
423 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
424 }
425}
426
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700427void BuffersArrayImpl::grow(
428 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
429 CHECK_LT(mBuffers.size(), newSize);
430 while (mBuffers.size() < newSize) {
431 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
432 }
433}
434
Wonsik Kim469c8342019-04-11 16:46:09 -0700435size_t BuffersArrayImpl::numClientBuffers() const {
436 return std::count_if(
437 mBuffers.begin(), mBuffers.end(),
438 [](const Entry &entry) {
439 return entry.ownedByClient;
440 });
441}
442
Wonsik Kima39882b2019-06-20 16:13:56 -0700443size_t BuffersArrayImpl::arraySize() const {
444 return mBuffers.size();
445}
446
Wonsik Kim469c8342019-04-11 16:46:09 -0700447// InputBuffersArray
448
449void InputBuffersArray::initialize(
450 const FlexBuffersImpl &impl,
451 size_t minSize,
452 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700453 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700454 mImpl.initialize(impl, minSize, allocate);
455}
456
457void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
458 mImpl.getArray(array);
459}
460
461bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
462 sp<Codec2Buffer> c2Buffer;
463 status_t err = mImpl.grabBuffer(index, &c2Buffer);
464 if (err == OK) {
465 c2Buffer->setFormat(mFormat);
466 handleImageData(c2Buffer);
467 *buffer = c2Buffer;
468 return true;
469 }
470 return false;
471}
472
473bool InputBuffersArray::releaseBuffer(
474 const sp<MediaCodecBuffer> &buffer,
475 std::shared_ptr<C2Buffer> *c2buffer,
476 bool release) {
477 return mImpl.returnBuffer(buffer, c2buffer, release);
478}
479
480bool InputBuffersArray::expireComponentBuffer(
481 const std::shared_ptr<C2Buffer> &c2buffer) {
482 return mImpl.expireComponentBuffer(c2buffer);
483}
484
485void InputBuffersArray::flush() {
486 mImpl.flush();
487}
488
489size_t InputBuffersArray::numClientBuffers() const {
490 return mImpl.numClientBuffers();
491}
492
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700493sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
494 return mAllocate();
495}
496
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800497// SlotInputBuffers
498
499bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
500 sp<Codec2Buffer> newBuffer = createNewBuffer();
501 *index = mImpl.assignSlot(newBuffer);
502 *buffer = newBuffer;
503 return true;
504}
505
506bool SlotInputBuffers::releaseBuffer(
507 const sp<MediaCodecBuffer> &buffer,
508 std::shared_ptr<C2Buffer> *c2buffer,
509 bool release) {
510 return mImpl.releaseSlot(buffer, c2buffer, release);
511}
512
513bool SlotInputBuffers::expireComponentBuffer(
514 const std::shared_ptr<C2Buffer> &c2buffer) {
515 return mImpl.expireComponentBuffer(c2buffer);
516}
517
518void SlotInputBuffers::flush() {
519 mImpl.flush();
520}
521
522std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
523 TRESPASS("Array mode should not be called at non-legacy mode");
524 return nullptr;
525}
526
527size_t SlotInputBuffers::numClientBuffers() const {
528 return mImpl.numClientBuffers();
529}
530
531sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
532 return new DummyContainerBuffer{mFormat, nullptr};
533}
534
Wonsik Kim469c8342019-04-11 16:46:09 -0700535// LinearInputBuffers
536
537bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700538 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700539 if (newBuffer == nullptr) {
540 return false;
541 }
542 *index = mImpl.assignSlot(newBuffer);
543 *buffer = newBuffer;
544 return true;
545}
546
547bool LinearInputBuffers::releaseBuffer(
548 const sp<MediaCodecBuffer> &buffer,
549 std::shared_ptr<C2Buffer> *c2buffer,
550 bool release) {
551 return mImpl.releaseSlot(buffer, c2buffer, release);
552}
553
554bool LinearInputBuffers::expireComponentBuffer(
555 const std::shared_ptr<C2Buffer> &c2buffer) {
556 return mImpl.expireComponentBuffer(c2buffer);
557}
558
559void LinearInputBuffers::flush() {
560 // This is no-op by default unless we're in array mode where we need to keep
561 // track of the flushed work.
562 mImpl.flush();
563}
564
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700565std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700566 std::unique_ptr<InputBuffersArray> array(
567 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
568 array->setPool(mPool);
569 array->setFormat(mFormat);
570 array->initialize(
571 mImpl,
572 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700573 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
574 return Alloc(pool, format);
575 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700576 return std::move(array);
577}
578
579size_t LinearInputBuffers::numClientBuffers() const {
580 return mImpl.numClientBuffers();
581}
582
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700583// static
584sp<Codec2Buffer> LinearInputBuffers::Alloc(
585 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
586 int32_t capacity = kLinearBufferSize;
587 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
588 if ((size_t)capacity > kMaxLinearBufferSize) {
589 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
590 capacity = kMaxLinearBufferSize;
591 }
592
593 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700594 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
595 std::shared_ptr<C2LinearBlock> block;
596
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700597 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700598 if (err != C2_OK) {
599 return nullptr;
600 }
601
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700602 return LinearBlockBuffer::Allocate(format, block);
603}
604
605sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
606 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700607}
608
609// EncryptedLinearInputBuffers
610
611EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
612 bool secure,
613 const sp<MemoryDealer> &dealer,
614 const sp<ICrypto> &crypto,
615 int32_t heapSeqNum,
616 size_t capacity,
617 size_t numInputSlots,
618 const char *componentName, const char *name)
619 : LinearInputBuffers(componentName, name),
620 mUsage({0, 0}),
621 mDealer(dealer),
622 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700623 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700624 if (secure) {
625 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
626 } else {
627 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
628 }
629 for (size_t i = 0; i < numInputSlots; ++i) {
630 sp<IMemory> memory = mDealer->allocate(capacity);
631 if (memory == nullptr) {
632 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
633 mName, i);
634 break;
635 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700636 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700637 }
638}
639
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700640std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
641 std::unique_ptr<InputBuffersArray> array(
642 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
643 array->setPool(mPool);
644 array->setFormat(mFormat);
645 array->initialize(
646 mImpl,
647 size,
648 [pool = mPool,
649 format = mFormat,
650 usage = mUsage,
651 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
652 return Alloc(pool, format, usage, memoryVector);
653 });
654 return std::move(array);
655}
656
657
658// static
659sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
660 const std::shared_ptr<C2BlockPool> &pool,
661 const sp<AMessage> &format,
662 C2MemoryUsage usage,
663 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
664 int32_t capacity = kLinearBufferSize;
665 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
666 if ((size_t)capacity > kMaxLinearBufferSize) {
667 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
668 capacity = kMaxLinearBufferSize;
669 }
670
Wonsik Kim469c8342019-04-11 16:46:09 -0700671 sp<IMemory> memory;
672 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700673 int32_t heapSeqNum = -1;
674 for (; slot < memoryVector->size(); ++slot) {
675 if (memoryVector->at(slot).block.expired()) {
676 memory = memoryVector->at(slot).memory;
677 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700678 break;
679 }
680 }
681 if (memory == nullptr) {
682 return nullptr;
683 }
684
685 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700686 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700687 if (err != C2_OK || block == nullptr) {
688 return nullptr;
689 }
690
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700691 memoryVector->at(slot).block = block;
692 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
693}
694
695sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
696 // TODO: android_2020
697 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700698}
699
700// GraphicMetadataInputBuffers
701
702GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
703 const char *componentName, const char *name)
704 : InputBuffers(componentName, name),
705 mImpl(mName),
706 mStore(GetCodec2PlatformAllocatorStore()) { }
707
708bool GraphicMetadataInputBuffers::requestNewBuffer(
709 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700710 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700711 if (newBuffer == nullptr) {
712 return false;
713 }
714 *index = mImpl.assignSlot(newBuffer);
715 *buffer = newBuffer;
716 return true;
717}
718
719bool GraphicMetadataInputBuffers::releaseBuffer(
720 const sp<MediaCodecBuffer> &buffer,
721 std::shared_ptr<C2Buffer> *c2buffer,
722 bool release) {
723 return mImpl.releaseSlot(buffer, c2buffer, release);
724}
725
726bool GraphicMetadataInputBuffers::expireComponentBuffer(
727 const std::shared_ptr<C2Buffer> &c2buffer) {
728 return mImpl.expireComponentBuffer(c2buffer);
729}
730
731void GraphicMetadataInputBuffers::flush() {
732 // This is no-op by default unless we're in array mode where we need to keep
733 // track of the flushed work.
734}
735
736std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
737 size_t size) {
738 std::shared_ptr<C2Allocator> alloc;
739 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
740 if (err != C2_OK) {
741 return nullptr;
742 }
743 std::unique_ptr<InputBuffersArray> array(
744 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
745 array->setPool(mPool);
746 array->setFormat(mFormat);
747 array->initialize(
748 mImpl,
749 size,
750 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
751 return new GraphicMetadataBuffer(format, alloc);
752 });
753 return std::move(array);
754}
755
756size_t GraphicMetadataInputBuffers::numClientBuffers() const {
757 return mImpl.numClientBuffers();
758}
759
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700760sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
761 std::shared_ptr<C2Allocator> alloc;
762 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
763 if (err != C2_OK) {
764 return nullptr;
765 }
766 return new GraphicMetadataBuffer(mFormat, alloc);
767}
768
Wonsik Kim469c8342019-04-11 16:46:09 -0700769// GraphicInputBuffers
770
771GraphicInputBuffers::GraphicInputBuffers(
772 size_t numInputSlots, const char *componentName, const char *name)
773 : InputBuffers(componentName, name),
774 mImpl(mName),
775 mLocalBufferPool(LocalBufferPool::Create(
776 kMaxLinearBufferSize * numInputSlots)) { }
777
778bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700779 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700780 if (newBuffer == nullptr) {
781 return false;
782 }
783 *index = mImpl.assignSlot(newBuffer);
784 handleImageData(newBuffer);
785 *buffer = newBuffer;
786 return true;
787}
788
789bool GraphicInputBuffers::releaseBuffer(
790 const sp<MediaCodecBuffer> &buffer,
791 std::shared_ptr<C2Buffer> *c2buffer,
792 bool release) {
793 return mImpl.releaseSlot(buffer, c2buffer, release);
794}
795
796bool GraphicInputBuffers::expireComponentBuffer(
797 const std::shared_ptr<C2Buffer> &c2buffer) {
798 return mImpl.expireComponentBuffer(c2buffer);
799}
800
801void GraphicInputBuffers::flush() {
802 // This is no-op by default unless we're in array mode where we need to keep
803 // track of the flushed work.
804}
805
806std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
807 std::unique_ptr<InputBuffersArray> array(
808 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
809 array->setPool(mPool);
810 array->setFormat(mFormat);
811 array->initialize(
812 mImpl,
813 size,
814 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
815 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
816 return AllocateGraphicBuffer(
817 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
818 });
819 return std::move(array);
820}
821
822size_t GraphicInputBuffers::numClientBuffers() const {
823 return mImpl.numClientBuffers();
824}
825
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700826sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
827 // TODO: read usage from intf
828 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
829 return AllocateGraphicBuffer(
830 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
831}
832
Wonsik Kim469c8342019-04-11 16:46:09 -0700833// OutputBuffersArray
834
835void OutputBuffersArray::initialize(
836 const FlexBuffersImpl &impl,
837 size_t minSize,
838 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700839 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700840 mImpl.initialize(impl, minSize, allocate);
841}
842
843status_t OutputBuffersArray::registerBuffer(
844 const std::shared_ptr<C2Buffer> &buffer,
845 size_t *index,
846 sp<MediaCodecBuffer> *clientBuffer) {
847 sp<Codec2Buffer> c2Buffer;
848 status_t err = mImpl.grabBuffer(
849 index,
850 &c2Buffer,
851 [buffer](const sp<Codec2Buffer> &clientBuffer) {
852 return clientBuffer->canCopy(buffer);
853 });
854 if (err == WOULD_BLOCK) {
855 ALOGV("[%s] buffers temporarily not available", mName);
856 return err;
857 } else if (err != OK) {
858 ALOGD("[%s] grabBuffer failed: %d", mName, err);
859 return err;
860 }
861 c2Buffer->setFormat(mFormat);
862 if (!c2Buffer->copy(buffer)) {
863 ALOGD("[%s] copy buffer failed", mName);
864 return WOULD_BLOCK;
865 }
866 submit(c2Buffer);
867 handleImageData(c2Buffer);
868 *clientBuffer = c2Buffer;
869 ALOGV("[%s] grabbed buffer %zu", mName, *index);
870 return OK;
871}
872
873status_t OutputBuffersArray::registerCsd(
874 const C2StreamInitDataInfo::output *csd,
875 size_t *index,
876 sp<MediaCodecBuffer> *clientBuffer) {
877 sp<Codec2Buffer> c2Buffer;
878 status_t err = mImpl.grabBuffer(
879 index,
880 &c2Buffer,
881 [csd](const sp<Codec2Buffer> &clientBuffer) {
882 return clientBuffer->base() != nullptr
883 && clientBuffer->capacity() >= csd->flexCount();
884 });
885 if (err != OK) {
886 return err;
887 }
888 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
889 c2Buffer->setRange(0, csd->flexCount());
890 c2Buffer->setFormat(mFormat);
891 *clientBuffer = c2Buffer;
892 return OK;
893}
894
895bool OutputBuffersArray::releaseBuffer(
896 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
897 return mImpl.returnBuffer(buffer, c2buffer, true);
898}
899
900void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
901 (void)flushedWork;
902 mImpl.flush();
903 if (mSkipCutBuffer != nullptr) {
904 mSkipCutBuffer->clear();
905 }
906}
907
908void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
909 mImpl.getArray(array);
910}
911
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700912size_t OutputBuffersArray::numClientBuffers() const {
913 return mImpl.numClientBuffers();
914}
915
Wonsik Kim469c8342019-04-11 16:46:09 -0700916void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700917 switch (c2buffer->data().type()) {
918 case C2BufferData::LINEAR: {
919 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -0700920 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
921 const uint32_t block_size = linear_blocks.front().size();
922 if (block_size < kMaxLinearBufferSize / 2) {
923 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -0700924 } else {
925 size = kMaxLinearBufferSize;
926 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700927 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -0700928 return new LocalLinearBuffer(format, new ABuffer(size));
929 };
Wonsik Kima39882b2019-06-20 16:13:56 -0700930 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -0700931 break;
932 }
933
Wonsik Kima39882b2019-06-20 16:13:56 -0700934 case C2BufferData::GRAPHIC: {
935 // This is only called for RawGraphicOutputBuffers.
936 mAlloc = [format = mFormat,
937 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
938 return ConstGraphicBlockBuffer::AllocateEmpty(
939 format,
940 [lbp](size_t capacity) {
941 return lbp->newBuffer(capacity);
942 });
943 };
944 ALOGD("[%s] reallocating with graphic buffer: format = %s",
945 mName, mFormat->debugString().c_str());
946 break;
947 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700948
949 case C2BufferData::INVALID: [[fallthrough]];
950 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
951 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
952 default:
953 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
954 return;
955 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700956 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700957}
958
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700959void OutputBuffersArray::grow(size_t newSize) {
960 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700961}
962
963// FlexOutputBuffers
964
965status_t FlexOutputBuffers::registerBuffer(
966 const std::shared_ptr<C2Buffer> &buffer,
967 size_t *index,
968 sp<MediaCodecBuffer> *clientBuffer) {
969 sp<Codec2Buffer> newBuffer = wrap(buffer);
970 if (newBuffer == nullptr) {
971 return NO_MEMORY;
972 }
973 newBuffer->setFormat(mFormat);
974 *index = mImpl.assignSlot(newBuffer);
975 handleImageData(newBuffer);
976 *clientBuffer = newBuffer;
977 ALOGV("[%s] registered buffer %zu", mName, *index);
978 return OK;
979}
980
981status_t FlexOutputBuffers::registerCsd(
982 const C2StreamInitDataInfo::output *csd,
983 size_t *index,
984 sp<MediaCodecBuffer> *clientBuffer) {
985 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
986 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
987 *index = mImpl.assignSlot(newBuffer);
988 *clientBuffer = newBuffer;
989 return OK;
990}
991
992bool FlexOutputBuffers::releaseBuffer(
993 const sp<MediaCodecBuffer> &buffer,
994 std::shared_ptr<C2Buffer> *c2buffer) {
995 return mImpl.releaseSlot(buffer, c2buffer, true);
996}
997
998void FlexOutputBuffers::flush(
999 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1000 (void) flushedWork;
1001 // This is no-op by default unless we're in array mode where we need to keep
1002 // track of the flushed work.
1003}
1004
1005std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
1006 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1007 array->setFormat(mFormat);
1008 array->transferSkipCutBuffer(mSkipCutBuffer);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001009 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1010 array->initialize(mImpl, size, alloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001011 return std::move(array);
1012}
1013
1014size_t FlexOutputBuffers::numClientBuffers() const {
1015 return mImpl.numClientBuffers();
1016}
1017
1018// LinearOutputBuffers
1019
1020void LinearOutputBuffers::flush(
1021 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1022 if (mSkipCutBuffer != nullptr) {
1023 mSkipCutBuffer->clear();
1024 }
1025 FlexOutputBuffers::flush(flushedWork);
1026}
1027
1028sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1029 if (buffer == nullptr) {
1030 ALOGV("[%s] using a dummy buffer", mName);
1031 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1032 }
1033 if (buffer->data().type() != C2BufferData::LINEAR) {
1034 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1035 // We expect linear output buffers from the component.
1036 return nullptr;
1037 }
1038 if (buffer->data().linearBlocks().size() != 1u) {
1039 ALOGV("[%s] no linear buffers", mName);
1040 // We expect one and only one linear block from the component.
1041 return nullptr;
1042 }
1043 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1044 if (clientBuffer == nullptr) {
1045 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1046 return nullptr;
1047 }
1048 submit(clientBuffer);
1049 return clientBuffer;
1050}
1051
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001052std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1053 return [format = mFormat]{
1054 // TODO: proper max output size
1055 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1056 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001057}
1058
1059// GraphicOutputBuffers
1060
1061sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1062 return new DummyContainerBuffer(mFormat, buffer);
1063}
1064
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001065std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1066 return [format = mFormat]{
1067 return new DummyContainerBuffer(format);
1068 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001069}
1070
1071// RawGraphicOutputBuffers
1072
1073RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1074 size_t numOutputSlots, const char *componentName, const char *name)
1075 : FlexOutputBuffers(componentName, name),
1076 mLocalBufferPool(LocalBufferPool::Create(
1077 kMaxLinearBufferSize * numOutputSlots)) { }
1078
1079sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1080 if (buffer == nullptr) {
1081 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1082 mFormat,
1083 [lbp = mLocalBufferPool](size_t capacity) {
1084 return lbp->newBuffer(capacity);
1085 });
1086 if (c2buffer == nullptr) {
1087 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1088 return nullptr;
1089 }
1090 c2buffer->setRange(0, 0);
1091 return c2buffer;
1092 } else {
1093 return ConstGraphicBlockBuffer::Allocate(
1094 mFormat,
1095 buffer,
1096 [lbp = mLocalBufferPool](size_t capacity) {
1097 return lbp->newBuffer(capacity);
1098 });
1099 }
1100}
1101
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001102std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1103 return [format = mFormat, lbp = mLocalBufferPool]{
1104 return ConstGraphicBlockBuffer::AllocateEmpty(
1105 format,
1106 [lbp](size_t capacity) {
1107 return lbp->newBuffer(capacity);
1108 });
1109 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001110}
1111
1112} // namespace android