Add experimental session replay capturing on Windows#1404
Conversation
There was a problem hiding this comment.
Woah, amazing stuff! 🥇
There's a lot in the MP4 writer and video encoder that a casual reader might not understand in detail, but I scrolled through nevertheless. 😅 I didn't notice anything Windows-specific in them, so would it be possible to enable this for other platforms in the future?
|
@jpnurmi Thanks! And you're right - the muxer and most of the encoder are platform-agnostic so technically there's nothing stopping them from running elsewhere. For now I kept this Windows-only since it's the primary target for Unreal and The next step is hooking in the other |
JoshuaMoelans
left a comment
There was a problem hiding this comment.
LGTM! a few open questions just to clarify some stuff, but nothing blocking :D
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a777cf2. Configure here.
JoshuaMoelans
left a comment
There was a problem hiding this comment.
Thanks for addressing the questions! 🚀🚀🚀
This PR adds a dedicated "Session Replay" docs page for Unreal SDK. Related items: - getsentry/sentry-unreal#1404 - getsentry/sentry-unreal#1386 - getsentry/sentry-xbox#136

This PR adds an opt-in session replay feature for Windows allowing the SDK to continuously record the last several seconds of gameplay into a MP4 file and attach it to crash reports.
Example crash event with Session Replay attached (Windows).
Architecture
The feature is a four-stage pipeline (backbuffer capture → H.264 encode → fMP4 mux → rolling rotation), each stage living on its own thread so nothing blocks the game or render thread.
FSentryBackBufferCapture (render thread) hooks Slate's
OnBackBufferReadyToPresent, throttles capture to the configured frame rate, and copies each captured frame into a BGRA8 texture that can be consumed by the encoder.FSentryVideoEncoder (dedicated thread) submits those textures to the AVCodecs H.264 encoder, asynchronously drains compressed packets, converts the Annex-B bitstream to AVCC format, and groups encoded samples into fragments at keyframe boundaries.
FSentryFMP4Writer is a lightweight, stateless muxer that converts SPS/PPS data and AVCC samples into ISO-BMFF structures, producing the
ftyp+moovinitialization segment once and amoof+mdatpair for each fragment.FSentrySessionReplayRecorder acts as the orchestrator. It owns the capture hook and encoder, maintains a rolling ring buffer of completed fragments, and runs a rotation thread that periodically assembles the initialization segment and fragment ring into a complete recording before replacing the on-disk file.
Engine Dependencies
Session Replay depends on Unreal Engine’s experimental
AVCodecsplugin family (available from UE 5.2 onward). Usage is gated in two layers:Build-time: The feature is only compiled and linked when the consuming project has the
AVCodecsCoreplugin enabled andAttachSessionReplayset.Build.csinspects the project descriptor, and only then definesUSE_SENTRY_SESSION_REPLAY. If either condition is missing, the Session Replay sources are excluded entirely and no encoder/capture code is built for that platform/configuration.Runtime:
AttachSessionReplayis validated again at startup. If it is disabled, the recorder does not initialize, even if the module was compiled in.Other Considerations
Backbuffer → BGRA8 conversion : NVENC’s D3D12 path only accepts BGRA8, while many projects render to 10-bit (PF_A2B10G10R10) or HDR backbuffers. Additionally, Slate does not create its backbuffer with the
ShaderResourceflag, so it cannot be sampled directly. The capture path therefore hardware-copies the backbuffer into a scratch texture we own (same format, correct usage flags), then runsAddDrawTexturePass(engine-provided) to convert scratch → BGRA8 pool texture. If the source is already BGRA8, this second step degenerates into a straight GPU copy; otherwise, conversion happens via the engine pixel shader.Wall-clock based timing : Timing is based on
FPlatformTime::Seconds()rather than frame count. Fragment duration and keyframe cadence are derived from real elapsed time instead of the render frame rate, since gameplay is inherently variable (hitches, alt-tab, throttling). Frame-based timing would cause drift, turning a 12s window into 20s+ under load. Sample durations are measured against wall-clock deltas and clamped (e.g., 2s max) to guard against stalls.TFDT rebasing on rotation : Each fragment embeds decode timestamps. When the ring buffer evicts older fragments, remaining fragments may no longer start at t=0, which leads to incorrect duration reporting in players. During rotation, the first surviving fragment is rewritten so its timeline starts at t=0.
Write-on-rotate: Each snapshot is written to a temporary file and then renamed over the target. This ensures Sentry's backend only ever observes either the previous complete snapshot or the newly finished one - never a partially written (torn) file.
Known Limitations
Testing
To evaluate the performance impact introduced by Session Replay, the game binary was profiled twice: once with replay disabled to establish a baseline, and once with replay enabled to measure the overhead. Per-frame timings were captured using Unreal Engine’s CSV profiler.
The majority of the additional cost comes from the render-thread backbuffer capture hook. The game thread, RHI thread, and GPU are only minimally affected, since encoding and file rotation are performed on dedicated background threads.
Setup
UE 5.7.4, Win64 Development build)3840×2160) fullscreen exclusive viar.SetRes 3840x2160fto bypass Windows DPI-scaled working-area clamping. 4K represents the worst-case replay workload due to the larger backbuffer copy and encode cost, so the measured overhead bounds the impact at lower resolutions.Performance Impact
Replay adds approximately 0.20 ms per frame at 4K:
This is well below the threshold of noticeable overhead for typical game performance targets.
Documentation
Related items