Android MediaCodec加快解码和渲染处理方案及其源码分析

此处直接根据NDK实现来源码分析描述问题

问题描述和原理分析:

在我们直接使用MediaCodec进行解码和渲染时,一般情况下大家可以都习惯性在同一个线程中完成MediaCodec的解码和渲染,其实际我们应该拆分成两部分来处理,将解码和渲染放入不同线程完成,如此就会加快解码和渲染,其实现原理是,同一个线程中,解码和渲染将会被互相影响,而渲染是有一个Fence栅栏Buffer标记,可以简单理解为VSync屏幕刷新周期信号,若是60fps则VSync将会在16.67ms通知屏幕刷新信号一次,因此若在调用MediaCodec的渲染接口【AMediaCodec_releaseOutputBuffer】时(java层MediaCodec同理),将会在buffer处理放入Surface时被Fence栅栏wait。

因此若放在不同线程,那么将不会相互影响,即解码和渲染都将会被加快。
先写结论:
软解码时将会被阻塞渲染,而硬解码时将会是异步直接归还BUffer给Surface,但是本文要讨论的是,解码器分为了输入队列和输出队列,我们应该将输入队列和输出队列分两个线程进行解码,原因是输出队列可能会多次执行即一个输入Buffer可能会在收到多次输出Buffer才结束当前帧解码完成,另外若是硬解码器则可以将输出队列和渲染操作放入同一个线程,如此将会加快解码和渲染。

源码分析:

// [frameworks/av/media/ndk/NdkMediaCodec.cpp]
EXPORT
media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
   
    if (render) {
   
    	// 请求渲染
        return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
    } else {
   
        return translate_error(mData->mCodec->releaseOutputBuffer(idx));
    }
}

renderOutputBufferAndRelease实现:
注意该方法调用是同步调用,即会被阻塞的调用

// [frameworks/av/media/libstagefright/MediaCodec.cpp]
status_t MediaCodec::renderOutputBufferAndRelease(size_t index) {
   
    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
    msg->setSize("index", index);
    msg->setInt32("render", true);

    sp<AMessage> response;
    return PostAndAwaitResponse(msg, &response);
}

接收渲染事件处理

// [frameworks/av/media/libstagefright/MediaCodec.cpp]
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
   
    switch (msg->what()) {
   
        case kWhatReleaseOutputBuffer:
        {
   
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (!isExecuting
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值