Windows平台如何实现多屏幕采集录制并推送RTMP或轻量级RTSP服务

技术背景

好多开发者在传统行业监控的时候,跟我们对接Windows平台屏幕或摄像头RTMP推送|轻量级RTSP服务模块,有这个的一个技术诉求,他们需要同时采集到多个屏幕,并输出到不同的RTMP或RTSP URL,确保每个屏幕都可以被看到,本文基于此,主要介绍,如何在Windows平台实现多屏幕采集并实现RTMP或轻量级RTSP服务。

技术实现

我们知道,在 Windows平台上,可以使用 EnumDisplayMonitors 函数进行多屏采集。以下是关于这个函数的详细介绍:

一、函数概述

EnumDisplayMonitors 是 Windows API 中的一个函数,用于枚举所有的显示监视器(屏幕)。

函数原型:

BOOL EnumDisplayMonitors(
  HDC             hdc,
  LPCRECT         lprcClip,
  MONITORENUMPROC lpfnEnum,
  LPARAM          dwData
);

参数说明

  • hdc:设备上下文环境的句柄。如果此参数为 NULL,则使用整个桌面。
  • lprcClip:指向一个矩形区域的指针,用于指定裁剪区域。如果此参数为 NULL,则不进行裁剪。
  • lpfnEnum:指向一个回调函数的指针。每当找到一个监视器时,系统将调用这个回调函数。
  • dwData:应用程序定义的回调函数的参数。

返回值:如果函数成功,则返回 TRUE;否则,返回 FALSE

二、使用步骤

定义回调函数
回调函数是在枚举过程中,系统为每个找到的监视器调用的函数。回调函数的原型通常如下:

BOOL CALLBACK MonitorEnumProc(
  HMONITOR hMonitor,
  HDC      hdcMonitor,
  LPRECT   lprcMonitor,
  LPARAM   dwData
);

在回调函数中,可以根据需要对每个监视器进行处理。例如,可以获取监视器的信息、进行屏幕采集等。

调用 EnumDisplayMonitors 函数
在主程序中,调用 EnumDisplayMonitors 函数,并传入相应的参数。例如:

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    // 在这里处理每个监视器
    return TRUE;
}

int main()
{
    EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
    return 0;
}

获取监视器信息
在回调函数中,可以使用其他 Windows API 函数来获取监视器的信息。例如,可以使用 GetMonitorInfo 函数获取监视器的详细信息,包括名称、位置、尺寸等。

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    MONITORINFO mi;
    mi.cbSize = sizeof(MONITORINFO);
    if (GetMonitorInfo(hMonitor, &mi))
    {
        // 处理监视器信息
        std::cout << "Monitor Name: " << mi.szDevice << std::endl;
        std::cout << "Monitor Position: (" << mi.rcMonitor.left << ", " << mi.rcMonitor.top << ")";
        std::cout << ", Size: (" << mi.rcMonitor.right - mi.rcMonitor.left << ", " << mi.rcMonitor.bottom - mi.rcMonitor.top << ")" << std::endl;
    }
    return TRUE;
}

进行屏幕采集
一旦获取了监视器的信息,就可以使用相应的技术进行屏幕采集。例如,可以使用 BitBlt 函数将屏幕内容复制到一个内存设备上下文,然后进行进一步的处理或保存。

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    MONITORINFO mi;
    mi.cbSize = sizeof(MONITORINFO);
    if (GetMonitorInfo(hMonitor, &mi))
    {
        // 进行屏幕采集
        HDC hdcSrc = CreateDC(mi.szDevice, NULL, NULL, NULL);
        HDC hdcDst = CreateCompatibleDC(hdcSrc);
        int width = mi.rcMonitor.right - mi.rcMonitor.left;
        int height = mi.rcMonitor.bottom - mi.rcMonitor.top;
        HBITMAP hbmp = CreateCompatibleBitmap(hdcSrc, width, height);
        SelectObject(hdcDst, hbmp);
        BitBlt(hdcDst, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);

        // 保存采集的图像或进行其他处理

        DeleteObject(hbmp);
        DeleteDC(hdcDst);
        DeleteDC(hdcSrc);
    }
    return TRUE;
}

在获取到显示器数量、名称、坐标、大小和主辅设备等信息后,采集屏幕图像,从Win8开始,不再支持32位以下bpp显示设置, 实现中可以假设采集到的都是32位RGB图像,再把RGB转YUV, 编码输出RTMP/RTSP就好了,屏幕选择的和屏幕层叠加的接口设计如下:

/*
 * Copyright (C) daniusdk.com. All rights reserved. 
 * WeChat: xinsheng120
 */
typedef struct _NT_PB_ScreenLayerConfigV3
{
	NT_PB_LayerBaseConfig	base_;
	NT_PB_RectRegion		clip_region_; // 如果是全屏幕的话,请全部填充0
	NT_PVOID				reserve1_; // 保留字段1
 
#define NT_PB_SCREEN_LAYER_FLAG_NONE	 (0)
#define NT_PB_SCREEN_LAYER_FLAG_DISPLAY_OPTION_DEVICE_NAME (1u<<0)
	NT_UINT32               flags_;
	NT_INT32                scale_filter_mode_;  // 缩放质量, 0的话SDK将使用默认值, 目前可设置范围为[1, 3], 值越大缩放质量越好,但越耗性能
 
#define NT_PB_SCREEN_LAYER_DISPLAY_OPTION_BUFFER_SIZE (256)
	NT_CHAR					display_option_[NT_PB_SCREEN_LAYER_DISPLAY_OPTION_BUFFER_SIZE];
} NT_PB_ScreenLayerConfigV3;
 
 
typedef layer_conf_wrapper<NT_PB_ScreenLayerConfigV3, NT_PB_E_LAYER_TYPE_SCREEN> ScreenLayerConfigWrapperV3;
 
 
NT_UINT32 NT_API NT_PB_SetCaptureDisplayDeviceName(NT_HANDLE handle, NT_PCSTR name_utf8);

以大牛直播SDK启动RTSP服务为例,每个屏幕采集编码,对应一个RTSP拉流的URL。

选择好帧率、码率后,点击“配置查看RTSP服务”按钮,进入配置轻量级RTSP服务页面:

配置查看RTSP服务:

发布RTSP流后,页面回调界面,生成两个rtsp拉流的url,如果是三个屏幕,默认会生成三个rtsp的url,然后用windwows平台RTSP直播播放模块,做测试即可。是不是非常方便?

三、注意事项

  1. 权限问题
    在进行屏幕采集时,可能需要管理员权限。如果程序在没有管理员权限的情况下运行,可能会导致采集失败。
  2. 性能考虑
    屏幕采集可能会消耗一定的系统资源,特别是在同时采集多个屏幕时。需要注意性能问题,避免影响系统的正常运行。
  3. 兼容性
    不同版本的 Windows 系统可能会有一些差异,需要确保代码在目标系统上的兼容性。

总结

总之,使用 EnumDisplayMonitors 函数可以方便地进行 Windows 平台上的多屏采集。通过定义回调函数并结合其他 Windows API 函数,可以获取监视器信息并进行屏幕采集等操作。在使用过程中,需要注意权限、性能和兼容性等问题。配合大牛直播SDK的推送模块,可以轻松实现Windows平台下的多屏幕采集功能逻辑。感兴趣的开发者,可以私信单独跟我沟通探讨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值