FFMPEG录屏(19)--- 枚举Windows下的屏幕列表,并获取名称、缩略图

news/2024/10/20 0:08:12/

在Windows下枚举显示器列表并获取名称、缩略图

在Windows系统中,枚举显示器列表并获取它们的名称和缩略图是一个常见的需求。本文将详细介绍如何实现这一功能,涉及到的主要技术包括Windows API和C++编程。

获取显示器信息

首先,我们需要一个函数来枚举所有的显示器,并获取它们的名称和缩略图。

int enum_screens(enumerator_param &param) {BOOL enum_result = TRUE;for (int device_index = 0;; ++device_index) {DISPLAY_DEVICEW device;device.cb = sizeof(device);enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0);if (!enum_result) {break;}if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) {continue;}bool is_primary = false;if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {is_primary = true;}DEVMODEW device_mode;device_mode.dmSize = sizeof(device_mode);device_mode.dmDriverExtra = 0;BOOL result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);if (!result) {break;}traa_screen_source_info screen_info;screen_info.is_window = false;screen_info.id = device_index;screen_info.rect = traa_rect(device_mode.dmPosition.x, device_mode.dmPosition.y,device_mode.dmPelsWidth, device_mode.dmPelsHeight);auto utf8_name = string_trans::unicode_to_utf8(device.DeviceName);strncpy_s(const_cast<char *>(screen_info.title), sizeof(screen_info.title) - 1,utf8_name.c_str(), utf8_name.length());if (param.thumbnail_size.width > 0 && param.thumbnail_size.height > 0 &&param.thumbnail_instance) {capture_utils::get_screen_image_by_gdi(screen_info.rect, param.thumbnail_size,const_cast<uint8_t **>(&screen_info.thumbnail_data),screen_info.thumbnail_size);}param.infos.push_back(screen_info);}return traa_error::TRAA_ERROR_NONE;
}

这个函数使用EnumDisplayDevicesW来枚举所有的显示器,并使用EnumDisplaySettingsExW来获取每个显示器的设置。然后,我们将显示器的信息存储在traa_screen_source_info结构体中,并将其添加到参数的infos向量中。

获取缩略图

获取显示器的缩略图是一个关键步骤。我们需要使用GDI(图形设备接口)来捕获屏幕图像,并将其缩放到我们需要的大小。

bool capture_utils::get_screen_image_by_gdi(const traa_rect &rect, const traa_size &target_size,uint8_t **data, traa_size &scaled_size) {const desktop_size scaled_desktop_size =calc_scaled_size(desktop_size(rect.right - rect.left, rect.bottom - rect.top),desktop_size(target_size.width, target_size.height));if (scaled_desktop_size.is_empty()) {LOG_ERROR("calc scaled scaled_size failed, get empty scaled_size");return false;}HDC screen_dc = ::GetDC(nullptr);if (!screen_dc) {LOG_ERROR("get screen dc failed: {}", ::GetLastError());return false;}bool result = false;HANDLE section = nullptr;uint8_t *bitmap_data = nullptr;HBITMAP bitmap = nullptr;HDC compatible_dc = nullptr;HGDIOBJ old_obj = nullptr;do {constexpr int bytes_per_pixel = desktop_frame::kBytesPerPixel;BITMAPINFO bmi = {};bmi.bmiHeader.biWidth = scaled_desktop_size.width();bmi.bmiHeader.biHeight = -scaled_desktop_size.height();bmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 32;bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);bmi.bmiHeader.biSizeImage =scaled_desktop_size.width() * scaled_desktop_size.height() * bytes_per_pixel;bitmap = ::CreateDIBSection(screen_dc, &bmi, DIB_RGB_COLORS, (void **)&bitmap_data, section, 0);if (!bitmap) {LOG_ERROR("create dib section failed: {}", ::GetLastError());break;}compatible_dc = ::CreateCompatibleDC(screen_dc);old_obj = ::SelectObject(compatible_dc, bitmap);if (!old_obj || old_obj == HGDI_ERROR) {LOG_ERROR("select object failed: {}", ::GetLastError());break;}SetStretchBltMode(compatible_dc, COLORONCOLOR);result = ::StretchBlt(compatible_dc, 0, 0, scaled_desktop_size.width(),scaled_desktop_size.height(), screen_dc, rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top, SRCCOPY | CAPTUREBLT);if (!result) {LOG_ERROR("stretch blt failed: {}", ::GetLastError());break;}*data = new uint8_t[bmi.bmiHeader.biSizeImage];if (!*data) {LOG_ERROR("alloc memory for thumbnail data failed: {}", ::GetLastError());break;}memcpy_s(*data, bmi.bmiHeader.biSizeImage, bitmap_data, bmi.bmiHeader.biSizeImage);scaled_size = scaled_desktop_size.to_traa_size();} while (0);if (bitmap) {::DeleteObject(bitmap);}if (compatible_dc) {if (old_obj) {::SelectObject(compatible_dc, old_obj);}::DeleteDC(compatible_dc);}::ReleaseDC(nullptr, screen_dc);if (!result && *data) {delete[] * data;*data = nullptr;}return result;
}

这个函数使用CreateDIBSection创建一个设备独立位图(DIB),然后使用StretchBlt将屏幕图像复制到位图中。最后,我们将位图数据复制到一个新的缓冲区中,并返回缩放后的大小。

整合一切

最后,我们需要一个函数来整合所有的步骤,枚举显示器并获取它们的名称和缩略图。

int screen_source_info_enumerator::enum_screen_source_info(const traa_size icon_size,const traa_size thumbnail_size,const unsigned int external_flags,traa_screen_source_info **infos,int *count) {std::unique_ptr<thumbnail> thumbnail_instance;if (thumbnail_size.width > 0 && thumbnail_size.height > 0) {thumbnail_instance.reset(new thumbnail());}enumerator_param param = {icon_size, thumbnail_size, external_flags, {}, thumbnail_instance.get()};enum_windows(param);enum_screens(param);*count = static_cast<int>(param.infos.size());*infos =reinterpret_cast<traa_screen_source_info *>(new traa_screen_source_info[param.infos.size()]);if (*infos == nullptr) {LOG_ERROR("alloca memroy for infos failed: {}", ::GetLastError());return traa_error::TRAA_ERROR_OUT_OF_MEMORY;}for (size_t i = 0; i < param.infos.size(); ++i) {auto &source_info = param.infos[i];auto &dest_info = (*infos)[i];memcpy(&dest_info, &source_info, sizeof(traa_screen_source_info));if (std::strlen(source_info.title) > 0) {strncpy_s(const_cast<char *>(dest_info.title), sizeof(dest_info.title) - 1, source_info.title,std::strlen(source_info.title));}if (std::strlen(source_info.process_path) > 0) {strncpy_s(const_cast<char *>(dest_info.process_path), sizeof(dest_info.process_path) - 1,source_info.process_path, std::strlen(source_info.process_path));}}return traa_error::TRAA_ERROR_NONE;
}

这个函数创建一个thumbnail实例,并调用enum_windowsenum_screens来枚举窗口和显示器。然后,它将枚举到的信息复制到一个新的缓冲区中,并返回信息的数量。

通过上述步骤,我们可以在Windows系统中枚举显示器列表,并获取它们的名称和缩略图。这一过程涉及到Windows API的使用、窗口属性的获取、图标和缩略图的处理等多个方面。希望本文能对您有所帮助。

最近有点懒了,这还是copilot生成的。。。

源码传送

traa


http://www.ppmy.cn/news/1540370.html

相关文章

【升华】python基础包NumPy学习

NumPy是使用Python进行科学计算的基础软件包。除其他外&#xff0c;它包括&#xff1a; 功能强大的N维数组对象。精密广播功能函数。集成 C/C和Fortran 代码的工具。强大的线性代数、傅立叶变换和随机数功能。 # 1、安装包 $ pip install numpy# 2、进入python的交互式界面 $…

FFmpeg 4.3 音视频-多路H265监控录放C++开发四 :RGB颜色

一 RGB 的意义&#xff1f; 为什么要从RGB 开始讲起呢&#xff1f; 因为最终传输到显卡显示器的颜色都是RGB 即使能处理YUV的API&#xff0c;本质上也是帮你做了从 YUV 到 RGB的转换。 RGB888 表示 R 占8bit&#xff0c;G 占8bit&#xff0c;B 占8bit&#xff0c;也就是每一…

解锁A/B测试:如何用数据驱动的实验提升你的网站和应用

来源&#xff1a;Gallo, A. (2017, June 28). A refresher on A/B testing. Harvard Business Review. https://hbr.org/2017/06/a-refresher-on-ab-testing 在数字化时代&#xff0c;我们每天都在被大量的信息和广告轰炸。那么&#xff0c;如何让你的网站或应用脱颖而出&…

通信工程学习:什么是VPN虚拟私人网络

VPN&#xff1a;虚拟私人网络 VPN&#xff0c;即虚拟私人网络&#xff08;Virtual Private Network&#xff09;&#xff0c;是一种通过公共网络&#xff08;如互联网&#xff09;建立的加密连接&#xff0c;用于保护用户的网络连接和数据传输的安全与隐私。以下是关于VPN的详细…

QGroundControl最新版本MacOS平台编译(使用CMakeLists.txt)

1.下载源码: git clone https://github.com/mavlink/qgroundcontrol.git --recursive 2.安装依赖: brew install GStreamer 设置环境变量:GST_PLUGIN_PATH 安装SDL2: brew install SDL2

Qt 自绘开关按钮以及设计器中的提升为用法

文章目录 自绘按钮实现概要效果图代码 提升为用法介绍步骤 总结 自绘按钮实现 概要 当我们需要一个开关样式的QPushbutton&#xff0c;没有图片的话&#xff0c;我们可以采用自绘的形式实现。且使用QtDesinger中提升为Promote to的功能加入界面中&#xff0c;而不是使用代码的…

流体力学笔记

目录 1、名词2、湍流与涡流3 涡激振动4 压力面与吸力面参考&#xff1a;[空气动力学的“他山之石”](https://zhuanlan.zhihu.com/p/412542513) 1、名词 转列&#xff1a;transition 涡脱落&#xff1a;vortex shedding 涡分离&#xff1a;vortex rupture 气动噪声&#xff1a…

SpringBoot配置文件敏感信息如何加密?及踩坑总结(全面讲解)

目录 1.添加依赖 2.接下来去生成密文 3.然后在命令行窗口通过mvn命令去调用这个插件 4.接下来会生成对对应的密文&#xff0c;然后去替换application.properties中的对应内容 5.运行程序解密 在软件开发中&#xff0c;保护敏感信息如数据库密码、API密钥等是至关重要的。J…