问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

视频帧率与显示器刷新率不匹配问题

创作时间:
作者:
@小白创作中心

视频帧率与显示器刷新率不匹配问题

引用
1
来源
1.
https://faichou.com/posts/25fps-to-60hz/

在视频播放过程中,我们有时会遇到画面卡顿、掉帧、不流畅等问题。这些问题往往与视频的帧率和显示器的刷新率不匹配有关。本文将从技术角度深入探讨这一现象,并通过代码分析其背后的原理。

如图所示,当视频的帧率为25fps时,每帧画面的渲染时间为40ms(1/25秒)。如果显示器的刷新率为50Hz,即每20ms刷新一次,那么显示器刷新两次正好可以显示一帧画面。但是,当显示器的刷新率为60Hz时,问题就出现了。60Hz意味着每16.67ms刷新一次,这与40ms的帧率无法完美匹配。

在这种情况下,程序会将一帧画面延迟40ms后渲染下一帧。由于显示器在第三次刷新时才会完成当前帧的渲染,因此第一帧画面实际上在屏幕上显示了3个屏幕时间(即3次刷新周期,约50ms)。随后的帧则会显示2个屏幕时间(约33ms)。这种不均匀的显示时间会导致画面出现卡顿、掉帧等现象。

这个问题在ffmpeg的视频同步代码中有所体现:

double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {
  double frame_delay;
  /* if we have pts, set video clock to it */
  is->video_clock = pts;
  } else {
    /* if we aren't given a pts, set it to the clock */
    pts = is->video_clock;
  }
  /* update the video clock */
  frame_delay = av_q2d(is->video_st->codec->time_base);
  /* if we are repeating a frame, adjust clock accordingly */
  frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
  is->video_clock += frame_delay;
  return pts;
}

其中frame_delay代表一帧画面在显示器上的时长。代码中使用了repeat_pict来计算延迟,这个值表示画面重复的次数。官方解释指出,对于隔行扫描的帧,repeat_pict可以设置为1,而对于逐行扫描的帧,它可以设置为2的倍数。然而,现代设备中已经很少使用隔行扫描,因此这个值通常为0。

在ffplay.c中,实际是通过frame_rate来计算一帧视频的播放时长:

duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);

对于24fps的视频,frame_rate.den为1,frame_rate.num为24,通过av_q2d计算出的duration为1/24秒。

虽然很多播放器会优先使用AVFrame中的duration值,但如果该值为空,则会使用frame_rate来计算:

frame.duration = avframe.pointee.duration
if frame.duration == 0, avframe.pointee.sample_rate != 0, frame.timebase.num != 0 {
  frame.duration = Int64(avframe.pointee.nb_samples) * Int64(frame.timebase.den) / (Int64(avframe.pointee.sample_rate) * Int64(frame.timebase.num))
}

总之,repeat_pict这个值主要是为了兼容老的播放设备,比如在3:2下拉转换中保持原始电影的帧率和运动感。在现代设备中,这个值通常为0,实际的帧率控制主要依赖于frame_rate

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号