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