1 /*
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
28 namespace android {
29
30 namespace {
31
AllocateGraphicBuffer(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,uint32_t pixelFormat,const C2MemoryUsage & usage,const std::shared_ptr<LocalBufferPool> & localBufferPool)32 sp<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
setFormat(const sp<AMessage> & format)64 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
65 CHECK(format != nullptr);
66 mFormat = format;
67 }
68
dupFormat()69 sp<AMessage> CCodecBuffers::dupFormat() {
70 return mFormat != nullptr ? mFormat->dup() : nullptr;
71 }
72
handleImageData(const sp<Codec2Buffer> & buffer)73 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
74 sp<ABuffer> imageDataCandidate = buffer->getImageData();
75 if (imageDataCandidate == nullptr) {
76 return;
77 }
78 sp<ABuffer> imageData;
79 if (!mFormat->findBuffer("image-data", &imageData)
80 || imageDataCandidate->size() != imageData->size()
81 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
82 ALOGD("[%s] updating image-data", mName);
83 sp<AMessage> newFormat = dupFormat();
84 newFormat->setBuffer("image-data", imageDataCandidate);
85 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
86 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
87 int32_t stride = img->mPlane[0].mRowInc;
88 newFormat->setInt32(KEY_STRIDE, stride);
89 ALOGD("[%s] updating stride = %d", mName, stride);
90 if (img->mNumPlanes > 1 && stride > 0) {
91 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
92 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
93 ALOGD("[%s] updating vstride = %d", mName, vstride);
94 }
95 }
96 setFormat(newFormat);
97 buffer->setFormat(newFormat);
98 }
99 }
100
101 // InputBuffers
102
cloneAndReleaseBuffer(const sp<MediaCodecBuffer> & buffer)103 sp<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
121 // OutputBuffers
122
initSkipCutBuffer(int32_t delay,int32_t padding,int32_t sampleRate,int32_t channelCount)123 void 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
updateSkipCutBuffer(int32_t sampleRate,int32_t channelCount)132 void 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
submit(const sp<MediaCodecBuffer> & buffer)145 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
146 if (mSkipCutBuffer != nullptr) {
147 mSkipCutBuffer->submit(buffer);
148 }
149 }
150
transferSkipCutBuffer(const sp<SkipCutBuffer> & scb)151 void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
152 mSkipCutBuffer = scb;
153 }
154
setSkipCutBuffer(int32_t skip,int32_t cut,int32_t channelCount)155 void 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
Create(size_t poolCapacity)167 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
168 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
169 }
170
newBuffer(size_t capacity)171 sp<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
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)199 LocalBufferPool::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
~VectorBuffer()206 LocalBufferPool::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
returnVector(std::vector<uint8_t> && vec)215 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
216 Mutex::Autolock lock(mMutex);
217 mPool.push_front(std::move(vec));
218 }
219
220 // FlexBuffersImpl
221
assignSlot(const sp<Codec2Buffer> & buffer)222 size_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
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)234 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)265 bool 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
flush()280 void FlexBuffersImpl::flush() {
281 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
282 mBuffers.clear();
283 }
284
numClientBuffers() const285 size_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
numComponentBuffers() const293 size_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
301 // BuffersArrayImpl
302
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)303 void 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
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)323 status_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
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)347 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)383 bool 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
getArray(Vector<sp<MediaCodecBuffer>> * array) const405 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
406 array->clear();
407 for (const Entry &entry : mBuffers) {
408 array->push(entry.clientBuffer);
409 }
410 }
411
flush()412 void BuffersArrayImpl::flush() {
413 for (Entry &entry : mBuffers) {
414 entry.ownedByClient = false;
415 }
416 }
417
realloc(std::function<sp<Codec2Buffer> ()> alloc)418 void 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
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)426 void 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
numClientBuffers() const434 size_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
arraySize() const442 size_t BuffersArrayImpl::arraySize() const {
443 return mBuffers.size();
444 }
445
446 // InputBuffersArray
447
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)448 void InputBuffersArray::initialize(
449 const FlexBuffersImpl &impl,
450 size_t minSize,
451 std::function<sp<Codec2Buffer>()> allocate) {
452 mAllocate = allocate;
453 mImpl.initialize(impl, minSize, allocate);
454 }
455
getArray(Vector<sp<MediaCodecBuffer>> * array) const456 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
457 mImpl.getArray(array);
458 }
459
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)460 bool 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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)472 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)479 bool InputBuffersArray::expireComponentBuffer(
480 const std::shared_ptr<C2Buffer> &c2buffer) {
481 return mImpl.expireComponentBuffer(c2buffer);
482 }
483
flush()484 void InputBuffersArray::flush() {
485 mImpl.flush();
486 }
487
numClientBuffers() const488 size_t InputBuffersArray::numClientBuffers() const {
489 return mImpl.numClientBuffers();
490 }
491
createNewBuffer()492 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
493 return mAllocate();
494 }
495
496 // LinearInputBuffers
497
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)498 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
499 sp<Codec2Buffer> newBuffer = createNewBuffer();
500 if (newBuffer == nullptr) {
501 return false;
502 }
503 *index = mImpl.assignSlot(newBuffer);
504 *buffer = newBuffer;
505 return true;
506 }
507
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)508 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)515 bool LinearInputBuffers::expireComponentBuffer(
516 const std::shared_ptr<C2Buffer> &c2buffer) {
517 return mImpl.expireComponentBuffer(c2buffer);
518 }
519
flush()520 void 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
toArrayMode(size_t size)526 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
527 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,
534 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
535 return Alloc(pool, format);
536 });
537 return std::move(array);
538 }
539
numClientBuffers() const540 size_t LinearInputBuffers::numClientBuffers() const {
541 return mImpl.numClientBuffers();
542 }
543
544 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)545 sp<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
555 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
556 std::shared_ptr<C2LinearBlock> block;
557
558 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
559 if (err != C2_OK) {
560 return nullptr;
561 }
562
563 return LinearBlockBuffer::Allocate(format, block);
564 }
565
createNewBuffer()566 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
567 return Alloc(mPool, mFormat);
568 }
569
570 // EncryptedLinearInputBuffers
571
EncryptedLinearInputBuffers(bool secure,const sp<MemoryDealer> & dealer,const sp<ICrypto> & crypto,int32_t heapSeqNum,size_t capacity,size_t numInputSlots,const char * componentName,const char * name)572 EncryptedLinearInputBuffers::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),
584 mMemoryVector(new std::vector<Entry>){
585 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 }
597 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
598 }
599 }
600
toArrayMode(size_t size)601 std::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
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)620 sp<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
632 sp<IMemory> memory;
633 size_t slot = 0;
634 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;
639 break;
640 }
641 }
642 if (memory == nullptr) {
643 return nullptr;
644 }
645
646 std::shared_ptr<C2LinearBlock> block;
647 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
648 if (err != C2_OK || block == nullptr) {
649 return nullptr;
650 }
651
652 memoryVector->at(slot).block = block;
653 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
654 }
655
createNewBuffer()656 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
657 // TODO: android_2020
658 return nullptr;
659 }
660
661 // GraphicMetadataInputBuffers
662
GraphicMetadataInputBuffers(const char * componentName,const char * name)663 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
664 const char *componentName, const char *name)
665 : InputBuffers(componentName, name),
666 mImpl(mName),
667 mStore(GetCodec2PlatformAllocatorStore()) { }
668
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)669 bool GraphicMetadataInputBuffers::requestNewBuffer(
670 size_t *index, sp<MediaCodecBuffer> *buffer) {
671 sp<Codec2Buffer> newBuffer = createNewBuffer();
672 if (newBuffer == nullptr) {
673 return false;
674 }
675 *index = mImpl.assignSlot(newBuffer);
676 *buffer = newBuffer;
677 return true;
678 }
679
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)680 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)687 bool GraphicMetadataInputBuffers::expireComponentBuffer(
688 const std::shared_ptr<C2Buffer> &c2buffer) {
689 return mImpl.expireComponentBuffer(c2buffer);
690 }
691
flush()692 void 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
toArrayMode(size_t size)697 std::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
numClientBuffers() const717 size_t GraphicMetadataInputBuffers::numClientBuffers() const {
718 return mImpl.numClientBuffers();
719 }
720
createNewBuffer()721 sp<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
730 // GraphicInputBuffers
731
GraphicInputBuffers(size_t numInputSlots,const char * componentName,const char * name)732 GraphicInputBuffers::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
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)739 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
740 sp<Codec2Buffer> newBuffer = createNewBuffer();
741 if (newBuffer == nullptr) {
742 return false;
743 }
744 *index = mImpl.assignSlot(newBuffer);
745 handleImageData(newBuffer);
746 *buffer = newBuffer;
747 return true;
748 }
749
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)750 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)757 bool GraphicInputBuffers::expireComponentBuffer(
758 const std::shared_ptr<C2Buffer> &c2buffer) {
759 return mImpl.expireComponentBuffer(c2buffer);
760 }
761
flush()762 void 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
toArrayMode(size_t size)767 std::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
numClientBuffers() const783 size_t GraphicInputBuffers::numClientBuffers() const {
784 return mImpl.numClientBuffers();
785 }
786
createNewBuffer()787 sp<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
794 // OutputBuffersArray
795
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)796 void OutputBuffersArray::initialize(
797 const FlexBuffersImpl &impl,
798 size_t minSize,
799 std::function<sp<Codec2Buffer>()> allocate) {
800 mAlloc = allocate;
801 mImpl.initialize(impl, minSize, allocate);
802 }
803
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)804 status_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
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)834 status_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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)856 bool OutputBuffersArray::releaseBuffer(
857 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
858 return mImpl.returnBuffer(buffer, c2buffer, true);
859 }
860
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)861 void 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
getArray(Vector<sp<MediaCodecBuffer>> * array) const869 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
870 mImpl.getArray(array);
871 }
872
numClientBuffers() const873 size_t OutputBuffersArray::numClientBuffers() const {
874 return mImpl.numClientBuffers();
875 }
876
realloc(const std::shared_ptr<C2Buffer> & c2buffer)877 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
878 switch (c2buffer->data().type()) {
879 case C2BufferData::LINEAR: {
880 uint32_t size = kLinearBufferSize;
881 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;
885 } else {
886 size = kMaxLinearBufferSize;
887 }
888 mAlloc = [format = mFormat, size] {
889 return new LocalLinearBuffer(format, new ABuffer(size));
890 };
891 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
892 break;
893 }
894
895 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 }
909
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 }
917 mImpl.realloc(mAlloc);
918 }
919
grow(size_t newSize)920 void OutputBuffersArray::grow(size_t newSize) {
921 mImpl.grow(newSize, mAlloc);
922 }
923
924 // FlexOutputBuffers
925
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)926 status_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
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)942 status_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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)953 bool FlexOutputBuffers::releaseBuffer(
954 const sp<MediaCodecBuffer> &buffer,
955 std::shared_ptr<C2Buffer> *c2buffer) {
956 return mImpl.releaseSlot(buffer, c2buffer, true);
957 }
958
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)959 void 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
toArrayMode(size_t size)966 std::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);
970 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
971 array->initialize(mImpl, size, alloc);
972 return std::move(array);
973 }
974
numClientBuffers() const975 size_t FlexOutputBuffers::numClientBuffers() const {
976 return mImpl.numClientBuffers();
977 }
978
979 // LinearOutputBuffers
980
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)981 void 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
wrap(const std::shared_ptr<C2Buffer> & buffer)989 sp<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
getAlloc()1013 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1014 return [format = mFormat]{
1015 // TODO: proper max output size
1016 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1017 };
1018 }
1019
1020 // GraphicOutputBuffers
1021
wrap(const std::shared_ptr<C2Buffer> & buffer)1022 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1023 return new DummyContainerBuffer(mFormat, buffer);
1024 }
1025
getAlloc()1026 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1027 return [format = mFormat]{
1028 return new DummyContainerBuffer(format);
1029 };
1030 }
1031
1032 // RawGraphicOutputBuffers
1033
RawGraphicOutputBuffers(size_t numOutputSlots,const char * componentName,const char * name)1034 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1035 size_t numOutputSlots, const char *componentName, const char *name)
1036 : FlexOutputBuffers(componentName, name),
1037 mLocalBufferPool(LocalBufferPool::Create(
1038 kMaxLinearBufferSize * numOutputSlots)) { }
1039
wrap(const std::shared_ptr<C2Buffer> & buffer)1040 sp<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
getAlloc()1063 std::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 };
1071 }
1072
1073 } // namespace android
1074