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 ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
276 mName, outputFormat->debugString().c_str());
277 updateSkipCutBuffer(outputFormat, entry.notify);
278 }
279
280 if (entry.notify) {
281 if (outputFormat) {
282 setFormat(outputFormat);
283 } else if (mUnreportedFormat) {
284 outputFormat = mUnreportedFormat;
285 setFormat(outputFormat);
286 }
287 mUnreportedFormat = nullptr;
288 } else {
289 if (outputFormat) {
290 mUnreportedFormat = outputFormat;
291 } else if (!mUnreportedFormat) {
292 mUnreportedFormat = mFormat;
293 }
294 }
295
296 // Flushing mReorderStash because no other buffers should come after output
297 // EOS.
298 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
299 // Flush reorder stash
300 setReorderDepth(0);
301 }
302
303 if (!entry.notify) {
304 mPending.pop_front();
305 return DISCARD;
306 }
307
308 // Try to register the buffer.
309 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
310 if (err != OK) {
311 if (err != WOULD_BLOCK) {
312 return REALLOCATE;
313 }
314 return RETRY;
315 }
316
317 // Append information from the front stash entry to outBuffer.
318 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
319 (*outBuffer)->meta()->setInt32("flags", entry.flags);
320 ALOGV("[%s] popFromStashAndRegister: "
321 "out buffer index = %zu [%p] => %p + %zu (%lld)",
322 mName, *index, outBuffer->get(),
323 (*outBuffer)->data(), (*outBuffer)->size(),
324 (long long)entry.timestamp);
325
326 // The front entry of mPending will be removed now that the registration
327 // succeeded.
328 mPending.pop_front();
329 return NOTIFY_CLIENT;
330 }
331
popPending(StashEntry * entry)332 bool OutputBuffers::popPending(StashEntry *entry) {
333 if (mPending.empty()) {
334 return false;
335 }
336 *entry = mPending.front();
337 mPending.pop_front();
338 return true;
339 }
340
deferPending(const OutputBuffers::StashEntry & entry)341 void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
342 mPending.push_front(entry);
343 }
344
hasPending() const345 bool OutputBuffers::hasPending() const {
346 return !mPending.empty();
347 }
348
less(const C2WorkOrdinalStruct & o1,const C2WorkOrdinalStruct & o2) const349 bool OutputBuffers::less(
350 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
351 switch (mKey) {
352 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
353 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
354 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
355 default:
356 ALOGD("Unrecognized key; default to timestamp");
357 return o1.frameIndex < o2.frameIndex;
358 }
359 }
360
361 // LocalBufferPool
362
363 constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
364 constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
365
Create()366 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
367 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
368 }
369
newBuffer(size_t capacity)370 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
371 Mutex::Autolock lock(mMutex);
372 auto it = std::find_if(
373 mPool.begin(), mPool.end(),
374 [capacity](const std::vector<uint8_t> &vec) {
375 return vec.capacity() >= capacity;
376 });
377 if (it != mPool.end()) {
378 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
379 mPool.erase(it);
380 return buffer;
381 }
382 if (mUsedSize + capacity > mPoolCapacity) {
383 while (!mPool.empty()) {
384 mUsedSize -= mPool.back().capacity();
385 mPool.pop_back();
386 }
387 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
388 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
389 mPoolCapacity, mPoolCapacity * 2);
390 mPoolCapacity *= 2;
391 }
392 if (mUsedSize + capacity > mPoolCapacity) {
393 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
394 mUsedSize, capacity, mPoolCapacity);
395 return nullptr;
396 }
397 }
398 std::vector<uint8_t> vec(capacity);
399 mUsedSize += vec.capacity();
400 return new VectorBuffer(std::move(vec), shared_from_this());
401 }
402
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)403 LocalBufferPool::VectorBuffer::VectorBuffer(
404 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
405 : ABuffer(vec.data(), vec.capacity()),
406 mVec(std::move(vec)),
407 mPool(pool) {
408 }
409
~VectorBuffer()410 LocalBufferPool::VectorBuffer::~VectorBuffer() {
411 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
412 if (pool) {
413 // If pool is alive, return the vector back to the pool so that
414 // it can be recycled.
415 pool->returnVector(std::move(mVec));
416 }
417 }
418
returnVector(std::vector<uint8_t> && vec)419 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
420 Mutex::Autolock lock(mMutex);
421 mPool.push_front(std::move(vec));
422 }
423
424 // FlexBuffersImpl
425
assignSlot(const sp<Codec2Buffer> & buffer)426 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
427 for (size_t i = 0; i < mBuffers.size(); ++i) {
428 if (mBuffers[i].clientBuffer == nullptr
429 && mBuffers[i].compBuffer.expired()) {
430 mBuffers[i].clientBuffer = buffer;
431 return i;
432 }
433 }
434 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
435 return mBuffers.size() - 1;
436 }
437
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)438 bool FlexBuffersImpl::releaseSlot(
439 const sp<MediaCodecBuffer> &buffer,
440 std::shared_ptr<C2Buffer> *c2buffer,
441 bool release) {
442 sp<Codec2Buffer> clientBuffer;
443 size_t index = mBuffers.size();
444 for (size_t i = 0; i < mBuffers.size(); ++i) {
445 if (mBuffers[i].clientBuffer == buffer) {
446 clientBuffer = mBuffers[i].clientBuffer;
447 if (release) {
448 mBuffers[i].clientBuffer.clear();
449 }
450 index = i;
451 break;
452 }
453 }
454 if (clientBuffer == nullptr) {
455 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
456 return false;
457 }
458 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
459 if (!result) {
460 result = clientBuffer->asC2Buffer();
461 clientBuffer->clearC2BufferRefs();
462 mBuffers[index].compBuffer = result;
463 }
464 if (c2buffer) {
465 *c2buffer = result;
466 }
467 return true;
468 }
469
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)470 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
471 for (size_t i = 0; i < mBuffers.size(); ++i) {
472 std::shared_ptr<C2Buffer> compBuffer =
473 mBuffers[i].compBuffer.lock();
474 if (!compBuffer || compBuffer != c2buffer) {
475 continue;
476 }
477 mBuffers[i].compBuffer.reset();
478 ALOGV("[%s] codec released buffer #%zu", mName, i);
479 return true;
480 }
481 ALOGV("[%s] codec released an unknown buffer", mName);
482 return false;
483 }
484
flush()485 void FlexBuffersImpl::flush() {
486 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
487 mBuffers.clear();
488 }
489
numClientBuffers() const490 size_t FlexBuffersImpl::numClientBuffers() const {
491 return std::count_if(
492 mBuffers.begin(), mBuffers.end(),
493 [](const Entry &entry) {
494 return (entry.clientBuffer != nullptr);
495 });
496 }
497
numComponentBuffers() const498 size_t FlexBuffersImpl::numComponentBuffers() const {
499 return std::count_if(
500 mBuffers.begin(), mBuffers.end(),
501 [](const Entry &entry) {
502 return !entry.compBuffer.expired();
503 });
504 }
505
506 // BuffersArrayImpl
507
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)508 void BuffersArrayImpl::initialize(
509 const FlexBuffersImpl &impl,
510 size_t minSize,
511 std::function<sp<Codec2Buffer>()> allocate) {
512 mImplName = impl.mImplName + "[N]";
513 mName = mImplName.c_str();
514 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
515 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
516 bool ownedByClient = (clientBuffer != nullptr);
517 if (!ownedByClient) {
518 clientBuffer = allocate();
519 }
520 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
521 }
522 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
523 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
524 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
525 }
526 }
527
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)528 status_t BuffersArrayImpl::grabBuffer(
529 size_t *index,
530 sp<Codec2Buffer> *buffer,
531 std::function<bool(const sp<Codec2Buffer> &)> match) {
532 // allBuffersDontMatch remains true if all buffers are available but
533 // match() returns false for every buffer.
534 bool allBuffersDontMatch = true;
535 for (size_t i = 0; i < mBuffers.size(); ++i) {
536 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
537 if (match(mBuffers[i].clientBuffer)) {
538 mBuffers[i].ownedByClient = true;
539 *buffer = mBuffers[i].clientBuffer;
540 (*buffer)->meta()->clear();
541 (*buffer)->setRange(0, (*buffer)->capacity());
542 *index = i;
543 return OK;
544 }
545 } else {
546 allBuffersDontMatch = false;
547 }
548 }
549 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
550 }
551
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)552 bool BuffersArrayImpl::returnBuffer(
553 const sp<MediaCodecBuffer> &buffer,
554 std::shared_ptr<C2Buffer> *c2buffer,
555 bool release) {
556 sp<Codec2Buffer> clientBuffer;
557 size_t index = mBuffers.size();
558 for (size_t i = 0; i < mBuffers.size(); ++i) {
559 if (mBuffers[i].clientBuffer == buffer) {
560 if (!mBuffers[i].ownedByClient) {
561 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
562 mName, i);
563 }
564 clientBuffer = mBuffers[i].clientBuffer;
565 if (release) {
566 mBuffers[i].ownedByClient = false;
567 }
568 index = i;
569 break;
570 }
571 }
572 if (clientBuffer == nullptr) {
573 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
574 return false;
575 }
576 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
577 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
578 if (!result) {
579 result = clientBuffer->asC2Buffer();
580 clientBuffer->clearC2BufferRefs();
581 mBuffers[index].compBuffer = result;
582 }
583 if (c2buffer) {
584 *c2buffer = result;
585 }
586 return true;
587 }
588
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)589 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
590 for (size_t i = 0; i < mBuffers.size(); ++i) {
591 std::shared_ptr<C2Buffer> compBuffer =
592 mBuffers[i].compBuffer.lock();
593 if (!compBuffer) {
594 continue;
595 }
596 if (c2buffer == compBuffer) {
597 if (mBuffers[i].ownedByClient) {
598 // This should not happen.
599 ALOGD("[%s] codec released a buffer owned by client "
600 "(index %zu)", mName, i);
601 }
602 mBuffers[i].compBuffer.reset();
603 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
604 return true;
605 }
606 }
607 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
608 return false;
609 }
610
getArray(Vector<sp<MediaCodecBuffer>> * array) const611 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
612 array->clear();
613 for (const Entry &entry : mBuffers) {
614 array->push(entry.clientBuffer);
615 }
616 }
617
flush()618 void BuffersArrayImpl::flush() {
619 for (Entry &entry : mBuffers) {
620 entry.ownedByClient = false;
621 }
622 }
623
realloc(std::function<sp<Codec2Buffer> ()> alloc)624 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
625 size_t size = mBuffers.size();
626 mBuffers.clear();
627 for (size_t i = 0; i < size; ++i) {
628 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
629 }
630 }
631
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)632 void BuffersArrayImpl::grow(
633 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
634 CHECK_LT(mBuffers.size(), newSize);
635 while (mBuffers.size() < newSize) {
636 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
637 }
638 }
639
numClientBuffers() const640 size_t BuffersArrayImpl::numClientBuffers() const {
641 return std::count_if(
642 mBuffers.begin(), mBuffers.end(),
643 [](const Entry &entry) {
644 return entry.ownedByClient;
645 });
646 }
647
arraySize() const648 size_t BuffersArrayImpl::arraySize() const {
649 return mBuffers.size();
650 }
651
652 // InputBuffersArray
653
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)654 void InputBuffersArray::initialize(
655 const FlexBuffersImpl &impl,
656 size_t minSize,
657 std::function<sp<Codec2Buffer>()> allocate) {
658 mAllocate = allocate;
659 mImpl.initialize(impl, minSize, allocate);
660 }
661
getArray(Vector<sp<MediaCodecBuffer>> * array) const662 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
663 mImpl.getArray(array);
664 }
665
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)666 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
667 sp<Codec2Buffer> c2Buffer;
668 status_t err = mImpl.grabBuffer(index, &c2Buffer);
669 if (err == OK) {
670 c2Buffer->setFormat(mFormat);
671 handleImageData(c2Buffer);
672 *buffer = c2Buffer;
673 return true;
674 }
675 return false;
676 }
677
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)678 bool InputBuffersArray::releaseBuffer(
679 const sp<MediaCodecBuffer> &buffer,
680 std::shared_ptr<C2Buffer> *c2buffer,
681 bool release) {
682 return mImpl.returnBuffer(buffer, c2buffer, release);
683 }
684
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)685 bool InputBuffersArray::expireComponentBuffer(
686 const std::shared_ptr<C2Buffer> &c2buffer) {
687 return mImpl.expireComponentBuffer(c2buffer);
688 }
689
flush()690 void InputBuffersArray::flush() {
691 mImpl.flush();
692 }
693
numClientBuffers() const694 size_t InputBuffersArray::numClientBuffers() const {
695 return mImpl.numClientBuffers();
696 }
697
createNewBuffer()698 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
699 return mAllocate();
700 }
701
702 // SlotInputBuffers
703
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)704 bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
705 sp<Codec2Buffer> newBuffer = createNewBuffer();
706 *index = mImpl.assignSlot(newBuffer);
707 *buffer = newBuffer;
708 return true;
709 }
710
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)711 bool SlotInputBuffers::releaseBuffer(
712 const sp<MediaCodecBuffer> &buffer,
713 std::shared_ptr<C2Buffer> *c2buffer,
714 bool release) {
715 return mImpl.releaseSlot(buffer, c2buffer, release);
716 }
717
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)718 bool SlotInputBuffers::expireComponentBuffer(
719 const std::shared_ptr<C2Buffer> &c2buffer) {
720 return mImpl.expireComponentBuffer(c2buffer);
721 }
722
flush()723 void SlotInputBuffers::flush() {
724 mImpl.flush();
725 }
726
toArrayMode(size_t)727 std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
728 TRESPASS("Array mode should not be called at non-legacy mode");
729 return nullptr;
730 }
731
numClientBuffers() const732 size_t SlotInputBuffers::numClientBuffers() const {
733 return mImpl.numClientBuffers();
734 }
735
createNewBuffer()736 sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
737 return new DummyContainerBuffer{mFormat, nullptr};
738 }
739
740 // LinearInputBuffers
741
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)742 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
743 sp<Codec2Buffer> newBuffer = createNewBuffer();
744 if (newBuffer == nullptr) {
745 return false;
746 }
747 *index = mImpl.assignSlot(newBuffer);
748 *buffer = newBuffer;
749 return true;
750 }
751
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)752 bool LinearInputBuffers::releaseBuffer(
753 const sp<MediaCodecBuffer> &buffer,
754 std::shared_ptr<C2Buffer> *c2buffer,
755 bool release) {
756 return mImpl.releaseSlot(buffer, c2buffer, release);
757 }
758
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)759 bool LinearInputBuffers::expireComponentBuffer(
760 const std::shared_ptr<C2Buffer> &c2buffer) {
761 return mImpl.expireComponentBuffer(c2buffer);
762 }
763
flush()764 void LinearInputBuffers::flush() {
765 // This is no-op by default unless we're in array mode where we need to keep
766 // track of the flushed work.
767 mImpl.flush();
768 }
769
toArrayMode(size_t size)770 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
771 std::unique_ptr<InputBuffersArray> array(
772 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
773 array->setPool(mPool);
774 array->setFormat(mFormat);
775 array->initialize(
776 mImpl,
777 size,
778 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
779 return Alloc(pool, format);
780 });
781 return std::move(array);
782 }
783
numClientBuffers() const784 size_t LinearInputBuffers::numClientBuffers() const {
785 return mImpl.numClientBuffers();
786 }
787
788 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)789 sp<Codec2Buffer> LinearInputBuffers::Alloc(
790 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
791 int32_t capacity = kLinearBufferSize;
792 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
793 if ((size_t)capacity > kMaxLinearBufferSize) {
794 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
795 capacity = kMaxLinearBufferSize;
796 }
797
798 // TODO: read usage from intf
799 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
800 std::shared_ptr<C2LinearBlock> block;
801
802 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
803 if (err != C2_OK) {
804 return nullptr;
805 }
806
807 return LinearBlockBuffer::Allocate(format, block);
808 }
809
createNewBuffer()810 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
811 return Alloc(mPool, mFormat);
812 }
813
814 // EncryptedLinearInputBuffers
815
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)816 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
817 bool secure,
818 const sp<MemoryDealer> &dealer,
819 const sp<ICrypto> &crypto,
820 int32_t heapSeqNum,
821 size_t capacity,
822 size_t numInputSlots,
823 const char *componentName, const char *name)
824 : LinearInputBuffers(componentName, name),
825 mUsage({0, 0}),
826 mDealer(dealer),
827 mCrypto(crypto),
828 mMemoryVector(new std::vector<Entry>){
829 if (secure) {
830 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
831 } else {
832 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
833 }
834 for (size_t i = 0; i < numInputSlots; ++i) {
835 sp<IMemory> memory = mDealer->allocate(capacity);
836 if (memory == nullptr) {
837 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
838 mName, i);
839 break;
840 }
841 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
842 }
843 }
844
toArrayMode(size_t size)845 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
846 std::unique_ptr<InputBuffersArray> array(
847 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
848 array->setPool(mPool);
849 array->setFormat(mFormat);
850 array->initialize(
851 mImpl,
852 size,
853 [pool = mPool,
854 format = mFormat,
855 usage = mUsage,
856 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
857 return Alloc(pool, format, usage, memoryVector);
858 });
859 return std::move(array);
860 }
861
862
863 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)864 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
865 const std::shared_ptr<C2BlockPool> &pool,
866 const sp<AMessage> &format,
867 C2MemoryUsage usage,
868 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
869 int32_t capacity = kLinearBufferSize;
870 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
871 if ((size_t)capacity > kMaxLinearBufferSize) {
872 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
873 capacity = kMaxLinearBufferSize;
874 }
875
876 sp<IMemory> memory;
877 size_t slot = 0;
878 int32_t heapSeqNum = -1;
879 for (; slot < memoryVector->size(); ++slot) {
880 if (memoryVector->at(slot).block.expired()) {
881 memory = memoryVector->at(slot).memory;
882 heapSeqNum = memoryVector->at(slot).heapSeqNum;
883 break;
884 }
885 }
886 if (memory == nullptr) {
887 return nullptr;
888 }
889
890 std::shared_ptr<C2LinearBlock> block;
891 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
892 if (err != C2_OK || block == nullptr) {
893 return nullptr;
894 }
895
896 memoryVector->at(slot).block = block;
897 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
898 }
899
createNewBuffer()900 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
901 // TODO: android_2020
902 return nullptr;
903 }
904
905 // GraphicMetadataInputBuffers
906
GraphicMetadataInputBuffers(const char * componentName,const char * name)907 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
908 const char *componentName, const char *name)
909 : InputBuffers(componentName, name),
910 mImpl(mName),
911 mStore(GetCodec2PlatformAllocatorStore()) { }
912
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)913 bool GraphicMetadataInputBuffers::requestNewBuffer(
914 size_t *index, sp<MediaCodecBuffer> *buffer) {
915 sp<Codec2Buffer> newBuffer = createNewBuffer();
916 if (newBuffer == nullptr) {
917 return false;
918 }
919 *index = mImpl.assignSlot(newBuffer);
920 *buffer = newBuffer;
921 return true;
922 }
923
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)924 bool GraphicMetadataInputBuffers::releaseBuffer(
925 const sp<MediaCodecBuffer> &buffer,
926 std::shared_ptr<C2Buffer> *c2buffer,
927 bool release) {
928 return mImpl.releaseSlot(buffer, c2buffer, release);
929 }
930
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)931 bool GraphicMetadataInputBuffers::expireComponentBuffer(
932 const std::shared_ptr<C2Buffer> &c2buffer) {
933 return mImpl.expireComponentBuffer(c2buffer);
934 }
935
flush()936 void GraphicMetadataInputBuffers::flush() {
937 // This is no-op by default unless we're in array mode where we need to keep
938 // track of the flushed work.
939 }
940
toArrayMode(size_t size)941 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
942 size_t size) {
943 std::shared_ptr<C2Allocator> alloc;
944 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
945 if (err != C2_OK) {
946 return nullptr;
947 }
948 std::unique_ptr<InputBuffersArray> array(
949 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
950 array->setPool(mPool);
951 array->setFormat(mFormat);
952 array->initialize(
953 mImpl,
954 size,
955 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
956 return new GraphicMetadataBuffer(format, alloc);
957 });
958 return std::move(array);
959 }
960
numClientBuffers() const961 size_t GraphicMetadataInputBuffers::numClientBuffers() const {
962 return mImpl.numClientBuffers();
963 }
964
createNewBuffer()965 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
966 std::shared_ptr<C2Allocator> alloc;
967 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
968 if (err != C2_OK) {
969 return nullptr;
970 }
971 return new GraphicMetadataBuffer(mFormat, alloc);
972 }
973
974 // GraphicInputBuffers
975
GraphicInputBuffers(const char * componentName,const char * name)976 GraphicInputBuffers::GraphicInputBuffers(
977 const char *componentName, const char *name)
978 : InputBuffers(componentName, name),
979 mImpl(mName),
980 mLocalBufferPool(LocalBufferPool::Create()) { }
981
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)982 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
983 sp<Codec2Buffer> newBuffer = createNewBuffer();
984 if (newBuffer == nullptr) {
985 return false;
986 }
987 *index = mImpl.assignSlot(newBuffer);
988 handleImageData(newBuffer);
989 *buffer = newBuffer;
990 return true;
991 }
992
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)993 bool GraphicInputBuffers::releaseBuffer(
994 const sp<MediaCodecBuffer> &buffer,
995 std::shared_ptr<C2Buffer> *c2buffer,
996 bool release) {
997 return mImpl.releaseSlot(buffer, c2buffer, release);
998 }
999
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1000 bool GraphicInputBuffers::expireComponentBuffer(
1001 const std::shared_ptr<C2Buffer> &c2buffer) {
1002 return mImpl.expireComponentBuffer(c2buffer);
1003 }
1004
flush()1005 void GraphicInputBuffers::flush() {
1006 // This is no-op by default unless we're in array mode where we need to keep
1007 // track of the flushed work.
1008 }
1009
toArrayMode(size_t size)1010 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1011 std::unique_ptr<InputBuffersArray> array(
1012 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1013 array->setPool(mPool);
1014 array->setFormat(mFormat);
1015 array->initialize(
1016 mImpl,
1017 size,
1018 [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1019 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1020 return AllocateGraphicBuffer(
1021 pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1022 });
1023 return std::move(array);
1024 }
1025
numClientBuffers() const1026 size_t GraphicInputBuffers::numClientBuffers() const {
1027 return mImpl.numClientBuffers();
1028 }
1029
createNewBuffer()1030 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1031 // TODO: read usage from intf
1032 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1033 return AllocateGraphicBuffer(
1034 mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1035 }
1036
1037 // OutputBuffersArray
1038
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)1039 void OutputBuffersArray::initialize(
1040 const FlexBuffersImpl &impl,
1041 size_t minSize,
1042 std::function<sp<Codec2Buffer>()> allocate) {
1043 mAlloc = allocate;
1044 mImpl.initialize(impl, minSize, allocate);
1045 }
1046
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1047 status_t OutputBuffersArray::registerBuffer(
1048 const std::shared_ptr<C2Buffer> &buffer,
1049 size_t *index,
1050 sp<MediaCodecBuffer> *clientBuffer) {
1051 sp<Codec2Buffer> c2Buffer;
1052 status_t err = mImpl.grabBuffer(
1053 index,
1054 &c2Buffer,
1055 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1056 return clientBuffer->canCopy(buffer);
1057 });
1058 if (err == WOULD_BLOCK) {
1059 ALOGV("[%s] buffers temporarily not available", mName);
1060 return err;
1061 } else if (err != OK) {
1062 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1063 return err;
1064 }
1065 c2Buffer->setFormat(mFormat);
1066 if (!c2Buffer->copy(buffer)) {
1067 ALOGD("[%s] copy buffer failed", mName);
1068 return WOULD_BLOCK;
1069 }
1070 submit(c2Buffer);
1071 handleImageData(c2Buffer);
1072 *clientBuffer = c2Buffer;
1073 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1074 return OK;
1075 }
1076
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1077 status_t OutputBuffersArray::registerCsd(
1078 const C2StreamInitDataInfo::output *csd,
1079 size_t *index,
1080 sp<MediaCodecBuffer> *clientBuffer) {
1081 sp<Codec2Buffer> c2Buffer;
1082 status_t err = mImpl.grabBuffer(
1083 index,
1084 &c2Buffer,
1085 [csd](const sp<Codec2Buffer> &clientBuffer) {
1086 return clientBuffer->base() != nullptr
1087 && clientBuffer->capacity() >= csd->flexCount();
1088 });
1089 if (err != OK) {
1090 return err;
1091 }
1092 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1093 c2Buffer->setRange(0, csd->flexCount());
1094 c2Buffer->setFormat(mFormat);
1095 *clientBuffer = c2Buffer;
1096 return OK;
1097 }
1098
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1099 bool OutputBuffersArray::releaseBuffer(
1100 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1101 return mImpl.returnBuffer(buffer, c2buffer, true);
1102 }
1103
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1104 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1105 (void)flushedWork;
1106 mImpl.flush();
1107 if (mSkipCutBuffer != nullptr) {
1108 mSkipCutBuffer->clear();
1109 }
1110 }
1111
getArray(Vector<sp<MediaCodecBuffer>> * array) const1112 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1113 mImpl.getArray(array);
1114 }
1115
numClientBuffers() const1116 size_t OutputBuffersArray::numClientBuffers() const {
1117 return mImpl.numClientBuffers();
1118 }
1119
realloc(const std::shared_ptr<C2Buffer> & c2buffer)1120 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
1121 switch (c2buffer->data().type()) {
1122 case C2BufferData::LINEAR: {
1123 uint32_t size = kLinearBufferSize;
1124 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1125 const uint32_t block_size = linear_blocks.front().size();
1126 if (block_size < kMaxLinearBufferSize / 2) {
1127 size = block_size * 2;
1128 } else {
1129 size = kMaxLinearBufferSize;
1130 }
1131 mAlloc = [format = mFormat, size] {
1132 return new LocalLinearBuffer(format, new ABuffer(size));
1133 };
1134 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
1135 break;
1136 }
1137
1138 case C2BufferData::GRAPHIC: {
1139 // This is only called for RawGraphicOutputBuffers.
1140 mAlloc = [format = mFormat,
1141 lbp = LocalBufferPool::Create()] {
1142 return ConstGraphicBlockBuffer::AllocateEmpty(
1143 format,
1144 [lbp](size_t capacity) {
1145 return lbp->newBuffer(capacity);
1146 });
1147 };
1148 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1149 mName, mFormat->debugString().c_str());
1150 break;
1151 }
1152
1153 case C2BufferData::INVALID: [[fallthrough]];
1154 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1155 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1156 default:
1157 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1158 return;
1159 }
1160 mImpl.realloc(mAlloc);
1161 }
1162
grow(size_t newSize)1163 void OutputBuffersArray::grow(size_t newSize) {
1164 mImpl.grow(newSize, mAlloc);
1165 }
1166
transferFrom(OutputBuffers * source)1167 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1168 mFormat = source->mFormat;
1169 mSkipCutBuffer = source->mSkipCutBuffer;
1170 mUnreportedFormat = source->mUnreportedFormat;
1171 mPending = std::move(source->mPending);
1172 mReorderStash = std::move(source->mReorderStash);
1173 mDepth = source->mDepth;
1174 mKey = source->mKey;
1175 }
1176
1177 // FlexOutputBuffers
1178
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1179 status_t FlexOutputBuffers::registerBuffer(
1180 const std::shared_ptr<C2Buffer> &buffer,
1181 size_t *index,
1182 sp<MediaCodecBuffer> *clientBuffer) {
1183 sp<Codec2Buffer> newBuffer = wrap(buffer);
1184 if (newBuffer == nullptr) {
1185 return NO_MEMORY;
1186 }
1187 newBuffer->setFormat(mFormat);
1188 *index = mImpl.assignSlot(newBuffer);
1189 handleImageData(newBuffer);
1190 *clientBuffer = newBuffer;
1191 ALOGV("[%s] registered buffer %zu", mName, *index);
1192 return OK;
1193 }
1194
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1195 status_t FlexOutputBuffers::registerCsd(
1196 const C2StreamInitDataInfo::output *csd,
1197 size_t *index,
1198 sp<MediaCodecBuffer> *clientBuffer) {
1199 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1200 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1201 *index = mImpl.assignSlot(newBuffer);
1202 *clientBuffer = newBuffer;
1203 return OK;
1204 }
1205
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1206 bool FlexOutputBuffers::releaseBuffer(
1207 const sp<MediaCodecBuffer> &buffer,
1208 std::shared_ptr<C2Buffer> *c2buffer) {
1209 return mImpl.releaseSlot(buffer, c2buffer, true);
1210 }
1211
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1212 void FlexOutputBuffers::flush(
1213 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1214 (void) flushedWork;
1215 // This is no-op by default unless we're in array mode where we need to keep
1216 // track of the flushed work.
1217 }
1218
toArrayMode(size_t size)1219 std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
1220 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1221 array->transferFrom(this);
1222 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1223 array->initialize(mImpl, size, alloc);
1224 return array;
1225 }
1226
numClientBuffers() const1227 size_t FlexOutputBuffers::numClientBuffers() const {
1228 return mImpl.numClientBuffers();
1229 }
1230
1231 // LinearOutputBuffers
1232
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1233 void LinearOutputBuffers::flush(
1234 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1235 if (mSkipCutBuffer != nullptr) {
1236 mSkipCutBuffer->clear();
1237 }
1238 FlexOutputBuffers::flush(flushedWork);
1239 }
1240
wrap(const std::shared_ptr<C2Buffer> & buffer)1241 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1242 if (buffer == nullptr) {
1243 ALOGV("[%s] using a dummy buffer", mName);
1244 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1245 }
1246 if (buffer->data().type() != C2BufferData::LINEAR) {
1247 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1248 // We expect linear output buffers from the component.
1249 return nullptr;
1250 }
1251 if (buffer->data().linearBlocks().size() != 1u) {
1252 ALOGV("[%s] no linear buffers", mName);
1253 // We expect one and only one linear block from the component.
1254 return nullptr;
1255 }
1256 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1257 if (clientBuffer == nullptr) {
1258 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1259 return nullptr;
1260 }
1261 submit(clientBuffer);
1262 return clientBuffer;
1263 }
1264
getAlloc()1265 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1266 return [format = mFormat]{
1267 // TODO: proper max output size
1268 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1269 };
1270 }
1271
1272 // GraphicOutputBuffers
1273
wrap(const std::shared_ptr<C2Buffer> & buffer)1274 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1275 return new DummyContainerBuffer(mFormat, buffer);
1276 }
1277
getAlloc()1278 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1279 return [format = mFormat]{
1280 return new DummyContainerBuffer(format);
1281 };
1282 }
1283
1284 // RawGraphicOutputBuffers
1285
RawGraphicOutputBuffers(const char * componentName,const char * name)1286 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1287 const char *componentName, const char *name)
1288 : FlexOutputBuffers(componentName, name),
1289 mLocalBufferPool(LocalBufferPool::Create()) { }
1290
wrap(const std::shared_ptr<C2Buffer> & buffer)1291 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1292 if (buffer == nullptr) {
1293 sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1294 mFormat,
1295 [lbp = mLocalBufferPool](size_t capacity) {
1296 return lbp->newBuffer(capacity);
1297 });
1298 if (c2buffer == nullptr) {
1299 ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1300 return nullptr;
1301 }
1302 c2buffer->setRange(0, 0);
1303 return c2buffer;
1304 } else {
1305 return ConstGraphicBlockBuffer::Allocate(
1306 mFormat,
1307 buffer,
1308 [lbp = mLocalBufferPool](size_t capacity) {
1309 return lbp->newBuffer(capacity);
1310 });
1311 }
1312 }
1313
getAlloc()1314 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1315 return [format = mFormat, lbp = mLocalBufferPool]{
1316 return ConstGraphicBlockBuffer::AllocateEmpty(
1317 format,
1318 [lbp](size_t capacity) {
1319 return lbp->newBuffer(capacity);
1320 });
1321 };
1322 }
1323
1324 } // namespace android
1325