ffplay源码分析(2)

ffplay源码分析(1)

1音视频同步基础

因为音视频解码,输出都是在不同线程中完成的,且有些片源音视频本身的pts 就存在飘动, 因此需要引入音视频同步机制。用一句话来总结音视频同步就是"慢了等,快了丢"。

在ffplay 中, 需要时刻将音频,视频时间与系统时间对齐(set_clock)。通过引入pts_drift 变量,记录系统时间与音频,视频时间的差值。 当set_clock() 时,pts_drift = pts - os time。

当get_clock() 时,得到的pts = os_time + pts_drift.。

在ffplay 中, 音视频同步策略有三种:

1 视频同步到音频:将视频的pts 与master  clock比较,慢了等,快了丢。

2 音频同步到视频, 将音频的pts 与master clock 做比较,通过重采样库,控制样本输出。

3 音视频同步到外部时钟:复用了前两种的策略,等效与前两种的叠加。

什么是master clock? 

以谁为准的时间, 比如视频同步到音频, 那就以音频的pts 作为master clock.

/* get the current master clock value */
static double get_master_clock(VideoState *is)
{
    double val;

    switch (get_master_sync_type(is)) {
        case AV_SYNC_VIDEO_MASTER:
            val = get_clock(&is->vidclk);
            break;
        case AV_SYNC_AUDIO_MASTER:
            val = get_clock(&is->audclk);
            break;
        default:
            val = get_clock(&is->extclk);
            break;
    }
    return val;
}

 

2 视频同步到音频

视频同步到音频是在ffplay.c 中的video_refresh() 函数中完成的。通过引入frame_timer 来决定当前帧是否够了,慢了等,快了丢

 /* compute nominal last_duration */
 last_duration = vp_duration(is, lastvp, vp);//计算上一帧应该显示的时长
 delay = compute_target_delay(last_duration, is);//上一帧显示时长 + 音视频pts 的diff

 time= av_gettime_relative()/1000000.0;
 if (time < is->frame_timer + delay) { //查看上一帧显示时间是否够了
    *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
    goto display;// 不够,慢了等,继续上一帧显示
    }
    is->frame_timer += delay;//够了, 更新当前帧显示时间
                ............
 /*下面为丢帧逻辑*/
 if (frame_queue_nb_remaining(&is->pictq) > 1) {
                Frame *nextvp = frame_queue_peek_next(&is->pictq);
                duration = vp_duration(is, vp, nextvp);
                //如果系统时间 > 当前帧显示时间 + 当前帧显示的duration, 则丢弃
                if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
                    is->frame_drops_late++;
                    frame_queue_next(&is->pictq);//快了丢,跳到下一帧,丢弃当前帧
                    goto retry;//retry,当前帧不再显示
                }

 

3 音视同步到视频

与视频同步到音频逻辑不同, 音频同步到视频并不能简单的慢了等,快了丢,因为人耳对声音特别敏感。 因此音频同步到视频,通过重采样库,控制音频样本的输出时间。

在ffplay中, 音频同步到视频逻辑在audio_decode_frame().

static int audio_decode_frame(VideoState *is)
{
 ......
 //与video clk 比较,计算应该数据的样本数
 wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);
//判断是否需要重采样
if (af->frame->format        != is->audio_src.fmt            ||
        dec_channel_layout       != is->audio_src.channel_layout ||
        af->frame->sample_rate   != is->audio_src.freq           ||
        (wanted_nb_samples       != af->frame->nb_samples && !is->swr_ctx)) {
        swr_free(&is->swr_ctx);
//重新设置重采样参数
        is->swr_ctx = swr_alloc_set_opts(NULL,
                                         is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
                                         dec_channel_layout,           af->frame->format, af->frame->sample_rate,
                                         0, NULL);
        i
        }
..........
       //利用重采样库,实现对样本的插入删除
       len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
............
}

4 音视频同步到外部时钟

我们可以自由的选择音视频同步的方式,其实仔细看代码可以发现,音视频同步的选择,其实就是选择不同的clock 来作为master clock 。当选择外部时钟时,就会get_clock(&is->extck)。然后音频,视频输出就与extck 进行比较。因此同步到外部时钟 相当于 视频同步到音频,音频同步到视频的叠加。

/* get the current master clock value */
static double get_master_clock(VideoState *is)
{
    double val;

    switch (get_master_sync_type(is)) {
        case AV_SYNC_VIDEO_MASTER:
            val = get_clock(&is->vidclk);
            break;
        case AV_SYNC_AUDIO_MASTER:
            val = get_clock(&is->audclk);
            break;
        default:
            val = get_clock(&is->extclk);
            break;
    }
    return val;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值