NuPlayer源码分析(四)NuPlayer在Android Q与Android 5.1版本上的差异对比

一、引言:
因为之前方便本地调试,所以对于nuplayer的分析是基于Android5.1版本的,在熟悉了整个架构之后,在AndroidQ版本上对nuplayer的所有流程做了一个分析,发现变动不是特别大,主要体现在三个方面:

1.将5.1版本用于协调解码及渲染的主动循环改为了MediaCodec的消息回调方式;
2.handleAnInputBuffer和handleAnOutputBuffer均变为了MediaCodec的消息回调方式;
3.修正了视频帧校准的bug;

二、消息回调的分析:
AndroidQ版本onConfigure函数有如下代码片段:

onConfigure@NuPlayerDecoder.cpp:
void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
    
    
	...
    sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
    mCodec->setCallback(reply);
    ...
}

看下MediaCodec中的setCallback函数实现:

status_t MediaCodec::setCallback(const sp<AMessage> &callback) {
    
    
    sp<AMessage> msg = new AMessage(kWhatSetCallback, this);
    msg->setMessage("callback", callback);

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

这里会将传入的kWhatCodecNotify消息写入到kWhatSetCallback中,看下kWhatSetCallback的消息处理:

 case kWhatSetCallback:
 {
    
    
     uint32_t replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));

     if (mState == UNINITIALIZED
             || mState == INITIALIZING
             || isExecuting()) {
    
    
         // callback can't be set after codec is executing,
         // or before it's initialized (as the callback
         // will be cleared when it goes to INITIALIZED)
         PostReplyWithError(replyID, INVALID_OPERATION);
         break;
     }

     sp<AMessage> callback;
     CHECK(msg->findMessage("callback", &callback));

	 /* 保存kWhatCodecNotify这个消息 */
     mCallback = callback;

     if (mCallback != NULL) {
    
    
         ALOGI("MediaCodec will operate in async mode");
         mFlags |= kFlagIsAsync;
     } else {
    
    
         mFlags &= ~kFlagIsAsync;
     }

     sp<AMessage> response = new AMessage;
     response->postReply(replyID);
     break;
 }

我们可以看到,onConfigure函数会将kWhatCodecNotify这个消息传入到MediaCodec中,当有可用的输入输出buffer的时候,OMX会调用MediaCodec的
onInputBufferAvailableonOutputBufferAvailable函数,将这个消息发出来:

void MediaCodec::onInputBufferAvailable() {
    
    
    int32_t index;
    while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) {
    
    
    	/* 深拷贝该消息 */
        sp<AMessage> msg = mCallback->dup();
        /* 注明是处理input/output */
        msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
        msg->setInt32("index", index);
        msg->post();
    }
}

NuPlayerDecoder.cpp对该消息的处理就会去调用handleAnInputBufferhandleAnInputBuffer了。

三、同步校准的修改:
5.1版本的代码,会在送显之前去校准同步时间点,结果到了送显的时候,并没有用这个值,因此白校准了,但是AndroidQ上我看逻辑就改过来了,在真正要送显的时候再去校准的:

onDrainVideoQueue@NuPlayerRenderer.cpp:
void NuPlayer::Renderer::onDrainVideoQueue() {
    
    
	...
	/* 1.获得预估送显时间 */
	realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
	...
	/* 2.校准送显时间 */
	realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
	...
}

四、AndroidQ版本逻辑:
在这里插入图片描述
逻辑调用图上除了最后处理解码和渲染是使用的消息机制,其他没有区别;
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/achina2011jy/article/details/113992018