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