You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Windows Graphics Capture API录制指定屏幕区域?

实现指定区域的屏幕录制(基于Windows Graphics Capture API)

核心思路

Windows Graphics Capture API本身不直接支持区域录制,但可以通过捕获完整的显示器/窗口画面后,在编码阶段裁剪指定区域实现需求。核心步骤为:

  1. 捕获目标区域所属的显示器/窗口的完整画面
  2. 在编码前对每一帧进行裁剪,仅保留指定的x、y坐标及宽高范围的内容

修改现有代码实现区域录制

1. 新增带区域参数的录制函数

修改原RecordScreen函数,添加区域参数,并将编码器的宽高指定为目标区域的尺寸:

private async void RecordScreen(GraphicsCaptureItem item, int captureX, int captureY, int captureWidth, int captureHeight)
{
    _device = Direct3D11Helpers.CreateDevice();

    uint frameRate = 30;
    uint bitrate = 3 * 1000000; 
    // 使用指定区域的宽高作为编码器输出尺寸
    var width = (uint)captureWidth;
    var height = (uint)captureHeight;

    try
    {
        newFile = GetTempFile();
        using (var stream = new FileStream(newFile, FileMode.CreateNew).AsRandomAccessStream())
        // 初始化编码器时传入裁剪区域参数
        using (_encoder = new Encoder(_device, item, captureX, captureY, captureWidth, captureHeight))
        {
            await _encoder.EncodeAsync(
                stream,
                width, height, bitrate,
                frameRate);
        }
    }
    catch (Exception ex)
    {
        // 建议添加异常日志,便于调试排查
        // Debug.WriteLine($"录制异常:{ex.Message}");
    }
}

2. 修改Encoder类,添加帧裁剪逻辑

针对你参考的Encoder类,新增裁剪参数并在帧处理阶段添加Direct3D裁剪操作:

// 在Encoder类中新增私有变量存储区域参数
private readonly int _captureX;
private readonly int _captureY;
private readonly int _captureWidth;
private readonly int _captureHeight;
private readonly GraphicsCaptureItem _item;
private readonly IDirect3DDevice _device;

// 修改构造函数,接收区域参数
public Encoder(IDirect3DDevice device, GraphicsCaptureItem item, int captureX, int captureY, int captureWidth, int captureHeight)
{
    _device = device;
    _item = item;
    _captureX = captureX;
    _captureY = captureY;
    _captureWidth = captureWidth;
    _captureHeight = captureHeight;
}

// 帧处理方法中添加裁剪逻辑
private async Task ProcessFrame(Direct3DSurface surface)
{
    // 将捕获的画面转换为Direct3D11纹理
    using var sourceTexture = Direct3D11Helpers.CreateSharpDXTexture(surface, _device);
    
    // 创建对应裁剪尺寸的目标纹理
    var textureDesc = sourceTexture.Description;
    textureDesc.Width = _captureWidth;
    textureDesc.Height = _captureHeight;
    textureDesc.MipLevels = 1;
    using var croppedTexture = new Texture2D(_device.AsSharpDXDevice(), textureDesc);
    
    // 执行区域复制(裁剪)
    var context = _device.AsSharpDXDevice().ImmediateContext;
    var sourceRect = new Rectangle(_captureX, _captureY, _captureWidth, _captureHeight);
    context.CopySubresourceRegion(croppedTexture, 0, 0, 0, 0, sourceTexture, 0, sourceRect);
    
    // 将裁剪后的纹理传入编码器
    await _mediaEncoder.EncodeFrameAsync(croppedTexture.AsWindowsRuntimeTexture());
}

3. 获取目标区域所属的显示器(针对全局坐标)

如果输入的是全局屏幕坐标,需先找到对应显示器的句柄,再创建捕获项:

// 获取指定全局坐标所属的显示器句柄
public static IntPtr GetMonitorFromGlobalPoint(int x, int y)
{
    return MonitorFromPoint(new POINT { X = x, Y = y }, MONITOR_DEFAULTTONEAREST);
}

// 导入Windows API
[DllImport("user32.dll")]
private static extern IntPtr MonitorFromPoint(POINT pt, uint dwFlags);

private const uint MONITOR_DEFAULTTONEAREST = 0x00000002;

[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
    public int X;
    public int Y;
}

调用示例:

// 示例:录制全局坐标(100,100)处,宽800高600的区域
int captureX = 100;
int captureY = 100;
int captureWidth = 800;
int captureHeight = 600;

var monitorHandle = GetMonitorFromGlobalPoint(captureX, captureY);
var captureItem = CreateItemForMonitor(monitorHandle);
RecordScreen(captureItem, captureX, captureY, captureWidth, captureHeight);

注意事项

  • 需确保指定的区域完全在捕获的显示器/窗口范围内,避免裁剪出错
  • 若录制窗口内的相对区域,需将窗口内坐标转换为全局坐标,或捕获窗口后使用窗口内相对坐标裁剪
  • 裁剪操作会增加性能开销,可根据硬件配置调整帧率和比特率优化体验

内容的提问来源于stack exchange,提问作者Riz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:25:16