本文 是对 obs studio 26.0.2 说明文档 OBS Studio Backend Design 部分的翻译,根据实际项目中理解添加了自己的润色。
https://obsproject.com/docs/backend-design.html
1,插件
1.1、source,加载用于显示或者输出的视频,文件,图片,声音等等,还可以用来音视频的过滤器
1.2、output,输出录制,推流数据,输入可以是原始非压缩数据,也可以是压缩数据
1.3、encode,音视频数据编码器输出数据是output的输入,编码器x264, NVENC, Quicksync,这只是三个例子,可以自己实现
1.4、services,暂时忽略,是推流服务器,有的服务器可能有自己的格式
2,libobs线程
2.1 obs_graphics_thread 专门用来做视频渲染 代码文件libobs/obs_video.c
2.2 video_thread 专门用来做编码和输出(output) 代码文件libobs/media-io/video-io.c
2.3 audio_thread 专门用来做音频的处理,编码和输出
3,输出通道(output channels)
音视频的渲染是从output channel开始的。通过obs_set_output_source()函数把source放到output channel中。可以同时显示多个源(分层显示)。场景(sence)或者转场(transitions)可以拥有多个子源(sub-source),这些子源又可以拥有子源。一个场景(sence)包含多个源(source)可以将其绘制为一组,每个源具有特定的特效(变换),场景只是另一种类型的源。频道(channel)可以用来渲染高度复杂的souce组合。obs中的前端只是一个例子,并没有充分利用后端的这种设计。obs目前只用一个输出通道一次渲染一个场景。但是他确实利用额外的通道来处理诸如在“音视频”中设置的全局音视频源之外的事情。
(作者注:“输出通道”不能与输出对象或音频通道混淆。输出通道用于设置要输出的源,输出对象用于实际的流/录制等。)
4,视频管道概述
图形管道有两个线程运行:一个专用图形线程用来做图形渲染和最终的合成,另一个线程做视频的编码和输出。
分配给输出通道(output channel)的视频源(source)将按照0~maxchannel的顺序依次绘制到最终的纹理上(final texture)。当所有的视频源都绘制完成之后,最终的纹理将会被转化为libobs设置为的任何格式(通常是YUV格式)。转换为后端视频格式之后,他将与时间戳一起封装到当前video handler中(obs_core_video::video)。
然后这一帧数据将会被放到一个缓冲队列中(队列最大为max_cache_size)。并发出一个信号量,然后video-io线程尽可能的处理这些线程。当缓冲池满了的时候,他将复制队列中的最后一帧,以降低视频编码的数量(相当于丢帧)从而降低cpu使用率。这就是为啥子当编码器跟不上视频输出的时候会感觉跳帧一样。视频会被发送到仍和一个原始输出(raw output)或者编码器。
如果它被发送到一个视频编码器对象(libobs/obs encoder.c),它会对帧进行编码,并将编码后的数据包发送到编码器所连接的输出端(可以是多个)。如果输出同时接收编码的视频/音频,它会将数据包放入交织队列,以确保编码的数据包以单调的时间戳顺序发送[4]。
5,音频管道概述
音频管道从一个音频处理模块中的专用音频线程开始运行(libobs/media-io/audio-io.c),假如AUDIO_OUTPUT_FRAMES设置为1024,则音频线程每1024个音频样本“嘀嗒”(处理音频数据)一次(以48khz为间隔,大约每21毫秒一次),并调用audio_callback方法(libobs/obs-audio.c),大部分的音频处理都是在这个方法中完成。
音频源通过obs_source_output_audio方法来输出自己的声音,音频数据会被向后加入(append)或者插入一个循环缓冲池中(obs_source::audio_input_buf).如果音频source的采样率(sample rate),通道(channel)等参数和后端设置的不同,这些音频数据就会被重新混合/重采样(resample)。在插入之前,音频数据也会被和其source链接的滤波器处理。
每一个音频分片(tick),音频线程都有一个音频源树的引用(存储的是所有的输出/处理(output/proocess)的音频源)。在每一个音频源叶节点上(audio source),他将音频数据根据当前的时间戳存放在循环缓冲池中(obs_source::audio_input_buf),同时存入obs_source::audio_output_buf.
然后,存放在 叶source (leaves)的 obs_source::audio_out_buf中的音频数据(audio samples)在通过树结构的source节点时被处理(混合,重采样,channel转换等等)。具有过个子source的source,比如包含多个场景(sence)或者转场(transitioning)通过obs_source_info::audio_render回调函数来处理/混合其子source的音频数据。例如,在两个音频源之间进行切换的时候他将允许这种转场有淡入淡出的效果。混音和处理后的音频数据存储在就近的节点的obs_source::audio_output_buf中,并重复该过程直到所有的节点(source)都遍历完成(到达根节点)。
最后,当音频数据到达快照树的根部时,所有相关source的音频数据就混合处理完成了。最终的数据将会发送给(处于活动状态(actived)的)outputs或者编码器。
如果音频数据是被发往音频编码器,编码器会对音频数据进行编码,并将编码数据包发到编码器连接的输出端(可以是多个)。如果输出端同时接受音视频数据,该输出端将会吧数据包交叉放入队列,以确保编码的数据包以时间戳的先后顺序发送。
编码的数据包或原始音频数据随后被发送到输出端。