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