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