ScreenRecorder 源码分析

ScreenRecorder 源码分析

简介

ScreenRecorder 是一个使用 Windows 原生 C++ API 开发的屏幕录制库,通过 C++/CLI 封装供 C# 调用。它提供了高性能、低延迟的屏幕录制能力,支持多种输入源和输出格式。

核心特性

  • 支持将屏幕录制成视频、图片、长截图、gif
  • 支持多源输入:窗口、显示器、视频、图片、GIF 等
  • 支持 WGC (Windows Graphics Capture) 和 DXGI 两种捕获方式
  • 提供 C# 友好的 API 接口

项目架构概览

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      C# Application                          │
│                   (ScreenRecorder.dll)                    │
└─────────────────────────┬───────────────────────────────────┘
                          │ C++/CLI 封装层
┌─────────────────────────▼───────────────────────────────────┐
│                   Native C++ Core                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │RecordingMgr │  │ CaptureMgr  │  │ OutputMgr   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │ TextureMgr  │  │  MouseMgr   │  │  AudioMgr   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
└─────────────────────────┬───────────────────────────────────┘
                          │ Windows APIs
┌─────────────────────────▼───────────────────────────────────┐
│    WGC API    │    DXGI Desktop Duplication   │  MediaFoundation │
└─────────────────────────────────────────────────────────────┘

核心组件职责:

  • RecordingManager:录制流程总控,协调各组件
  • ScreenCaptureManager:屏幕捕获,支持多源叠加
  • OutputManager:音视频编码输出
  • TextureManager:DirectX 纹理处理
  • MouseManager:鼠标指针渲染
  • AudioManager:音频采集与同步

RecorderOptions 配置体系

RecorderOptions 是录制的核心配置类,控制所有录制参数。开始录制前需创建并设置 RecorderOptions。

cpp 复制代码
property VideoEncoderOptions^ VideoEncoderOptions;
property SourceOptions^ SourceOptions;
property OutputOptions^ OutputOptions;
property AudioOptions^ AudioOptions;
property MouseOptions^ MouseOptions;
property OverLayOptions^ OverlayOptions;
property SnapshotOptions^ SnapshotOptions;
property LogOptions^ LogOptions;

VideoEncoderOptions - 视频编码参数

控制视频编码质量、帧率、码率等核心参数。

SourceOptions - 输入源参数

控制录制内容来源。支持显示器、窗口、相机、图片、视频、GIF 作为输入源,可添加多个输入源实现叠加效果。

常用属性/方法

cpp 复制代码
property List<RecordingSourceBase^>^ RecordingSources;

RecordingSources.Add()    // 添加一个输入源
RecordingSources.Clear()  // 移除所有输入源

注意 :新创建的 SourceOptions 中 RecordingSources 列表为空,需添加输入源后才能录制。也可直接使用 SourceOptions.MainMonitor 录制主显示器。

OutputOptions - 输出控制

属性 说明
SourceRect 录制区域,为空录制整个区域,否则按指定大小裁剪
IsVideoCaptureEnabled 是否录制视频,false 时只录制音频
IsVideoFramePreviewEnabled 是否为每帧生成 Bitmap 预览
VideoFramePreviewSize 预览 Bitmap 的尺寸(像素)
StretchMode 图像缩放模式:None/Fill/Uniform/UniformToFill
OutputFrameSize 输出视频帧尺寸,可在 SourceRect 基础上缩放
RecorderMode 录制模式:Video/Slideshow/Screenshot

AudioOptions - 音频参数

属性 说明
IsAudioEnabled 是否启用音频录制
Bitrate 音频比特率
AudioChannels 通道数量
IsOutputDeviceEnabled 是否录制输出音频(默认开启)
IsInputDeviceEnabled 是否录制输入音频(默认关闭)
InputVolume / OutputVolume 输入/输出音量(0.0~1.0)
ForceInputDeviceMono 修复"伪立体声、单边有声"问题

MouseOptions - 鼠标显示

属性 说明
IsMousePointerEnabled 显示鼠标指针(默认开启)
IsMouseClicksDetected 点击时显示彩色圆点提示
MouseLeftClickDetectionColor 左键提示颜色(默认黄色 #FFFF00)
MouseClickDetectionRadius 提示圆点半径(默认 20 像素)
MouseClickDetectionDuration 提示持续时间(默认 150ms)

SnapshotOptions - 截图设置

属性 说明
SnapshotFormat 图片格式:PNG/JPEG/TIFF/BMP
SnapshotsWithVideo 录制视频时同时保存截图
SnapshotsIntervalMillis 截图间隔(毫秒)
SnapshotsDirectory 截图保存目录

RecordingSource 录制源

录制源定义"录什么",支持多种类型:

录制源 说明
WindowRecordingSource 窗口录制
DisplayRecordingSource 显示器录制(支持 WGC/DXGI)
VideoCaptureRecordingSource 相机录制
VideoRecordingSource 视频文件录制
ImageRecordingSource 图片文件录制
RecordableCamera 相机录制源(继承自 VideoCaptureRecordingSource)
RecordableWindow 窗口录制源(继承自 WindowRecordingSource)
RecordableDisplay 显示器录制源(继承自 DisplayRecordingSource)

核心流程分析

录制入口

cpp 复制代码
RecordingManager::BeginRecording(_In_opt_ std::wstring path, _In_opt_ IStream *stream)

流程步骤

  1. 检查状态:验证是否正在录制
  2. 检查依赖:确认系统支持录制 API
  3. 设置输出路径ConfigureOutputDir(path)
  4. 启动录制任务:创建异步任务执行录制
  5. 初始化各管理器
    • TextureManager:纹理处理
    • OutputManager:编码输出
    • ScreenCaptureManager:屏幕捕获
    • MouseManager:鼠标渲染
  6. 启动录制循环StartRecorderLoop()
  7. 启动屏幕捕获m_CaptureManager->StartCapture()

录制循环核心逻辑

复制代码
while (true) {
    1. 处理错误事件
    2. 暂停处理
    3. 捕获一帧:AcquireNextFrame()
    4. 前处理:Overlay叠加 → 鼠标渲染 → 裁剪/缩放
    5. 写入输出:OutputManager->RenderFrame()
}

多源叠加原理

ScreenRecorderLib 支持多输入源叠加,实现画中画、水印等效果。

叠加流程

复制代码
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Source 1   │    │  Source 2   │    │  Overlay    │
│ (主显示器)   │    │ (摄像头)    │    │  (Logo)     │
└──────┬──────┘    └──────┬──────┘    └──────┬──────┘
       │                  │                  │
       ▼                  ▼                  ▼
┌──────────────────────────────────────────────────┐
│              TextureManager (GPU合成)             │
│         按位置/层级将纹理绘制到共享画布            │
└──────────────────────────┬───────────────────────┘
                           │
                           ▼
                   ┌───────────────┐
                   │ 最终合成纹理   │
                   └───────────────┘

关键代码

cpp 复制代码
// 处理叠加层
m_CaptureManager->ProcessOverlays(pTexture, &updatedOverlaysCount);

// 纹理变换:裁剪 → 缩放 → 居中填充
ProcessTextureTransforms(pTexture, &processedTexture, 
    videoInputFrameRect, videoOutputFrameSize);

每个 Source/Overlay 可独立配置位置、大小、拉伸模式,由 TextureManager 统一合成。


音视频同步机制

采用外部时钟源 + 音频时间修正策略,本质是视频同步音频。

核心算法

复制代码
1. 获取媒体时钟时间戳
2. 计算理论视频帧时长 = 当前时间 - 上帧开始时间
3. 抓取对应时长的音频数据
4. 根据实际音频长度计算时间偏差
5. 修正视频帧时间戳

关键代码

cpp 复制代码
// 视频帧时长 ≈ 音频长度
model.Duration = duration100Nanos + diff;

// PTS 向音频时间轴对齐
model.StartPos = lastFrameStartPos100Nanos + totalDiff;

时间轴设计

  • 基准时间轴lastFrameStartPos100Nanos 严格按帧率递增
  • 修正时间轴totalDiff 累计音频误差

通过这种方式,即使音频采样存在微小偏差,视频也能保持与音频同步。


图片保存与 WIC

WIC (Windows Imaging Component)

WIC 是 Windows 提供的图像编解码系统组件,支持多种格式的读写、转换、缩放。

IStream 抽象

cpp 复制代码
// 继承关系
IUnknown → IStream → IWICStream

// 核心方法
Read()   // 读字节
Write()  // 写字节
Seek()   // 定位
Stat()   // 获取流大小

IStream 提供统一的流抽象,支持文件、内存、网络等数据源,图片编码器将数据写入 IStream,便于实现 GIF、滚动截图等功能。


C++/CLI 封装设计

设计目标

  1. 性能:核心逻辑使用原生 C++,避免托管开销
  2. 易用性:提供 C# 友好的 API
  3. 跨语言:支持 C#、VB.NET 等 .NET 语言调用

封装结构

cpp 复制代码
// C++/CLI 托管类
public ref class RecorderOptions {
    property VideoEncoderOptions^ VideoEncoderOptions;
    property SourceOptions^ SourceOptions;
    // ...
};

// 调用原生 C++ 实现
class RecordingManager {
    // 原生实现
};

类型映射

C++ 类型 C++/CLI 托管类型
std::wstring System::String^
std::vector System::Collections::Generic::List^
原生指针 IntPtr 或托管包装类

性能调优建议

1. 选择合适的捕获 API

API 适用场景 特点
WGC Windows 10 1903+ 低延迟,支持 UWP 窗口
DXGI 全兼容 高性能,需 Vista+
csharp 复制代码
// 推荐:让库自动选择
var options = new SourceOptions();
// 库会根据系统版本自动选择最优 API

2. 合理设置帧率和分辨率

csharp 复制代码
// 演示录制:15-24 fps 足够
options.VideoEncoderOptions.Framerate = 24;

// 游戏录制:30-60 fps
options.VideoEncoderOptions.Framerate = 30;

// 控制输出分辨率,减少编码压力
options.OutputOptions.OutputFrameSize = new Size(1280, 720);

3. 码率与编码器选择

csharp 复制代码
// H.264 编码,质量优先
options.VideoEncoderOptions.IsFixedFramerate = true;
options.VideoEncoderOptions.BitrateMode = BitrateControlMode.Quality;

// 网络传输场景,码率优先
options.VideoEncoderOptions.BitrateMode = BitrateControlMode.UnconstrainedVBR;
options.VideoEncoderOptions.Bitrate = 2_000_000; // 2 Mbps

4. 避免不必要的预览

csharp 复制代码
// 仅在需要实时预览时启用
options.OutputOptions.IsVideoFramePreviewEnabled = false;

// 如果需要预览,缩小预览尺寸
options.OutputOptions.VideoFramePreviewSize = new Size(320, 180);

5. 纹理复用

底层使用 TextureManager 复用 D3D11 纹理,避免频繁分配。对于长时间录制,确保:

  • 不要频繁修改 OutputFrameSize
  • 避免动态添加/移除大量 Overlay

常见问题

Q: 录屏出现绿色区域

现象:指定区域录制时,出现绿色空白区域。

原因:DPI Awareness 问题。Windows 对 DPI-unaware 进程进行虚拟化,导致获取的分辨率不正确。

解决方法 :在项目中添加 app.manifest

xml 复制代码
<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
      PerMonitorV2
    </dpiAwareness>
  </windowsSettings>
</application>

总结

ScreenRecorder 是一个设计精良的录屏库,其核心优势在于:

  1. 多源叠加:灵活的输入源组合,支持复杂场景
  2. 高性能架构:DirectX 11 + Media Foundation,充分利用 GPU
  3. C++/CLI 封装:兼顾性能与易用性
  4. 音视频同步:精确的时间轴控制
相关推荐
枳实-叶2 小时前
音频基础知识
音视频
不才小强3 小时前
Windows Graphics Capture (WGC) 屏幕捕获简介
windows·音视频
云边散步5 小时前
godot2D游戏教程系列二(23)
笔记·学习·游戏·音视频·游戏开发
linkingvision6 小时前
国产操作系统和国产GPU 能代替Windows + Intel的安防视频客户端解码功能么
音视频·视频监控·国产显卡·vaapi·国产cpu·国产gpu
AI服务老曹6 小时前
打破协议孤岛:基于 GB28181/RTSP 的 AI 视频统一接入网关架构解析(源码级)
人工智能·架构·音视频
烧饼Fighting6 小时前
java+vue推rtsp流实现视频播放(由javacv+ffmpg转为vlcj)
java·开发语言·音视频
Black蜡笔小新7 小时前
GB28181/GB35114/RTSP/ONVIF视频监控平台EasyCVR平台视频质量诊断扩展服务插件
音视频
ai产品老杨8 小时前
终结碎片化:基于GB28181/RTSP协议网关与边缘协同的企业级AI视频平台架构深度解析(附源码交付)
人工智能·架构·音视频
EasyGBS8 小时前
实战落地:国标GB28181视频平台EasyGBS+国密GB35114协议,双重保障赋能智慧安防全场景安全高效联网
人工智能·安全·音视频