A cross-platform .NET library for capturing screenshots, video recordings (with audio), and performance metrics (FPS, 1% / 0.1% lows, frametimes) from a running game or window.
It captures externally (no code injected into the game) using each OS's native capture stack, so it is anti-cheat-safe and works regardless of the game's graphics API (DirectX 9–12, Vulkan, OpenGL). No FFmpeg dependency.
- Windows — Windows Graphics Capture + Media Foundation + WASAPI + PresentMon/ETW. Fully implemented and verified.
- Linux — MangoHud metrics (covers native and Proton/DirectX titles),
grim+gpu-screen-recorder. Metrics tested; capture/record authored (needs a Linux desktop to verify). - macOS —
screencapture(video only in v1). Authored (needs a Mac to verify); the richer ScreenCaptureKit/AVFoundation backend is future work.
- .NET 10 SDK/runtime.
- Windows: Windows 10 build 1903 (19041) or later for the full feature set.
- Metrics on Windows require running as administrator (real-time ETW session).
- Linux/macOS require the relevant CLI tools installed (see Platform notes).
The library is not on NuGet yet — reference the projects (or built DLLs). Reference the API package plus the backend for each OS you target; each backend registers itself automatically at runtime based on the current OS.
<ItemGroup>
<ProjectReference Include="path/to/src/GameOverlay.Capture/GameOverlay.Capture.csproj" />
<!-- Windows backend (net10.0-windows10.0.19041.0) -->
<ProjectReference Include="path/to/src/GameOverlay.Capture.Windows/GameOverlay.Capture.Windows.csproj"
Condition="'$(TargetFramework)' == 'net10.0-windows10.0.19041.0'" />
<!-- Linux / macOS backends (net10.0) -->
<ProjectReference Include="path/to/src/GameOverlay.Capture.Linux/GameOverlay.Capture.Linux.csproj"
Condition="'$(TargetFramework)' == 'net10.0'" />
<ProjectReference Include="path/to/src/GameOverlay.Capture.MacOS/GameOverlay.Capture.MacOS.csproj"
Condition="'$(TargetFramework)' == 'net10.0'" />
</ItemGroup>You only need the backend(s) for the OSes you ship to. All public types are in the
GameOverlay.Capture namespace.
using GameOverlay.Capture;
var target = CaptureTarget.FromProcess("Rayman Origins"); // by process name
// CaptureTarget.FromProcess(pid) | FromWindow(hwnd) | FromMonitor(hmonitor) | Interactive()await using var session = await CaptureSession.CreateAsync(target);
await session.SaveScreenshotAsync("shot.png"); // format inferred from extension (.png/.jpg)await using var session = await CaptureSession.CreateAsync(target);
var recording = await session.StartRecordingAsync(new RecordingOptions
{
OutputPath = "clip.mp4",
Video = new VideoOptions
{
Codec = VideoCodec.H264, // or Hevc
FrameRate = 60, // paced to this rate
Quality = VideoQuality.High, // or set Bitrate directly
},
Audio = new AudioOptions
{
SystemLoopback = true, // game/system audio -> in the video
Microphone = MicrophoneOptions.Default, // mic -> sidecar "clip.mic.m4a"
Bitrate = 160_000, // AAC bits/sec per track
},
});
await Task.Delay(TimeSpan.FromSeconds(10));
await recording.StopAsync(); // finalises clip.mp4 (+ clip.mic.m4a)On Windows the game/system audio is embedded in the video; the microphone is written to a
separate sidecar file next to it (<output>.mic.m4a).
await using var session = await CaptureSession.CreateAsync(target);
session.Metrics.SampleReady += (_, s) =>
Console.WriteLine($"{s.Fps:F0} fps ({s.FrameTimeMs:F1} ms)"); // live, per frame
session.Metrics.Start();
await Task.Delay(TimeSpan.FromSeconds(30));
session.Metrics.Stop();
MetricsSummary summary = session.Metrics.GetSummary();
Console.WriteLine($"avg {summary.AverageFps:F1} | 1% low {summary.OnePercentLowFps:F1} " +
$"| 0.1% low {summary.PointOnePercentLowFps:F1} | min {summary.MinFps:F1}");Windows metrics use PresentMon/ETW and require the process to run as administrator. On Linux, launch the game with MangoHud logging enabled (metrics parse its CSV). macOS game FPS is not available programmatically (Metal HUD / Instruments only).
Use these to populate a settings UI:
foreach (var d in CaptureCapabilities.GetInputDevices()) // microphones
Console.WriteLine($"{(d.IsDefault ? "*" : " ")} {d.Name} ({d.Id})");
foreach (var d in CaptureCapabilities.GetOutputDevices()) // system/loopback endpoints
Console.WriteLine(d.Name);
IReadOnlyList<int> fps = CaptureCapabilities.CommonFrameRates; // 24,30,50,60,120,144,240 (+ any value)
IReadOnlyList<VideoQuality> qualities = CaptureCapabilities.VideoQualities; // Low..VeryHigh
IReadOnlyList<VideoCodec> codecs = CaptureCapabilities.VideoCodecs; // H264, Hevc
IReadOnlyList<int> audioKbps = CaptureCapabilities.AudioBitratesKbps; // 96,128,160,192
// Record from a specific microphone:
var mic = new MicrophoneOptions { DeviceId = CaptureCapabilities.GetInputDevices()[0].Id };CaptureSession.CreateAsync(target, options?, backend?) — resolves the OS backend automatically;
throws PlatformNotSupportedException if none is registered.
| Type | Key members |
|---|---|
CaptureTarget |
FromWindow(hwnd), FromProcess(pid/name), FromMonitor(hmon), Interactive() |
CaptureOptions |
CaptureCursor, HideCaptureBorder (Win11), UseDesktopDuplication (Win, monitor-only), FrameRateCap |
RecordingOptions |
OutputPath (required), Video, Audio, Container (Auto/Mp4/Mkv) |
VideoOptions |
Codec, FrameRate, Quality (Low..VeryHigh), Bitrate (override), UseHardware |
AudioOptions |
SystemLoopback, Microphone, Bitrate (AAC bits/sec), SeparateTracks |
MetricsSummary |
AverageFps, MinFps, MaxFps, OnePercentLowFps, PointOnePercentLowFps, P95/P99FrameTimeMs, FrameCount, DurationSeconds |
Quality vs bitrate: VideoQuality derives a bitrate from resolution × frame rate; set
VideoOptions.Bitrate (bits/sec) to override it. AudioOptions.Bitrate snaps to the nearest
supported AAC rate (96/128/160/192 kbps).
- Windows — Uses Windows Graphics Capture (per-window/monitor, API-agnostic). Frame rate is
paced to
VideoOptions.FrameRate; timestamps come from the compositor's presentation time for low jitter.UseDesktopDuplicationforces the monitor-only DXGI fallback (e.g. older Windows). Exclusive-fullscreen games may capture black — run the game borderless/windowed (WindowsDiagnostics.IsExclusiveFullscreenActive()detects this). - Linux — Metrics reuse MangoHud (a Vulkan layer; Proton routes DirectX → Vulkan, so it
covers Windows games too); launch the game with MangoHud logging. Screenshots need
grim(Wayland) /spectacle/gnome-screenshot; recording needsgpu-screen-recorder. - macOS — Uses the built-in
screencapture(video only, no audio in v1); grant Screen Recording permission. Game FPS metrics are not available programmatically.
dotnet build GameOverlay.Capture.slnx
dotnet test GameOverlay.Capture.slnxTry the sample CLI (samples/GameOverlay.Capture.Cli):
# On Windows, run the Windows-TFM build:
dotnet run --project samples/GameOverlay.Capture.Cli -f net10.0-windows10.0.19041.0 -- devices
dotnet run --project samples/GameOverlay.Capture.Cli -f net10.0-windows10.0.19041.0 -- shot --process "Game" shot.png
dotnet run --project samples/GameOverlay.Capture.Cli -f net10.0-windows10.0.19041.0 -- record --process "Game" clip.mp4 --seconds 10 --audio --mic --fps 60 --quality high
dotnet run --project samples/GameOverlay.Capture.Cli -f net10.0-windows10.0.19041.0 -- metrics --process "Game" --seconds 30 # run elevatedA platform-neutral core (GameOverlay.Capture / .Core) defines the public API and a set of
backend interfaces (IFrameSource, IAudioSource, IRecorder, IMetricsProvider,
ICaptureBackend, …) plus shared logic (frametime statistics, the recording state machine). Each
per-OS backend implements those interfaces and self-registers via a module initializer, so the
correct backend is selected at runtime by RID. The shared FrameTimeStatistics / FrameTimeTracker
compute the FPS numbers identically across platforms.
| Capability | Windows | Linux | macOS |
|---|---|---|---|
| Screenshot | ✅ verified | ||
| Video recording | ✅ verified | ||
| System audio in video | ✅ verified | ❌ (needs AVFoundation) | |
| Microphone (sidecar) | ✅ verified | ❌ (needs AVFoundation) | |
| FPS / frametime metrics | ✅ (elevated) | ✅ parser tested | ❌ documented gap |
Future: in-process PipeWire capture (Linux), a native ScreenCaptureKit/AVFoundation backend (macOS, for system audio + mic), and an optional injection/overlay path (advanced, anti-cheat risk).
Licensed under the MIT License.