request-free-img

探秘OBS帧率控制:从视觉暂留到代码实现

视觉暂留:动画的基础

这是一个视频中的一张静止图像,而这是这个视频中1秒钟内的所有静止图像
当我们把这30幅静止图像连续播放,便形成了我们平时看到的视频

人之所以能将连续播放的静止图像感知为动画,得益于人眼的一个神奇特性——视觉暂留
当我们看到一个画面时,这个画面在我们视网膜上不会立即消失,而是会短暂停留大约1/16秒

帧率(FPS)的标准

也就是说,如果单张图像切换速度低于每秒16帧,我们就会感觉到明显的卡顿
而当达到每秒24帧时,人眼就会觉得画面是基本流畅的,这也是电影的标准
而每秒30帧则是视频常用的标准

这便形成了FPS,也就是每秒帧率
帧率越高,人眼感觉到的画面越流畅

视频软件如何精确控制帧率?

那视频软件是如何精确控制每秒帧率的呢?
今天我们就以OBS的代码为例,来讲解在OBS中帧率的控制原理

图形渲染主循环:obs_graphics_thread_loop

obs_graphics_thread_loop是OBS中的图形渲染主循环函数

首先它会记录帧以纳秒为单位的开始时间
然后这一堆是图形上下文的处理
这一行,OBS会对所有添加到场景的SOURCE进行处理,调用之后source就会生成一帧图像
这几行是Windows消息处理
然后这个output_frames是输出一帧画面
这里render_displays是将一帧画面渲染到界面上

计算帧生成时间

接着这一行是计算上边的代码执行消耗的时间

frame_time_ns = os_gettime_ns() - frame_start;

核心控制:video_sleep函数

控制帧率主要实现是在这个video_sleep函数来实现。
这个函数的主要目的是确保视频处理按照设定的时间间隔进行,从而间接地控制了帧率
传进去的这个video_time是当前时间以纳秒为单位,
interval则是通过用户在界面上设定的帧率计算出来的需要间隔的时间,也是以纳秒为单位
我们跳进去看一下

os_sleepto_ns:纳秒级休眠与帧数补偿

函数中的主要实现是调用os_sleepto_ns
它尝试让程序休眠到一个纳秒级的目标时间t
如果成功休眠,则更新*p_time为t,并设置count为1,表示这段时间内只处理了一帧
如果未能成功休眠(可能是因为系统调度等原因),则计算实际经过的时间udiff
根据clamped_diffinterval_ns计算在这段时间内应该处理的帧数count,并更新*p_time为新的时间点
后面就是更新统计信息

回到主循环:更新帧率统计

再回到obs_graphics_thread_loop函数中,后边就是如果时间达到1秒,就更新一下视频的FPS

再循环不断的处理,这样就可以使OBS能够在一个稳定的帧率下高效地处理视频流

你学会了吗?


更多问题探讨,请关注公众号:程序员角