obs源码分析【一】:main函数

本文深入剖析OBS项目源码,介绍了如何定位main函数、项目架构、crash处理、配置管理、日志记录、网络请求等功能实现细节。此外,还探讨了Qt界面适配高DPI屏幕的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  最近对obs的代码感兴趣了,在obs里也抠了不少功能出来用到项目上,准备把自己的心得记录下来,有兴趣的可以一起留言讨论。
  在学习obs源码之前,需要先编译obs的源码,有需要的可以看上一篇,obs项目的编译方法,需要的可以点击【obs编译方法

main函数在哪里

  obs的界面是Qt写的,目测没用到QML, 既然是Qt, 那先从main函数开始,如果你是一个新手,在几百个cpp文件中,怎么快速找到main函数呢,ctrl F全局搜索

main(

  经过查找,可以很快确定是在obs-app里面, 如下图
在这里插入图片描述

  找到main函数,万里长城第一步开始了,剩下的就是坚持看,调试。

obs项目架构

  来看看obs项目的构成
在这里插入图片描述
  我现在编译的版本是50个项目,大概分为5大块
(1)core 是一些核心渲染功能,dx, opengl等
(2)deps :obs的一些依赖
(3)frontend: 前端,也就是Qt界面
(4)plugins插件:比如录制,推流,x264编码等
(5)scripting: python lua脚本,这个可以不用关心
  OBS是客户端项目,那么先从界面开始,主界面是OBSBasic.ui, 在frontend-obs模块可以找到
在这里插入图片描述

  打开看看:
在这里插入图片描述
  原始界面比较朴素,经过qss渲染后就很漂亮的,颜值提高时隔档次。
  界面找到了,回到main函数,看看main函数做什么。

main函数浅析

crash的处理

  首先是crash的处理,win32客户端开发的常规手段

#ifdef _WIN32
	obs_init_win32_crash_handler();
	SetErrorMode(SEM_FAILCRITICALERRORS);
	load_debug_privilege();
	base_set_crash_handler(main_crash_handler, nullptr);
#endif

其实本质还是调用了SetUnhandledExceptionFilter,如下:

void initialize_crash_handler(void)
{
	static bool initialized = false;

	if (!initialized) {
		SetUnhandledExceptionFilter(exception_handler);
		initialized = true;
	}
}

这个异常处理有什么用呢,它主要是在程序崩溃时生成dump文件,给程序员提供分析的依据,关于dump文件的生成与调试,可以看我的这篇博客:【C++程序生成dump文件并分析dump

obs配置

下面的代码

upgrade_settings();

这是做什么,打开basic.ini看看,怎么找到basic.ini, everything搜一搜就出来了,如下:

[General]
Name=未命名

[Video]
BaseCX=1920
BaseCY=1080
OutputCX=1920
OutputCY=1080
FPSType=0
FPSCommon=60

[Panels]
CookieId=5683CD9D974512F7

[SimpleOutput]
RecEncoder=x264
RecQuality=Small
FilePath=D:/
RecFormat=mp4
StreamEncoder=x264
Preset=veryfast

[Output]
Mode=Simple

[AdvOut]
TrackIndex=1
RecType=Standard
RecTracks=1
FLVTrack=1
FFOutputToFile=true
FFFormat=
FFFormatMimeType=
FFVEncoderId=0
FFVEncoder=
FFAEncoderId=0
FFAEncoder=
FFAudioMixes=1
VodTrackIndex=2

看这些参数可以猜测,应该是启动时的一些参数功能加载,具体代码得具体分析。把软件的一些配置做保存,下次打开时可以直接使用,这是常规操作,但是它的路径比较隐蔽,普通用户找不到C:\Users\One\AppData\Roaming\obs-studio\basic\profiles\未命名\basic.ini

obs log

下面是log的使用了,作为客户端开发,不会写用log是很尴尬的,看看obs的log怎么写,直接上代码:

base_get_log_handler(&def_log_handler, nullptr);
fstream logFile;
int ret = run_program(logFile, argc, argv);

blog(LOG_INFO, "Number of memory leaks: %ld", bnum_allocs());
base_set_log_handler(nullptr, nullptr);

跟踪代码可以看到obs的log和其它日志框架也是差不多的,大概分6个等级trace,debug,info,error,warning,fatal. 套路一样,API不同而已,但是写一个好的log也不是那么容易的,需要考虑到在多线程时如何打印,以及cpu消耗等,一个小小的log功能,并不那么简单,如果喜欢obs的log, 抠下来,用到你的项目中去,当然还有其它C++日志库,例如glog, log4cplus等。

static void def_log_handler(int log_level, const char *format, va_list args,
			    void *param)
{
	char out[4096];
	vsnprintf(out, sizeof(out), format, args);

	if (log_level <= log_output_level) {
		switch (log_level) {
		case LOG_DEBUG:
			fprintf(stdout, "debug: %s\n", out);
			fflush(stdout);
			break;

		case LOG_INFO:
			fprintf(stdout, "info: %s\n", out);
			fflush(stdout);
			break;

		case LOG_WARNING:
			fprintf(stdout, "warning: %s\n", out);
			fflush(stdout);
			break;

		case LOG_ERROR:
			fprintf(stderr, "error: %s\n", out);
			fflush(stderr);
		}
	}

	UNUSED_PARAMETER(param);
}

在main函数中还有个功能是命令参数的初始化处理,可以去看看。
obs有推流的功能,那当然少不了网络的参与,下面这个函数是libcurl功能的封装:

网络请求libcurl

curl_global_init(CURL_GLOBAL_ALL);

关于网络部分以后我再分享。

主界面

以上都是obs的初始化及设置,作为Qt项目,那最关键的当然是进入主界面啊,看了main函数这么多代码,都没找到w.show, exec()等关键字眼,当然,作为牛逼的项目,代码这么容易被你看懂,那就不是牛逼的项目了,主界面的加载是在下面这句代码:
在这里插入图片描述
进到run_program中瞅瞅,你就会找到show, exec等,例如
在这里插入图片描述

Qt适配高dpi屏幕

run_program做了很多事,我们先聊个基础问题,Qt怎么适配高分屏?
来看看obs的处理办法:

#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
	QGuiApplication::setAttribute(opt_disable_high_dpi_scaling
					      ? Qt::AA_DisableHighDpiScaling
					      : Qt::AA_EnableHighDpiScaling);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) && defined(_WIN32)
	QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
		Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif

具体什么功能,自己去查Qt助手。

总结

  main函数先分析这么多了,来总结一下本篇内容,根据以上的分析可以看到,写一个客户端项目,首先需要做哪些工作呢?
(1)crash的处理,dump文件生成
(2)log功能
(3)网络功能
(4)高dpi适配
(5)界面处理
(6)多语言
  以上功能在obs main函数中都做了,在项目开发中,如果有必要,可以借鉴obs的代码,所以说看看好的项目还是很有必要的。

  阅读obs源码分析全部文章,请点击【obs源码分析专栏

### RTKLIB源码示例与GPS GNSS实现 RTKLIB 是种广泛应用于全球导航卫星系统(GNSS)定位技术的开源库,支持实时动态(RTK)差分定位和其他多种定位模式。以下是基于 RTKLIB 的典型代码片段以及其实现 GPS 和 GNSS 功能的核心逻辑。 #### 配置环境 为了运行和理解 RTKLIB 源码,首先需要设置开发环境。假设已按照引用描述完成了 RTKLIB 在 Visual Studio 中的配置[^4],接下来可以通过分析核心功能模块来了解其工作原理。 --- #### 核心代码示例:基线解算 以下是个简化版的 RTKLIB 基线解算过程: ```c #include "rtklib.h" int main() { obs_t obs; // 卫星观测数据结构体 nav_t nav; // 星历数据结构体 sol_t sol; // 解算结果结构体 rtk_t rtk; // RTK 结构体 double pos[3]; // 输出位置坐标 init_rtk(&rtk); // 初始化 RTK 参数 read_obs("base.obs", &obs); // 读取基准站观测文件 read_nav("gps.nav", &nav); // 读取星历文件 for (int i = 0; i < obs.n; i++) { if (!rtkpos(obs.data[i], &nav, &rtk, &sol)) { printf("Error in positioning at epoch %d\n", i); continue; } ecef2pos(sol.rr, pos); // 将 ECEF 转换为地理坐标 printf("Position: Lat=%.6f, Lon=%.6f, Ht=%.3f\n", DEG(pos[0]), DEG(pos[1]), pos[2]); } return 0; } ``` 上述代码展示了如何利用 `rtkpos` 函数进行单历元的基线解算,并将最终的位置转换为纬度、经度和高程形式输出[^3]。 --- #### 关键算法解析 ##### 1. **几何距离计算** 在 RTK 差分解算过程中,几何距离的计算是非常重要的步。通常会通过如下方式实现: ```c double geo_distance(double *rx_pos, double *sat_pos) { double dx = rx_pos[0] - sat_pos[0]; double dy = rx_pos[1] - sat_pos[1]; double dz = rx_pos[2] - sat_pos[2]; return sqrt(dx*dx + dy*dy + dz*dz); } ``` 此函数用于计算接收机与卫星之间的欧几里得距离[^2]。 ##### 2. **伪距残差计算** 伪距残差是非差分定位的关键部分之,具体实现可能类似于以下代码: ```c void zdres(int type, const obsd_t *obs, int nr, const double rs[][6], const double dts[], unsigned char svh[], const nav_t *nav, rtksol_t *rb, opt_t *opt, int flag, double y[], double e[], double azel[]) { for (int i = 0; i < nr && i < 2 * MAXOBS; i++) { double pr_res = compute_pseudorange_residual(obs[i].P, rs[i][0], rb->rb); y[i] = pr_res; if (pr_res > THRESHOLD || !check_satellite_health(svh[i])) { e[i] = 0; // 设置权重为零表示该测量不可靠 } else { e[i] = WEIGHT_FACTOR / pow(pr_res, 2); } } } ``` 这段代码实现了伪距残差的计算及其可靠性评估。 --- #### 数据流概述 RTKLIB 的整体数据处理流程可以分为以下几个阶段: 1. 输入原始观测数据和星历数据。 2. 对观测数据进行预处理,包括剔除异常值和健康状态检测。 3. 使用卡尔曼滤波或其他方法估计接收机的状态向量(如位置、速度等)。 4. 输出最终的定位结果或误差统计信息。 这些步骤的具体实现依赖于多个内部函数和外部输入文件的支持[^1]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

令狐掌门

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值