目录

  • main函数在哪里
  • obs项目架构
  • main函数浅析
    • crash的处理
    • obs配置
    • obs log
    • 网络请求libcurl
    • 主界面
    • Qt适配高dpi屏幕
  • 总结

  最近对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 _WIN32obs_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源码分析专栏】

obs源码分析【一】:main函数相关推荐

  1. SequoiaDB 系列之五 :源码分析之main函数

    好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...

  2. x265源码分析:main函数及CLIOptions结构体解释

    /** * 返回码信息:* 0 – 编码成功:* 1 – 命令行解释失败:* 2 – 编码器打开失败:* 3 – 生成流头部失败:* 4 – 编码出错:* 5 – 打开csv文件失败.*/ int m ...

  3. Linux内核 eBPF基础:ftrace源码分析:过滤函数和开启追踪

    Linux内核 eBPF基础 ftrace基础:过滤函数和开启追踪 荣涛 2021年5月12日 本文相关注释代码:https://github.com/Rtoax/linux-5.10.13 上篇文章 ...

  4. jQuery源码分析之$.grep()函数四问

    问题1:jQuery.grep源码是什么? //grep函数,第三个参数表示是否根据fn的结果取反! grep: function( elems, callback, invert ) { var c ...

  5. jQuery源码分析之$.inArray()函数

    测试代码1: //indexOf原生方法:indexOf(特定的元素,开始下标); //同时indexOf的第二个参数可以是负数,表示从倒数第几个开始,记住,此时不是看下标,而是看倒数第几个! var ...

  6. obs源码分析【五】:音频采集线程

      在第三篇介绍了视频的线程,音频的线程代码也是在那一块儿: if (!ResetAudio())throw "Failed to initialize audio";   音频线 ...

  7. activemq源码笔记:main函数小结

    main函数文件路径: activemq-master\activemq-master\activemq-console\src\main\java\org\apache\activemq\conso ...

  8. 【Dual-Path-RNN-Pytorch源码分析】loss函数:SI-SNR

    DPRNN使用的loss函数是 SI-SNR SI-SNR 是scale-invariant source-to-noise ratio的缩写,中文翻译为尺度不变的信噪比,意思是不受信号变化影响的信噪 ...

  9. 【rnnoise源码分析】compute_frame_feature函数

    函数签名 /** * @param st 全局context,存储一些上下文用的变量和结构体 * @param X 根据入参in生成的频域数据,其中在训练时,低频部分被全部清零 * @param P ...

最新文章

  1. decimal在存储过程和C#中的应用
  2. 数据挖掘讲座:我所知道的一点Data Mining
  3. ITK:为图像中标记区域的边界上色
  4. visual c++ build tools的安装与使用
  5. Python 位操作运算符
  6. socket 编程入门教程(一)TCP server 端:5、创建监听嵌套字
  7. JavaScript生成指定范围内的随机数
  8. 利用SciTE的导出功能保持代码语法着色效果
  9. Python中的datetime日期格式化
  10. SQL内部连接3个表?
  11. python协程详解_彻底搞懂python协程-第一篇(关键词1-4)
  12. springboot集成ureport2
  13. zencart模板如何设计
  14. 【转】用 Go 构建一个区块链
  15. 《Qt5:键盘事件》
  16. 模拟键盘鼠标事件有两种方法
  17. 编译原理—实验二LL(1)语法分析(一)
  18. 自动给多个视频进行画面裁切,裁剪成一样的尺寸
  19. 读书有益——》摆渡人
  20. 【Chapter 3: Process】

热门文章

  1. 1.3windows命令行下使用blat发邮件带附件
  2. codevs4438 YJQ Runs Upstairs
  3. 学校的花花草草都印在我的脑海里
  4. 2020年全球网速排名
  5. 微型计算机inc,8位微型计算机的逻辑设计
  6. An Image is worth 16*16 words: Transformers for image recognition at scale.
  7. iOS-微信分享成功回调问题
  8. 打印海报_新安装的字体用Word打印显示不出这种字体问题_保存为A0大小问题_ppt转换为PDF不失真问题
  9. 阿里云PK腾讯云,云计算的寡头对决即将到来
  10. vue中使用vue-typed-js