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