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