NuPlayer源码分析(三)视频帧处理分析及部分同步机制分析

一、引言:
在上一篇博客中,分析了音频部分的buffer处理。nuplayer在音视频buffer的处理上共用了很多代码,这篇博客将直接从差异上开始分析,nuplayer的同步机制整体来说,和exoplayer大同小异,都是基于码流中的pts和系统时间来进行预估,并结合垂直同步信号时间点来确定最终的送显时间。不同点在于nuplayer对于送显时间的校准太过复杂,很多都看不懂,但是如果不重点关注校准的内容的话,其他部分还是很好理解的。

二、确定视频帧送显时间:
音视频的buffer处理函数很多都共用,我们直接定位到NuPlayerRenderer.cpppostDrainVideoQueue_l函数:

void NuPlayer::Renderer::postDrainVideoQueue_l() {
   
    if (mDrainVideoQueuePending
            || mSyncQueues
            || (mPaused && mVideoSampleReceived)) {
   
        return;
    }

    if (mVideoQueue.empty()) {
   
        return;
    }

    QueueEntry &entry = *mVideoQueue.begin();

	/* 1.创建kWhatDrainVideoQueue消息用于后续投递处理 */
    sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
    msg->setInt32("generation", mVideoQueueGeneration);

    if (entry.mBuffer == NULL) {
   
        // EOS doesn't carry a timestamp.
        msg->post();
        mDrainVideoQueuePending = true;
        return;
    }

    int64_t delayUs;
    int64_t nowUs = ALooper::GetNowUs();
    int64_t realTimeUs;
    if (mFlags & FLAG_REAL_TIME) {
   
        int64_t mediaTimeUs;
        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
        realTimeUs = mediaTimeUs;
    } else {
   
        int64_t mediaTimeUs;
        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));

        if (mAnchorTimeMediaUs < 0) {
   
            setAnchorTime(mediaTimeUs, nowUs);
            mPausePositionMediaTimeUs = mediaTimeUs;
            mAnchorMaxMediaUs = mediaTimeUs;
            realTimeUs = nowUs;
        } else {
   
            /* 2.获取当前帧送显时间 */
            realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
        }
        if (!mHasAudio) {
   
            mAnchorMaxMediaUs = mediaTimeUs + 100000; // smooth out videos >= 10fps
        }

        // Heuristics to handle situation when media time changed without a
        // discontinuity. If we have not drained an audio buffer that was
        // received after this buffer, repost in 10 msec. Otherwise repost
        // in 500 msec.
        /* 当前帧渲染时间差 = 当前帧时间戳 - 当前帧送显时间 */
        /* 当前帧渲染时间差 = 当前帧送显时间 - 系统时间 */        
        delayUs = realTimeUs - nowUs;
        if (delayUs > 500000) {
   
            int64_t postDelayUs = 500000;
            if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
   
                postDelayUs = 10000;
            }
            msg->setWhat(kWhatPostDrainVideoQueue);
            msg->post(postDelayUs);
            mVideoScheduler->restart();
            ALOGI("possible video time jump of %dms, retrying in %dms",
                    (int)(delayUs / 1000), (int)(postDelayUs / 1000));
            mDrainVideoQueuePending = true;
            return;
        }
    }

    /* 3.校准送显时间 */
    realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值