Android CCodec Codec2 (二三)C2BufferQueueBlockPool - Ⅱ

上一篇文章对一些前置内容进行了介绍,这篇文章我们将继续阅读C2BufferQueueBlockPool的buffer分配相关内容。

1、fetchGraphicBlock

正式进入代码学习之前,还是先看下UML类图:

请添加图片描述

C2BufferQueueBlockPool::Impl的fetchGraphicBlock实现如下:

c2_status_t fetchGraphicBlock(
        uint32_t width,
        uint32_t height,
        uint32_t format,
        C2MemoryUsage usage,
        std::shared_ptr<C2GraphicBlock> *block /* nonnull */,
        C2Fence *fence) {
    block->reset();

    static int kMaxIgbpRetryDelayUs = 10000;

    std::unique_lock<std::mutex> lock(mMutex);
    // 1. 检查是否有效
    if (mInvalidated) {
        return C2_BAD_STATE;
    }
    // 2. 
    if (mLastDqLogTs == 0) {
        mLastDqLogTs = getTimestampNow();
    } else {
        int64_t now = getTimestampNow();
        if (now >= mLastDqLogTs + 5000000) {
            if (now >= mLastDqTs + 1000000 || mDqFailure > 5) {
                ALOGW("last successful dequeue was %lld us ago, "
                        "%zu consecutive failures",
                        (long long)(now - mLastDqTs), mDqFailure);
            }
            mLastDqLogTs = now;
        }
    }
    // 3. 删除mProducerId == 0的情况
    // 4.
    c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block, fence);
    // 5. 检查返回值
    if (status == C2_BLOCKING) {
        lock.unlock();
        if (!fence) {
            // in order not to drain cpu from component's spinning
            ::usleep(kMaxIgbpRetryDelayUs);
        }
    }
    return status;
}
  1. 检查mInvalidated是否为true,如果是则直接返回C2_BAD_STATE;使用者调用invalidate后将无法再分配buffer;
  2. fetchGraphicBlock添加log打印机制,每隔5s会进入if语句,如果超过1s没有获取output buffer或者连续获取失败5次就打印log;
  3. 移除mProducerId == 0的情况,因为有surface的情况下该条件不会成立;
  4. 进入fetchFromIgbp_l方法获取block。
  5. 检查返回值,如果返回C2_BLOCKING且fence为NULL,进入sleep;

1.1 fetchFromIgbp_l(一)

fetchFromIgbp_l代码比较长,我们分段阅读:

C2AndroidMemoryUsage androidUsage = usage;
status_t status{};
int slot{};
bool bufferNeedsReallocation{};
sp<Fence> fence = new Fence();
// 拿到同步变量
C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem(): nullptr;
{ // Call dequeueBuffer().
    c2_status_t c2Status;
    if (syncVar) {
        uint32_t waitId;
        // 1. 加锁,调用isDequeueableLocked判断当前是否有buffer可以dequeue
        syncVar->lock();
        if (!syncVar->isDequeueableLocked(&waitId)) {
            syncVar->unlock();
            // 2. 如果返回false,说明当前producer无可用buffer,创建C2Fence并返回C2_BLOCKING
            if (c2Fence) {
                *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
            }
            return C2_BLOCKING;
        }
        // 3. 如果当前同步状态不是STATUS_ACTIVE,此时不能获取buffer,返回C2_BLOCKING
        if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_ACTIVE) {
            waitId = syncVar->getWaitIdLocked();
            syncVar->unlock();
            if (c2Fence) {
                *c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
            }
            return C2_BLOCKING;
        }
        // 4. 到这说明producer有可用buffer,修改mCurDequeueCount,解锁
        syncVar->notifyDequeuedLocked();
        syncVar->unlock();
        // 5. 调用dequeueBuffer,从producer获取buffer
        c2Status = dequeueBuffer(width, height, format, androidUsage,
                        &slot, &bufferNeedsReallocation, &fence);
        // 6. 如果获取失败需要重新修改mCurDequeueCount
        if (c2Status != C2_OK) {
            syncVar->lock();
            syncVar->notifyQueuedLocked();
            syncVar->unlock();
        }
    } else {
        c2Status = dequeueBuffer(width, height, format, usage,
                        &slot, &bufferNeedsReallocation, &fence);
    }
    if (c2Status != C2_OK) {
        return c2Status;
    }
    // 7. 刷新debug flag
    mDqFailure = 0;
    mLastDqTs = getTimestampNow();  
}

上述代码的主要目的是调用IGraphicBufferProducer::dequeueBuffer方法,从NativeWindow中获取一块buffer。在真正获取buffer之前,会检查同步变量C2SyncVariables的状态:

  • 如果isDequeueableLocked返回true,说明producer中有空闲buffer,否则说明buffer已经全部dequeue出来;
  • 如果getSyncStatusLocked返回值不等于STATUS_ACTIVE,说明当前producer还未配置完成,也有可能当前正处于切换surface的状态,这些状态下是不能获取output buffer的;

接下来进入到dequeueBuffer中,代码不长但是HIDL调用让人难受:

c2_status_t dequeueBuffer(
        uint32_t width,
        uint32_t height,
        uint32_t format,
        C2AndroidMemoryUsage androidUsage,
        int *slot, bool *needsRealloc, sp<Fence> *fence) {
    status_t status{}; 
    using Input = HGraphicBufferProducer::DequeueBufferInput;
    using Output = HGraphicBufferProducer::DequeueBufferOutput;
    // 1. 获取output buffer
    Return<void> transResult = mProducer->dequeueBuffer(
            Input{
                width,
                height,
                format,
                androidUsage.asGrallocUsage()},
            [&status, slot, needsRealloc,
                fence](HStatus hStatus,
                        int32_t hSlot,
                        Output const& hOutput) {
                *slot = static_cast<int>(hSlot);
                if (!h2b(hStatus, &status) ||
                        !h2b(hOutput.fence, fence)) {
                    status = ::android::BAD_VALUE;
                } else {
                    *needsRealloc =
                            hOutput.bufferNeedsReallocation;
                }
            });
    // 2. 检查返回值
    if (!transResult.isOk() || status != android::OK) {
        if (transResult.isOk()) {
            ++mDqFailure;
            if (status == android::INVALID_OPERATION ||
                status == android::TIMED_OUT ||
                status == android::WOULD_BLOCK) {
                // Dequeue buffer is blocked temporarily. Retrying is
                // required.
                return C2_BLOCKING;
            }
        }
        ALOGD("cannot dequeue buffer %d", status);
        return C2_BAD_VALUE;
    }
    return C2_OK;
}

2、小结


原文阅读:
Android Codec2(二三)C2BufferQueueBlockPool - Ⅱ

扫描下方二维码,关注公众号《青山渺渺》阅读音视频开发内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值