Nuplayer 音视频同步学习笔记

目录

1. 处理解码之后的数据

(1) handleAnOutputBuffer

(2). queueBuffer 

2. AudioBuffer的处理

(1) postDrainAudioQueue_l

(2) onDrainAudioQueue

3. Video Buffer的处理

(1) postDrainVideoQueue

(2) onDrainVideoQueue

4. AVsync Audio更新锚点时间

(1) AVsync原理

(2) Audi如何更新锚点

5. AVsync Video 获取显示的时间(系统时间)

(1) nowMediaUs 当前播放媒体时间

(2) outRealUs Buffer的显示时间


1. 处理解码之后的数据

(1) handleAnOutputBuffer

    NuPlayerDecoder调用handleAnOutputBuffer处理解码之后的音视频数据.  函数最终会调用NuPlayerDecoderRenderer::queueBuffer处理这个Buffer

bool NuPlayer::Decoder::handleAnOutputBuffer(size_t index, size_t offset, size_t size, 
                                             int64_t timeUs, int32_t flags) {
    sp<MediaCodecBuffer> buffer;
    //根据Index从MediaCodec获取Buffer
    mCodec->getOutputBuffer(index, &buffer);
    mOutputBuffers.editItemAt(index) = buffer;
    // 把offset size timeUs信息添加到buffer中
    // 其中timeUs是buffer的媒体时间(Buffer在媒体文件的位置)
    buffer->setRange(offset, size);
    buffer->meta()->clear();
    buffer->meta()->setInt64("timeUs", timeUs);
    // 创建一个消息kWhatRenderBuffer, 消息会被传入到NuplayerRenderer,
    // 当Buffer被Renderer处理完成后,就会发送这个消息消息
    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
    reply->setSize("buffer-ix", index);
    reply->setInt32("generation", mBufferGeneration);

    // 调用NuplayerRenderer 的 queueBuffer
    mRenderer->queueBuffer(mIsAudio, buffer, reply);

(2). queueBuffer 

    把音视频的buffer添加到Render的队列 mAudioQueue(audio) mVideoQueue(!audio)
    <1> queueBuffer发送消息kWhatQueueBuffer调用Renderer::onQueueBuffer

void NuPlayer::Renderer::queueBuffer(bool audio, const sp<MediaCodecBuffer> &buffer, const sp<AMessage> &notifyConsumed) {
    int64_t mediaTimeUs = -1;
    buffer->meta()->findInt64("timeUs", &mediaTimeUs);
    // 发送消息kWhatQueueBuffer, 调用onQueueBuffer
    // 把Decoder传入的消息notifyConsumed放入到新创建的msg
    sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
    msg->setInt32("queueGeneration", getQueueGeneration(audio));
    msg->setInt32("audio", static_cast<int32_t>(audio));
    msg->setObject("buffer", buffer);
    msg->setMessage("notifyConsumed", notifyConsumed);
    msg->post();

<2> 把音视频Buffer添加到队列mAudioQueue, mVideoQueue。调用postDrainAudioQueue_l, postDrainVideoQueue处理各自队列中的Buffer

void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg)
    // 判断是Audio数据还是Video的数据
    if (audio)  mHasAudio = true;
    else        mHasVideo = true;
    //创建并初始化一个mVideoScheduler
    if (mHasVideo)
        if (mVideoScheduler == NULL)
            mVideoScheduler = new VideoFrameScheduler();
            mVideoScheduler->init();
    //创建一个队列的节点用来保存buffer的信息。
    CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
    QueueEntry entry;
    entry.mBuffer = buffer;
    // Decoder传入的消息kWhatRenderBuffer被放入到节点
    entry.mNotifyConsumed = notifyConsumed;
    entry.mOffset = 0;
    entry.mFinalResult = OK;
    entry.mBufferOrdinal = ++mTotalBuffersQueued;

    // 把创建的节点push到音频数据的队列和视频数据的队列 mAudioQueue  mVideoQueue
    // 调用postDrainAudioQueue_l 或 postDrainVideoQueue,清空音视频数据的队列
    if (audio) {
        mAudioQueue.push_back(entry);
        postDrainAudioQueue_l();
    } else {
        mVideoQueue.push_back(entry);
        postDrainVideoQueue();
    }

2. AudioBuffer的处理

(1) postDrainAudioQueue_l

调用onDrainAudioQueue来处理Auido队列的Buffer

void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs)
    //发送消息 kWhatDrainAudioQueue, 调用 
    sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
    msg->setInt32("drainGeneration", mAudioDrainGeneration);
    msg->post(delayUs);
case kWhatDrainAudioQueue
    // 接下来主要的工作在onDrainAudioQueue中完成
    if (onDrainAudioQueue()) {
        // 函数onDrainAud
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值