OBS源码分析之render_video处理流程
来源:互联网 发布:淘宝网开店卖什么好 编辑:程序博客网 时间:2024/06/05 19:15
最近在看OBS源码,发现其复杂度真不是一般的高,看到render_video时脑子混乱了,经过单步调试跟踪才终于明朗了,下面先贴上源码:
static inline voidrender_video(obs_source_t *source)
{
if(source->info.type != OBS_SOURCE_TYPE_FILTER &&
(source->info.output_flags &OBS_SOURCE_VIDEO) == 0)
return;
if(source->info.type == OBS_SOURCE_TYPE_INPUT &&
(source->info.output_flags &OBS_SOURCE_ASYNC) != 0 &&
!source->rendering_filter) {
if(deinterlacing_enabled(source))
deinterlace_update_async_video(source);
obs_source_update_async_video(source);
}
if(!source->context.data || !source->enabled) {
if(source->filter_parent)
obs_source_skip_video_filter(source);
return;
}
if(source->filters.num && !source->rendering_filter)
obs_source_render_filters(source);
elseif (source->info.video_render)
obs_source_main_render(source);
elseif (source->filter_target)
obs_source_video_render(source->filter_target);
elseif (deinterlacing_enabled(source))
deinterlace_render(source);
else
obs_source_render_async_video(source);
}
如果source不是OBS_SOURCE_TYPE_FILTER且不是OBS_SOURCE_VIDEO直接退出;
如果source为OBS_SOURCE_TYPE_INPUT且是OBS_SOURCE_ASYNC,并且!source->rendering_filter(对source进行滤镜处理时会将此变量值true)
if(deinterlacing_enabled(source))
deinterlace_update_async_video(source);
obs_source_update_async_video(source);
黄色部分先不管,看看
staticvoid obs_source_update_async_video(obs_source_t *source)
{
if(!source->async_rendered) {
structobs_source_frame *frame = obs_source_get_frame(source);
if(frame)
frame= filter_async_video(source, frame);
source->async_rendered= true;
if(frame) {
source->timing_adjust=
os_gettime_ns()- frame->timestamp;
source->timing_set= true;
if(set_async_texture_size(source, frame)) {
update_async_texture(source,frame,
source->async_texture,
source->async_texrender);
}
obs_source_release_frame(source,frame);
}
}
}
首先
if(!source->async_rendered) {
structobs_source_frame *frame = obs_source_get_frame(source);
source->async_rendered这个变量在obs_source_video_tick得到最近的一帧视频后值false,(obs_source_video_tick?姑且认为是采集视频源输出帧数据)表示没有进行异步渲染,因此这里if的意思就是对还没有进行异步渲染的帧进行render;
接下来source->async_rendered= true;与obs_source_video_tick对应;
下面做了些时间戳的处理,先不细说;继续往下遇到一个重点:
update_async_texture(source,frame,
source->async_texture,
source->async_texrender);
这个函数进行了帧色彩空间转换,采用PBO技术将frame数据传到source->async_texture,然后渲染到文理source->async_texrender->target;一大堆图像渲染引擎的东东,可以先略过。
接着回到render_video如果这个source只是一个简单的source,(怎样算简单?直接走到最后一个else的就是简单的了这样的source只是一个INPUT,且没有任何过滤器,也没有自己的video_render方法)这样就直接到了
static inline voidobs_source_render_async_video(obs_source_t *source)
{
if(source->async_texture && source->async_active)
obs_source_draw_async_texture(source);
}
这个函数很简单就一个IF也是同步用的,
if(source->async_texture && source->async_active)
obs_source_draw_async_texture(source);
source->async_texture 上面已经提到,source->async_active在obs_source_output_video中进行赋值,如果视频源输出了新的帧会将此变量值true,也就是说视频源输出帧之后才进行obs_source_draw_async_texture;继续看这个函数的具体实现:
static voidobs_source_draw_async_texture(struct obs_source *source)
{
gs_effect_t *effect = gs_get_effect();
bool yuv =format_is_yuv(source->async_format);
bool limited_range = yuv &&!source->async_full_range;
constchar *type = yuv ? "DrawMatrix" :"Draw";
bool def_draw = (!effect);
gs_technique_t*tech = NULL;
if(def_draw) {
effect= obs_get_base_effect(OBS_EFFECT_DEFAULT);
tech= gs_effect_get_technique(effect, type);
gs_technique_begin(tech);
gs_technique_begin_pass(tech,0);
}
obs_source_draw_texture(source,effect,
yuv? source->async_color_matrix : NULL,
limited_range? source->async_color_range_min : NULL,
limited_range? source->async_color_range_max : NULL);
if(def_draw) {
gs_technique_end_pass(tech);
gs_technique_end(tech);
}
}
这个函数实现了将source->async_texrender->target作为文理,再次进行一遍渲染,当然两次渲染是用的shader不同,细心的人会发现这次渲染没有设置渲染到哪里,那最终输出到哪了?既然没有设置渲染到哪里,那就自然是渲染到之前设置的目标上了,最终目的就是我们的屏幕;
最简单的source就说完了,那就继续复杂点的:
拿带filler的来说吧,source是可以带filler的,而且还可以带多个,大体的处理流程是:
1、update_async_texture,将原始帧数据渲染到FBO,
2、然后走到下面这个分支:
if(source->filters.num && !source->rendering_filter)
obs_source_render_filters(source);
static inline voidobs_source_render_filters(obs_source_t *source)
{
source->rendering_filter= true;
obs_source_video_render(source->filters.array[0]);
source->rendering_filter= false;
}
voidobs_source_video_render(obs_source_t *source)
{
if(!obs_source_valid(source, "obs_source_video_render"))
return;
obs_source_addref(source);
render_video(source);
obs_source_release(source);
}
代码很简单,对第一个filler执行render_video,(又到了render_video)
继续往下走可能走到两个分支:
(1)else if (source->info.video_render)
obs_source_main_render(source);
(2)else if (source->filter_target)
obs_source_video_render(source->filter_target);
先说分支(1)吧,大家都知道filler是有次序的,在OBS中FILLER的执行时递归实现的画个图说一下吧:
FILLER1是source的第一个FILLER,obs_source_main_render,的输入是FILLER1,但是FILLER1要先执行FILLER2,FILLER2要先执行FILLER3,FILLER3对frame处理之后,返回到FILLER2;然后FILLER1;然后SOURCE,
每个FILLER的执行都是首先filter_texrender->target设置与FBO绑定,然后渲染其前面的FILLER,最后渲染自己。
再说分支(2),对于没有video_render方法的FILLER,直接渲染其前面的FILLER;
- OBS源码分析之render_video处理流程
- OBS源码分析之rtmp
- obs源码分析
- twemproxy源码分析之四:处理流程
- OBS源码分析--视频采集显示
- 云客Drupal8源码分析之核心处理流程HttpKernel(drupal8执行流程)
- obs-studio源码阅读笔记:学习obs流程的第一步,test程序
- apache(httpd-2.2.14) mod_ssl源码分析之二(mod_ssl处理流程分析)
- apache(httpd-2.2.14) mod_ssl源码分析之三(mod_ssl处理流程分析)
- HBase1.0.0源码分析之请求处理流程分析以Put操作为例(一)
- HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)
- live555源码分析----SETUP命令处理流程
- Struts2请求处理流程及源码分析
- Struts2请求处理流程及源码分析
- Struts2请求处理流程及源码分析
- Struts2请求处理流程及源码分析
- Struts2请求处理流程及源码分析
- Struts2请求处理流程及源码分析
- 模仿ajax写的简单实现
- 大型网站架构之分布式消息队列
- hdu 1714 RedField
- stm 32 IO重映射
- log4j不同的类输出到不同的日志文件中
- OBS源码分析之render_video处理流程
- ROS 使用stage进行(LaserScan)激光扫描仿真
- 百度地图集成——搜索
- Activity 生命周期、、dialog Activity
- ztree实现表格风格的树状结构
- Scrapy爬虫框架抓取中文结果为Unicode编码,如何转换UTF-8编码的解决办法
- JavaScript中__proto__与prototype的关系
- 浅谈Java容器
- PyCharm2017.3专业版注册码