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