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