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/MediaCodec.h>
25 #include <media/stagefright/MediaCodecConstants.h>
26 #include <media/stagefright/SkipCutBuffer.h>
27 #include <mediadrm/ICrypto.h>
28
29 #include "CCodecBuffers.h"
30
31 namespace android {
32
33 namespace {
34
AllocateGraphicBuffer(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,uint32_t pixelFormat,const C2MemoryUsage & usage,const std::shared_ptr<LocalBufferPool> & localBufferPool)35 sp<GraphicBlockBuffer> AllocateGraphicBuffer(
36 const std::shared_ptr<C2BlockPool> &pool,
37 const sp<AMessage> &format,
38 uint32_t pixelFormat,
39 const C2MemoryUsage &usage,
40 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
41 int32_t width, height;
42 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
43 ALOGD("format lacks width or height");
44 return nullptr;
45 }
46
47 std::shared_ptr<C2GraphicBlock> block;
48 c2_status_t err = pool->fetchGraphicBlock(
49 width, height, pixelFormat, usage, &block);
50 if (err != C2_OK) {
51 ALOGD("fetch graphic block failed: %d", err);
52 return nullptr;
53 }
54
55 return GraphicBlockBuffer::Allocate(
56 format,
57 block,
58 [localBufferPool](size_t capacity) {
59 return localBufferPool->newBuffer(capacity);
60 });
61 }
62
63 } // namespace
64
65 // CCodecBuffers
66
setFormat(const sp<AMessage> & format)67 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
68 CHECK(format != nullptr);
69 mFormat = format;
70 }
71
dupFormat()72 sp<AMessage> CCodecBuffers::dupFormat() {
73 return mFormat != nullptr ? mFormat->dup() : nullptr;
74 }
75
handleImageData(const sp<Codec2Buffer> & buffer)76 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
77 sp<ABuffer> imageDataCandidate = buffer->getImageData();
78 if (imageDataCandidate == nullptr) {
79 return;
80 }
81 sp<ABuffer> imageData;
82 if (!mFormat->findBuffer("image-data", &imageData)
83 || imageDataCandidate->size() != imageData->size()
84 || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
85 ALOGD("[%s] updating image-data", mName);
86 sp<AMessage> newFormat = dupFormat();
87 newFormat->setBuffer("image-data", imageDataCandidate);
88 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
89 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
90 int32_t stride = img->mPlane[0].mRowInc;
91 newFormat->setInt32(KEY_STRIDE, stride);
92 ALOGD("[%s] updating stride = %d", mName, stride);
93 if (img->mNumPlanes > 1 && stride > 0) {
94 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
95 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
96 ALOGD("[%s] updating vstride = %d", mName, vstride);
97 }
98 }
99 setFormat(newFormat);
100 buffer->setFormat(newFormat);
101 }
102 }
103
104 // InputBuffers
105
cloneAndReleaseBuffer(const sp<MediaCodecBuffer> & buffer)106 sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
107 sp<Codec2Buffer> copy = createNewBuffer();
108 if (copy == nullptr) {
109 return nullptr;
110 }
111 std::shared_ptr<C2Buffer> c2buffer;
112 if (!releaseBuffer(buffer, &c2buffer, true)) {
113 return nullptr;
114 }
115 if (!copy->canCopy(c2buffer)) {
116 return nullptr;
117 }
118 if (!copy->copy(c2buffer)) {
119 return nullptr;
120 }
121 return copy;
122 }
123
124 // OutputBuffers
125
OutputBuffers(const char * componentName,const char * name)126 OutputBuffers::OutputBuffers(const char *componentName, const char *name)
127 : CCodecBuffers(componentName, name) { }
128
129 OutputBuffers::~OutputBuffers() = default;
130
initSkipCutBuffer(int32_t delay,int32_t padding,int32_t sampleRate,int32_t channelCount)131 void OutputBuffers::initSkipCutBuffer(
132 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
133 CHECK(mSkipCutBuffer == nullptr);
134 mDelay = delay;
135 mPadding = padding;
136 mSampleRate = sampleRate;
137 mChannelCount = channelCount;
138 setSkipCutBuffer(delay, padding);
139 }
140
updateSkipCutBuffer(int32_t sampleRate,int32_t channelCount)141 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
142 if (mSkipCutBuffer == nullptr) {
143 return;
144 }
145 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
146 return;
147 }
148 int32_t delay = mDelay;
149 int32_t padding = mPadding;
150 if (sampleRate != mSampleRate) {
151 delay = ((int64_t)delay * sampleRate) / mSampleRate;
152 padding = ((int64_t)padding * sampleRate) / mSampleRate;
153 }
154 mSampleRate = sampleRate;
155 mChannelCount = channelCount;
156 setSkipCutBuffer(delay, padding);
157 }
158
updateSkipCutBuffer(const sp<AMessage> & format,bool notify)159 void OutputBuffers::updateSkipCutBuffer(
160 const sp<AMessage> &format, bool notify) {
161 AString mediaType;
162 if (format->findString(KEY_MIME, &mediaType)
163 && mediaType == MIMETYPE_AUDIO_RAW) {
164 int32_t channelCount;
165 int32_t sampleRate;
166 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
167 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
168 updateSkipCutBuffer(sampleRate, channelCount);
169 }
170 }
171 if (notify) {
172 mUnreportedFormat = nullptr;
173 }
174 }
175
submit(const sp<MediaCodecBuffer> & buffer)176 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
177 if (mSkipCutBuffer != nullptr) {
178 mSkipCutBuffer->submit(buffer);
179 }
180 }
181
setSkipCutBuffer(int32_t skip,int32_t cut)182 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
183 if (mSkipCutBuffer != nullptr) {
184 size_t prevSize = mSkipCutBuffer->size();
185 if (prevSize != 0u) {
186 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
187 }
188 }
189 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
190 }
191
clearStash()192 void OutputBuffers::clearStash() {
193 mPending.clear();
194 mReorderStash.clear();
195 mDepth = 0;
196 mKey = C2Config::ORDINAL;
197 mUnreportedFormat = nullptr;
198 }
199
flushStash()200 void OutputBuffers::flushStash() {
201 for (StashEntry& e : mPending) {
202 e.notify = false;
203 }
204 for (StashEntry& e : mReorderStash) {
205 e.notify = false;
206 }
207 }
208
getReorderDepth() const209 uint32_t OutputBuffers::getReorderDepth() const {
210 return mDepth;
211 }
212
setReorderDepth(uint32_t depth)213 void OutputBuffers::setReorderDepth(uint32_t depth) {
214 mPending.splice(mPending.end(), mReorderStash);
215 mDepth = depth;
216 }
217
setReorderKey(C2Config::ordinal_key_t key)218 void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
219 mPending.splice(mPending.end(), mReorderStash);
220 mKey = key;
221 }
222
pushToStash(const std::shared_ptr<C2Buffer> & buffer,bool notify,int64_t timestamp,int32_t flags,const sp<AMessage> & format,const C2WorkOrdinalStruct & ordinal)223 void OutputBuffers::pushToStash(
224 const std::shared_ptr<C2Buffer>& buffer,
225 bool notify,
226 int64_t timestamp,
227 int32_t flags,
228 const sp<AMessage>& format,
229 const C2WorkOrdinalStruct& ordinal) {
230 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
231 if (!buffer && eos) {
232 // TRICKY: we may be violating ordering of the stash here. Because we
233 // don't expect any more emplace() calls after this, the ordering should
234 // not matter.
235 mReorderStash.emplace_back(
236 buffer, notify, timestamp, flags, format, ordinal);
237 } else {
238 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
239 auto it = mReorderStash.begin();
240 for (; it != mReorderStash.end(); ++it) {
241 if (less(ordinal, it->ordinal)) {
242 break;
243 }
244 }
245 mReorderStash.emplace(it,
246 buffer, notify, timestamp, flags, format, ordinal);
247 if (eos) {
248 mReorderStash.back().flags =
249 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
250 }
251 }
252 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
253 mPending.push_back(mReorderStash.front());
254 mReorderStash.pop_front();
255 }
256 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
257 }
258
popFromStashAndRegister(std::shared_ptr<C2Buffer> * c2Buffer,size_t * index,sp<MediaCodecBuffer> * outBuffer)259 OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
260 std::shared_ptr<C2Buffer>* c2Buffer,
261 size_t* index,
262 sp<MediaCodecBuffer>* outBuffer) {
263 if (mPending.empty()) {
264 return SKIP;
265 }
266
267 // Retrieve the first entry.
268 StashEntry &entry = mPending.front();
269
270 *c2Buffer = entry.buffer;
271 sp<AMessage> outputFormat = entry.format;
272
273 // The output format can be processed without a registered slot.
274 if (outputFormat) {
275 updateSkipCutBuffer(outputFormat, entry.notify);
276 }
277
278 if (entry.notify) {
279 if (outputFormat) {
280 setFormat(outputFormat);
281 } else if (mUnreportedFormat) {
282 outputFormat = mUnreportedFormat;
283 setFormat(outputFormat);
284 }
285 mUnreportedFormat = nullptr;
286 } else {
287 if (outputFormat) {
288 mUnreportedFormat = outputFormat;
289 } else if (!mUnreportedFormat) {
290 mUnreportedFormat = mFormat;
291 }
292 }
293
294 // Flushing mReorderStash because no other buffers should come after output
295 // EOS.
296 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
297 // Flush reorder stash
298 setReorderDepth(0);
299 }
300
301 if (!entry.notify) {
302 if (outputFormat) {
303 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
304 mName, outputFormat->debugString().c_str());
305 }
306 mPending.pop_front();
307 return DISCARD;
308 }
309
310 // Try to register the buffer.
311 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
312 if (err != OK) {
313 if (err != WOULD_BLOCK) {
314 return REALLOCATE;
315 }
316 return RETRY;
317 }
318
319 // Append information from the front stash entry to outBuffer.
320 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
321 (*outBuffer)->meta()->setInt32("flags", entry.flags);
322 if (outputFormat) {
323 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
324 mName, outputFormat->debugString().c_str());
325 }
326 ALOGV("[%s] popFromStashAndRegister: "
327 "out buffer index = %zu [%p] => %p + %zu (%lld)",
328 mName, *index, outBuffer->get(),
329 (*outBuffer)->data(), (*outBuffer)->size(),
330 (long long)entry.timestamp);
331
332 // The front entry of mPending will be removed now that the registration
333 // succeeded.
334 mPending.pop_front();
335 return NOTIFY_CLIENT;
336 }
337
popPending(StashEntry * entry)338 bool OutputBuffers::popPending(StashEntry *entry) {
339 if (mPending.empty()) {
340 return false;
341 }
342 *entry = mPending.front();
343 mPending.pop_front();
344 return true;
345 }
346
deferPending(const OutputBuffers::StashEntry & entry)347 void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
348 mPending.push_front(entry);
349 }
350
hasPending() const351 bool OutputBuffers::hasPending() const {
352 return !mPending.empty();
353 }
354
less(const C2WorkOrdinalStruct & o1,const C2WorkOrdinalStruct & o2) const355 bool OutputBuffers::less(
356 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
357 switch (mKey) {
358 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
359 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
360 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
361 default:
362 ALOGD("Unrecognized key; default to timestamp");
363 return o1.frameIndex < o2.frameIndex;
364 }
365 }
366
367 // LocalBufferPool
368
369 constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
370 constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
371
Create()372 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
373 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
374 }
375
newBuffer(size_t capacity)376 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
377 Mutex::Autolock lock(mMutex);
378 auto it = std::find_if(
379 mPool.begin(), mPool.end(),
380 [capacity](const std::vector<uint8_t> &vec) {
381 return vec.capacity() >= capacity;
382 });
383 if (it != mPool.end()) {
384 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
385 mPool.erase(it);
386 return buffer;
387 }
388 if (mUsedSize + capacity > mPoolCapacity) {
389 while (!mPool.empty()) {
390 mUsedSize -= mPool.back().capacity();
391 mPool.pop_back();
392 }
393 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
394 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
395 mPoolCapacity, mPoolCapacity * 2);
396 mPoolCapacity *= 2;
397 }
398 if (mUsedSize + capacity > mPoolCapacity) {
399 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
400 mUsedSize, capacity, mPoolCapacity);
401 return nullptr;
402 }
403 }
404 std::vector<uint8_t> vec(capacity);
405 mUsedSize += vec.capacity();
406 return new VectorBuffer(std::move(vec), shared_from_this());
407 }
408
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)409 LocalBufferPool::VectorBuffer::VectorBuffer(
410 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
411 : ABuffer(vec.data(), vec.capacity()),
412 mVec(std::move(vec)),
413 mPool(pool) {
414 }
415
~VectorBuffer()416 LocalBufferPool::VectorBuffer::~VectorBuffer() {
417 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
418 if (pool) {
419 // If pool is alive, return the vector back to the pool so that
420 // it can be recycled.
421 pool->returnVector(std::move(mVec));
422 }
423 }
424
returnVector(std::vector<uint8_t> && vec)425 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
426 Mutex::Autolock lock(mMutex);
427 mPool.push_front(std::move(vec));
428 }
429
430 // FlexBuffersImpl
431
assignSlot(const sp<Codec2Buffer> & buffer)432 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
433 for (size_t i = 0; i < mBuffers.size(); ++i) {
434 if (mBuffers[i].clientBuffer == nullptr
435 && mBuffers[i].compBuffer.expired()) {
436 mBuffers[i].clientBuffer = buffer;
437 return i;
438 }
439 }
440 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
441 return mBuffers.size() - 1;
442 }
443
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)444 bool FlexBuffersImpl::releaseSlot(
445 const sp<MediaCodecBuffer> &buffer,
446 std::shared_ptr<C2Buffer> *c2buffer,
447 bool release) {
448 sp<Codec2Buffer> clientBuffer;
449 size_t index = mBuffers.size();
450 for (size_t i = 0; i < mBuffers.size(); ++i) {
451 if (mBuffers[i].clientBuffer == buffer) {
452 clientBuffer = mBuffers[i].clientBuffer;
453 if (release) {
454 mBuffers[i].clientBuffer.clear();
455 }
456 index = i;
457 break;
458 }
459 }
460 if (clientBuffer == nullptr) {
461 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
462 return false;
463 }
464 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
465 if (!result) {
466 result = clientBuffer->asC2Buffer();
467 clientBuffer->clearC2BufferRefs();
468 mBuffers[index].compBuffer = result;
469 }
470 if (c2buffer) {
471 *c2buffer = result;
472 }
473 return true;
474 }
475
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)476 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
477 for (size_t i = 0; i < mBuffers.size(); ++i) {
478 std::shared_ptr<C2Buffer> compBuffer =
479 mBuffers[i].compBuffer.lock();
480 if (!compBuffer || compBuffer != c2buffer) {
481 continue;
482 }
483 mBuffers[i].compBuffer.reset();
484 ALOGV("[%s] codec released buffer #%zu", mName, i);
485 return true;
486 }
487 ALOGV("[%s] codec released an unknown buffer", mName);
488 return false;
489 }
490
flush()491 void FlexBuffersImpl::flush() {
492 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
493 mBuffers.clear();
494 }
495
numActiveSlots() const496 size_t FlexBuffersImpl::numActiveSlots() const {
497 return std::count_if(
498 mBuffers.begin(), mBuffers.end(),
499 [](const Entry &entry) {
500 return (entry.clientBuffer != nullptr
501 || !entry.compBuffer.expired());
502 });
503 }
504
numComponentBuffers() const505 size_t FlexBuffersImpl::numComponentBuffers() const {
506 return std::count_if(
507 mBuffers.begin(), mBuffers.end(),
508 [](const Entry &entry) {
509 return !entry.compBuffer.expired();
510 });
511 }
512
513 // BuffersArrayImpl
514
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)515 void BuffersArrayImpl::initialize(
516 const FlexBuffersImpl &impl,
517 size_t minSize,
518 std::function<sp<Codec2Buffer>()> allocate) {
519 mImplName = impl.mImplName + "[N]";
520 mName = mImplName.c_str();
521 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
522 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
523 bool ownedByClient = (clientBuffer != nullptr);
524 if (!ownedByClient) {
525 clientBuffer = allocate();
526 }
527 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
528 }
529 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
530 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
531 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
532 }
533 }
534
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)535 status_t BuffersArrayImpl::grabBuffer(
536 size_t *index,
537 sp<Codec2Buffer> *buffer,
538 std::function<bool(const sp<Codec2Buffer> &)> match) {
539 // allBuffersDontMatch remains true if all buffers are available but
540 // match() returns false for every buffer.
541 bool allBuffersDontMatch = true;
542 for (size_t i = 0; i < mBuffers.size(); ++i) {
543 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
544 if (match(mBuffers[i].clientBuffer)) {
545 mBuffers[i].ownedByClient = true;
546 *buffer = mBuffers[i].clientBuffer;
547 (*buffer)->meta()->clear();
548 (*buffer)->setRange(0, (*buffer)->capacity());
549 *index = i;
550 return OK;
551 }
552 } else {
553 allBuffersDontMatch = false;
554 }
555 }
556 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
557 }
558
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)559 bool BuffersArrayImpl::returnBuffer(
560 const sp<MediaCodecBuffer> &buffer,
561 std::shared_ptr<C2Buffer> *c2buffer,
562 bool release) {
563 sp<Codec2Buffer> clientBuffer;
564 size_t index = mBuffers.size();
565 for (size_t i = 0; i < mBuffers.size(); ++i) {
566 if (mBuffers[i].clientBuffer == buffer) {
567 if (!mBuffers[i].ownedByClient) {
568 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
569 mName, i);
570 }
571 clientBuffer = mBuffers[i].clientBuffer;
572 if (release) {
573 mBuffers[i].ownedByClient = false;
574 }
575 index = i;
576 break;
577 }
578 }
579 if (clientBuffer == nullptr) {
580 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
581 return false;
582 }
583 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
584 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
585 if (!result) {
586 result = clientBuffer->asC2Buffer();
587 clientBuffer->clearC2BufferRefs();
588 mBuffers[index].compBuffer = result;
589 }
590 if (c2buffer) {
591 *c2buffer = result;
592 }
593 return true;
594 }
595
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)596 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
597 for (size_t i = 0; i < mBuffers.size(); ++i) {
598 std::shared_ptr<C2Buffer> compBuffer =
599 mBuffers[i].compBuffer.lock();
600 if (!compBuffer) {
601 continue;
602 }
603 if (c2buffer == compBuffer) {
604 if (mBuffers[i].ownedByClient) {
605 // This should not happen.
606 ALOGD("[%s] codec released a buffer owned by client "
607 "(index %zu)", mName, i);
608 }
609 mBuffers[i].compBuffer.reset();
610 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
611 return true;
612 }
613 }
614 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
615 return false;
616 }
617
getArray(Vector<sp<MediaCodecBuffer>> * array) const618 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
619 array->clear();
620 for (const Entry &entry : mBuffers) {
621 array->push(entry.clientBuffer);
622 }
623 }
624
flush()625 void BuffersArrayImpl::flush() {
626 for (Entry &entry : mBuffers) {
627 entry.ownedByClient = false;
628 }
629 }
630
realloc(std::function<sp<Codec2Buffer> ()> alloc)631 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
632 size_t size = mBuffers.size();
633 mBuffers.clear();
634 for (size_t i = 0; i < size; ++i) {
635 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
636 }
637 }
638
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)639 void BuffersArrayImpl::grow(
640 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
641 CHECK_LT(mBuffers.size(), newSize);
642 while (mBuffers.size() < newSize) {
643 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
644 }
645 }
646
numActiveSlots() const647 size_t BuffersArrayImpl::numActiveSlots() const {
648 return std::count_if(
649 mBuffers.begin(), mBuffers.end(),
650 [](const Entry &entry) {
651 return entry.ownedByClient || !entry.compBuffer.expired();
652 });
653 }
654
arraySize() const655 size_t BuffersArrayImpl::arraySize() const {
656 return mBuffers.size();
657 }
658
659 // InputBuffersArray
660
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)661 void InputBuffersArray::initialize(
662 const FlexBuffersImpl &impl,
663 size_t minSize,
664 std::function<sp<Codec2Buffer>()> allocate) {
665 mAllocate = allocate;
666 mImpl.initialize(impl, minSize, allocate);
667 }
668
getArray(Vector<sp<MediaCodecBuffer>> * array) const669 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
670 mImpl.getArray(array);
671 }
672
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)673 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
674 sp<Codec2Buffer> c2Buffer;
675 status_t err = mImpl.grabBuffer(index, &c2Buffer);
676 if (err == OK) {
677 c2Buffer->setFormat(mFormat);
678 handleImageData(c2Buffer);
679 *buffer = c2Buffer;
680 return true;
681 }
682 return false;
683 }
684
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)685 bool InputBuffersArray::releaseBuffer(
686 const sp<MediaCodecBuffer> &buffer,
687 std::shared_ptr<C2Buffer> *c2buffer,
688 bool release) {
689 return mImpl.returnBuffer(buffer, c2buffer, release);
690 }
691
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)692 bool InputBuffersArray::expireComponentBuffer(
693 const std::shared_ptr<C2Buffer> &c2buffer) {
694 return mImpl.expireComponentBuffer(c2buffer);
695 }
696
flush()697 void InputBuffersArray::flush() {
698 mImpl.flush();
699 }
700
numActiveSlots() const701 size_t InputBuffersArray::numActiveSlots() const {
702 return mImpl.numActiveSlots();
703 }
704
createNewBuffer()705 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
706 return mAllocate();
707 }
708
709 // SlotInputBuffers
710
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)711 bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
712 sp<Codec2Buffer> newBuffer = createNewBuffer();
713 *index = mImpl.assignSlot(newBuffer);
714 *buffer = newBuffer;
715 return true;
716 }
717
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)718 bool SlotInputBuffers::releaseBuffer(
719 const sp<MediaCodecBuffer> &buffer,
720 std::shared_ptr<C2Buffer> *c2buffer,
721 bool release) {
722 return mImpl.releaseSlot(buffer, c2buffer, release);
723 }
724
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)725 bool SlotInputBuffers::expireComponentBuffer(
726 const std::shared_ptr<C2Buffer> &c2buffer) {
727 return mImpl.expireComponentBuffer(c2buffer);
728 }
729
flush()730 void SlotInputBuffers::flush() {
731 mImpl.flush();
732 }
733
toArrayMode(size_t)734 std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
735 TRESPASS("Array mode should not be called at non-legacy mode");
736 return nullptr;
737 }
738
numActiveSlots() const739 size_t SlotInputBuffers::numActiveSlots() const {
740 return mImpl.numActiveSlots();
741 }
742
createNewBuffer()743 sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
744 return new DummyContainerBuffer{mFormat, nullptr};
745 }
746
747 // LinearInputBuffers
748
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)749 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
750 sp<Codec2Buffer> newBuffer = createNewBuffer();
751 if (newBuffer == nullptr) {
752 return false;
753 }
754 *index = mImpl.assignSlot(newBuffer);
755 *buffer = newBuffer;
756 return true;
757 }
758
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)759 bool LinearInputBuffers::releaseBuffer(
760 const sp<MediaCodecBuffer> &buffer,
761 std::shared_ptr<C2Buffer> *c2buffer,
762 bool release) {
763 return mImpl.releaseSlot(buffer, c2buffer, release);
764 }
765
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)766 bool LinearInputBuffers::expireComponentBuffer(
767 const std::shared_ptr<C2Buffer> &c2buffer) {
768 return mImpl.expireComponentBuffer(c2buffer);
769 }
770
flush()771 void LinearInputBuffers::flush() {
772 // This is no-op by default unless we're in array mode where we need to keep
773 // track of the flushed work.
774 mImpl.flush();
775 }
776
toArrayMode(size_t size)777 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
778 std::unique_ptr<InputBuffersArray> array(
779 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
780 array->setPool(mPool);
781 array->setFormat(mFormat);
782 array->initialize(
783 mImpl,
784 size,
785 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
786 return Alloc(pool, format);
787 });
788 return std::move(array);
789 }
790
numActiveSlots() const791 size_t LinearInputBuffers::numActiveSlots() const {
792 return mImpl.numActiveSlots();
793 }
794
795 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)796 sp<Codec2Buffer> LinearInputBuffers::Alloc(
797 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
798 int32_t capacity = kLinearBufferSize;
799 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
800 if ((size_t)capacity > kMaxLinearBufferSize) {
801 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
802 capacity = kMaxLinearBufferSize;
803 }
804
805 // TODO: read usage from intf
806 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
807 std::shared_ptr<C2LinearBlock> block;
808
809 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
810 if (err != C2_OK) {
811 return nullptr;
812 }
813
814 return LinearBlockBuffer::Allocate(format, block);
815 }
816
createNewBuffer()817 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
818 return Alloc(mPool, mFormat);
819 }
820
821 // EncryptedLinearInputBuffers
822
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)823 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
824 bool secure,
825 const sp<MemoryDealer> &dealer,
826 const sp<ICrypto> &crypto,
827 int32_t heapSeqNum,
828 size_t capacity,
829 size_t numInputSlots,
830 const char *componentName, const char *name)
831 : LinearInputBuffers(componentName, name),
832 mUsage({0, 0}),
833 mDealer(dealer),
834 mCrypto(crypto),
835 mMemoryVector(new std::vector<Entry>){
836 if (secure) {
837 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
838 } else {
839 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
840 }
841 for (size_t i = 0; i < numInputSlots; ++i) {
842 sp<IMemory> memory = mDealer->allocate(capacity);
843 if (memory == nullptr) {
844 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
845 mName, i);
846 break;
847 }
848 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
849 }
850 }
851
toArrayMode(size_t size)852 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
853 std::unique_ptr<InputBuffersArray> array(
854 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
855 array->setPool(mPool);
856 array->setFormat(mFormat);
857 array->initialize(
858 mImpl,
859 size,
860 [pool = mPool,
861 format = mFormat,
862 usage = mUsage,
863 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
864 return Alloc(pool, format, usage, memoryVector);
865 });
866 return std::move(array);
867 }
868
869
870 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)871 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
872 const std::shared_ptr<C2BlockPool> &pool,
873 const sp<AMessage> &format,
874 C2MemoryUsage usage,
875 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
876 int32_t capacity = kLinearBufferSize;
877 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
878 if ((size_t)capacity > kMaxLinearBufferSize) {
879 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
880 capacity = kMaxLinearBufferSize;
881 }
882
883 sp<IMemory> memory;
884 size_t slot = 0;
885 int32_t heapSeqNum = -1;
886 for (; slot < memoryVector->size(); ++slot) {
887 if (memoryVector->at(slot).block.expired()) {
888 memory = memoryVector->at(slot).memory;
889 heapSeqNum = memoryVector->at(slot).heapSeqNum;
890 break;
891 }
892 }
893 if (memory == nullptr) {
894 return nullptr;
895 }
896
897 std::shared_ptr<C2LinearBlock> block;
898 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
899 if (err != C2_OK || block == nullptr) {
900 return nullptr;
901 }
902
903 memoryVector->at(slot).block = block;
904 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
905 }
906
createNewBuffer()907 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
908 // TODO: android_2020
909 return nullptr;
910 }
911
912 // GraphicMetadataInputBuffers
913
GraphicMetadataInputBuffers(const char * componentName,const char * name)914 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
915 const char *componentName, const char *name)
916 : InputBuffers(componentName, name),
917 mImpl(mName),
918 mStore(GetCodec2PlatformAllocatorStore()) { }
919
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)920 bool GraphicMetadataInputBuffers::requestNewBuffer(
921 size_t *index, sp<MediaCodecBuffer> *buffer) {
922 sp<Codec2Buffer> newBuffer = createNewBuffer();
923 if (newBuffer == nullptr) {
924 return false;
925 }
926 *index = mImpl.assignSlot(newBuffer);
927 *buffer = newBuffer;
928 return true;
929 }
930
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)931 bool GraphicMetadataInputBuffers::releaseBuffer(
932 const sp<MediaCodecBuffer> &buffer,
933 std::shared_ptr<C2Buffer> *c2buffer,
934 bool release) {
935 return mImpl.releaseSlot(buffer, c2buffer, release);
936 }
937
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)938 bool GraphicMetadataInputBuffers::expireComponentBuffer(
939 const std::shared_ptr<C2Buffer> &c2buffer) {
940 return mImpl.expireComponentBuffer(c2buffer);
941 }
942
flush()943 void GraphicMetadataInputBuffers::flush() {
944 // This is no-op by default unless we're in array mode where we need to keep
945 // track of the flushed work.
946 }
947
toArrayMode(size_t size)948 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
949 size_t size) {
950 std::shared_ptr<C2Allocator> alloc;
951 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
952 if (err != C2_OK) {
953 return nullptr;
954 }
955 std::unique_ptr<InputBuffersArray> array(
956 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
957 array->setPool(mPool);
958 array->setFormat(mFormat);
959 array->initialize(
960 mImpl,
961 size,
962 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
963 return new GraphicMetadataBuffer(format, alloc);
964 });
965 return std::move(array);
966 }
967
numActiveSlots() const968 size_t GraphicMetadataInputBuffers::numActiveSlots() const {
969 return mImpl.numActiveSlots();
970 }
971
createNewBuffer()972 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
973 std::shared_ptr<C2Allocator> alloc;
974 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
975 if (err != C2_OK) {
976 return nullptr;
977 }
978 return new GraphicMetadataBuffer(mFormat, alloc);
979 }
980
981 // GraphicInputBuffers
982
GraphicInputBuffers(const char * componentName,const char * name)983 GraphicInputBuffers::GraphicInputBuffers(
984 const char *componentName, const char *name)
985 : InputBuffers(componentName, name),
986 mImpl(mName),
987 mLocalBufferPool(LocalBufferPool::Create()) { }
988
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)989 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
990 sp<Codec2Buffer> newBuffer = createNewBuffer();
991 if (newBuffer == nullptr) {
992 return false;
993 }
994 *index = mImpl.assignSlot(newBuffer);
995 handleImageData(newBuffer);
996 *buffer = newBuffer;
997 return true;
998 }
999
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1000 bool GraphicInputBuffers::releaseBuffer(
1001 const sp<MediaCodecBuffer> &buffer,
1002 std::shared_ptr<C2Buffer> *c2buffer,
1003 bool release) {
1004 return mImpl.releaseSlot(buffer, c2buffer, release);
1005 }
1006
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1007 bool GraphicInputBuffers::expireComponentBuffer(
1008 const std::shared_ptr<C2Buffer> &c2buffer) {
1009 return mImpl.expireComponentBuffer(c2buffer);
1010 }
1011
flush()1012 void GraphicInputBuffers::flush() {
1013 // This is no-op by default unless we're in array mode where we need to keep
1014 // track of the flushed work.
1015 }
1016
toArrayMode(size_t size)1017 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1018 std::unique_ptr<InputBuffersArray> array(
1019 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1020 array->setPool(mPool);
1021 array->setFormat(mFormat);
1022 array->initialize(
1023 mImpl,
1024 size,
1025 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1026 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1027 return AllocateGraphicBuffer(
1028 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1029 });
1030 return std::move(array);
1031 }
1032
numActiveSlots() const1033 size_t GraphicInputBuffers::numActiveSlots() const {
1034 return mImpl.numActiveSlots();
1035 }
1036
createNewBuffer()1037 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1038 // TODO: read usage from intf
1039 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1040 return AllocateGraphicBuffer(
1041 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1042 }
1043
1044 // OutputBuffersArray
1045
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)1046 void OutputBuffersArray::initialize(
1047 const FlexBuffersImpl &impl,
1048 size_t minSize,
1049 std::function<sp<Codec2Buffer>()> allocate) {
1050 mAlloc = allocate;
1051 mImpl.initialize(impl, minSize, allocate);
1052 }
1053
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1054 status_t OutputBuffersArray::registerBuffer(
1055 const std::shared_ptr<C2Buffer> &buffer,
1056 size_t *index,
1057 sp<MediaCodecBuffer> *clientBuffer) {
1058 sp<Codec2Buffer> c2Buffer;
1059 status_t err = mImpl.grabBuffer(
1060 index,
1061 &c2Buffer,
1062 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1063 return clientBuffer->canCopy(buffer);
1064 });
1065 if (err == WOULD_BLOCK) {
1066 ALOGV("[%s] buffers temporarily not available", mName);
1067 return err;
1068 } else if (err != OK) {
1069 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1070 return err;
1071 }
1072 c2Buffer->setFormat(mFormat);
1073 if (!c2Buffer->copy(buffer)) {
1074 ALOGD("[%s] copy buffer failed", mName);
1075 return WOULD_BLOCK;
1076 }
1077 submit(c2Buffer);
1078 handleImageData(c2Buffer);
1079 *clientBuffer = c2Buffer;
1080 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1081 return OK;
1082 }
1083
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1084 status_t OutputBuffersArray::registerCsd(
1085 const C2StreamInitDataInfo::output *csd,
1086 size_t *index,
1087 sp<MediaCodecBuffer> *clientBuffer) {
1088 sp<Codec2Buffer> c2Buffer;
1089 status_t err = mImpl.grabBuffer(
1090 index,
1091 &c2Buffer,
1092 [csd](const sp<Codec2Buffer> &clientBuffer) {
1093 return clientBuffer->base() != nullptr
1094 && clientBuffer->capacity() >= csd->flexCount();
1095 });
1096 if (err != OK) {
1097 return err;
1098 }
1099 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1100 c2Buffer->setRange(0, csd->flexCount());
1101 c2Buffer->setFormat(mFormat);
1102 *clientBuffer = c2Buffer;
1103 return OK;
1104 }
1105
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1106 bool OutputBuffersArray::releaseBuffer(
1107 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1108 return mImpl.returnBuffer(buffer, c2buffer, true);
1109 }
1110
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1111 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1112 (void)flushedWork;
1113 mImpl.flush();
1114 if (mSkipCutBuffer != nullptr) {
1115 mSkipCutBuffer->clear();
1116 }
1117 }
1118
getArray(Vector<sp<MediaCodecBuffer>> * array) const1119 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1120 mImpl.getArray(array);
1121 }
1122
numActiveSlots() const1123 size_t OutputBuffersArray::numActiveSlots() const {
1124 return mImpl.numActiveSlots();
1125 }
1126
realloc(const std::shared_ptr<C2Buffer> & c2buffer)1127 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
1128 switch (c2buffer->data().type()) {
1129 case C2BufferData::LINEAR: {
1130 uint32_t size = kLinearBufferSize;
1131 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1132 const uint32_t block_size = linear_blocks.front().size();
1133 if (block_size < kMaxLinearBufferSize / 2) {
1134 size = block_size * 2;
1135 } else {
1136 size = kMaxLinearBufferSize;
1137 }
1138 mAlloc = [format = mFormat, size] {
1139 return new LocalLinearBuffer(format, new ABuffer(size));
1140 };
1141 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
1142 break;
1143 }
1144
1145 case C2BufferData::GRAPHIC: {
1146 // This is only called for RawGraphicOutputBuffers.
1147 mAlloc = [format = mFormat,
1148 lbp = LocalBufferPool::Create()] {
1149 return ConstGraphicBlockBuffer::AllocateEmpty(
1150 format,
1151 [lbp](size_t capacity) {
1152 return lbp->newBuffer(capacity);
1153 });
1154 };
1155 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1156 mName, mFormat->debugString().c_str());
1157 break;
1158 }
1159
1160 case C2BufferData::INVALID: [[fallthrough]];
1161 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1162 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1163 default:
1164 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1165 return;
1166 }
1167 mImpl.realloc(mAlloc);
1168 }
1169
grow(size_t newSize)1170 void OutputBuffersArray::grow(size_t newSize) {
1171 mImpl.grow(newSize, mAlloc);
1172 }
1173
transferFrom(OutputBuffers * source)1174 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1175 mFormat = source->mFormat;
1176 mSkipCutBuffer = source->mSkipCutBuffer;
1177 mUnreportedFormat = source->mUnreportedFormat;
1178 mPending = std::move(source->mPending);
1179 mReorderStash = std::move(source->mReorderStash);
1180 mDepth = source->mDepth;
1181 mKey = source->mKey;
1182 }
1183
1184 // FlexOutputBuffers
1185
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1186 status_t FlexOutputBuffers::registerBuffer(
1187 const std::shared_ptr<C2Buffer> &buffer,
1188 size_t *index,
1189 sp<MediaCodecBuffer> *clientBuffer) {
1190 sp<Codec2Buffer> newBuffer = wrap(buffer);
1191 if (newBuffer == nullptr) {
1192 return NO_MEMORY;
1193 }
1194 newBuffer->setFormat(mFormat);
1195 *index = mImpl.assignSlot(newBuffer);
1196 handleImageData(newBuffer);
1197 *clientBuffer = newBuffer;
1198 ALOGV("[%s] registered buffer %zu", mName, *index);
1199 return OK;
1200 }
1201
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1202 status_t FlexOutputBuffers::registerCsd(
1203 const C2StreamInitDataInfo::output *csd,
1204 size_t *index,
1205 sp<MediaCodecBuffer> *clientBuffer) {
1206 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1207 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1208 *index = mImpl.assignSlot(newBuffer);
1209 *clientBuffer = newBuffer;
1210 return OK;
1211 }
1212
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1213 bool FlexOutputBuffers::releaseBuffer(
1214 const sp<MediaCodecBuffer> &buffer,
1215 std::shared_ptr<C2Buffer> *c2buffer) {
1216 return mImpl.releaseSlot(buffer, c2buffer, true);
1217 }
1218
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1219 void FlexOutputBuffers::flush(
1220 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1221 (void) flushedWork;
1222 // This is no-op by default unless we're in array mode where we need to keep
1223 // track of the flushed work.
1224 }
1225
toArrayMode(size_t size)1226 std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
1227 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1228 array->transferFrom(this);
1229 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1230 array->initialize(mImpl, size, alloc);
1231 return array;
1232 }
1233
numActiveSlots() const1234 size_t FlexOutputBuffers::numActiveSlots() const {
1235 return mImpl.numActiveSlots();
1236 }
1237
1238 // LinearOutputBuffers
1239
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1240 void LinearOutputBuffers::flush(
1241 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1242 if (mSkipCutBuffer != nullptr) {
1243 mSkipCutBuffer->clear();
1244 }
1245 FlexOutputBuffers::flush(flushedWork);
1246 }
1247
wrap(const std::shared_ptr<C2Buffer> & buffer)1248 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1249 if (buffer == nullptr) {
1250 ALOGV("[%s] using a dummy buffer", mName);
1251 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1252 }
1253 if (buffer->data().type() != C2BufferData::LINEAR) {
1254 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1255 // We expect linear output buffers from the component.
1256 return nullptr;
1257 }
1258 if (buffer->data().linearBlocks().size() != 1u) {
1259 ALOGV("[%s] no linear buffers", mName);
1260 // We expect one and only one linear block from the component.
1261 return nullptr;
1262 }
1263 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1264 if (clientBuffer == nullptr) {
1265 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1266 return nullptr;
1267 }
1268 submit(clientBuffer);
1269 return clientBuffer;
1270 }
1271
getAlloc()1272 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1273 return [format = mFormat]{
1274 // TODO: proper max output size
1275 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1276 };
1277 }
1278
1279 // GraphicOutputBuffers
1280
wrap(const std::shared_ptr<C2Buffer> & buffer)1281 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1282 return new DummyContainerBuffer(mFormat, buffer);
1283 }
1284
getAlloc()1285 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1286 return [format = mFormat]{
1287 return new DummyContainerBuffer(format);
1288 };
1289 }
1290
1291 // RawGraphicOutputBuffers
1292
RawGraphicOutputBuffers(const char * componentName,const char * name)1293 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1294 const char *componentName, const char *name)
1295 : FlexOutputBuffers(componentName, name),
1296 mLocalBufferPool(LocalBufferPool::Create()) { }
1297
wrap(const std::shared_ptr<C2Buffer> & buffer)1298 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1299 if (buffer == nullptr) {
1300 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1301 mFormat,
1302 [lbp = mLocalBufferPool](size_t capacity) {
1303 return lbp->newBuffer(capacity);
1304 });
1305 if (c2buffer == nullptr) {
1306 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1307 return nullptr;
1308 }
1309 c2buffer->setRange(0, 0);
1310 return c2buffer;
1311 } else {
1312 return ConstGraphicBlockBuffer::Allocate(
1313 mFormat,
1314 buffer,
1315 [lbp = mLocalBufferPool](size_t capacity) {
1316 return lbp->newBuffer(capacity);
1317 });
1318 }
1319 }
1320
getAlloc()1321 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1322 return [format = mFormat, lbp = mLocalBufferPool]{
1323 return ConstGraphicBlockBuffer::AllocateEmpty(
1324 format,
1325 [lbp](size_t capacity) {
1326 return lbp->newBuffer(capacity);
1327 });
1328 };
1329 }
1330
1331 } // namespace android
1332