Qt开发实战:屏幕录制项目中学习到的知识与遇到的难题

Qt开发实战:屏幕录制项目中学习到的知识与遇到的难题


一、音频采集:RtAudio库

1.1 RtAudio简介

RtAudio是一个强大的C++类库,旨在为实时音频输入/输出提供统一的API。无论你是在Linux、Macintosh OS X还是Windows平台上开发,RtAudio都能帮助你轻松地与计算机音频硬件进行交互。

通过支持多种音频API(如ALSA、JACK、PulseAudio、OSS、CoreAudio、DirectSound、ASIO和WASAPI),RtAudio确保了在不同操作系统上的无缝集成和高效性能。

项目地址https://github.com/thestk/rtaudio

1.2 在Qt项目中的应用

在本次项目中,使用RtAudio来采集扬声器的声音。由于是在Windows环境下开发,需要在RtAudio.h中定义宏来启用Windows音频API:

cpp 复制代码
#define __WINDOWS_WASAPI__

WASAPI(Windows Audio Session API)是Windows Vista及以上版本提供的音频接口,具有低延迟、高性能的特点,非常适合实时音频采集场景。


二、安装程序制作

2.1 NSIS + Qt方案

NSIS(Nullsoft Scriptable Install System)是一个专业的开源安装程序制作工具,结合Qt可以实现美观的安装界面。

参考资源

2.2 卸载脚本关键分析

卸载部分的NSIS脚本需要处理以下几个关键点:

核心代码解析

nsis 复制代码
# 定义卸载程序的用户界面页面顺序
UninstPage custom un.QtUninstConfirmPage
UninstPage instfiles

# 准备卸载程序的运行环境
Function un.onInit
    InitPluginsDir
    # 加载Qt相关DLL
    File /oname=$PLUGINSDIR\Qt5Core${QT_DLL_SUFFIX}.dll "$%QTDIR%\bin\Qt5Core${QT_DLL_SUFFIX}.dll"
    File /oname=$PLUGINSDIR\Qt5Gui${QT_DLL_SUFFIX}.dll "$%QTDIR%\bin\Qt5Gui${QT_DLL_SUFFIX}.dll"
    # ... 更多DLL加载
FunctionEnd

# 调用Qt界面进行卸载确认
Function un.QtUninstConfirmPage
    GetFunctionAddress $0 un.OnUIPrepared
    ${UI_PLUGIN_NAME}::BindUninstallEventToNsisFunc "UNINST_UI_PREPARED" $0
    
    GetFunctionAddress $0 un.OnUserConfirmUninstall
    ${UI_PLUGIN_NAME}::BindUninstallEventToNsisFunc "UNINST_USER_CONFIRM" $0
FunctionEnd

2.3 Inno Setup方案

Inno Setup是另一个流行的安装程序制作工具,但相对NSIS而言,自定义界面的灵活性稍逊一筹。

教程资源https://www.bilibili.com/video/BV15k4y1R7cL


三、程序更新机制

3.1 实现思路

程序更新采用独立的更新程序方案:

  1. 客户端检测到新版本,启动更新程序
  2. 客户端自行关闭
  3. 更新程序从服务端下载更新包
  4. 更新程序覆盖所有dll和exe文件

3.2 关键设计

后门机制 :当getVersion接口返回is_enforce为99时,不能通过程序自身更新,需要用户手动卸载、下载安装包、重新安装。

包格式规范

  • 安装包:ZRecorder-setup-x.x.x.exe
  • 更新包:ZRecorder-update-x.x.x.zip

3.3 注意事项

卸载程序删除的是安装目录下的所有文件,因此更新包覆盖不会影响卸载流程。


四、高DPI适配问题

4.1 问题现象

在设置了系统缩放比的电脑上,程序界面显示异常:

4.2 解决方案

方案一:禁用缩放

完全禁用程序的缩放,使程序不随系统进行缩放:

cpp 复制代码
#include <QApplication>

int main(int argc, char *argv[]) {
    // 禁用Qt的高DPI自动缩放
    QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
    
    QApplication app(argc, argv);
    return app.exec();
}

方案二:启用高DPI支持(推荐)

cpp 复制代码
#include <QApplication>

int main(int argc, char *argv[]) {
    // 必须在创建QApplication前调用
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    // 设置舍入策略为直接使用原始缩放值
    QApplication::setHighDpiScaleFactorRoundingPolicy(
        Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
    
    QApplication app(argc, argv);
    return app.exec();
}

Qt::HighDpiScaleFactorRoundingPolicy枚举值说明:

说明
Round 四舍五入到整数(默认)
Ceil 向上取整
Floor 向下取整
PassThrough 直接使用原始缩放值(推荐)

五、图标模糊问题

5.1 使用SVG格式

推荐使用SVG格式图片,可以在任意缩放比例下保持清晰。

注意事项

  • 如果在label上SVG显示不出来,可以在程序中使用一个QSvgWidget
  • 将QWidget提升为QSvgWidget
  • QLabel无法提升为QSvgWidget

5.2 获取屏幕缩放信息

cpp 复制代码
// 获取所有屏幕的缩放比
QList<QScreen*> screens = QApplication::screens();
for (QScreen* screen : screens) {
    qreal dpi = screen->logicalDotsPerInch() / 96.0;
    qreal ratio = screen->devicePixelRatio();
    qDebug() << "Screen:" << screen->name();
    qDebug() << "DPI scaling:" << dpi;
    qDebug() << "Pixel ratio:" << ratio;
}

// 获取当前屏幕的缩放比
QScreen* currentScreen = this->window()->screen();
if (currentScreen) {
    qreal ratio = currentScreen->devicePixelRatio();
}

5.3 解决图片模糊的方法


六、ICO图标格式

6.1 格式特点

ICO格式是Windows操作系统专用的图标文件格式,一个ICO文件可以包含多个不同尺寸的图片(如16×16、32×32、48×48、256×256等),系统会根据需要自动选择合适的尺寸显示。

6.2 最佳实践


七、全局快捷键

7.1 使用QHotkey库

即使在最小化、焦点不在程序上,快捷键也能生效。推荐使用第三方库QHotkey实现。

编译步骤

bash 复制代码
git clone https://gitee.com/bihj9919/QHotkey.git

# 配置CMake(32位示例)
cmake -B build -S . -A Win32 -DQT_DEFAULT_MAJOR_VERSION=5 \
    -DCMAKE_PREFIX_PATH="G:\Qt\5.15.2\msvc2019"

# 编译Release版本
cmake --build build --config Release

# 安装
cmake --install build --prefix build

八、系统托盘菜单圆角

实现圆角托盘菜单需要自定义样式,参考资源:


九、提高录制帧率

9.1 当前方案分析

BitBlt + FFmpeg软件编码

  • BitBlt截取1080p屏幕约30ms
  • 软件编码约12ms
  • 性能瓶颈在屏幕截取
  • 多线程优化后最多实现30fps

9.2 优化方案

使用DirectX进行屏幕截取 + libyuv裁剪和颜色空间转换

DirectX是微软开发的高性能多媒体接口,性能优于BitBlt。

9.3 帧率控制机制

双线程架构

  • 采集线程:屏幕采集、裁剪、颜色空间转换,按设置帧率固定间隔抓取
  • 编码线程:编码、写入MP4文件,根据PTS值从队列取数据

PTS处理逻辑

  1. 期望PTS > 队首PTS:丢弃旧帧,直到队首PTS >= 期望PTS
  2. 期望PTS < 队首PTS:直接使用队首帧
  3. 队列为空:重复上一帧

9.4 注意事项

使用优化方案可以达到60fps,但需要注意音视频同步问题。


十、窗口边框阴影

10.1 问题场景

当程序主体色为白色,移动到白色背景上时,程序边框不可见。

10.2 解决方案

cpp 复制代码
setContentsMargins(8, 8, 8, 8);  // 为阴影留出空间

QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
shadow->setBlurRadius(8);        // 阴影半径
shadow->setOffset(0, 0);         // 阴影偏移
shadow->setColor(QColor(0, 0, 0, 60));  // 阴影颜色
shadow->setEnabled(true);
ui->centralwidget->setGraphicsEffect(shadow);

10.3 边距设置说明

  • setContentsMargins():设置窗口内所有内容距离窗口边框的距离
  • UI文件中的layoutMargin:控件距离布局容器的距离
  • 两者叠加:实际控件距离窗口边框 = 两者之和

十一、安装程序轮播图闪动问题

11.1 问题原因

为程序添加阴影后,设置显示图片的透明度失效,导致出现空白或闪动。

11.2 解决思路

需要调整阴影效果与透明度动画的配合方式,确保两者不冲突。

相关推荐
要开心吖ZSH2 小时前
MP4 转 WAV 音频转码方案详解(ProcessBuilder + FFmpeg)
java·ffmpeg·音视频
deepdata_cn3 小时前
移动端高并发视频合成
音视频·视频合成
人还是要有梦想的3 小时前
QT的基本学习路线
开发语言·qt·学习
艾莉丝努力练剑3 小时前
【QT】QT快捷键整理
linux·运维·服务器·开发语言·图像处理·人工智能·qt
黑化暴龙魔神--幻梦3 小时前
QT使用TRANSLATIONS添加多国翻译(详细过程)
qt·自动翻译
程序员_大白3 小时前
【2025版】最新Qt下载安装及配置教程(非常详细)零基础入门到精通,收藏这篇就够了
开发语言·qt
我在人间贩卖青春3 小时前
Qt多媒体编程
qt·多媒体编程
高亚奇3 小时前
QT版本 MSVC/MinGW/GCC 含义及如何区分
开发语言·qt