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