1 /*
2  * Copyright 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "CCodecBuffers"
19 #include <utils/Log.h>
20 
21 #include <C2PlatformSupport.h>
22 
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/MediaCodecConstants.h>
25 
26 #include "CCodecBuffers.h"
27 
28 namespace android {
29 
30 namespace {
31 
AllocateGraphicBuffer(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,uint32_t pixelFormat,const C2MemoryUsage & usage,const std::shared_ptr<LocalBufferPool> & localBufferPool)32 sp<GraphicBlockBuffer> AllocateGraphicBuffer(
33         const std::shared_ptr<C2BlockPool> &pool,
34         const sp<AMessage> &format,
35         uint32_t pixelFormat,
36         const C2MemoryUsage &usage,
37         const std::shared_ptr<LocalBufferPool> &localBufferPool) {
38     int32_t width, height;
39     if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
40         ALOGD("format lacks width or height");
41         return nullptr;
42     }
43 
44     std::shared_ptr<C2GraphicBlock> block;
45     c2_status_t err = pool->fetchGraphicBlock(
46             width, height, pixelFormat, usage, &block);
47     if (err != C2_OK) {
48         ALOGD("fetch graphic block failed: %d", err);
49         return nullptr;
50     }
51 
52     return GraphicBlockBuffer::Allocate(
53             format,
54             block,
55             [localBufferPool](size_t capacity) {
56                 return localBufferPool->newBuffer(capacity);
57             });
58 }
59 
60 }  // namespace
61 
62 // CCodecBuffers
63 
setFormat(const sp<AMessage> & format)64 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
65     CHECK(format != nullptr);
66     mFormat = format;
67 }
68 
dupFormat()69 sp<AMessage> CCodecBuffers::dupFormat() {
70     return mFormat != nullptr ? mFormat->dup() : nullptr;
71 }
72 
handleImageData(const sp<Codec2Buffer> & buffer)73 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
74     sp<ABuffer> imageDataCandidate = buffer->getImageData();
75     if (imageDataCandidate == nullptr) {
76         return;
77     }
78     sp<ABuffer> imageData;
79     if (!mFormat->findBuffer("image-data", &imageData)
80             || imageDataCandidate->size() != imageData->size()
81             || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
82         ALOGD("[%s] updating image-data", mName);
83         sp<AMessage> newFormat = dupFormat();
84         newFormat->setBuffer("image-data", imageDataCandidate);
85         MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
86         if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
87             int32_t stride = img->mPlane[0].mRowInc;
88             newFormat->setInt32(KEY_STRIDE, stride);
89             ALOGD("[%s] updating stride = %d", mName, stride);
90             if (img->mNumPlanes > 1 && stride > 0) {
91                 int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
92                 newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
93                 ALOGD("[%s] updating vstride = %d", mName, vstride);
94             }
95         }
96         setFormat(newFormat);
97         buffer->setFormat(newFormat);
98     }
99 }
100 
101 // InputBuffers
102 
cloneAndReleaseBuffer(const sp<MediaCodecBuffer> & buffer)103 sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
104     sp<Codec2Buffer> copy = createNewBuffer();
105     if (copy == nullptr) {
106         return nullptr;
107     }
108     std::shared_ptr<C2Buffer> c2buffer;
109     if (!releaseBuffer(buffer, &c2buffer, true)) {
110         return nullptr;
111     }
112     if (!copy->canCopy(c2buffer)) {
113         return nullptr;
114     }
115     if (!copy->copy(c2buffer)) {
116         return nullptr;
117     }
118     return copy;
119 }
120 
121 // OutputBuffers
122 
initSkipCutBuffer(int32_t delay,int32_t padding,int32_t sampleRate,int32_t channelCount)123 void OutputBuffers::initSkipCutBuffer(
124         int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
125     CHECK(mSkipCutBuffer == nullptr);
126     mDelay = delay;
127     mPadding = padding;
128     mSampleRate = sampleRate;
129     setSkipCutBuffer(delay, padding, channelCount);
130 }
131 
updateSkipCutBuffer(int32_t sampleRate,int32_t channelCount)132 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
133     if (mSkipCutBuffer == nullptr) {
134         return;
135     }
136     int32_t delay = mDelay;
137     int32_t padding = mPadding;
138     if (sampleRate != mSampleRate) {
139         delay = ((int64_t)delay * sampleRate) / mSampleRate;
140         padding = ((int64_t)padding * sampleRate) / mSampleRate;
141     }
142     setSkipCutBuffer(delay, padding, channelCount);
143 }
144 
submit(const sp<MediaCodecBuffer> & buffer)145 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
146     if (mSkipCutBuffer != nullptr) {
147         mSkipCutBuffer->submit(buffer);
148     }
149 }
150 
transferSkipCutBuffer(const sp<SkipCutBuffer> & scb)151 void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
152     mSkipCutBuffer = scb;
153 }
154 
setSkipCutBuffer(int32_t skip,int32_t cut,int32_t channelCount)155 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
156     if (mSkipCutBuffer != nullptr) {
157         size_t prevSize = mSkipCutBuffer->size();
158         if (prevSize != 0u) {
159             ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
160         }
161     }
162     mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
163 }
164 
165 // LocalBufferPool
166 
Create(size_t poolCapacity)167 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
168     return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
169 }
170 
newBuffer(size_t capacity)171 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
172     Mutex::Autolock lock(mMutex);
173     auto it = std::find_if(
174             mPool.begin(), mPool.end(),
175             [capacity](const std::vector<uint8_t> &vec) {
176                 return vec.capacity() >= capacity;
177             });
178     if (it != mPool.end()) {
179         sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
180         mPool.erase(it);
181         return buffer;
182     }
183     if (mUsedSize + capacity > mPoolCapacity) {
184         while (!mPool.empty()) {
185             mUsedSize -= mPool.back().capacity();
186             mPool.pop_back();
187         }
188         if (mUsedSize + capacity > mPoolCapacity) {
189             ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
190                     mUsedSize, capacity, mPoolCapacity);
191             return nullptr;
192         }
193     }
194     std::vector<uint8_t> vec(capacity);
195     mUsedSize += vec.capacity();
196     return new VectorBuffer(std::move(vec), shared_from_this());
197 }
198 
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)199 LocalBufferPool::VectorBuffer::VectorBuffer(
200         std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
201     : ABuffer(vec.data(), vec.capacity()),
202       mVec(std::move(vec)),
203       mPool(pool) {
204 }
205 
~VectorBuffer()206 LocalBufferPool::VectorBuffer::~VectorBuffer() {
207     std::shared_ptr<LocalBufferPool> pool = mPool.lock();
208     if (pool) {
209         // If pool is alive, return the vector back to the pool so that
210         // it can be recycled.
211         pool->returnVector(std::move(mVec));
212     }
213 }
214 
returnVector(std::vector<uint8_t> && vec)215 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
216     Mutex::Autolock lock(mMutex);
217     mPool.push_front(std::move(vec));
218 }
219 
220 // FlexBuffersImpl
221 
assignSlot(const sp<Codec2Buffer> & buffer)222 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
223     for (size_t i = 0; i < mBuffers.size(); ++i) {
224         if (mBuffers[i].clientBuffer == nullptr
225                 && mBuffers[i].compBuffer.expired()) {
226             mBuffers[i].clientBuffer = buffer;
227             return i;
228         }
229     }
230     mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
231     return mBuffers.size() - 1;
232 }
233 
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)234 bool FlexBuffersImpl::releaseSlot(
235         const sp<MediaCodecBuffer> &buffer,
236         std::shared_ptr<C2Buffer> *c2buffer,
237         bool release) {
238     sp<Codec2Buffer> clientBuffer;
239     size_t index = mBuffers.size();
240     for (size_t i = 0; i < mBuffers.size(); ++i) {
241         if (mBuffers[i].clientBuffer == buffer) {
242             clientBuffer = mBuffers[i].clientBuffer;
243             if (release) {
244                 mBuffers[i].clientBuffer.clear();
245             }
246             index = i;
247             break;
248         }
249     }
250     if (clientBuffer == nullptr) {
251         ALOGV("[%s] %s: No matching buffer found", mName, __func__);
252         return false;
253     }
254     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
255     if (!result) {
256         result = clientBuffer->asC2Buffer();
257         mBuffers[index].compBuffer = result;
258     }
259     if (c2buffer) {
260         *c2buffer = result;
261     }
262     return true;
263 }
264 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)265 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
266     for (size_t i = 0; i < mBuffers.size(); ++i) {
267         std::shared_ptr<C2Buffer> compBuffer =
268                 mBuffers[i].compBuffer.lock();
269         if (!compBuffer || compBuffer != c2buffer) {
270             continue;
271         }
272         mBuffers[i].compBuffer.reset();
273         ALOGV("[%s] codec released buffer #%zu", mName, i);
274         return true;
275     }
276     ALOGV("[%s] codec released an unknown buffer", mName);
277     return false;
278 }
279 
flush()280 void FlexBuffersImpl::flush() {
281     ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
282     mBuffers.clear();
283 }
284 
numClientBuffers() const285 size_t FlexBuffersImpl::numClientBuffers() const {
286     return std::count_if(
287             mBuffers.begin(), mBuffers.end(),
288             [](const Entry &entry) {
289                 return (entry.clientBuffer != nullptr);
290             });
291 }
292 
numComponentBuffers() const293 size_t FlexBuffersImpl::numComponentBuffers() const {
294     return std::count_if(
295             mBuffers.begin(), mBuffers.end(),
296             [](const Entry &entry) {
297                 return !entry.compBuffer.expired();
298             });
299 }
300 
301 // BuffersArrayImpl
302 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)303 void BuffersArrayImpl::initialize(
304         const FlexBuffersImpl &impl,
305         size_t minSize,
306         std::function<sp<Codec2Buffer>()> allocate) {
307     mImplName = impl.mImplName + "[N]";
308     mName = mImplName.c_str();
309     for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
310         sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
311         bool ownedByClient = (clientBuffer != nullptr);
312         if (!ownedByClient) {
313             clientBuffer = allocate();
314         }
315         mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
316     }
317     ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
318     for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
319         mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
320     }
321 }
322 
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)323 status_t BuffersArrayImpl::grabBuffer(
324         size_t *index,
325         sp<Codec2Buffer> *buffer,
326         std::function<bool(const sp<Codec2Buffer> &)> match) {
327     // allBuffersDontMatch remains true if all buffers are available but
328     // match() returns false for every buffer.
329     bool allBuffersDontMatch = true;
330     for (size_t i = 0; i < mBuffers.size(); ++i) {
331         if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
332             if (match(mBuffers[i].clientBuffer)) {
333                 mBuffers[i].ownedByClient = true;
334                 *buffer = mBuffers[i].clientBuffer;
335                 (*buffer)->meta()->clear();
336                 (*buffer)->setRange(0, (*buffer)->capacity());
337                 *index = i;
338                 return OK;
339             }
340         } else {
341             allBuffersDontMatch = false;
342         }
343     }
344     return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
345 }
346 
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)347 bool BuffersArrayImpl::returnBuffer(
348         const sp<MediaCodecBuffer> &buffer,
349         std::shared_ptr<C2Buffer> *c2buffer,
350         bool release) {
351     sp<Codec2Buffer> clientBuffer;
352     size_t index = mBuffers.size();
353     for (size_t i = 0; i < mBuffers.size(); ++i) {
354         if (mBuffers[i].clientBuffer == buffer) {
355             if (!mBuffers[i].ownedByClient) {
356                 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
357                       mName, i);
358             }
359             clientBuffer = mBuffers[i].clientBuffer;
360             if (release) {
361                 mBuffers[i].ownedByClient = false;
362             }
363             index = i;
364             break;
365         }
366     }
367     if (clientBuffer == nullptr) {
368         ALOGV("[%s] %s: No matching buffer found", mName, __func__);
369         return false;
370     }
371     ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
372     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
373     if (!result) {
374         result = clientBuffer->asC2Buffer();
375         mBuffers[index].compBuffer = result;
376     }
377     if (c2buffer) {
378         *c2buffer = result;
379     }
380     return true;
381 }
382 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)383 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
384     for (size_t i = 0; i < mBuffers.size(); ++i) {
385         std::shared_ptr<C2Buffer> compBuffer =
386                 mBuffers[i].compBuffer.lock();
387         if (!compBuffer) {
388             continue;
389         }
390         if (c2buffer == compBuffer) {
391             if (mBuffers[i].ownedByClient) {
392                 // This should not happen.
393                 ALOGD("[%s] codec released a buffer owned by client "
394                       "(index %zu)", mName, i);
395             }
396             mBuffers[i].compBuffer.reset();
397             ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
398             return true;
399         }
400     }
401     ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
402     return false;
403 }
404 
getArray(Vector<sp<MediaCodecBuffer>> * array) const405 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
406     array->clear();
407     for (const Entry &entry : mBuffers) {
408         array->push(entry.clientBuffer);
409     }
410 }
411 
flush()412 void BuffersArrayImpl::flush() {
413     for (Entry &entry : mBuffers) {
414         entry.ownedByClient = false;
415     }
416 }
417 
realloc(std::function<sp<Codec2Buffer> ()> alloc)418 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
419     size_t size = mBuffers.size();
420     mBuffers.clear();
421     for (size_t i = 0; i < size; ++i) {
422         mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
423     }
424 }
425 
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)426 void BuffersArrayImpl::grow(
427         size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
428     CHECK_LT(mBuffers.size(), newSize);
429     while (mBuffers.size() < newSize) {
430         mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
431     }
432 }
433 
numClientBuffers() const434 size_t BuffersArrayImpl::numClientBuffers() const {
435     return std::count_if(
436             mBuffers.begin(), mBuffers.end(),
437             [](const Entry &entry) {
438                 return entry.ownedByClient;
439             });
440 }
441 
arraySize() const442 size_t BuffersArrayImpl::arraySize() const {
443     return mBuffers.size();
444 }
445 
446 // InputBuffersArray
447 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)448 void InputBuffersArray::initialize(
449         const FlexBuffersImpl &impl,
450         size_t minSize,
451         std::function<sp<Codec2Buffer>()> allocate) {
452     mAllocate = allocate;
453     mImpl.initialize(impl, minSize, allocate);
454 }
455 
getArray(Vector<sp<MediaCodecBuffer>> * array) const456 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
457     mImpl.getArray(array);
458 }
459 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)460 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
461     sp<Codec2Buffer> c2Buffer;
462     status_t err = mImpl.grabBuffer(index, &c2Buffer);
463     if (err == OK) {
464         c2Buffer->setFormat(mFormat);
465         handleImageData(c2Buffer);
466         *buffer = c2Buffer;
467         return true;
468     }
469     return false;
470 }
471 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)472 bool InputBuffersArray::releaseBuffer(
473         const sp<MediaCodecBuffer> &buffer,
474         std::shared_ptr<C2Buffer> *c2buffer,
475         bool release) {
476     return mImpl.returnBuffer(buffer, c2buffer, release);
477 }
478 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)479 bool InputBuffersArray::expireComponentBuffer(
480         const std::shared_ptr<C2Buffer> &c2buffer) {
481     return mImpl.expireComponentBuffer(c2buffer);
482 }
483 
flush()484 void InputBuffersArray::flush() {
485     mImpl.flush();
486 }
487 
numClientBuffers() const488 size_t InputBuffersArray::numClientBuffers() const {
489     return mImpl.numClientBuffers();
490 }
491 
createNewBuffer()492 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
493     return mAllocate();
494 }
495 
496 // LinearInputBuffers
497 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)498 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
499     sp<Codec2Buffer> newBuffer = createNewBuffer();
500     if (newBuffer == nullptr) {
501         return false;
502     }
503     *index = mImpl.assignSlot(newBuffer);
504     *buffer = newBuffer;
505     return true;
506 }
507 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)508 bool LinearInputBuffers::releaseBuffer(
509         const sp<MediaCodecBuffer> &buffer,
510         std::shared_ptr<C2Buffer> *c2buffer,
511         bool release) {
512     return mImpl.releaseSlot(buffer, c2buffer, release);
513 }
514 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)515 bool LinearInputBuffers::expireComponentBuffer(
516         const std::shared_ptr<C2Buffer> &c2buffer) {
517     return mImpl.expireComponentBuffer(c2buffer);
518 }
519 
flush()520 void LinearInputBuffers::flush() {
521     // This is no-op by default unless we're in array mode where we need to keep
522     // track of the flushed work.
523     mImpl.flush();
524 }
525 
toArrayMode(size_t size)526 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
527     std::unique_ptr<InputBuffersArray> array(
528             new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
529     array->setPool(mPool);
530     array->setFormat(mFormat);
531     array->initialize(
532             mImpl,
533             size,
534             [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
535                 return Alloc(pool, format);
536             });
537     return std::move(array);
538 }
539 
numClientBuffers() const540 size_t LinearInputBuffers::numClientBuffers() const {
541     return mImpl.numClientBuffers();
542 }
543 
544 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)545 sp<Codec2Buffer> LinearInputBuffers::Alloc(
546         const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
547     int32_t capacity = kLinearBufferSize;
548     (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
549     if ((size_t)capacity > kMaxLinearBufferSize) {
550         ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
551         capacity = kMaxLinearBufferSize;
552     }
553 
554     // TODO: read usage from intf
555     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
556     std::shared_ptr<C2LinearBlock> block;
557 
558     c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
559     if (err != C2_OK) {
560         return nullptr;
561     }
562 
563     return LinearBlockBuffer::Allocate(format, block);
564 }
565 
createNewBuffer()566 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
567     return Alloc(mPool, mFormat);
568 }
569 
570 // EncryptedLinearInputBuffers
571 
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)572 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
573         bool secure,
574         const sp<MemoryDealer> &dealer,
575         const sp<ICrypto> &crypto,
576         int32_t heapSeqNum,
577         size_t capacity,
578         size_t numInputSlots,
579         const char *componentName, const char *name)
580     : LinearInputBuffers(componentName, name),
581       mUsage({0, 0}),
582       mDealer(dealer),
583       mCrypto(crypto),
584       mMemoryVector(new std::vector<Entry>){
585     if (secure) {
586         mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
587     } else {
588         mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
589     }
590     for (size_t i = 0; i < numInputSlots; ++i) {
591         sp<IMemory> memory = mDealer->allocate(capacity);
592         if (memory == nullptr) {
593             ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
594                   mName, i);
595             break;
596         }
597         mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
598     }
599 }
600 
toArrayMode(size_t size)601 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
602     std::unique_ptr<InputBuffersArray> array(
603             new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
604     array->setPool(mPool);
605     array->setFormat(mFormat);
606     array->initialize(
607             mImpl,
608             size,
609             [pool = mPool,
610              format = mFormat,
611              usage = mUsage,
612              memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
613                 return Alloc(pool, format, usage, memoryVector);
614             });
615     return std::move(array);
616 }
617 
618 
619 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)620 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
621         const std::shared_ptr<C2BlockPool> &pool,
622         const sp<AMessage> &format,
623         C2MemoryUsage usage,
624         const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
625     int32_t capacity = kLinearBufferSize;
626     (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
627     if ((size_t)capacity > kMaxLinearBufferSize) {
628         ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
629         capacity = kMaxLinearBufferSize;
630     }
631 
632     sp<IMemory> memory;
633     size_t slot = 0;
634     int32_t heapSeqNum = -1;
635     for (; slot < memoryVector->size(); ++slot) {
636         if (memoryVector->at(slot).block.expired()) {
637             memory = memoryVector->at(slot).memory;
638             heapSeqNum = memoryVector->at(slot).heapSeqNum;
639             break;
640         }
641     }
642     if (memory == nullptr) {
643         return nullptr;
644     }
645 
646     std::shared_ptr<C2LinearBlock> block;
647     c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
648     if (err != C2_OK || block == nullptr) {
649         return nullptr;
650     }
651 
652     memoryVector->at(slot).block = block;
653     return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
654 }
655 
createNewBuffer()656 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
657     // TODO: android_2020
658     return nullptr;
659 }
660 
661 // GraphicMetadataInputBuffers
662 
GraphicMetadataInputBuffers(const char * componentName,const char * name)663 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
664         const char *componentName, const char *name)
665     : InputBuffers(componentName, name),
666       mImpl(mName),
667       mStore(GetCodec2PlatformAllocatorStore()) { }
668 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)669 bool GraphicMetadataInputBuffers::requestNewBuffer(
670         size_t *index, sp<MediaCodecBuffer> *buffer) {
671     sp<Codec2Buffer> newBuffer = createNewBuffer();
672     if (newBuffer == nullptr) {
673         return false;
674     }
675     *index = mImpl.assignSlot(newBuffer);
676     *buffer = newBuffer;
677     return true;
678 }
679 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)680 bool GraphicMetadataInputBuffers::releaseBuffer(
681         const sp<MediaCodecBuffer> &buffer,
682         std::shared_ptr<C2Buffer> *c2buffer,
683         bool release) {
684     return mImpl.releaseSlot(buffer, c2buffer, release);
685 }
686 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)687 bool GraphicMetadataInputBuffers::expireComponentBuffer(
688         const std::shared_ptr<C2Buffer> &c2buffer) {
689     return mImpl.expireComponentBuffer(c2buffer);
690 }
691 
flush()692 void GraphicMetadataInputBuffers::flush() {
693     // This is no-op by default unless we're in array mode where we need to keep
694     // track of the flushed work.
695 }
696 
toArrayMode(size_t size)697 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
698         size_t size) {
699     std::shared_ptr<C2Allocator> alloc;
700     c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
701     if (err != C2_OK) {
702         return nullptr;
703     }
704     std::unique_ptr<InputBuffersArray> array(
705             new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
706     array->setPool(mPool);
707     array->setFormat(mFormat);
708     array->initialize(
709             mImpl,
710             size,
711             [format = mFormat, alloc]() -> sp<Codec2Buffer> {
712                 return new GraphicMetadataBuffer(format, alloc);
713             });
714     return std::move(array);
715 }
716 
numClientBuffers() const717 size_t GraphicMetadataInputBuffers::numClientBuffers() const {
718     return mImpl.numClientBuffers();
719 }
720 
createNewBuffer()721 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
722     std::shared_ptr<C2Allocator> alloc;
723     c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
724     if (err != C2_OK) {
725         return nullptr;
726     }
727     return new GraphicMetadataBuffer(mFormat, alloc);
728 }
729 
730 // GraphicInputBuffers
731 
GraphicInputBuffers(size_t numInputSlots,const char * componentName,const char * name)732 GraphicInputBuffers::GraphicInputBuffers(
733         size_t numInputSlots, const char *componentName, const char *name)
734     : InputBuffers(componentName, name),
735       mImpl(mName),
736       mLocalBufferPool(LocalBufferPool::Create(
737               kMaxLinearBufferSize * numInputSlots)) { }
738 
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)739 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
740     sp<Codec2Buffer> newBuffer = createNewBuffer();
741     if (newBuffer == nullptr) {
742         return false;
743     }
744     *index = mImpl.assignSlot(newBuffer);
745     handleImageData(newBuffer);
746     *buffer = newBuffer;
747     return true;
748 }
749 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)750 bool GraphicInputBuffers::releaseBuffer(
751         const sp<MediaCodecBuffer> &buffer,
752         std::shared_ptr<C2Buffer> *c2buffer,
753         bool release) {
754     return mImpl.releaseSlot(buffer, c2buffer, release);
755 }
756 
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)757 bool GraphicInputBuffers::expireComponentBuffer(
758         const std::shared_ptr<C2Buffer> &c2buffer) {
759     return mImpl.expireComponentBuffer(c2buffer);
760 }
761 
flush()762 void GraphicInputBuffers::flush() {
763     // This is no-op by default unless we're in array mode where we need to keep
764     // track of the flushed work.
765 }
766 
toArrayMode(size_t size)767 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
768     std::unique_ptr<InputBuffersArray> array(
769             new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
770     array->setPool(mPool);
771     array->setFormat(mFormat);
772     array->initialize(
773             mImpl,
774             size,
775             [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
776                 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
777                 return AllocateGraphicBuffer(
778                         pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
779             });
780     return std::move(array);
781 }
782 
numClientBuffers() const783 size_t GraphicInputBuffers::numClientBuffers() const {
784     return mImpl.numClientBuffers();
785 }
786 
createNewBuffer()787 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
788     // TODO: read usage from intf
789     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
790     return AllocateGraphicBuffer(
791             mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
792 }
793 
794 // OutputBuffersArray
795 
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)796 void OutputBuffersArray::initialize(
797         const FlexBuffersImpl &impl,
798         size_t minSize,
799         std::function<sp<Codec2Buffer>()> allocate) {
800     mAlloc = allocate;
801     mImpl.initialize(impl, minSize, allocate);
802 }
803 
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)804 status_t OutputBuffersArray::registerBuffer(
805         const std::shared_ptr<C2Buffer> &buffer,
806         size_t *index,
807         sp<MediaCodecBuffer> *clientBuffer) {
808     sp<Codec2Buffer> c2Buffer;
809     status_t err = mImpl.grabBuffer(
810             index,
811             &c2Buffer,
812             [buffer](const sp<Codec2Buffer> &clientBuffer) {
813                 return clientBuffer->canCopy(buffer);
814             });
815     if (err == WOULD_BLOCK) {
816         ALOGV("[%s] buffers temporarily not available", mName);
817         return err;
818     } else if (err != OK) {
819         ALOGD("[%s] grabBuffer failed: %d", mName, err);
820         return err;
821     }
822     c2Buffer->setFormat(mFormat);
823     if (!c2Buffer->copy(buffer)) {
824         ALOGD("[%s] copy buffer failed", mName);
825         return WOULD_BLOCK;
826     }
827     submit(c2Buffer);
828     handleImageData(c2Buffer);
829     *clientBuffer = c2Buffer;
830     ALOGV("[%s] grabbed buffer %zu", mName, *index);
831     return OK;
832 }
833 
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)834 status_t OutputBuffersArray::registerCsd(
835         const C2StreamInitDataInfo::output *csd,
836         size_t *index,
837         sp<MediaCodecBuffer> *clientBuffer) {
838     sp<Codec2Buffer> c2Buffer;
839     status_t err = mImpl.grabBuffer(
840             index,
841             &c2Buffer,
842             [csd](const sp<Codec2Buffer> &clientBuffer) {
843                 return clientBuffer->base() != nullptr
844                         && clientBuffer->capacity() >= csd->flexCount();
845             });
846     if (err != OK) {
847         return err;
848     }
849     memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
850     c2Buffer->setRange(0, csd->flexCount());
851     c2Buffer->setFormat(mFormat);
852     *clientBuffer = c2Buffer;
853     return OK;
854 }
855 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)856 bool OutputBuffersArray::releaseBuffer(
857         const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
858     return mImpl.returnBuffer(buffer, c2buffer, true);
859 }
860 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)861 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
862     (void)flushedWork;
863     mImpl.flush();
864     if (mSkipCutBuffer != nullptr) {
865         mSkipCutBuffer->clear();
866     }
867 }
868 
getArray(Vector<sp<MediaCodecBuffer>> * array) const869 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
870     mImpl.getArray(array);
871 }
872 
numClientBuffers() const873 size_t OutputBuffersArray::numClientBuffers() const {
874     return mImpl.numClientBuffers();
875 }
876 
realloc(const std::shared_ptr<C2Buffer> & c2buffer)877 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
878     switch (c2buffer->data().type()) {
879         case C2BufferData::LINEAR: {
880             uint32_t size = kLinearBufferSize;
881             const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
882             const uint32_t block_size = linear_blocks.front().size();
883             if (block_size < kMaxLinearBufferSize / 2) {
884                 size = block_size * 2;
885             } else {
886                 size = kMaxLinearBufferSize;
887             }
888             mAlloc = [format = mFormat, size] {
889                 return new LocalLinearBuffer(format, new ABuffer(size));
890             };
891             ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
892             break;
893         }
894 
895         case C2BufferData::GRAPHIC: {
896             // This is only called for RawGraphicOutputBuffers.
897             mAlloc = [format = mFormat,
898                       lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
899                 return ConstGraphicBlockBuffer::AllocateEmpty(
900                         format,
901                         [lbp](size_t capacity) {
902                             return lbp->newBuffer(capacity);
903                         });
904             };
905             ALOGD("[%s] reallocating with graphic buffer: format = %s",
906                   mName, mFormat->debugString().c_str());
907             break;
908         }
909 
910         case C2BufferData::INVALID:         [[fallthrough]];
911         case C2BufferData::LINEAR_CHUNKS:   [[fallthrough]];
912         case C2BufferData::GRAPHIC_CHUNKS:  [[fallthrough]];
913         default:
914             ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
915             return;
916     }
917     mImpl.realloc(mAlloc);
918 }
919 
grow(size_t newSize)920 void OutputBuffersArray::grow(size_t newSize) {
921     mImpl.grow(newSize, mAlloc);
922 }
923 
924 // FlexOutputBuffers
925 
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)926 status_t FlexOutputBuffers::registerBuffer(
927         const std::shared_ptr<C2Buffer> &buffer,
928         size_t *index,
929         sp<MediaCodecBuffer> *clientBuffer) {
930     sp<Codec2Buffer> newBuffer = wrap(buffer);
931     if (newBuffer == nullptr) {
932         return NO_MEMORY;
933     }
934     newBuffer->setFormat(mFormat);
935     *index = mImpl.assignSlot(newBuffer);
936     handleImageData(newBuffer);
937     *clientBuffer = newBuffer;
938     ALOGV("[%s] registered buffer %zu", mName, *index);
939     return OK;
940 }
941 
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)942 status_t FlexOutputBuffers::registerCsd(
943         const C2StreamInitDataInfo::output *csd,
944         size_t *index,
945         sp<MediaCodecBuffer> *clientBuffer) {
946     sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
947             mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
948     *index = mImpl.assignSlot(newBuffer);
949     *clientBuffer = newBuffer;
950     return OK;
951 }
952 
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)953 bool FlexOutputBuffers::releaseBuffer(
954         const sp<MediaCodecBuffer> &buffer,
955         std::shared_ptr<C2Buffer> *c2buffer) {
956     return mImpl.releaseSlot(buffer, c2buffer, true);
957 }
958 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)959 void FlexOutputBuffers::flush(
960         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
961     (void) flushedWork;
962     // This is no-op by default unless we're in array mode where we need to keep
963     // track of the flushed work.
964 }
965 
toArrayMode(size_t size)966 std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
967     std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
968     array->setFormat(mFormat);
969     array->transferSkipCutBuffer(mSkipCutBuffer);
970     std::function<sp<Codec2Buffer>()> alloc = getAlloc();
971     array->initialize(mImpl, size, alloc);
972     return std::move(array);
973 }
974 
numClientBuffers() const975 size_t FlexOutputBuffers::numClientBuffers() const {
976     return mImpl.numClientBuffers();
977 }
978 
979 // LinearOutputBuffers
980 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)981 void LinearOutputBuffers::flush(
982         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
983     if (mSkipCutBuffer != nullptr) {
984         mSkipCutBuffer->clear();
985     }
986     FlexOutputBuffers::flush(flushedWork);
987 }
988 
wrap(const std::shared_ptr<C2Buffer> & buffer)989 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
990     if (buffer == nullptr) {
991         ALOGV("[%s] using a dummy buffer", mName);
992         return new LocalLinearBuffer(mFormat, new ABuffer(0));
993     }
994     if (buffer->data().type() != C2BufferData::LINEAR) {
995         ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
996         // We expect linear output buffers from the component.
997         return nullptr;
998     }
999     if (buffer->data().linearBlocks().size() != 1u) {
1000         ALOGV("[%s] no linear buffers", mName);
1001         // We expect one and only one linear block from the component.
1002         return nullptr;
1003     }
1004     sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1005     if (clientBuffer == nullptr) {
1006         ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1007         return nullptr;
1008     }
1009     submit(clientBuffer);
1010     return clientBuffer;
1011 }
1012 
getAlloc()1013 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1014     return [format = mFormat]{
1015         // TODO: proper max output size
1016         return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1017     };
1018 }
1019 
1020 // GraphicOutputBuffers
1021 
wrap(const std::shared_ptr<C2Buffer> & buffer)1022 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1023     return new DummyContainerBuffer(mFormat, buffer);
1024 }
1025 
getAlloc()1026 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1027     return [format = mFormat]{
1028         return new DummyContainerBuffer(format);
1029     };
1030 }
1031 
1032 // RawGraphicOutputBuffers
1033 
RawGraphicOutputBuffers(size_t numOutputSlots,const char * componentName,const char * name)1034 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1035         size_t numOutputSlots, const char *componentName, const char *name)
1036     : FlexOutputBuffers(componentName, name),
1037       mLocalBufferPool(LocalBufferPool::Create(
1038               kMaxLinearBufferSize * numOutputSlots)) { }
1039 
wrap(const std::shared_ptr<C2Buffer> & buffer)1040 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1041     if (buffer == nullptr) {
1042         sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
1043                 mFormat,
1044                 [lbp = mLocalBufferPool](size_t capacity) {
1045                     return lbp->newBuffer(capacity);
1046                 });
1047         if (c2buffer == nullptr) {
1048             ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
1049             return nullptr;
1050         }
1051         c2buffer->setRange(0, 0);
1052         return c2buffer;
1053     } else {
1054         return ConstGraphicBlockBuffer::Allocate(
1055                 mFormat,
1056                 buffer,
1057                 [lbp = mLocalBufferPool](size_t capacity) {
1058                     return lbp->newBuffer(capacity);
1059                 });
1060     }
1061 }
1062 
getAlloc()1063 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1064     return [format = mFormat, lbp = mLocalBufferPool]{
1065         return ConstGraphicBlockBuffer::AllocateEmpty(
1066                 format,
1067                 [lbp](size_t capacity) {
1068                     return lbp->newBuffer(capacity);
1069                 });
1070     };
1071 }
1072 
1073 }  // namespace android
1074