以前工作中参与了一些音视频程序的开发,不过使用的都是芯片公司的SDK,没有研究到更深入一层,比如说音视频同步是怎么回事。只好自己抽点时间出来分析开源代码了,做音视频编解码的人都知道ffmpeg,他在各种音视频播放软件当中已经使用很多了。当然,这里不是来分析音视频播放软件,如果真的想学习,自己可以研究一下ffmpeg自带的一个简单播放器ffplay,在这里不对ffplay做详细分析,只拿出来他的音视频同步一部分来详细分析(下面代码取自ffmpeg-0.5)。

在ffplay里的视频图像更新是在一个timer里面更新的,当有timer事件时就会调用video_refresh_timer()函数,而在这个函数里面会调用compute_frame_delay()计算下一帧图像显示的时间
video_refresh_timer()
    /* launch timer for next picture */
    schedule_refresh(is, (int)(compute_frame_delay(vp->pts, is) * 1000 + 0.5));

compute_frame_delay()的参数frame_current_pts表示当前图像的pts,参数is是全局videoState结构指针。
static double compute_frame_delay(double frame_current_pts, VideoState *is){
    double actual_delay, delay, sync_threshold, ref_clock, diff;

    /* compute nominal delay */
    delay = frame_current_pts - is->frame_last_pts;      // frame_last_pts存着上一帧图像的pts,用当前帧的pts减去上一帧的pts,从而计算出一个估计的delay值
    if (delay <= 0 || delay >= 10.0) {                            // 这个delay值有一个范围,如果超出范围的话,则用上一次的delay值
        /* if incorrect delay, use previous one */
        delay = is->frame_last_delay;                               // frame_last_delay存放前面一次计算得到的delay值
    } else {
        is->frame_last_delay = delay;                               // 如果计算出来的值合法,则保存下来
    }
    is->frame_last_pts = frame_current_pts;                 // 将当前帧的pts保存下来

    /* update delay to follow master synchronisation source */                      // 更新delay值用于跟随主同步源
    if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
         is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {                          // 音频做主同步源或外部时钟做同步源时进入
        /* if video is slave, we try to correct big delays by
           duplicating or deleting a frame */
        ref_clock = get_master_clock(is);                                     // 得到主时钟源的当前时钟值做为参考时钟
        diff = frame_current_pts - ref_clock;                                // 当前帧的pts减去参考时钟,结果diff可能为正值,也可能为负值

        /* skip or repeat frame. We take into account the
           delay to compute the threshold. I still don't know
           if it is the best guess */
        sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);  // delay和AV_SYNC_THRESHOLD之间取一个最大值
        if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
            if (diff <= -sync_threshold)                                          // sync_threshold绝对是个>0的值
                delay = 0;                                                                 // 如果diff是个很小的负数,则说明当前视频帧已经落后于主时钟源了,下一帧图像应该快点显示,所以delay=0
            else if (diff >= sync_threshold)
                delay = 2 * delay;                                                     // 如果diff是一个比较大的正数,则说明当前视频帧已经超前于主时钟源了,下一帧图像应该延迟显示
        }
    }

    is->frame_timer += delay;                                                    // frame_timer是一个delay累加的值,
    /* compute the REAL delay (we need to do that to avoid
       long term errors */
    actual_delay = is->frame_timer - (av_gettime() / 1000000.0);  // frame_timer减去当前系统时钟,得到一个actual_delay值
    if (actual_delay < 0.010) {
        /* XXX: should skip picture */
        actual_delay = 0.010;
    }

#if defined(DEBUG_SYNC)
    printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
            delay, actual_delay, frame_current_pts, -diff);
#endif

    return actual_delay;                                            // actual_delay将做为下一次帧图像更新的TIMER参数
}

****
1. 在ffplay当中并没有跳帧的作法,只是通过控制视频帧显示速度来实现音/视频同步的。
2. 一般情况下,音频不容易同步到视频,但视频比较容易同步到音频,因为音频输出的采样率等参数一般都是固定的,设定好以后消耗数据的速率基本是固定的,很难在播放过程当中动态调整,
   而视频显示的图像更新速率更容易调整些。通常可以通过加速刷新,跳帧等办法来调整。

既然同步的时候用到的系统时钟,那当pause/resume时又做了些什么来保证同步不出问题呢?这是需要考虑的一个重要问题,来看stream_pause()函数
static void stream_pause(VideoState *is)
{
    is->paused = !is->paused;    // 反转paused值
    if (!is->paused) {
        // 如果是resume操作,则要更新当前视频帧的pts
        is->video_current_pts = get_video_clock(is);
        
        // video_current_pts_time记录了上一帧视频图像显示时的系统时钟, av_gettime() - is->video_current_pts_time得到的结果刚好是pause这段时间间隔,通过这种方式保证了frame_timer永远记录的是ffplay启动后到当前时间点的时间间隔
        is->frame_timer += (av_gettime() - is->video_current_pts_time) / 1000000.0;
    }
}

好了,是不是对音视频同步有了一定认识呢。这里只做了一点点简单的分析,我的分析不一定准确,只做参考学习,如果有人发现问题,请告诉我。ffplay的代码实现很完整,如果有兴趣,可以自己尝试去分析一下音频同步到视频的或音/视频同步到外部时钟的实现。

http://blog.chinaunix.net/uid-20364597-id-3510052.html

ffplay的音视频同步分析的更多相关文章

  1. (转)ffplay的音视频同步分析之视频同步到音频

          以前工作中参与了一些音视频程序的开发,不过使用的都是芯片公司的SDK,没有研究到更深入一层,比如说音视频同步是怎么回事.只好自己抽点时间出来分析开源代码了,做音视频编解码的人都知道ffmp ...

  2. ffmpeg 2.3版本号, 关于ffplay音视频同步的分析

    近期学习播放器的一些东西.所以接触了ffmpeg,看源代码的过程中.就想了解一下ffplay是怎么处理音视频同步的,之前仅仅大概知道通过pts来进行同步,但对于怎样实现却不甚了解,所以想借助这个机会, ...

  3. ffplay(2.0.1)中的音视频同步

    最近在看ffmpeg相关的一些东西,以及一些播放器相关资料和代码. 然后对于ffmpeg-2.0.1版本下的ffplay进行了大概的代码阅读,其中这里把里面的音视频同步,按个人的理解,暂时在这里作个笔 ...

  4. vlc源码分析(五) 流媒体的音视频同步

    vlc播放流媒体时实现音视频同步,简单来说就是发送方发送的RTP包带有时间戳,接收方根据此时间戳不断校正本地时钟,播放音视频时根据本地时钟进行同步播放.首先了解两个概念:stream clock和sy ...

  5. FFmpeg简易播放器的实现-音视频同步

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10284653.html 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...

  6. Android 音视频同步(A/V Sync)

    1.  音视频同步原理 1)时间戳 音视频同步主要用于在音视频流的播放过程中,让同一时刻录制的声音和图像在播放的时候尽可能的在同一个时间输出. 解决音视频同步问题的最佳方案就是时间戳:首先选择一个参考 ...

  7. 通俗的解释下音视频同步里pcr作用

    PCR同步在非硬件精确时钟源的情况还是谨慎使用,gstreamer里面采用PCR同步,但是发现好多ffmpeg转的片儿,或者是CP方的片源,pcr打得很粗糙的,老是有跳帧等现象.音视频同步,有三种方法 ...

  8. 直播APP源码是如何实现音视频同步的

    1.  音视频同步原理 1)时间戳 直播APP源码音视频同步主要用于在音视频流的播放过程中,让同一时刻录制的声音和图像在播放的时候尽可能的在同一个时间输出. 解决直播APP源码音视频同步问题的最佳方案 ...

  9. Android 音视频同步机制

    一.概述 音视频同步(avsync),是影响多媒体应用体验质量的一个重要因素.而我们在看到音视频同步的时候,最先想到的就是对齐两者的pts,但是实际使用中的各类播放器,其音视频同步机制都比这些复杂的多 ...

随机推荐

  1. 机器学习(6): 层次聚类 hierarchical clustering

    假设有N个待聚类的样本,对于层次聚类来说,步骤:        1.(初始化)把每个样本归为一类,计算每两个类之间的距离,也就是样本与样本之间的相似度:        2.寻找各个类之间最近的两个类, ...

  2. 软件测试自动化之- 基于反射的UI自动化测试框架 - UI Automation Test Framework

    测试自动化程序的任务 基于反射的ui测试自动化程序,要完成的6项任务: 通过某种方式从测试套件程序中运行待测程序(AUT: Applicaton Under Test),以便于两个程序之间进行通信 操 ...

  3. linux系统中用户切换

    1. Linux系统中用户切换的命令为su,语法为: su [-fmp] [-c command] [-s shell] [--help] [--version] [-] [USER [ARG]] 参 ...

  4. Linux 共享库(动态库)

    Linux 系统上有两类根本不同的 Linux 可执行程序.第一类是静态链接的可执行程序.静态可执行程序包含执行所需的所有函数 — 换句话说,它们是“完整的”.因为这一原因,静态可执行程序不依赖任何外 ...

  5. cocos2d-x开发记录:二,基本概念(导演,场景,层和精灵,场景切换,效果)

    四,Director Scene Layer和Sprite(导演,场景,层和精灵) 1.Scenes(场景) 一个场景 (用CCScene对象实现)相当于APP工作流的独立部分.一些人也喜欢叫做“屏幕 ...

  6. documentdb

    https://azure.microsoft.com/en-us/services/documentdb/ https://www.simple-talk.com/cloud/cloud-data/ ...

  7. js将时间戳转换成正常的yyyy-m-d格式

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. [未解决]Ajax-读取并解析XML,动态生成select下拉列表框

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  9. js photoswipe 相册使用 移动pc端均可

    http://photoswipe.com/ 官网  这里使用的是最新 4.1.1版本 http://photoswipe.com/documentation/getting-started.html ...

  10. VBA学习笔记(9)--生成点拨(1)

    说明(2017.3.26): 1. 还没写完,写到新建文件夹了,下一步新建word,重命名,查找点拨,把点拨复制进去,因为要给点拨编号,应该会很麻烦 Public Sub test1() Dim pa ...