ffplay是FFmpeg开源下的一款兼容性极强的极简播放器。在进行二次开发ffplay时seek跳转功能的添加是播放器不可缺少的一项功能。下面讲解一下播放器执行seek时内部流程以及如何提升seek后的播放稳定性。seek是播放器按照指定时间戳位置进行播放位置跳转的操作其逻辑与网络断网重连后刷新流、重新同步思路类似丢弃旧数据使用新的音视频帧重新解码与同步。其本质是以目标位置附近的I帧为起点重新解码调用avcodec_flush_buffers清空解码器缓存避免旧帧输出刷新解码器上下文。其中添加了时序serial用来区分seek前旧帧与seek后新帧要播放的音视频帧。每次seek后全局时序serial当serial时序不一致的时候进行drop帧时序一致的时候再进行音视频同步播放。ffplay标准seek流程1.全局serial2.清空AVPacket队列向队列插入flush_pkt触发队列清空并将队列serial同步更新3.执行av_seek_frame定位到目标时间戳附近的I帧/关键帧4.重置/刷新音视频解码器内部缓冲5.清空Frame队列这个通过frame帧时序与frame帧队列时序不一致时进行drop帧6.初始化音频主时钟为后续音视频同步做准备下面问题来了视频渲染快音频播放慢视频线程会等待音频主时钟等到音频主时钟推进到pts后视频才渲染实现音视频同步。另外一种情况向后seek常见情况音频还未解码出有效帧、音频主时钟未更新视频线程因“等时钟”而卡死不动。我的优化方案是seek之后先强制渲染几帧视频让音频线程有时间完成有效音频帧输出并更新主时钟只有这样音频时钟动起来视频才能进行同步不然视频会卡在那里主要作用就是防止视频依旧对齐未更新的音频时钟导致一直等待。本质是时钟源未就绪同步堵塞。此时另一种方案能够提升播放器鲁棒性增加一个seek_clock_flag标志位。seek后标志位置为false当音频输出第一帧更新主时钟时再置为true视频渲染线程根据这个标志位为true时再进行音视频同步。