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