Graphics Capture API是Windows 10 1809+官方推荐的低开销、高兼容抓屏方案,支持多显示器、HDR、窗口级捕获,需在UI线程创建Session,配合D3D11设备与B8G8R8A8格式纹理,避免CPU拷贝与内存频繁分配。

Windows平台用Graphics Capture API抓屏最可靠
Windows 10 1809+ 系统下,Graphics Capture API是微软官方推荐的低开销、高兼容屏幕捕获方案,比老旧的BitBlt或Desktop Duplication更易用且支持多显示器、缩放、HDR和窗口级捕获。它不依赖GDI,避免了DPI缩放错位、黑边、截不到UWP应用等问题。
关键实操点:
-
GraphicsCaptureSession必须在UI线程(通常是Win32消息循环线程)创建并启动,否则StartCapture会静默失败 - 捕获帧需用
Direct3D11设备(ID3D11Device)配合DXGI_FORMAT_B8G8R8A8_UNORM格式纹理,不能直接用BYTE*内存拷贝——否则性能崩盘 - 每帧回调中调用
frame.Surface->GetTexture()拿到ID3D11Texture2D后,立刻用CopyResource转存到可映射纹理,再用Map读取CPU可见内存;跳过这步直接Map默认纹理会触发GPU同步阻塞 - 别用
std::vector<uint8_t></uint8_t>存每一帧原始数据——频繁分配释放导致卡顿;应预分配环形缓冲区(如3帧ID3D11Texture2D对象复用)
编码环节绕不开Media Foundation推流
把BGRX图像喂给编码器不是“调个函数”就能完事。C++里没有现成的ffmpeg绑定可用时,Media Foundation是Windows唯一能稳定输出MP4/H.264的系统级方案,但它的配置极容易出错。
典型坑点:
立即学习“C++免费学习笔记(深入)”;
-
IMFMediaType设MF_MT_INTERLACE_MODE为MF_INTERLACE_MODE_PROGRESSIVE,否则部分显卡驱动会拒绝初始化编码器 - 输入类型必须显式设置
MF_MT_ALL_SAMPLES_INDEPENDENT=TRUE,否则H.264编码器可能丢帧 - 用
IMFSinkWriter写文件时,SetInputMediaType之后必须调一次BeginWriting,否则WriteSample返回MF_E_NOT_INITIALIZED - 帧时间戳(
sample->SetSampleTime)单位是100ns,不是毫秒——传错会导致视频加速/倒放或muxer崩溃
Linux下libpipewire比X11截屏靠谱得多
用XShmGetImage或XGetImage在现代Linux桌面(Wayland为主、X11为辅)上基本失效:Wayland禁止X11截全屏,NVIDIA驱动下XShm常返回黑图,且无法捕获鼠标指针。
正确路径是接入PipeWire:
- 需链接
-lpipewire-0.3 -lspa-0.2,头文件来自pipewire/pipewire.h和spa/param/video/format-utils.h - 创建
pw_stream时,param结构体必须填SPA_VIDEO_FORMAT_BGRx(不是RGBx),否则GStreamer后端解码失败 - 收到
PW_STREAM_STATE_STREAMING后才开始处理buffer,过早读pw_buffer的datas[0].data是空指针 - 别自己解析YUV420P——PipeWire默认输出的是BGRx线性内存,直接送编码器;转YUV反而引入色彩失真和性能损耗
macOS必须用AVCaptureScreenInput而非CGDisplayStream
CGDisplayStream虽底层高效,但自macOS 12起被标记为deprecated,且不支持捕获菜单栏、Dock、Mission Control等系统UI层;而AVCaptureScreenInput是AVFoundation官方支持的屏幕源,能完整捕获整个桌面(含鼠标),还自动处理Retina缩放。
关键细节:
- 初始化前必须调用
[AVCaptureScreenInput setShowsCursor:YES],否则鼠标永远不可见 - 输出
AVCaptureVideoDataOutput的videoSettings里要设(NSString*)kCVPixelBufferPixelFormatTypeKey: (NSNumber*)kCVPixelFormatType_32BGRA,否则CMSampleBufferRef里像素排列错乱 - 在
captureOutput:didOutputSampleBuffer:fromConnection:回调中,CMSampleBufferGetImageBuffer返回的CVPixelBufferRef需用CVPixelBufferLockBaseAddress加锁才能读取,漏掉这步会导致随机崩溃 - 别在主线程里做H.264编码——iOS/macOS上硬编码必须在独立串行队列(
dispatch_queue_t)中调用VTCompressionSessionEncodeFrame,否则超时或返回errSessionInvalid
跨平台最难的从来不是捕获本身,而是帧时间戳对齐、音频同步、异常恢复(比如窗口最小化时捕获暂停)、以及不同GPU驱动下纹理映射行为差异。这些细节不会报错,但会让录制出来的视频跳帧、音画不同步、或在某台机器上完全黑屏——得靠真实硬件反复测。


















