OBS 源码分析- 采集方案之二 (摄像头采集)

2024-04-25 20:58

本文主要是介绍OBS 源码分析- 采集方案之二 (摄像头采集),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1、OBS采集方案
  • 2、OBS 摄像头采集
    • 2.1 DirectShow 基础
    • 2.2 OBS 的实现

1、OBS采集方案

obs的视屏录制主要分3种:
窗口采集:采集应用程序窗口
显示器采集:也叫全屏采集,可以采集整个屏幕,当有多个显示器时,可以设置采集其中一个显示器
游戏采集:可以采集游戏窗口

extern struct obs_source_info duplicator_capture_info;
extern struct obs_source_info monitor_capture_info;
extern struct obs_source_info window_capture_info;
extern struct obs_source_info game_capture_info;

2、OBS 摄像头采集

obs 的方案采用 directshow 的方案,如果需要查看源码需要下载submodule, 因为在另外一个仓库。
在这里插入图片描述

2.1 DirectShow 基础

DirectShow 其主要设计目标是通过将应用程序与数据传输的复杂性、硬件差异和同步隔离,简化在 Windows 平台上创建数字媒体应用程序的任务 ,DirectShow简化媒体播放、格式转换和捕获任务

下图显示了应用程序、DirectShow组件以及应用程序支持的一些硬件和软件DirectShow之间的关系。
在这里插入图片描述
在这里插入图片描述
Filter是DirectShow技术体系中最基本的概念。如上图所示,DirectShow中的Filter分成三大类:Source Filter、Transform Filter、Render Filter。Source Filter就是提供数据源的Filter,所有的数据都是从Source Filter流出去的。不管是多媒体文件还是多媒体设备,Source Filter都进行了封装统一了接口,在使用方式上保持了一致。Transform Filter则是对数据进行操作处理的Filter,所有的图像操作都应该在这里进行。而Render Filter则是用来渲染图像的Filter,不管是保存到文件还是输出到其他地方,都由这个Render Filter来实现。Windows系统本身提供了非常多的Filter,我们在开发的时候可以直接使用。

下面是UI 界面配置directshow 软件(graphstudionext)的示意图,通过拖动就可以配置,filter 的概念。而整个图就 Filter Graph。如果需要就向 Filter Graph 添加filter , 并且链接 pin(引脚)
在这里插入图片描述

2.2 OBS 的实现

由于OBS 封装了dshow ,如果比较了解dshow ,那obs也是比较简单的,大家可以看下我整理的类图,帮助理解
类图
在这里插入图片描述

这边只说下,回调的数据接口在什么位置吧。回调接口是通过配置中callback 传进入的。 回调接口是DShowInput::OnVideoData

bool DShowInput::UpdateVideoConfig(obs_data_t *settings) {
videoConfig.name = id.name;videoConfig.path = id.path;videoConfig.useDefaultConfig = resType == ResType_Preferred;videoConfig.cx = cx;videoConfig.cy_abs = abs(cy);videoConfig.cy_flip = cy < 0;videoConfig.frameInterval = interval;videoConfig.internalFormat = format;deviceHasAudio = dev.audioAttached;deviceHasSeparateAudioFilter = dev.separateAudioFilter;//设置回调函数videoConfig.callback = std::bind(&DShowInput::OnVideoData, this,placeholders::_1, placeholders::_2,placeholders::_3, placeholders::_4,placeholders::_5, placeholders::_6);videoConfig.format = videoConfig.internalFormat;if (!device.SetVideoConfig(&videoConfig)) {blog(LOG_WARNING, "%s: device.SetVideoConfig failed",obs_source_get_name(source));return false;}}

最终数据存放到source->async_frames,

static void
obs_source_output_video_internal(obs_source_t *source,const struct obs_source_frame *frame)
{if (!obs_source_valid(source, "obs_source_output_video"))return;if (!frame) {source->async_active = false;return;}struct obs_source_frame *output = cache_video(source, frame);/* ------------------------------------------- */pthread_mutex_lock(&source->async_mutex);if (output) {if (os_atomic_dec_long(&output->refs) == 0) {obs_source_frame_destroy(output);output = NULL;} else {da_push_back(source->async_frames, &output);source->async_active = true;}}pthread_mutex_unlock(&source->async_mutex);
}

在 tick_sources 中 循环调用所有source , obs_source_video_tick中获取视频frame,等待渲染使用

tick_sources ->obs_source_video_tick ->async_tick

static void async_tick(obs_source_t *source)
{uint64_t sys_time = obs->video.video_time;pthread_mutex_lock(&source->async_mutex);if (deinterlacing_enabled(source)) {deinterlace_process_last_frame(source, sys_time);} else {if (source->cur_async_frame) {remove_async_frame(source, source->cur_async_frame);source->cur_async_frame = NULL;}source->cur_async_frame = get_closest_frame(source, sys_time);}source->last_sys_timestamp = sys_time;pthread_mutex_unlock(&source->async_mutex);if (source->cur_async_frame)source->async_update_texture =set_async_texture_size(source, source->cur_async_frame);
}

在这里插入图片描述

这篇关于OBS 源码分析- 采集方案之二 (摄像头采集)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/935770

相关文章

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Redis 多规则限流和防重复提交方案实现小结

《Redis多规则限流和防重复提交方案实现小结》本文主要介绍了Redis多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣... 目录一:使用 String 结构记录固定时间段内某用户 IP 访问某接口的次数二:使用 Zset 进行

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维