QT/C++ 屏幕录像项目
FStarRTool_project_handbook
项目:FStarRTool — C++/Qt + FFmpeg 屏幕录像工具
技术栈:Qt 6.5 · FFmpeg 8.0 · C++17 · qMake/CMake
总代码量:≈ 2000 行 | 新建 10 个文件 | 修改 12 次
这个项目你能学到什么?
1. 技术能力提升
| 能力维度 | 具体收获 | 难度等级 | 实际应用场景 |
|---|---|---|---|
| C++ 面向对象 | 类封装、继承、多态、头文件分离、RAII 资源管理 | ⭐⭐⭐ | 任何 C++ 项目开发 |
| Qt GUI 开发 | 信号槽机制、布局系统、QSS 样式、事件处理、自定义控件 | ⭐⭐⭐⭐ | 桌面应用开发(跨平台) |
| Qt 进程管理 | QProcess 启停外部程序、进程间通信、优雅停止与强制终止 | ⭐⭐⭐⭐ | 集成第三方 CLI 工具 |
| Qt 绘图系统 | QPainter 2D 绘图、CompositionMode 合成模式、自定义全屏控件 | ⭐⭐⭐⭐ | 截图工具、画板、标注工具 |
| 音视频处理 | FFmpeg 命令行、屏幕捕获(gdigrab)、视频编码(H.264/H.265)、音频捕获(dshow) | ⭐⭐⭐⭐ | 直播推流、视频剪辑、录屏软件 |
| FFmpeg API | libavformat/libavcodec/libavutil、像素格式转换、编码参数调优 | ⭐⭐⭐⭐⭐ | 专业音视频开发 |
| 系统编程 | Windows API(窗口检测)、系统托盘、全局热键、屏幕坐标系 | ⭐⭐⭐ | 系统工具开发 |
| 软件工程 | 模块化设计、配置持久化(QSettings)、错误处理、编译打包发布 | ⭐⭐⭐ | 任何项目的工程化实践 |
2. 核心设计模式
| 设计模式 | 项目中的体现 | 学到的核心思想 |
|---|---|---|
| 信号槽(Observer) | 按钮点击 → startRecording(),录制完成 → 弹窗通知 |
松耦合:发送者不需要知道接收者是谁 |
| 封装(Encapsulation) | ScreenRecorder 封装 FFmpeg 进程的所有细节 |
对外只暴露 start()/stop(),内部实现完全隐藏 |
| RAII | ScreenRecorder 构造初始化 QProcess,析构自动清理 |
资源获取即初始化,异常安全 |
| 进程隔离 | 用 QProcess 调用 FFmpeg 而非直接链接 libav 库 | FFmpeg 崩溃不影响主程序,稳定性更高 |
| 状态模式 | updateUIState(bool recording) 根据状态切换按钮启用/禁用 |
集中管理 UI 状态,避免状态不一致 |
| 配置持久化 | QSettings 保存用户设置(输出路径、编码参数、帧率) | 关闭重开后恢复用户偏好 |
3. 面试加分点
| 加分项 | 说明 | 面试中如何表达 |
|---|---|---|
| 完整项目经验 | 从零到一的完整桌面应用,非 Demo | "我独立开发了一个屏幕录像工具,代码约 2000 行" |
| 跨领域技术融合 | C++/Qt(GUI)+ FFmpeg(音视频)+ Windows API(系统) | "核心难点在于 Qt 与 FFmpeg 的集成,以及 Windows API 窗口检测" |
| 工程化思维 | 模块划分、错误处理、配置管理、编译打包 | "采用进程隔离架构,FFmpeg 崩溃不影响主程序" |
| 问题解决能力 | FFmpeg 路径问题、音频设备降级、优雅停止 | "遇到音频设备不存在时,自动降级为无音频录制并通知用户" |
| 可扩展架构 | 预留了摄像头、画中画、标注等扩展接口 | "架构设计考虑了可扩展性,后续可平滑添加新功能" |
4. 学完后能做什么
| 方向 | 具体能力 | 示例项目 |
|---|---|---|
| 桌面工具开发 | 独立开发跨平台 Qt 桌面应用 | 截图工具、文件管理器、系统监控 |
| 音视频开发 | 使用 FFmpeg 进行音视频处理 | 直播推流、视频转码、音频编辑 |
| 系统工具 | 集成系统 API 开发工具类软件 | 剪贴板管理、快捷启动器、桌面美化 |
| 游戏辅助 | 屏幕捕获 + 图像识别 | 自动化测试工具、游戏录制 |
| 技术面试 | 扎实的 C++/Qt/音视频项目经验 | 能回答 RAII、信号槽、进程管理、编码原理等高频面试题 |
一、七天计划总览表
| 天数 | 主题 | 核心任务 | 新建/修改文件 | 新增代码量 | 关键产出 |
|---|---|---|---|---|---|
| Day 0 | 环境搭建 | 安装 Qt 6.5 + FFmpeg + 配置 qMake/CMake | — | — | 开发环境就绪,能编译运行空窗口 |
| Day 1 | Qt 基础入门 | 创建项目骨架、理解信号槽机制、搭建主窗口 UI 框架 | 新建 4 个 | 165 行 | 带按钮的主窗口,三组控件(录制区域/设置/控制)可点击响应 |
| Day 2 | UI 美化与交互 | 布局管理器嵌套、QSS 样式表、状态栏与计时器 | 修改 2 个 | 160 行 | 彩色按钮(绿/橙/红)、实时计时器、状态栏信息显示 |
| Day 3 | FFmpeg 命令行 | 掌握 FFmpeg 录屏命令、音频捕获、菜单栏与系统托盘 | 修改 2 个 | 110 行 | 菜单栏+快捷键(Ctrl+R/S/P)、系统托盘图标、FFmpeg 命令行录制验证 |
| Day 4 | FFmpeg 集成 | QProcess 管理外部进程、ScreenSelector 区域选择器、鼠标/键盘事件 | 新建 2 个,修改 1 个 | 240 行 | 全屏遮罩+鼠标拖拽选区、ESC/右键取消、FFmpeg 进程启停 |
| Day 5 | 核心录制模块 | 封装 ScreenRecorder 类、QPainter 绘图、系统托盘深度集成 | 新建 2 个,修改 2 个 | 230 行 | 完整录制流程(选区→录制→停止→保存)、优雅退出(发送 q 命令) |
| Day 6 | FFmpeg API 进阶 | libav* 编码流程、像素格式转换、编码参数调优 | 新建 2 个,修改 2 个 | 250 行 | H.264/H.265/VP9/AV1 四种编码支持、CRF/帧率/比特率可调 |
| Day 7 | 综合实战 | 编译打包发布、功能扩展、性能优化、错误处理完善 | 修改 3 个 | 130 行 | 可分发的安装包、配置持久化(QSettings)、完善的状态管理 |
二、每日知识点详解表
| 天数 | 知识领域 | 具体知识点 | 难度 | 掌握标志 |
|---|---|---|---|---|
| Day 0 | 环境配置 | Qt 6.5 安装、FFmpeg 下载与 PATH 配置、qMake/CMake 构建系统 | ⭐⭐ | 能成功编译运行一个 Qt 空窗口 |
| Day 1 | Qt 基础 | QMainWindow/QApplication 结构、信号与槽(Signal & Slot)、QPushButton/QLabel/QComboBox 控件、Q_OBJECT 宏、MOC 编译机制 | ⭐⭐ | 能用信号槽连接按钮点击事件,理解 connect() 语法 |
| Day 2 | Qt UI | QVBoxLayout/QHBoxLayout/QGridLayout 布局管理器、QGroupBox 分组、QSS 样式表(等价 CSS)、QTimer 定时器、QStatusBar 状态栏 | ⭐⭐⭐ | 能用嵌套布局搭建复杂界面,能用 QSS 给控件换肤 |
| Day 3 | FFmpeg 命令 | gdigrab 屏幕捕获、CRF 质量控制、libx264/libx265 编码器、dshow 音频捕获、立体声混音、QAction/QMenu/QSystemTrayIcon | ⭐⭐⭐ | 能用命令行录制屏幕+音频,能给应用加菜单栏和托盘 |
| Day 4 | 进程与事件 | QProcess 启停外部程序、QProcess 信号(finished/errorOccurred)、鼠标事件(press/move/release)、键盘事件、QPainter 全屏绘制、跨窗口坐标转换 | ⭐⭐⭐⭐ | 能用 QProcess 控制 FFmpeg,能实现全屏遮罩+鼠标选区 |
| Day 5 | 核心架构 | ScreenRecorder 类封装、FFmpeg 命令动态构建、优雅停止(q 命令 vs kill)、QPainter 绘图系统、RAII 内存管理、Qt 父子对象树 | ⭐⭐⭐⭐ | 能理解完整的录制启停流程,能读懂并修改 ScreenRecorder |
| Day 6 | 音视频 API | libavformat/libavcodec/libavutil API、像素格式转换(YUV420P/RGB)、编码参数调优(preset/tune/profile)、QSettings 配置持久化、SettingsDialog 设置对话框 | ⭐⭐⭐⭐⭐ | 能通过 API 精细控制编码参数,能保存/加载用户配置 |
| Day 7 | 工程实践 | Release 编译打包、Qt 部署工具(windeployqt)、错误处理边界情况、性能优化(内存/ CPU)、功能扩展方向(摄像头/画中画/标注) | ⭐⭐⭐⭐ | 能产出可分发的安装包,能规划后续功能迭代 |
三、项目文件结构表
| 文件名 | 职责 | 核心类/函数 | 对应学习日 |
|---|---|---|---|
main.cpp |
程序入口 | QApplication、MainWindow 创建与启动 |
Day 1 |
mainwindow.h/cpp |
主窗口 | setupUI()、startRecording()、stopRecording()、createMenus()、createTrayIcon() |
Day 1-7 |
screenrecorder.h/cpp |
录制核心 | ScreenRecorder(封装 FFmpeg 进程)、buildFFmpegArguments()、start()/stop() |
Day 5 |
screenselector.h/cpp |
区域选择 | ScreenSelector(全屏遮罩+鼠标选区)、paintEvent()、mousePressEvent() |
Day 4 |
regionselectdialog.h/cpp |
区域选择对话框 | 多种区域选择方式 | Day 5 |
settingsdialog.h/cpp |
设置对话框 | 输出路径、编码参数、QSettings 配置读写 | Day 6 |
recordingcontrolwidget.h/cpp |
悬浮控制栏 | 录制时的迷你控制面板 | Day 7 |
FStarRTool.pro |
qMake 构建配置 | 项目依赖、源文件列表 | Day 0 |
CMakeLists.txt |
CMake 构建配置 | 替代 qMake 的现代构建方式 | Day 7 |
四、学习路线图
Day 0 ─── 环境搭建 ── Qt 6.5 + FFmpeg + CMake
│
Day 1 ─── Qt 基础 ──── 信号与槽、应用结构、基础控件
│
Day 2 ─── Qt UI ───── 布局管理器、QSS 样式、对话框
│
Day 3 ─── FFmpeg CLI ── 屏幕录制、编码参数、音频捕获
│
Day 4 ─── Qt 进程 ──── QProcess、QTimer、事件系统、区域选择
│
Day 5 ─── Qt 绘图 ──── QPainter、ScreenRecorder、系统托盘
│
Day 6 ─── FFmpeg API ── libav* 编码流程、像素格式、配置持久化
│
Day 7 ─── 综合实战 ──── 编译打包、功能扩展、优化方向
│
└──→ 独立开发能力:Qt 桌面应用 + 音视频处理 + 系统工具
部分技术点讲解
一、框架
项目框架
FStarRTool/
├── main.cpp # 程序入口
├── mainwindow.h/cpp # 主窗口 UI 和逻辑
├── screenrecorder.h/cpp # FFmpeg 进程封装
├── screenselector.h/cpp # 窗口/区域选择
├── regionselectdialog.h/cpp # 区域选择对话框
├── settingsdialog.h/cpp # 设置对话框
└── videoencoder.h/cpp # FFmpeg 库编码器(可选)
知识体系框架
┌─────────────────────────────────────────────────────────────────┐
│ FStarRTool 知识体系 │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ C++ 基础 │ │ Qt 框架 │ │ 操作系统 │ │
│ │ • 类与对象 │ │ • 信号槽 │ │ • 进程管理 │ │
│ │ • 继承多态 │ │ • 事件系统 │ │ • 窗口管理 │ │
│ │ • 智能指针 │ │ • 布局 │ │ • 设备枚举 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 多媒体 │ │ UI/UX │ │ 工程实践 │ │
│ │ • FFmpeg │ │ • 拖拽选择 │ │ • 模块化 │ │
│ │ • 音频捕获 │ │ • 实时绘制 │ │ • 配置管理 │ │
│ │ • 视频编码 │ │ • 托盘图标 │ │ • 错误处理 │ │
│ │ • 设备检测 │ │ • 悬浮窗 │ │ • 打包部署 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
执行流程图
用户启动程序
↓
main() 初始化 QApplication
↓
创建 MainWindow
↓
setupUI() 创建界面
↓
用户点击"开始录制"
↓
startRecording() 调用
↓
recorder->start() 启动 FFmpeg
↓
recordingStarted 信号 → onRecordingStarted 槽
↓
FFmpeg 进程录制
↓
用户点击"停止"
↓
stopRecording() 调用
↓
recordingStopped 信号
↓
视频文件保存
二、屏幕捕获技术
1. Windows GDI 抓取(GDIGrab)
args << "-f" << "gdigrab";
args << "-i" << "desktop";
- 使用 FFmpeg 的
gdigrab输入设备 - 支持指定录制区域(
-offset_x/y、-video_size)
2. 三种录制模式
| 模式 | 实现方式 |
|---|---|
| 全屏 | QScreen::geometry() |
| 窗口 | Windows API WindowFromPoint + GetWindowRect |
| 区域 | 自定义 QRubberBand 矩形选择器 |
3. 跨平台窗口检测
#ifdef Q_OS_WIN
#include <windows.h>
HWND hwnd = WindowFromPoint(pt);
while (GetParent(hwnd) != NULL) hwnd = GetParent(hwnd);
#endif
部分面试题
3.1 项目设计类
Q1: 为什么要自己开发录屏工具?市场上不是有很多现成的吗?
标准答案:
主要有三个原因:
1. 学习目的:深入理解音视频处理原理,从零搭建完整项目
2. 定制需求:现有录屏工具要么收费(如 FastStone),要么功能冗余(如 OBS)
3. 技术验证:验证 Qt + FFmpeg 组合的可行性,为后续直播项目打基础
项目规模约 2000 行代码,核心模块包括:
- ScreenRecorder:FFmpeg 进程管理
- ScreenSelector:区域/窗口选择
- RegionSelectDialog:多种区域选择方式
- SettingsDialog:配置管理
Q2: 项目的整体架构是什么?
标准答案:
采用 MVC 变体架构:
┌─────────────────────────────────────────────────────┐
│ MainWindow (View + Controller) │
│ - UI 控件管理 │
│ - 用户交互响应 │
│ - 信号槽连接 │
├─────────────────────────────────────────────────────┤
│ ScreenRecorder (Model) │
│ - FFmpeg 进程封装 │
│ - 录制参数管理 │
│ - 错误处理 │
├─────────────────────────────────────────────────────┤
│ 辅助组件 │
│ - ScreenSelector: 窗口/区域选择 │
│ - RegionSelectDialog: 区域选择对话框 │
│ - SettingsDialog: 设置管理 │
│ - RecordingControlWidget: 悬浮控制栏 │
└─────────────────────────────────────────────────────┘
通信方式:Qt 信号槽(解耦)
数据持久化:QSettings(注册表/INI文件)
3.2 技术实现类
Q4: 如何实现窗口录制?如何找到鼠标下的窗口?
答案:
// 核心:Windows API + 跨平台条件编译
QRect ScreenSelector::getWindowGeometry(const QPoint &pos) {
#ifdef Q_OS_WIN
POINT pt = {pos.x(), pos.y()};
HWND hwnd = WindowFromPoint(pt);
// 关键:获取顶层窗口(而不是子窗口)
while (GetParent(hwnd) != NULL) {
hwnd = GetParent(hwnd);
}
// 排除桌面窗口
if (hwnd == GetDesktopWindow()) {
return QRect(); // 无效
}
RECT rect;
if (GetWindowRect(hwnd, &rect)) {
return QRect(rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top);
}
#endif
return QRect();
}
【扩展讨论】
- 为什么需要 GetParent 循环?
因为 WindowFromPoint 可能返回子窗口(如按钮),需要找到根窗口
- 如何处理最小化窗口?
IsIconic(hwnd) 检查,如果是则无法获取有效矩形
- 跨平台方案?
macOS: CGWindowListCopyWindowInfo
Linux: XQueryTree + XGetWindowAttributes
Q5: 区域选择时的橡皮筋效果如何实现?
答案:
【核心思路:绘制叠加层 + 清除遮罩】
void ScreenSelector::paintEvent(QPaintEvent *event) {
QPainter painter(this);
// 1. 绘制截图背景
painter.drawPixmap(0, 0, m_screenPixmap);
// 2. 绘制半透明黑色遮罩(覆盖全屏)
painter.fillRect(rect(), QColor(0, 0, 0, 100));
// 3. 清除选中区域的遮罩(露出原图)
if (m_selecting) {
QRect selectedArea = QRect(m_startPoint, m_currentPoint);
// 关键:CompositionMode_Clear 清除该区域
painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.fillRect(selectedArea, Qt::transparent);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
// 4. 绘制选择框边框
painter.setPen(QPen(QColor(0, 120, 215), 2));
painter.drawRect(selectedArea);
}
}
【技术点】
- QRubberBand:Qt 内置橡皮筋控件,可简化实现
- 为什么用 CompositionMode_Clear?高效,无需二次截图
- 如何确保精确性?记录鼠标按下和释放时的坐标
部分简历模板
模板一:C++ 开发工程师(综合型)
项目经历
FStarRTool — 桌面屏幕录像工具 | 个人项目 | 2025.01 - 2025.03
- 基于 Qt 6.5 框架独立开发了一款功能完整的桌面屏幕录像软件,支持全屏、窗口、自定义区域三种录制模式
- 集成 FFmpeg 8.0.1 音视频编解码能力,支持 H.264 / H.265 / VP9 / AV1 四种视频编码和 AAC / MP3 / Opus 三种音频编码
- 使用 DirectShow API 实现 Windows 音频设备自动检测与采集,支持系统音频(立体声混音)和麦克风双通道录制
- 实现了基于 GDI Grab 的屏幕截图采集、libswscale 色彩空间转换、libavcodec 视频编码的完整数据管线
- 通过 QSystemTrayIcon 实现系统托盘驻留与最小化录制,QSettings 实现配置持久化,支持快捷键操作
技术关键词: C++17, Qt 6.5, FFmpeg, libavcodec, libavformat, libswscale, DirectShow, GDI, 信号槽机制, QProcess, 多媒体编解码
#简历中的项目经历要怎么写##项目##C++##QT#
查看15道真题和解析