• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         updateSkipCutBuffer(outputFormat, entry.notify);
276     }
277 
278     if (entry.notify) {
279         if (outputFormat) {
280             setFormat(outputFormat);
281         } else if (mUnreportedFormat) {
282             outputFormat = mUnreportedFormat;
283             setFormat(outputFormat);
284         }
285         mUnreportedFormat = nullptr;
286     } else {
287         if (outputFormat) {
288             mUnreportedFormat = outputFormat;
289         } else if (!mUnreportedFormat) {
290             mUnreportedFormat = mFormat;
291         }
292     }
293 
294     // Flushing mReorderStash because no other buffers should come after output
295     // EOS.
296     if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
297         // Flush reorder stash
298         setReorderDepth(0);
299     }
300 
301     if (!entry.notify) {
302         if (outputFormat) {
303             ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
304                     mName, outputFormat->debugString().c_str());
305         }
306         mPending.pop_front();
307         return DISCARD;
308     }
309 
310     // Try to register the buffer.
311     status_t err = registerBuffer(*c2Buffer, index, outBuffer);
312     if (err != OK) {
313         if (err != WOULD_BLOCK) {
314             return REALLOCATE;
315         }
316         return RETRY;
317     }
318 
319     // Append information from the front stash entry to outBuffer.
320     (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
321     (*outBuffer)->meta()->setInt32("flags", entry.flags);
322     if (outputFormat) {
323         ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
324                 mName, outputFormat->debugString().c_str());
325     }
326     ALOGV("[%s] popFromStashAndRegister: "
327           "out buffer index = %zu [%p] => %p + %zu (%lld)",
328           mName, *index, outBuffer->get(),
329           (*outBuffer)->data(), (*outBuffer)->size(),
330           (long long)entry.timestamp);
331 
332     // The front entry of mPending will be removed now that the registration
333     // succeeded.
334     mPending.pop_front();
335     return NOTIFY_CLIENT;
336 }
337 
popPending(StashEntry * entry)338 bool OutputBuffers::popPending(StashEntry *entry) {
339     if (mPending.empty()) {
340         return false;
341     }
342     *entry = mPending.front();
343     mPending.pop_front();
344     return true;
345 }
346 
deferPending(const OutputBuffers::StashEntry & entry)347 void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
348     mPending.push_front(entry);
349 }
350 
hasPending() const351 bool OutputBuffers::hasPending() const {
352     return !mPending.empty();
353 }
354 
less(const C2WorkOrdinalStruct & o1,const C2WorkOrdinalStruct & o2) const355 bool OutputBuffers::less(
356         const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
357     switch (mKey) {
358         case C2Config::ORDINAL:   return o1.frameIndex < o2.frameIndex;
359         case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
360         case C2Config::CUSTOM:    return o1.customOrdinal < o2.customOrdinal;
361         default:
362             ALOGD("Unrecognized key; default to timestamp");
363             return o1.frameIndex < o2.frameIndex;
364     }
365 }
366 
367 // LocalBufferPool
368 
369 constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
370 constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
371 
Create()372 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
373     return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
374 }
375 
newBuffer(size_t capacity)376 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
377     Mutex::Autolock lock(mMutex);
378     auto it = std::find_if(
379             mPool.begin(), mPool.end(),
380             [capacity](const std::vector<uint8_t> &vec) {
381                 return vec.capacity() >= capacity;
382             });
383     if (it != mPool.end()) {
384         sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
385         mPool.erase(it);
386         return buffer;
387     }
388     if (mUsedSize + capacity > mPoolCapacity) {
389         while (!mPool.empty()) {
390             mUsedSize -= mPool.back().capacity();
391             mPool.pop_back();
392         }
393         while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
394             ALOGD("Increasing local buffer pool capacity from %zu to %zu",
395                   mPoolCapacity, mPoolCapacity * 2);
396             mPoolCapacity *= 2;
397         }
398         if (mUsedSize + capacity > mPoolCapacity) {
399             ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
400                     mUsedSize, capacity, mPoolCapacity);
401             return nullptr;
402         }
403     }
404     std::vector<uint8_t> vec(capacity);
405     mUsedSize += vec.capacity();
406     return new VectorBuffer(std::move(vec), shared_from_this());
407 }
408 
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)409 LocalBufferPool::VectorBuffer::VectorBuffer(
410         std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
411     : ABuffer(vec.data(), vec.capacity()),
412       mVec(std::move(vec)),
413       mPool(pool) {
414 }
415 
~VectorBuffer()416 LocalBufferPool::VectorBuffer::~VectorBuffer() {
417     std::shared_ptr<LocalBufferPool> pool = mPool.lock();
418     if (pool) {
419         // If pool is alive, return the vector back to the pool so that
420         // it can be recycled.
421         pool->returnVector(std::move(mVec));
422     }
423 }
424 
returnVector(std::vector<uint8_t> && vec)425 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
426     Mutex::Autolock lock(mMutex);
427     mPool.push_front(std::move(vec));
428 }
429 
430 // FlexBuffersImpl
431 
assignSlot(const sp<Codec2Buffer> & buffer)432 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
433     for (size_t i = 0; i < mBuffers.size(); ++i) {
434         if (mBuffers[i].clientBuffer == nullptr
435                 && mBuffers[i].compBuffer.expired()) {
436             mBuffers[i].clientBuffer = buffer;
437             return i;
438         }
439     }
440     mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
441     return mBuffers.size() - 1;
442 }
443 
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)444 bool FlexBuffersImpl::releaseSlot(
445         const sp<MediaCodecBuffer> &buffer,
446         std::shared_ptr<C2Buffer> *c2buffer,
447         bool release) {
448     sp<Codec2Buffer> clientBuffer;
449     size_t index = mBuffers.size();
450     for (size_t i = 0; i < mBuffers.size(); ++i) {
451         if (mBuffers[i].clientBuffer == buffer) {
452             clientBuffer = mBuffers[i].clientBuffer;
453             if (release) {
454                 mBuffers[i].clientBuffer.clear();
455             }
456             index = i;
457             break;
458         }
459     }
460     if (clientBuffer == nullptr) {
461         ALOGV("[%s] %s: No matching buffer found", mName, __func__);
462         return false;
463     }
464     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
465     if (!result) {
466         result = clientBuffer->asC2Buffer();
467         clientBuffer->clearC2BufferRefs();
468         mBuffers[index].compBuffer = result;
469     }
470     if (c2buffer) {
471         *c2buffer = result;
472     }
473     return true;
474 }
475 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)476 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
477     for (size_t i = 0; i < mBuffers.size(); ++i) {
478         std::shared_ptr<C2Buffer> compBuffer =
479                 mBuffers[i].compBuffer.lock();
480         if (!compBuffer || compBuffer != c2buffer) {
481             continue;
482         }
483         mBuffers[i].compBuffer.reset();
484         ALOGV("[%s] codec released buffer #%zu", mName, i);
485         return true;
486     }
487     ALOGV("[%s] codec released an unknown buffer", mName);
488     return false;
489 }
490 
flush()491 void FlexBuffersImpl::flush() {
492     ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
493     mBuffers.clear();
494 }
495 
numActiveSlots() const496 size_t FlexBuffersImpl::numActiveSlots() const {
497     return std::count_if(
498             mBuffers.begin(), mBuffers.end(),
499             [](const Entry &entry) {
500                 return (entry.clientBuffer != nullptr
501                         || !entry.compBuffer.expired());
502             });
503 }
504 
numComponentBuffers() const505 size_t FlexBuffersImpl::numComponentBuffers() const {
506     return std::count_if(
507             mBuffers.begin(), mBuffers.end(),
508             [](const Entry &entry) {
509                 return !entry.compBuffer.expired();
510             });
511 }
512 
513 // BuffersArrayImpl
514 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)515 void BuffersArrayImpl::initialize(
516         const FlexBuffersImpl &impl,
517         size_t minSize,
518         std::function<sp<Codec2Buffer>()> allocate) {
519     mImplName = impl.mImplName + "[N]";
520     mName = mImplName.c_str();
521     for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
522         sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
523         bool ownedByClient = (clientBuffer != nullptr);
524         if (!ownedByClient) {
525             clientBuffer = allocate();
526         }
527         mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
528     }
529     ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
530     for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
531         mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
532     }
533 }
534 
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)535 status_t BuffersArrayImpl::grabBuffer(
536         size_t *index,
537         sp<Codec2Buffer> *buffer,
538         std::function<bool(const sp<Codec2Buffer> &)> match) {
539     // allBuffersDontMatch remains true if all buffers are available but
540     // match() returns false for every buffer.
541     bool allBuffersDontMatch = true;
542     for (size_t i = 0; i < mBuffers.size(); ++i) {
543         if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
544             if (match(mBuffers[i].clientBuffer)) {
545                 mBuffers[i].ownedByClient = true;
546                 *buffer = mBuffers[i].clientBuffer;
547                 (*buffer)->meta()->clear();
548                 (*buffer)->setRange(0, (*buffer)->capacity());
549                 *index = i;
550                 return OK;
551             }
552         } else {
553             allBuffersDontMatch = false;
554         }
555     }
556     return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
557 }
558 
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)559 bool BuffersArrayImpl::returnBuffer(
560         const sp<MediaCodecBuffer> &buffer,
561         std::shared_ptr<C2Buffer> *c2buffer,
562         bool release) {
563     sp<Codec2Buffer> clientBuffer;
564     size_t index = mBuffers.size();
565     for (size_t i = 0; i < mBuffers.size(); ++i) {
566         if (mBuffers[i].clientBuffer == buffer) {
567             if (!mBuffers[i].ownedByClient) {
568                 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
569                       mName, i);
570             }
571             clientBuffer = mBuffers[i].clientBuffer;
572             if (release) {
573                 mBuffers[i].ownedByClient = false;
574             }
575             index = i;
576             break;
577         }
578     }
579     if (clientBuffer == nullptr) {
580         ALOGV("[%s] %s: No matching buffer found", mName, __func__);
581         return false;
582     }
583     ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
584     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
585     if (!result) {
586         result = clientBuffer->asC2Buffer();
587         clientBuffer->clearC2BufferRefs();
588         mBuffers[index].compBuffer = result;
589     }
590     if (c2buffer) {
591         *c2buffer = result;
592     }
593     return true;
594 }
595 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)596 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
597     for (size_t i = 0; i < mBuffers.size(); ++i) {
598         std::shared_ptr<C2Buffer> compBuffer =
599                 mBuffers[i].compBuffer.lock();
600         if (!compBuffer) {
601             continue;
602         }
603         if (c2buffer == compBuffer) {
604             if (mBuffers[i].ownedByClient) {
605                 // This should not happen.
606                 ALOGD("[%s] codec released a buffer owned by client "
607                       "(index %zu)", mName, i);
608             }
609             mBuffers[i].compBuffer.reset();
610             ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
611             return true;
612         }
613     }
614     ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
615     return false;
616 }
617 
getArray(Vector<sp<MediaCodecBuffer>> * array) const618 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
619     array->clear();
620     for (const Entry &entry : mBuffers) {
621         array->push(entry.clientBuffer);
622     }
623 }
624 
flush()625 void BuffersArrayImpl::flush() {
626     for (Entry &entry : mBuffers) {
627         entry.ownedByClient = false;
628     }
629 }
630 
realloc(std::function<sp<Codec2Buffer> ()> alloc)631 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
632     size_t size = mBuffers.size();
633     mBuffers.clear();
634     for (size_t i = 0; i < size; ++i) {
635         mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
636     }
637 }
638 
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)639 void BuffersArrayImpl::grow(
640         size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
641     CHECK_LT(mBuffers.size(), newSize);
642     while (mBuffers.size() < newSize) {
643         mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
644     }
645 }
646 
numActiveSlots() const647 size_t BuffersArrayImpl::numActiveSlots() const {
648     return std::count_if(
649             mBuffers.begin(), mBuffers.end(),
650             [](const Entry &entry) {
651                 return entry.ownedByClient || !entry.compBuffer.expired();
652             });
653 }
654 
arraySize() const655 size_t BuffersArrayImpl::arraySize() const {
656     return mBuffers.size();
657 }
658 
659 // InputBuffersArray
660 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)661 void InputBuffersArray::initialize(
662         const FlexBuffersImpl &impl,
663         size_t minSize,
664         std::function<sp<Codec2Buffer>()> allocate) {
665     mAllocate = allocate;
666     mImpl.initialize(impl, minSize, allocate);
667 }
668 
getArray(Vector<sp<MediaCodecBuffer>> * array) const669 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
670     mImpl.getArray(array);
671 }
672 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)673 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
674     sp<Codec2Buffer> c2Buffer;
675     status_t err = mImpl.grabBuffer(index, &c2Buffer);
676     if (err == OK) {
677         c2Buffer->setFormat(mFormat);
678         handleImageData(c2Buffer);
679         *buffer = c2Buffer;
680         return true;
681     }
682     return false;
683 }
684 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)685 bool InputBuffersArray::releaseBuffer(
686         const sp<MediaCodecBuffer> &buffer,
687         std::shared_ptr<C2Buffer> *c2buffer,
688         bool release) {
689     return mImpl.returnBuffer(buffer, c2buffer, release);
690 }
691 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)692 bool InputBuffersArray::expireComponentBuffer(
693         const std::shared_ptr<C2Buffer> &c2buffer) {
694     return mImpl.expireComponentBuffer(c2buffer);
695 }
696 
flush()697 void InputBuffersArray::flush() {
698     mImpl.flush();
699 }
700 
numActiveSlots() const701 size_t InputBuffersArray::numActiveSlots() const {
702     return mImpl.numActiveSlots();
703 }
704 
createNewBuffer()705 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
706     return mAllocate();
707 }
708 
709 // SlotInputBuffers
710 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)711 bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
712     sp<Codec2Buffer> newBuffer = createNewBuffer();
713     *index = mImpl.assignSlot(newBuffer);
714     *buffer = newBuffer;
715     return true;
716 }
717 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)718 bool SlotInputBuffers::releaseBuffer(
719         const sp<MediaCodecBuffer> &buffer,
720         std::shared_ptr<C2Buffer> *c2buffer,
721         bool release) {
722     return mImpl.releaseSlot(buffer, c2buffer, release);
723 }
724 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)725 bool SlotInputBuffers::expireComponentBuffer(
726         const std::shared_ptr<C2Buffer> &c2buffer) {
727     return mImpl.expireComponentBuffer(c2buffer);
728 }
729 
flush()730 void SlotInputBuffers::flush() {
731     mImpl.flush();
732 }
733 
toArrayMode(size_t)734 std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
735     TRESPASS("Array mode should not be called at non-legacy mode");
736     return nullptr;
737 }
738 
numActiveSlots() const739 size_t SlotInputBuffers::numActiveSlots() const {
740     return mImpl.numActiveSlots();
741 }
742 
createNewBuffer()743 sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
744     return new DummyContainerBuffer{mFormat, nullptr};
745 }
746 
747 // LinearInputBuffers
748 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)749 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
750     sp<Codec2Buffer> newBuffer = createNewBuffer();
751     if (newBuffer == nullptr) {
752         return false;
753     }
754     *index = mImpl.assignSlot(newBuffer);
755     *buffer = newBuffer;
756     return true;
757 }
758 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)759 bool LinearInputBuffers::releaseBuffer(
760         const sp<MediaCodecBuffer> &buffer,
761         std::shared_ptr<C2Buffer> *c2buffer,
762         bool release) {
763     return mImpl.releaseSlot(buffer, c2buffer, release);
764 }
765 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)766 bool LinearInputBuffers::expireComponentBuffer(
767         const std::shared_ptr<C2Buffer> &c2buffer) {
768     return mImpl.expireComponentBuffer(c2buffer);
769 }
770 
flush()771 void LinearInputBuffers::flush() {
772     // This is no-op by default unless we're in array mode where we need to keep
773     // track of the flushed work.
774     mImpl.flush();
775 }
776 
toArrayMode(size_t size)777 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
778     std::unique_ptr<InputBuffersArray> array(
779             new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
780     array->setPool(mPool);
781     array->setFormat(mFormat);
782     array->initialize(
783             mImpl,
784             size,
785             [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
786                 return Alloc(pool, format);
787             });
788     return std::move(array);
789 }
790 
numActiveSlots() const791 size_t LinearInputBuffers::numActiveSlots() const {
792     return mImpl.numActiveSlots();
793 }
794 
795 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)796 sp<Codec2Buffer> LinearInputBuffers::Alloc(
797         const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
798     int32_t capacity = kLinearBufferSize;
799     (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
800     if ((size_t)capacity > kMaxLinearBufferSize) {
801         ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
802         capacity = kMaxLinearBufferSize;
803     }
804 
805     // TODO: read usage from intf
806     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
807     std::shared_ptr<C2LinearBlock> block;
808 
809     c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
810     if (err != C2_OK) {
811         return nullptr;
812     }
813 
814     return LinearBlockBuffer::Allocate(format, block);
815 }
816 
createNewBuffer()817 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
818     return Alloc(mPool, mFormat);
819 }
820 
821 // EncryptedLinearInputBuffers
822 
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)823 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
824         bool secure,
825         const sp<MemoryDealer> &dealer,
826         const sp<ICrypto> &crypto,
827         int32_t heapSeqNum,
828         size_t capacity,
829         size_t numInputSlots,
830         const char *componentName, const char *name)
831     : LinearInputBuffers(componentName, name),
832       mUsage({0, 0}),
833       mDealer(dealer),
834       mCrypto(crypto),
835       mMemoryVector(new std::vector<Entry>){
836     if (secure) {
837         mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
838     } else {
839         mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
840     }
841     for (size_t i = 0; i < numInputSlots; ++i) {
842         sp<IMemory> memory = mDealer->allocate(capacity);
843         if (memory == nullptr) {
844             ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
845                   mName, i);
846             break;
847         }
848         mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
849     }
850 }
851 
toArrayMode(size_t size)852 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
853     std::unique_ptr<InputBuffersArray> array(
854             new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
855     array->setPool(mPool);
856     array->setFormat(mFormat);
857     array->initialize(
858             mImpl,
859             size,
860             [pool = mPool,
861              format = mFormat,
862              usage = mUsage,
863              memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
864                 return Alloc(pool, format, usage, memoryVector);
865             });
866     return std::move(array);
867 }
868 
869 
870 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)871 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
872         const std::shared_ptr<C2BlockPool> &pool,
873         const sp<AMessage> &format,
874         C2MemoryUsage usage,
875         const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
876     int32_t capacity = kLinearBufferSize;
877     (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
878     if ((size_t)capacity > kMaxLinearBufferSize) {
879         ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
880         capacity = kMaxLinearBufferSize;
881     }
882 
883     sp<IMemory> memory;
884     size_t slot = 0;
885     int32_t heapSeqNum = -1;
886     for (; slot < memoryVector->size(); ++slot) {
887         if (memoryVector->at(slot).block.expired()) {
888             memory = memoryVector->at(slot).memory;
889             heapSeqNum = memoryVector->at(slot).heapSeqNum;
890             break;
891         }
892     }
893     if (memory == nullptr) {
894         return nullptr;
895     }
896 
897     std::shared_ptr<C2LinearBlock> block;
898     c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
899     if (err != C2_OK || block == nullptr) {
900         return nullptr;
901     }
902 
903     memoryVector->at(slot).block = block;
904     return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
905 }
906 
createNewBuffer()907 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
908     // TODO: android_2020
909     return nullptr;
910 }
911 
912 // GraphicMetadataInputBuffers
913 
GraphicMetadataInputBuffers(const char * componentName,const char * name)914 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
915         const char *componentName, const char *name)
916     : InputBuffers(componentName, name),
917       mImpl(mName),
918       mStore(GetCodec2PlatformAllocatorStore()) { }
919 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)920 bool GraphicMetadataInputBuffers::requestNewBuffer(
921         size_t *index, sp<MediaCodecBuffer> *buffer) {
922     sp<Codec2Buffer> newBuffer = createNewBuffer();
923     if (newBuffer == nullptr) {
924         return false;
925     }
926     *index = mImpl.assignSlot(newBuffer);
927     *buffer = newBuffer;
928     return true;
929 }
930 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)931 bool GraphicMetadataInputBuffers::releaseBuffer(
932         const sp<MediaCodecBuffer> &buffer,
933         std::shared_ptr<C2Buffer> *c2buffer,
934         bool release) {
935     return mImpl.releaseSlot(buffer, c2buffer, release);
936 }
937 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)938 bool GraphicMetadataInputBuffers::expireComponentBuffer(
939         const std::shared_ptr<C2Buffer> &c2buffer) {
940     return mImpl.expireComponentBuffer(c2buffer);
941 }
942 
flush()943 void GraphicMetadataInputBuffers::flush() {
944     // This is no-op by default unless we're in array mode where we need to keep
945     // track of the flushed work.
946 }
947 
toArrayMode(size_t size)948 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
949         size_t size) {
950     std::shared_ptr<C2Allocator> alloc;
951     c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
952     if (err != C2_OK) {
953         return nullptr;
954     }
955     std::unique_ptr<InputBuffersArray> array(
956             new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
957     array->setPool(mPool);
958     array->setFormat(mFormat);
959     array->initialize(
960             mImpl,
961             size,
962             [format = mFormat, alloc]() -> sp<Codec2Buffer> {
963                 return new GraphicMetadataBuffer(format, alloc);
964             });
965     return std::move(array);
966 }
967 
numActiveSlots() const968 size_t GraphicMetadataInputBuffers::numActiveSlots() const {
969     return mImpl.numActiveSlots();
970 }
971 
createNewBuffer()972 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
973     std::shared_ptr<C2Allocator> alloc;
974     c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
975     if (err != C2_OK) {
976         return nullptr;
977     }
978     return new GraphicMetadataBuffer(mFormat, alloc);
979 }
980 
981 // GraphicInputBuffers
982 
GraphicInputBuffers(const char * componentName,const char * name)983 GraphicInputBuffers::GraphicInputBuffers(
984         const char *componentName, const char *name)
985     : InputBuffers(componentName, name),
986       mImpl(mName),
987       mLocalBufferPool(LocalBufferPool::Create()) { }
988 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)989 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
990     sp<Codec2Buffer> newBuffer = createNewBuffer();
991     if (newBuffer == nullptr) {
992         return false;
993     }
994     *index = mImpl.assignSlot(newBuffer);
995     handleImageData(newBuffer);
996     *buffer = newBuffer;
997     return true;
998 }
999 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1000 bool GraphicInputBuffers::releaseBuffer(
1001         const sp<MediaCodecBuffer> &buffer,
1002         std::shared_ptr<C2Buffer> *c2buffer,
1003         bool release) {
1004     return mImpl.releaseSlot(buffer, c2buffer, release);
1005 }
1006 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1007 bool GraphicInputBuffers::expireComponentBuffer(
1008         const std::shared_ptr<C2Buffer> &c2buffer) {
1009     return mImpl.expireComponentBuffer(c2buffer);
1010 }
1011 
flush()1012 void GraphicInputBuffers::flush() {
1013     // This is no-op by default unless we're in array mode where we need to keep
1014     // track of the flushed work.
1015 }
1016 
toArrayMode(size_t size)1017 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1018     std::unique_ptr<InputBuffersArray> array(
1019             new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1020     array->setPool(mPool);
1021     array->setFormat(mFormat);
1022     array->initialize(
1023             mImpl,
1024             size,
1025             [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
1026                 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1027                 return AllocateGraphicBuffer(
1028                         pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
1029             });
1030     return std::move(array);
1031 }
1032 
numActiveSlots() const1033 size_t GraphicInputBuffers::numActiveSlots() const {
1034     return mImpl.numActiveSlots();
1035 }
1036 
createNewBuffer()1037 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1038     // TODO: read usage from intf
1039     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1040     return AllocateGraphicBuffer(
1041             mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
1042 }
1043 
1044 // OutputBuffersArray
1045 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)1046 void OutputBuffersArray::initialize(
1047         const FlexBuffersImpl &impl,
1048         size_t minSize,
1049         std::function<sp<Codec2Buffer>()> allocate) {
1050     mAlloc = allocate;
1051     mImpl.initialize(impl, minSize, allocate);
1052 }
1053 
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1054 status_t OutputBuffersArray::registerBuffer(
1055         const std::shared_ptr<C2Buffer> &buffer,
1056         size_t *index,
1057         sp<MediaCodecBuffer> *clientBuffer) {
1058     sp<Codec2Buffer> c2Buffer;
1059     status_t err = mImpl.grabBuffer(
1060             index,
1061             &c2Buffer,
1062             [buffer](const sp<Codec2Buffer> &clientBuffer) {
1063                 return clientBuffer->canCopy(buffer);
1064             });
1065     if (err == WOULD_BLOCK) {
1066         ALOGV("[%s] buffers temporarily not available", mName);
1067         return err;
1068     } else if (err != OK) {
1069         ALOGD("[%s] grabBuffer failed: %d", mName, err);
1070         return err;
1071     }
1072     c2Buffer->setFormat(mFormat);
1073     if (!c2Buffer->copy(buffer)) {
1074         ALOGD("[%s] copy buffer failed", mName);
1075         return WOULD_BLOCK;
1076     }
1077     submit(c2Buffer);
1078     handleImageData(c2Buffer);
1079     *clientBuffer = c2Buffer;
1080     ALOGV("[%s] grabbed buffer %zu", mName, *index);
1081     return OK;
1082 }
1083 
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1084 status_t OutputBuffersArray::registerCsd(
1085         const C2StreamInitDataInfo::output *csd,
1086         size_t *index,
1087         sp<MediaCodecBuffer> *clientBuffer) {
1088     sp<Codec2Buffer> c2Buffer;
1089     status_t err = mImpl.grabBuffer(
1090             index,
1091             &c2Buffer,
1092             [csd](const sp<Codec2Buffer> &clientBuffer) {
1093                 return clientBuffer->base() != nullptr
1094                         && clientBuffer->capacity() >= csd->flexCount();
1095             });
1096     if (err != OK) {
1097         return err;
1098     }
1099     memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1100     c2Buffer->setRange(0, csd->flexCount());
1101     c2Buffer->setFormat(mFormat);
1102     *clientBuffer = c2Buffer;
1103     return OK;
1104 }
1105 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1106 bool OutputBuffersArray::releaseBuffer(
1107         const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1108     return mImpl.returnBuffer(buffer, c2buffer, true);
1109 }
1110 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1111 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1112     (void)flushedWork;
1113     mImpl.flush();
1114     if (mSkipCutBuffer != nullptr) {
1115         mSkipCutBuffer->clear();
1116     }
1117 }
1118 
getArray(Vector<sp<MediaCodecBuffer>> * array) const1119 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1120     mImpl.getArray(array);
1121 }
1122 
numActiveSlots() const1123 size_t OutputBuffersArray::numActiveSlots() const {
1124     return mImpl.numActiveSlots();
1125 }
1126 
realloc(const std::shared_ptr<C2Buffer> & c2buffer)1127 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
1128     switch (c2buffer->data().type()) {
1129         case C2BufferData::LINEAR: {
1130             uint32_t size = kLinearBufferSize;
1131             const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1132             const uint32_t block_size = linear_blocks.front().size();
1133             if (block_size < kMaxLinearBufferSize / 2) {
1134                 size = block_size * 2;
1135             } else {
1136                 size = kMaxLinearBufferSize;
1137             }
1138             mAlloc = [format = mFormat, size] {
1139                 return new LocalLinearBuffer(format, new ABuffer(size));
1140             };
1141             ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
1142             break;
1143         }
1144 
1145         case C2BufferData::GRAPHIC: {
1146             // This is only called for RawGraphicOutputBuffers.
1147             mAlloc = [format = mFormat,
1148                       lbp = LocalBufferPool::Create()] {
1149                 return ConstGraphicBlockBuffer::AllocateEmpty(
1150                         format,
1151                         [lbp](size_t capacity) {
1152                             return lbp->newBuffer(capacity);
1153                         });
1154             };
1155             ALOGD("[%s] reallocating with graphic buffer: format = %s",
1156                   mName, mFormat->debugString().c_str());
1157             break;
1158         }
1159 
1160         case C2BufferData::INVALID:         [[fallthrough]];
1161         case C2BufferData::LINEAR_CHUNKS:   [[fallthrough]];
1162         case C2BufferData::GRAPHIC_CHUNKS:  [[fallthrough]];
1163         default:
1164             ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1165             return;
1166     }
1167     mImpl.realloc(mAlloc);
1168 }
1169 
grow(size_t newSize)1170 void OutputBuffersArray::grow(size_t newSize) {
1171     mImpl.grow(newSize, mAlloc);
1172 }
1173 
transferFrom(OutputBuffers * source)1174 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1175     mFormat = source->mFormat;
1176     mSkipCutBuffer = source->mSkipCutBuffer;
1177     mUnreportedFormat = source->mUnreportedFormat;
1178     mPending = std::move(source->mPending);
1179     mReorderStash = std::move(source->mReorderStash);
1180     mDepth = source->mDepth;
1181     mKey = source->mKey;
1182 }
1183 
1184 // FlexOutputBuffers
1185 
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1186 status_t FlexOutputBuffers::registerBuffer(
1187         const std::shared_ptr<C2Buffer> &buffer,
1188         size_t *index,
1189         sp<MediaCodecBuffer> *clientBuffer) {
1190     sp<Codec2Buffer> newBuffer = wrap(buffer);
1191     if (newBuffer == nullptr) {
1192         return NO_MEMORY;
1193     }
1194     newBuffer->setFormat(mFormat);
1195     *index = mImpl.assignSlot(newBuffer);
1196     handleImageData(newBuffer);
1197     *clientBuffer = newBuffer;
1198     ALOGV("[%s] registered buffer %zu", mName, *index);
1199     return OK;
1200 }
1201 
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1202 status_t FlexOutputBuffers::registerCsd(
1203         const C2StreamInitDataInfo::output *csd,
1204         size_t *index,
1205         sp<MediaCodecBuffer> *clientBuffer) {
1206     sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1207             mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1208     *index = mImpl.assignSlot(newBuffer);
1209     *clientBuffer = newBuffer;
1210     return OK;
1211 }
1212 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1213 bool FlexOutputBuffers::releaseBuffer(
1214         const sp<MediaCodecBuffer> &buffer,
1215         std::shared_ptr<C2Buffer> *c2buffer) {
1216     return mImpl.releaseSlot(buffer, c2buffer, true);
1217 }
1218 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1219 void FlexOutputBuffers::flush(
1220         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1221     (void) flushedWork;
1222     // This is no-op by default unless we're in array mode where we need to keep
1223     // track of the flushed work.
1224 }
1225 
toArrayMode(size_t size)1226 std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
1227     std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1228     array->transferFrom(this);
1229     std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1230     array->initialize(mImpl, size, alloc);
1231     return array;
1232 }
1233 
numActiveSlots() const1234 size_t FlexOutputBuffers::numActiveSlots() const {
1235     return mImpl.numActiveSlots();
1236 }
1237 
1238 // LinearOutputBuffers
1239 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1240 void LinearOutputBuffers::flush(
1241         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1242     if (mSkipCutBuffer != nullptr) {
1243         mSkipCutBuffer->clear();
1244     }
1245     FlexOutputBuffers::flush(flushedWork);
1246 }
1247 
wrap(const std::shared_ptr<C2Buffer> & buffer)1248 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1249     if (buffer == nullptr) {
1250         ALOGV("[%s] using a dummy buffer", mName);
1251         return new LocalLinearBuffer(mFormat, new ABuffer(0));
1252     }
1253     if (buffer->data().type() != C2BufferData::LINEAR) {
1254         ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1255         // We expect linear output buffers from the component.
1256         return nullptr;
1257     }
1258     if (buffer->data().linearBlocks().size() != 1u) {
1259         ALOGV("[%s] no linear buffers", mName);
1260         // We expect one and only one linear block from the component.
1261         return nullptr;
1262     }
1263     sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1264     if (clientBuffer == nullptr) {
1265         ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1266         return nullptr;
1267     }
1268     submit(clientBuffer);
1269     return clientBuffer;
1270 }
1271 
getAlloc()1272 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1273     return [format = mFormat]{
1274         // TODO: proper max output size
1275         return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1276     };
1277 }
1278 
1279 // GraphicOutputBuffers
1280 
wrap(const std::shared_ptr<C2Buffer> & buffer)1281 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1282     return new DummyContainerBuffer(mFormat, buffer);
1283 }
1284 
getAlloc()1285 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1286     return [format = mFormat]{
1287         return new DummyContainerBuffer(format);
1288     };
1289 }
1290 
1291 // RawGraphicOutputBuffers
1292 
RawGraphicOutputBuffers(const char * componentName,const char * name)1293 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1294         const char *componentName, const char *name)
1295     : FlexOutputBuffers(componentName, name),
1296       mLocalBufferPool(LocalBufferPool::Create()) { }
1297 
wrap(const std::shared_ptr<C2Buffer> & buffer)1298 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1299     if (buffer == nullptr) {
1300         sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1301                 mFormat,
1302                 [lbp = mLocalBufferPool](size_t capacity) {
1303                     return lbp->newBuffer(capacity);
1304                 });
1305         if (c2buffer == nullptr) {
1306             ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1307             return nullptr;
1308         }
1309         c2buffer->setRange(0, 0);
1310         return c2buffer;
1311     } else {
1312         return ConstGraphicBlockBuffer::Allocate(
1313                 mFormat,
1314                 buffer,
1315                 [lbp = mLocalBufferPool](size_t capacity) {
1316                     return lbp->newBuffer(capacity);
1317                 });
1318     }
1319 }
1320 
getAlloc()1321 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1322     return [format = mFormat, lbp = mLocalBufferPool]{
1323         return ConstGraphicBlockBuffer::AllocateEmpty(
1324                 format,
1325                 [lbp](size_t capacity) {
1326                     return lbp->newBuffer(capacity);
1327                 });
1328     };
1329 }
1330 
1331 }  // namespace android
1332