blob: 2a0481061b58fff35890b34bbe35e535c6f951e0 [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 Kim469c8342019-04-11 16:46:09 -0700497// LinearInputBuffers
498
499bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700500 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700501 if (newBuffer == nullptr) {
502 return false;
503 }
504 *index = mImpl.assignSlot(newBuffer);
505 *buffer = newBuffer;
506 return true;
507}
508
509bool LinearInputBuffers::releaseBuffer(
510 const sp<MediaCodecBuffer> &buffer,
511 std::shared_ptr<C2Buffer> *c2buffer,
512 bool release) {
513 return mImpl.releaseSlot(buffer, c2buffer, release);
514}
515
516bool LinearInputBuffers::expireComponentBuffer(
517 const std::shared_ptr<C2Buffer> &c2buffer) {
518 return mImpl.expireComponentBuffer(c2buffer);
519}
520
521void LinearInputBuffers::flush() {
522 // This is no-op by default unless we're in array mode where we need to keep
523 // track of the flushed work.
524 mImpl.flush();
525}
526
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700527std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700528 std::unique_ptr<InputBuffersArray> array(
529 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
530 array->setPool(mPool);
531 array->setFormat(mFormat);
532 array->initialize(
533 mImpl,
534 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700535 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
536 return Alloc(pool, format);
537 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700538 return std::move(array);
539}
540
541size_t LinearInputBuffers::numClientBuffers() const {
542 return mImpl.numClientBuffers();
543}
544
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700545// static
546sp<Codec2Buffer> LinearInputBuffers::Alloc(
547 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
548 int32_t capacity = kLinearBufferSize;
549 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
550 if ((size_t)capacity > kMaxLinearBufferSize) {
551 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
552 capacity = kMaxLinearBufferSize;
553 }
554
555 // TODO: read usage from intf
Wonsik Kim469c8342019-04-11 16:46:09 -0700556 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
557 std::shared_ptr<C2LinearBlock> block;
558
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700559 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700560 if (err != C2_OK) {
561 return nullptr;
562 }
563
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700564 return LinearBlockBuffer::Allocate(format, block);
565}
566
567sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
568 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700569}
570
571// EncryptedLinearInputBuffers
572
573EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
574 bool secure,
575 const sp<MemoryDealer> &dealer,
576 const sp<ICrypto> &crypto,
577 int32_t heapSeqNum,
578 size_t capacity,
579 size_t numInputSlots,
580 const char *componentName, const char *name)
581 : LinearInputBuffers(componentName, name),
582 mUsage({0, 0}),
583 mDealer(dealer),
584 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700585 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700586 if (secure) {
587 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
588 } else {
589 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
590 }
591 for (size_t i = 0; i < numInputSlots; ++i) {
592 sp<IMemory> memory = mDealer->allocate(capacity);
593 if (memory == nullptr) {
594 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
595 mName, i);
596 break;
597 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700598 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700599 }
600}
601
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700602std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
603 std::unique_ptr<InputBuffersArray> array(
604 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
605 array->setPool(mPool);
606 array->setFormat(mFormat);
607 array->initialize(
608 mImpl,
609 size,
610 [pool = mPool,
611 format = mFormat,
612 usage = mUsage,
613 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
614 return Alloc(pool, format, usage, memoryVector);
615 });
616 return std::move(array);
617}
618
619
620// static
621sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
622 const std::shared_ptr<C2BlockPool> &pool,
623 const sp<AMessage> &format,
624 C2MemoryUsage usage,
625 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
626 int32_t capacity = kLinearBufferSize;
627 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
628 if ((size_t)capacity > kMaxLinearBufferSize) {
629 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
630 capacity = kMaxLinearBufferSize;
631 }
632
Wonsik Kim469c8342019-04-11 16:46:09 -0700633 sp<IMemory> memory;
634 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700635 int32_t heapSeqNum = -1;
636 for (; slot < memoryVector->size(); ++slot) {
637 if (memoryVector->at(slot).block.expired()) {
638 memory = memoryVector->at(slot).memory;
639 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700640 break;
641 }
642 }
643 if (memory == nullptr) {
644 return nullptr;
645 }
646
647 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700648 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700649 if (err != C2_OK || block == nullptr) {
650 return nullptr;
651 }
652
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700653 memoryVector->at(slot).block = block;
654 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
655}
656
657sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
658 // TODO: android_2020
659 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700660}
661
662// GraphicMetadataInputBuffers
663
664GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
665 const char *componentName, const char *name)
666 : InputBuffers(componentName, name),
667 mImpl(mName),
668 mStore(GetCodec2PlatformAllocatorStore()) { }
669
670bool GraphicMetadataInputBuffers::requestNewBuffer(
671 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700672 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700673 if (newBuffer == nullptr) {
674 return false;
675 }
676 *index = mImpl.assignSlot(newBuffer);
677 *buffer = newBuffer;
678 return true;
679}
680
681bool GraphicMetadataInputBuffers::releaseBuffer(
682 const sp<MediaCodecBuffer> &buffer,
683 std::shared_ptr<C2Buffer> *c2buffer,
684 bool release) {
685 return mImpl.releaseSlot(buffer, c2buffer, release);
686}
687
688bool GraphicMetadataInputBuffers::expireComponentBuffer(
689 const std::shared_ptr<C2Buffer> &c2buffer) {
690 return mImpl.expireComponentBuffer(c2buffer);
691}
692
693void GraphicMetadataInputBuffers::flush() {
694 // This is no-op by default unless we're in array mode where we need to keep
695 // track of the flushed work.
696}
697
698std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
699 size_t size) {
700 std::shared_ptr<C2Allocator> alloc;
701 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
702 if (err != C2_OK) {
703 return nullptr;
704 }
705 std::unique_ptr<InputBuffersArray> array(
706 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
707 array->setPool(mPool);
708 array->setFormat(mFormat);
709 array->initialize(
710 mImpl,
711 size,
712 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
713 return new GraphicMetadataBuffer(format, alloc);
714 });
715 return std::move(array);
716}
717
718size_t GraphicMetadataInputBuffers::numClientBuffers() const {
719 return mImpl.numClientBuffers();
720}
721
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700722sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
723 std::shared_ptr<C2Allocator> alloc;
724 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
725 if (err != C2_OK) {
726 return nullptr;
727 }
728 return new GraphicMetadataBuffer(mFormat, alloc);
729}
730
Wonsik Kim469c8342019-04-11 16:46:09 -0700731// GraphicInputBuffers
732
733GraphicInputBuffers::GraphicInputBuffers(
734 size_t numInputSlots, const char *componentName, const char *name)
735 : InputBuffers(componentName, name),
736 mImpl(mName),
737 mLocalBufferPool(LocalBufferPool::Create(
738 kMaxLinearBufferSize * numInputSlots)) { }
739
740bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700741 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700742 if (newBuffer == nullptr) {
743 return false;
744 }
745 *index = mImpl.assignSlot(newBuffer);
746 handleImageData(newBuffer);
747 *buffer = newBuffer;
748 return true;
749}
750
751bool GraphicInputBuffers::releaseBuffer(
752 const sp<MediaCodecBuffer> &buffer,
753 std::shared_ptr<C2Buffer> *c2buffer,
754 bool release) {
755 return mImpl.releaseSlot(buffer, c2buffer, release);
756}
757
758bool GraphicInputBuffers::expireComponentBuffer(
759 const std::shared_ptr<C2Buffer> &c2buffer) {
760 return mImpl.expireComponentBuffer(c2buffer);
761}
762
763void GraphicInputBuffers::flush() {
764 // This is no-op by default unless we're in array mode where we need to keep
765 // track of the flushed work.
766}
767
768std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
769 std::unique_ptr<InputBuffersArray> array(
770 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
771 array->setPool(mPool);
772 array->setFormat(mFormat);
773 array->initialize(
774 mImpl,
775 size,
776 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
777 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
778 return AllocateGraphicBuffer(
779 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
780 });
781 return std::move(array);
782}
783
784size_t GraphicInputBuffers::numClientBuffers() const {
785 return mImpl.numClientBuffers();
786}
787
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700788sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
789 // TODO: read usage from intf
790 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
791 return AllocateGraphicBuffer(
792 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
793}
794
Wonsik Kim469c8342019-04-11 16:46:09 -0700795// OutputBuffersArray
796
797void OutputBuffersArray::initialize(
798 const FlexBuffersImpl &impl,
799 size_t minSize,
800 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700801 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700802 mImpl.initialize(impl, minSize, allocate);
803}
804
805status_t OutputBuffersArray::registerBuffer(
806 const std::shared_ptr<C2Buffer> &buffer,
807 size_t *index,
808 sp<MediaCodecBuffer> *clientBuffer) {
809 sp<Codec2Buffer> c2Buffer;
810 status_t err = mImpl.grabBuffer(
811 index,
812 &c2Buffer,
813 [buffer](const sp<Codec2Buffer> &clientBuffer) {
814 return clientBuffer->canCopy(buffer);
815 });
816 if (err == WOULD_BLOCK) {
817 ALOGV("[%s] buffers temporarily not available", mName);
818 return err;
819 } else if (err != OK) {
820 ALOGD("[%s] grabBuffer failed: %d", mName, err);
821 return err;
822 }
823 c2Buffer->setFormat(mFormat);
824 if (!c2Buffer->copy(buffer)) {
825 ALOGD("[%s] copy buffer failed", mName);
826 return WOULD_BLOCK;
827 }
828 submit(c2Buffer);
829 handleImageData(c2Buffer);
830 *clientBuffer = c2Buffer;
831 ALOGV("[%s] grabbed buffer %zu", mName, *index);
832 return OK;
833}
834
835status_t OutputBuffersArray::registerCsd(
836 const C2StreamInitDataInfo::output *csd,
837 size_t *index,
838 sp<MediaCodecBuffer> *clientBuffer) {
839 sp<Codec2Buffer> c2Buffer;
840 status_t err = mImpl.grabBuffer(
841 index,
842 &c2Buffer,
843 [csd](const sp<Codec2Buffer> &clientBuffer) {
844 return clientBuffer->base() != nullptr
845 && clientBuffer->capacity() >= csd->flexCount();
846 });
847 if (err != OK) {
848 return err;
849 }
850 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
851 c2Buffer->setRange(0, csd->flexCount());
852 c2Buffer->setFormat(mFormat);
853 *clientBuffer = c2Buffer;
854 return OK;
855}
856
857bool OutputBuffersArray::releaseBuffer(
858 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
859 return mImpl.returnBuffer(buffer, c2buffer, true);
860}
861
862void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
863 (void)flushedWork;
864 mImpl.flush();
865 if (mSkipCutBuffer != nullptr) {
866 mSkipCutBuffer->clear();
867 }
868}
869
870void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
871 mImpl.getArray(array);
872}
873
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700874size_t OutputBuffersArray::numClientBuffers() const {
875 return mImpl.numClientBuffers();
876}
877
Wonsik Kim469c8342019-04-11 16:46:09 -0700878void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700879 switch (c2buffer->data().type()) {
880 case C2BufferData::LINEAR: {
881 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -0700882 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
883 const uint32_t block_size = linear_blocks.front().size();
884 if (block_size < kMaxLinearBufferSize / 2) {
885 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -0700886 } else {
887 size = kMaxLinearBufferSize;
888 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700889 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -0700890 return new LocalLinearBuffer(format, new ABuffer(size));
891 };
Wonsik Kima39882b2019-06-20 16:13:56 -0700892 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -0700893 break;
894 }
895
Wonsik Kima39882b2019-06-20 16:13:56 -0700896 case C2BufferData::GRAPHIC: {
897 // This is only called for RawGraphicOutputBuffers.
898 mAlloc = [format = mFormat,
899 lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
900 return ConstGraphicBlockBuffer::AllocateEmpty(
901 format,
902 [lbp](size_t capacity) {
903 return lbp->newBuffer(capacity);
904 });
905 };
906 ALOGD("[%s] reallocating with graphic buffer: format = %s",
907 mName, mFormat->debugString().c_str());
908 break;
909 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700910
911 case C2BufferData::INVALID: [[fallthrough]];
912 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
913 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
914 default:
915 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
916 return;
917 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700918 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700919}
920
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700921void OutputBuffersArray::grow(size_t newSize) {
922 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700923}
924
925// FlexOutputBuffers
926
927status_t FlexOutputBuffers::registerBuffer(
928 const std::shared_ptr<C2Buffer> &buffer,
929 size_t *index,
930 sp<MediaCodecBuffer> *clientBuffer) {
931 sp<Codec2Buffer> newBuffer = wrap(buffer);
932 if (newBuffer == nullptr) {
933 return NO_MEMORY;
934 }
935 newBuffer->setFormat(mFormat);
936 *index = mImpl.assignSlot(newBuffer);
937 handleImageData(newBuffer);
938 *clientBuffer = newBuffer;
939 ALOGV("[%s] registered buffer %zu", mName, *index);
940 return OK;
941}
942
943status_t FlexOutputBuffers::registerCsd(
944 const C2StreamInitDataInfo::output *csd,
945 size_t *index,
946 sp<MediaCodecBuffer> *clientBuffer) {
947 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
948 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
949 *index = mImpl.assignSlot(newBuffer);
950 *clientBuffer = newBuffer;
951 return OK;
952}
953
954bool FlexOutputBuffers::releaseBuffer(
955 const sp<MediaCodecBuffer> &buffer,
956 std::shared_ptr<C2Buffer> *c2buffer) {
957 return mImpl.releaseSlot(buffer, c2buffer, true);
958}
959
960void FlexOutputBuffers::flush(
961 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
962 (void) flushedWork;
963 // This is no-op by default unless we're in array mode where we need to keep
964 // track of the flushed work.
965}
966
967std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
968 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
969 array->setFormat(mFormat);
970 array->transferSkipCutBuffer(mSkipCutBuffer);
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700971 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
972 array->initialize(mImpl, size, alloc);
Wonsik Kim469c8342019-04-11 16:46:09 -0700973 return std::move(array);
974}
975
976size_t FlexOutputBuffers::numClientBuffers() const {
977 return mImpl.numClientBuffers();
978}
979
980// LinearOutputBuffers
981
982void LinearOutputBuffers::flush(
983 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
984 if (mSkipCutBuffer != nullptr) {
985 mSkipCutBuffer->clear();
986 }
987 FlexOutputBuffers::flush(flushedWork);
988}
989
990sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
991 if (buffer == nullptr) {
992 ALOGV("[%s] using a dummy buffer", mName);
993 return new LocalLinearBuffer(mFormat, new ABuffer(0));
994 }
995 if (buffer->data().type() != C2BufferData::LINEAR) {
996 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
997 // We expect linear output buffers from the component.
998 return nullptr;
999 }
1000 if (buffer->data().linearBlocks().size() != 1u) {
1001 ALOGV("[%s] no linear buffers", mName);
1002 // We expect one and only one linear block from the component.
1003 return nullptr;
1004 }
1005 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1006 if (clientBuffer == nullptr) {
1007 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1008 return nullptr;
1009 }
1010 submit(clientBuffer);
1011 return clientBuffer;
1012}
1013
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001014std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1015 return [format = mFormat]{
1016 // TODO: proper max output size
1017 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1018 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001019}
1020
1021// GraphicOutputBuffers
1022
1023sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1024 return new DummyContainerBuffer(mFormat, buffer);
1025}
1026
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001027std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1028 return [format = mFormat]{
1029 return new DummyContainerBuffer(format);
1030 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001031}
1032
1033// RawGraphicOutputBuffers
1034
1035RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1036 size_t numOutputSlots, const char *componentName, const char *name)
1037 : FlexOutputBuffers(componentName, name),
1038 mLocalBufferPool(LocalBufferPool::Create(
1039 kMaxLinearBufferSize * numOutputSlots)) { }
1040
1041sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1042 if (buffer == nullptr) {
1043 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1044 mFormat,
1045 [lbp = mLocalBufferPool](size_t capacity) {
1046 return lbp->newBuffer(capacity);
1047 });
1048 if (c2buffer == nullptr) {
1049 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1050 return nullptr;
1051 }
1052 c2buffer->setRange(0, 0);
1053 return c2buffer;
1054 } else {
1055 return ConstGraphicBlockBuffer::Allocate(
1056 mFormat,
1057 buffer,
1058 [lbp = mLocalBufferPool](size_t capacity) {
1059 return lbp->newBuffer(capacity);
1060 });
1061 }
1062}
1063
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001064std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1065 return [format = mFormat, lbp = mLocalBufferPool]{
1066 return ConstGraphicBlockBuffer::AllocateEmpty(
1067 format,
1068 [lbp](size_t capacity) {
1069 return lbp->newBuffer(capacity);
1070 });
1071 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001072}
1073
1074} // namespace android