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