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