Qt6+QML实现Windows屏幕录制

前言

Qt6提供了更丰富的多媒体支持类,使用Qt6 QMediaCaptureSession、QScreenCapture、QMediaRecorder,来实现一个屏幕录制的demo,其中QScreenCapture 最低版本 Qt6.5。支持录制的清晰度设置,选择视频保存位置,UI使用QML来实现。
Qt6还有一个比较好用的类 QWindowCapture, 可以针对窗口录屏。使用静态函数 QList<QCapturableWindow> capturableWindows()
可以获取当前可用的录制窗口,选择窗口进行录制。可以在本demo的基础上进行扩展。

效果图

本demo使用Qt6.8 MinGW进行编译,注意QScreenCapture最低支持Qt6.5,所以版本不能低于6.5.
在这里插入图片描述
在这里插入图片描述

正文

主要使用Qt6 QMediaCaptureSession、QScreenCapture、QMediaRecorder这三个关键的多媒体类来实现。
关键代码:

开始录制和结束录制:

void ScreenRecorder::startRecording()
{if (m_isRecording) {qDebug() << __FUNCTION__ << "Already recording, ignoring request";return;}qDebug() << __FUNCTION__ << "Starting recording process...";// 选择保存文件QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");QString defaultFileName = QString("%1/ScreenRecording_%2.mp4").arg(defaultPath).arg(timestamp);qDebug() << __FUNCTION__ << "Default save path:" << defaultFileName;QString filePath = QFileDialog::getSaveFileName(nullptr,tr("Save Recording"),defaultFileName,tr("Video Files (*.mp4)"));if (filePath.isEmpty()) {qDebug() << __FUNCTION__ << "User cancelled file selection";m_statusMessage = tr("Recording cancelled");emit statusMessageChanged();return;}qDebug() << __FUNCTION__ << "Selected file path:" << filePath;// 确保目录存在QFileInfo fileInfo(filePath);QDir dir = fileInfo.dir();if (!dir.exists()) {qDebug() << __FUNCTION__ << "Creating directory:" << dir.path();if (!dir.mkpath(".")) {qDebug() << __FUNCTION__ << "Failed to create directory";m_statusMessage = tr("Error: Could not create directory");emit statusMessageChanged();return;}}// 设置输出位置QUrl fileUrl = QUrl::fromLocalFile(filePath);qDebug() << __FUNCTION__ << "Setting output location:" << fileUrl.toString();m_recorder.setOutputLocation(fileUrl);// 更新质量设置updateQualitySettings();// 开始录制qDebug() << __FUNCTION__ << "Starting recorder...";m_recorder.record();// 启动计时器m_elapsedTimer.start();m_timer.start(1000); // 每秒更新一次m_isRecording = true;m_statusMessage = tr("Recording started");emit isRecordingChanged();emit statusMessageChanged();qDebug() << __FUNCTION__ << "Recording started successfully";
}void ScreenRecorder::stopRecording()
{if (!m_isRecording) {return;}qDebug() << __FUNCTION__ << "Stopping recording...";// 获取当前输出位置,用于验证QUrl outputLocation = m_recorder.outputLocation();qDebug() << __FUNCTION__ << "Output location:" << outputLocation.toLocalFile();// 停止录制m_recorder.stop();// 停止计时器m_timer.stop();// 检查文件是否存在QString filePath = outputLocation.toLocalFile();QFileInfo fileInfo(filePath);if (fileInfo.exists()) {qDebug() << __FUNCTION__ << "File saved successfully at:" << filePath;qDebug() << __FUNCTION__ << "File size:" << fileInfo.size() << "bytes";m_statusMessage = tr("Recording saved to %1").arg(filePath);} else {qDebug() << __FUNCTION__ << "Error: File not created at:" << filePath;m_statusMessage = tr("Error: Recording file not created");}m_isRecording = false;emit isRecordingChanged();emit statusMessageChanged();
}

设置录制器:

void ScreenRecorder::setupRecorder()
{qDebug() << __FUNCTION__ << "Setting up recorder...";// 设置捕获会话m_captureSession.setScreenCapture(&m_screenCapture);m_captureSession.setRecorder(&m_recorder);// 设置屏幕捕获m_screenCapture.setScreen(QGuiApplication::primaryScreen());m_screenCapture.setActive(true); // 激活屏幕捕获qDebug() << __FUNCTION__ << "Screen set to:" << QGuiApplication::primaryScreen()->name();qDebug() << __FUNCTION__ << "Screen capture active:" << m_screenCapture.isActive();// 设置录制器QMediaFormat format;format.setFileFormat(QMediaFormat::FileFormat::MPEG4);format.setVideoCodec(QMediaFormat::VideoCodec::H264);// 检查编解码器是否支持QList<QMediaFormat::VideoCodec> supportedCodecs = format.supportedVideoCodecs(QMediaFormat::Encode);qDebug() << __FUNCTION__ << "Supported video codecs:" << supportedCodecs;if (!supportedCodecs.contains(QMediaFormat::VideoCodec::H264)) {qDebug() << __FUNCTION__ << "Warning: H264 codec may not be supported";// 尝试使用第一个可用的编解码器if (!supportedCodecs.isEmpty()) {format.setVideoCodec(supportedCodecs.first());qDebug() << __FUNCTION__ << "Using alternative codec:" << supportedCodecs.first();}}m_recorder.setMediaFormat(format);qDebug() << __FUNCTION__ << "Media format set:" << format.fileFormat() << format.videoCodec();// 应用当前质量设置updateQualitySettings();// 连接信号connect(&m_recorder, &QMediaRecorder::recorderStateChanged,this, &ScreenRecorder::handleRecorderStateChanged);connect(&m_recorder, &QMediaRecorder::errorOccurred,this, &ScreenRecorder::handleError);qDebug() << __FUNCTION__ << "Recorder setup complete";
}

该功能是Qt结合ffmpeg来实现的,运行时会输出相关信息:qt.multimedia.ffmpeg: Using Qt multimedia with FFmpeg version 7.1 LGPL version 2.1 or later
Qt6还提供了很多非常好用的多媒体类,可以实现很多丰富的功能。本文仅演示基础使用,在此demo上可进行更多的扩展。


本文demo下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36941.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java---SpringMVC(2)

下文使用postman模拟客户端传递信息。 1.postman传参介绍 1.1传递单个参数 1.2传递多个参数 注意事项 使⽤基本类型&#xff08;int...&#xff09;来接收参数时, 参数必须传(除boolean类型), 否则会报500错误 类型不匹配时, 会报400错误 对于包装类型, 如果不传对应参数&a…

MySQL为什么默认使用RR隔离级别?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL为什么默认使用RR隔离级别&#xff1f;】面试题。希望对大家有帮助&#xff1b; MySQL为什么默认使用RR隔离级别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认使用 RR (Repeatable Read) …

人工智能之数学基础:线性方程组求解的得力助手——增广矩阵

本文重点 增广矩阵是一个极具实用价值的工具,尤其在处理线性方程组时,它展现了卓越的功效。通过整合系数和常数项,增广矩阵简化了计算过程并提供了判断方程组解集的有效方法。 增广矩阵的起源与定义 增广矩阵的概念源于线性方程组求解的需求。在解决线性方程组时,我们常…

【Axure高保真原型】增删改饼图

今天和大家分享能增删改的饼图的原型模版&#xff0c;该模版是用Axure原生元件制作的&#xff0c;所以不需要联网或者调用外部接口&#xff0c;使用也很方便&#xff0c;默认数据在中继器表格里填写&#xff0c;默认支持20个不同颜色的扇形&#xff0c;后续可根据实际需要自己增…

WordPress系统获取webshell的攻略

一.后台修改模板拿WebShell 1.进入Vulhub靶场并执⾏以下命令开启靶场&#xff1b;在浏览器中访问并安装好 #执⾏命令 cd /vulhub/wordpress/pwnscriptum docker-compose up -d 2. 修改其WP的模板&#xff0c;登陆WP后点击 【外 观】 --》 【编辑】 --》 404.php 3.插入一句话木…

Java反序列化CommonsBeanutils无依赖打Shiro

说明 如果您之前未了解过 Commons Collections&#xff08;CC&#xff09;利用链&#xff0c;建议您先阅读相关基础文章&#xff0c;然后再回头阅读此文章。这样可以更好地理解其中的内容 Java反序列化-Commons Collections3利用链分析详解 Java反序列化-Commons Collections…

用curl和python通过网络测试Ollama服务器的配置和状态

当一个Ollama服务器创建好后&#xff0c;除了用ollama指令来测试&#xff0c;还可以使用curl和python来通过网络测试Ollama的配置是否正确&#xff0c;远程是否能正常连上并与服务器进行交互。 目录 启动Ollama服务器 下载模型 curl测试 检查服务器状态 列出已安装的模型…

蓝桥杯青少组stema2025年3月9日scratch初级组真题——转动的图形

完整题目可查看&#xff1a; 转动的图形_scratch_少儿编程题库学习中心-嗨信奥https://www.hixinao.com/tiku/scratch/show-5106.html?_shareid3 程序演示可查看&#xff1a; 转动的图形-scratch作品-少儿编程题库学习中心-嗨信奥https://www.hixinao.com/scratch/creation…

杰理科技JL703N双模蓝牙芯片—云信

杰理科技JL703N芯片运算能力、接收灵敏度、发射功率、音频性能等指标均处于行业一流水平&#xff0c;能满足多场景的应用需求&#xff0c;具有以下明显优势&#xff1a; 一、高性能双核浮点CPU&#xff0c;算力十足 JL703N芯片搭载了32位高性能双核CPU&#xff0c;主频高达32…

Asp.net Core API 本地化

本文是一个demo&#xff0c;演示了如何根据用户接口查询字段(正常放header中),设置当前culture&#xff0c;并获取当前culture的key value给用户提示 创建Resources文件夹&#xff0c;添加以下三个文件 其中ExceptionUnuse 是一个空的类&#xff0c;供IStringLocalizer使用&a…

工业相机选型

工业相机选型 一、工业相机分类二、相机的主要参数2.1 分辨率2.2 速度2.3 光学接口 / 接口类型2.4 相机靶面尺寸2.5 像元尺寸2.6 精度 三、镜头介绍及选型方法3.1 工作距离&#xff08;WD&#xff09;3.2 视场角(FOV)3.3 &#xff08;镜头&#xff09;靶面尺寸3.4 帧率3.5 光圈…

eFish-SBC-RK3576 工业相机(IMX系列)方案设计

一、核心硬件架构 1. ‌图像传感器配置‌ ‌IMX系列选型‌&#xff1a; IMX678&#xff08;1/1.8" CMOS&#xff0c;2000万像素&#xff0c;全局快门&#xff0c;HDR 120dB&#xff09;IMX541&#xff08;2/3" CMOS&#xff0c;1200万像素&#xff0c;12bit ADC&…

网络华为HCIA+HCIP 广域网技术

目录 PPP协议 PPP链路建立流程 PPP链路接口状态机 LCP报文格式 LCP协商过程-正常协商 LCP协商过程-参数不匹配&#xff08;MRU&#xff09; LCP协商过程-参数不识别 PPP认证模式 - PAP PPP认证模式 - CHAP NCP协商 - 静态IP地址协商 NCP协商 - 动态IP地址协商 P…

B站pwn教程笔记-5

复习和回顾 首先复习一下ELF文件在内存和磁盘中的不同。内存只关注读写这权限&#xff0c;会合并一些代码段。 动态链接库只在内存中单独装在一份 因为很多软件都要用动态链接库了&#xff0c;不可能一个个单独复制一份。但是在有的调试环境下会单独显示出来各一份。 ld.so是装…

Vue Router 的核心实现原理是什么?

文章目录 一、路由模式实现原理1. Hash 模式2. History 模式 二、响应式路由系统1. 路由对象响应化2. 路由映射解析 三、组件渲染机制1. RouterView 实现2. 路由匹配流程 四、导航守卫系统1. 守卫执行流程2. 守卫类型对比 五、核心源码结构六、设计亮点分析七、性能优化策略总结…

CherryStudio + 火山引擎DeepSeek R1 告别服务器繁忙

CherryStudio 火山引擎DeepSeek R1 告别服务器繁忙 一、下载CherryStudio并安装 CherryStudio是功能强大的多模型桌面客户端&#xff0c;支持Windows、macOS和Linux系统。集成了多种主流的大语言模型&#xff08;如OpenAI、DeepSeek、Gemini等&#xff09;以及本地模型运行功…

Hessian 矩阵是什么

Hessian 矩阵是什么 目录 Hessian 矩阵是什么Hessian 矩阵的性质及举例说明**1. 对称性****2. 正定性决定极值类型****特征值为 2(正),因此原点 ( 0 , 0 ) (0, 0) (0,0) 是极小值点。****3. 牛顿法中的应用****4. 特征值与曲率方向****5. 机器学习中的实际意义**一、定义与…

C#从入门到精通(1)

目录 第一章 C#与VS介绍 第二章 第一个C#程序 &#xff08;1&#xff09;C#程序基本组成 1.命名空间 2.类 3.Main方法 4.注释 5.语句 6.标识符及关键字 &#xff08;2&#xff09;程序编写规范 1.代码编写规则 2.程序命名方法 3.元素命名规范 第三章 变量 &…

【LINUX操作系统】 动静态库的链接原理

初识linux&#xff08;16&#xff09; 动静态库&#xff08;手搓动静态库&#xff01;&#xff09;-CSDN博客 完成了对动静态库使用的学习&#xff0c;现在浅显理解下动态库加载的原理。 1. 宏观认知 磁盘中的应用程序main和动态库libmystdio.so先加载到内存中 加载到内存后&am…

广东启动“跨境电商+产业带”系列活动 三年打造30个产业振兴样板

大湾区经济网湾区财经快讯&#xff0c;近日&#xff0c;2025年广东省“跨境电商&#xff0b;产业带”助力“百千万工程”系列活动在中山市古镇镇启动。作为外贸领域新质生产力的重要载体&#xff0c;跨境电商将通过赋能县域特色产业带转型升级&#xff0c;为城乡融合与乡村振兴…