Home | History | Annotate | Download | only in sfplugin
      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 
     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 
     64 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
     65     CHECK(format != nullptr);
     66     mFormat = format;
     67 }
     68 
     69 sp<AMessage> CCodecBuffers::dupFormat() {
     70     return mFormat != nullptr ? mFormat->dup() : nullptr;
     71 }
     72 
     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 
    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 
    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 
    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 
    145 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
    146     if (mSkipCutBuffer != nullptr) {
    147         mSkipCutBuffer->submit(buffer);
    148     }
    149 }
    150 
    151 void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
    152     mSkipCutBuffer = scb;
    153 }
    154 
    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 
    167 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
    168     return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
    169 }
    170 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    280 void FlexBuffersImpl::flush() {
    281     ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
    282     mBuffers.clear();
    283 }
    284 
    285 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 
    293 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 
    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 
    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 
    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 
    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 
    405 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 
    412 void BuffersArrayImpl::flush() {
    413     for (Entry &entry : mBuffers) {
    414         entry.ownedByClient = false;
    415     }
    416 }
    417 
    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 
    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 
    434 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 
    442 size_t BuffersArrayImpl::arraySize() const {
    443     return mBuffers.size();
    444 }
    445 
    446 // InputBuffersArray
    447 
    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 
    456 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
    457     mImpl.getArray(array);
    458 }
    459 
    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 
    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 
    479 bool InputBuffersArray::expireComponentBuffer(
    480         const std::shared_ptr<C2Buffer> &c2buffer) {
    481     return mImpl.expireComponentBuffer(c2buffer);
    482 }
    483 
    484 void InputBuffersArray::flush() {
    485     mImpl.flush();
    486 }
    487 
    488 size_t InputBuffersArray::numClientBuffers() const {
    489     return mImpl.numClientBuffers();
    490 }
    491 
    492 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
    493     return mAllocate();
    494 }
    495 
    496 // LinearInputBuffers
    497 
    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 
    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 
    515 bool LinearInputBuffers::expireComponentBuffer(
    516         const std::shared_ptr<C2Buffer> &c2buffer) {
    517     return mImpl.expireComponentBuffer(c2buffer);
    518 }
    519 
    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 
    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 
    540 size_t LinearInputBuffers::numClientBuffers() const {
    541     return mImpl.numClientBuffers();
    542 }
    543 
    544 // static
    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 
    566 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
    567     return Alloc(mPool, mFormat);
    568 }
    569 
    570 // EncryptedLinearInputBuffers
    571 
    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 
    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
    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 
    656 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
    657     // TODO: android_2020
    658     return nullptr;
    659 }
    660 
    661 // GraphicMetadataInputBuffers
    662 
    663 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
    664         const char *componentName, const char *name)
    665     : InputBuffers(componentName, name),
    666       mImpl(mName),
    667       mStore(GetCodec2PlatformAllocatorStore()) { }
    668 
    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 
    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 
    687 bool GraphicMetadataInputBuffers::expireComponentBuffer(
    688         const std::shared_ptr<C2Buffer> &c2buffer) {
    689     return mImpl.expireComponentBuffer(c2buffer);
    690 }
    691 
    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 
    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 
    717 size_t GraphicMetadataInputBuffers::numClientBuffers() const {
    718     return mImpl.numClientBuffers();
    719 }
    720 
    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 
    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 
    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 
    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 
    757 bool GraphicInputBuffers::expireComponentBuffer(
    758         const std::shared_ptr<C2Buffer> &c2buffer) {
    759     return mImpl.expireComponentBuffer(c2buffer);
    760 }
    761 
    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 
    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 
    783 size_t GraphicInputBuffers::numClientBuffers() const {
    784     return mImpl.numClientBuffers();
    785 }
    786 
    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 
    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 
    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 
    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 
    856 bool OutputBuffersArray::releaseBuffer(
    857         const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
    858     return mImpl.returnBuffer(buffer, c2buffer, true);
    859 }
    860 
    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 
    869 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
    870     mImpl.getArray(array);
    871 }
    872 
    873 size_t OutputBuffersArray::numClientBuffers() const {
    874     return mImpl.numClientBuffers();
    875 }
    876 
    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 C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
    882             if (block.size() < kMaxLinearBufferSize / 2) {
    883                 size = block.size() * 2;
    884             } else {
    885                 size = kMaxLinearBufferSize;
    886             }
    887             mAlloc = [format = mFormat, size] {
    888                 return new LocalLinearBuffer(format, new ABuffer(size));
    889             };
    890             ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
    891             break;
    892         }
    893 
    894         case C2BufferData::GRAPHIC: {
    895             // This is only called for RawGraphicOutputBuffers.
    896             mAlloc = [format = mFormat,
    897                       lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
    898                 return ConstGraphicBlockBuffer::AllocateEmpty(
    899                         format,
    900                         [lbp](size_t capacity) {
    901                             return lbp->newBuffer(capacity);
    902                         });
    903             };
    904             ALOGD("[%s] reallocating with graphic buffer: format = %s",
    905                   mName, mFormat->debugString().c_str());
    906             break;
    907         }
    908 
    909         case C2BufferData::INVALID:         [[fallthrough]];
    910         case C2BufferData::LINEAR_CHUNKS:   [[fallthrough]];
    911         case C2BufferData::GRAPHIC_CHUNKS:  [[fallthrough]];
    912         default:
    913             ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
    914             return;
    915     }
    916     mImpl.realloc(mAlloc);
    917 }
    918 
    919 void OutputBuffersArray::grow(size_t newSize) {
    920     mImpl.grow(newSize, mAlloc);
    921 }
    922 
    923 // FlexOutputBuffers
    924 
    925 status_t FlexOutputBuffers::registerBuffer(
    926         const std::shared_ptr<C2Buffer> &buffer,
    927         size_t *index,
    928         sp<MediaCodecBuffer> *clientBuffer) {
    929     sp<Codec2Buffer> newBuffer = wrap(buffer);
    930     if (newBuffer == nullptr) {
    931         return NO_MEMORY;
    932     }
    933     newBuffer->setFormat(mFormat);
    934     *index = mImpl.assignSlot(newBuffer);
    935     handleImageData(newBuffer);
    936     *clientBuffer = newBuffer;
    937     ALOGV("[%s] registered buffer %zu", mName, *index);
    938     return OK;
    939 }
    940 
    941 status_t FlexOutputBuffers::registerCsd(
    942         const C2StreamInitDataInfo::output *csd,
    943         size_t *index,
    944         sp<MediaCodecBuffer> *clientBuffer) {
    945     sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
    946             mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
    947     *index = mImpl.assignSlot(newBuffer);
    948     *clientBuffer = newBuffer;
    949     return OK;
    950 }
    951 
    952 bool FlexOutputBuffers::releaseBuffer(
    953         const sp<MediaCodecBuffer> &buffer,
    954         std::shared_ptr<C2Buffer> *c2buffer) {
    955     return mImpl.releaseSlot(buffer, c2buffer, true);
    956 }
    957 
    958 void FlexOutputBuffers::flush(
    959         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
    960     (void) flushedWork;
    961     // This is no-op by default unless we're in array mode where we need to keep
    962     // track of the flushed work.
    963 }
    964 
    965 std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
    966     std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
    967     array->setFormat(mFormat);
    968     array->transferSkipCutBuffer(mSkipCutBuffer);
    969     std::function<sp<Codec2Buffer>()> alloc = getAlloc();
    970     array->initialize(mImpl, size, alloc);
    971     return std::move(array);
    972 }
    973 
    974 size_t FlexOutputBuffers::numClientBuffers() const {
    975     return mImpl.numClientBuffers();
    976 }
    977 
    978 // LinearOutputBuffers
    979 
    980 void LinearOutputBuffers::flush(
    981         const std::list<std::unique_ptr<C2Work>> &flushedWork) {
    982     if (mSkipCutBuffer != nullptr) {
    983         mSkipCutBuffer->clear();
    984     }
    985     FlexOutputBuffers::flush(flushedWork);
    986 }
    987 
    988 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
    989     if (buffer == nullptr) {
    990         ALOGV("[%s] using a dummy buffer", mName);
    991         return new LocalLinearBuffer(mFormat, new ABuffer(0));
    992     }
    993     if (buffer->data().type() != C2BufferData::LINEAR) {
    994         ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
    995         // We expect linear output buffers from the component.
    996         return nullptr;
    997     }
    998     if (buffer->data().linearBlocks().size() != 1u) {
    999         ALOGV("[%s] no linear buffers", mName);
   1000         // We expect one and only one linear block from the component.
   1001         return nullptr;
   1002     }
   1003     sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
   1004     if (clientBuffer == nullptr) {
   1005         ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
   1006         return nullptr;
   1007     }
   1008     submit(clientBuffer);
   1009     return clientBuffer;
   1010 }
   1011 
   1012 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
   1013     return [format = mFormat]{
   1014         // TODO: proper max output size
   1015         return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
   1016     };
   1017 }
   1018 
   1019 // GraphicOutputBuffers
   1020 
   1021 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
   1022     return new DummyContainerBuffer(mFormat, buffer);
   1023 }
   1024 
   1025 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
   1026     return [format = mFormat]{
   1027         return new DummyContainerBuffer(format);
   1028     };
   1029 }
   1030 
   1031 // RawGraphicOutputBuffers
   1032 
   1033 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
   1034         size_t numOutputSlots, const char *componentName, const char *name)
   1035     : FlexOutputBuffers(componentName, name),
   1036       mLocalBufferPool(LocalBufferPool::Create(
   1037               kMaxLinearBufferSize * numOutputSlots)) { }
   1038 
   1039 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
   1040     if (buffer == nullptr) {
   1041         sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
   1042                 mFormat,
   1043                 [lbp = mLocalBufferPool](size_t capacity) {
   1044                     return lbp->newBuffer(capacity);
   1045                 });
   1046         if (c2buffer == nullptr) {
   1047             ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
   1048             return nullptr;
   1049         }
   1050         c2buffer->setRange(0, 0);
   1051         return c2buffer;
   1052     } else {
   1053         return ConstGraphicBlockBuffer::Allocate(
   1054                 mFormat,
   1055                 buffer,
   1056                 [lbp = mLocalBufferPool](size_t capacity) {
   1057                     return lbp->newBuffer(capacity);
   1058                 });
   1059     }
   1060 }
   1061 
   1062 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
   1063     return [format = mFormat, lbp = mLocalBufferPool]{
   1064         return ConstGraphicBlockBuffer::AllocateEmpty(
   1065                 format,
   1066                 [lbp](size_t capacity) {
   1067                     return lbp->newBuffer(capacity);
   1068                 });
   1069     };
   1070 }
   1071 
   1072 }  // namespace android
   1073