Overview
The file src/Platform/Microsoft.Testing.Extensions.VideoRecorder/FfmpegVideoRecorder.cs has grown to 723 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files.
Current State
- File:
src/Platform/Microsoft.Testing.Extensions.VideoRecorder/FfmpegVideoRecorder.cs
- Size: 723 lines
- Language: C#
Structural Analysis
The file currently contains two top-level declarations and one large nested class:
-
VideoSegment struct (~34 lines, lines 18–51) — A small data model describing a finalized recording segment and its time range. Completely self-contained and unrelated to the recorder machinery.
-
FfmpegVideoRecorder class (~670 lines, lines 53–723) with four distinct concern groups:
- Core lifecycle (
Start, StopAsync, PruneSegments, ConcatAsync) — Public API for starting/stopping the continuous recorder and producing per-test clip files.
- FFmpeg argument building (
BuildSegmentArguments, BuildDefaultInput) — Platform-aware construction of the ffmpeg command line (gdigrab/avfoundation/x11grab inputs, encoder settings, segment muxer flags).
- Process management utilities (
RunFfmpegAsync, WaitForExitAsync, TryKill, DetachAndDispose, OnFfmpegOutput, ClearRecentFfmpegOutput, FindFfmpeg) — All the plumbing for launching, monitoring, and tearing down the ffmpeg child process.
- Windows-specific window-capture helpers (
TryGetCurrentProcessWindowRegion, TrySetPerMonitorDpiAwareThread, EnumerateCandidateWindows) plus the private nested NativeMethods class (~36 lines of P/Invoke declarations for GetConsoleWindow, GetForegroundWindow, GetSystemMetrics, SetThreadDpiAwarenessContext, IsWindowVisible, GetWindowRect, and RECT).
Refactoring Strategy
Proposed File Splits
Split the file into four focused files using C# partial classes where appropriate:
-
VideoSegment.cs (~35 lines)
- Contents: The
VideoSegment readonly struct
- Responsibility: Pure data model — a recording segment path plus its
[startSeconds, endSeconds) time range
-
FfmpegVideoRecorder.cs (~300 lines, trimmed from current 670)
- Contents: Fields, constructor, properties (
IsAvailable, FfmpegPath, RecordingStartUtc, SegmentDirectory), and the public lifecycle methods (Start, StopAsync, PruneSegments, ConcatAsync)
- Responsibility: Public API surface and recording lifecycle orchestration
-
FfmpegVideoRecorder.ProcessManagement.cs (~150 lines, partial class)
- Contents:
RunFfmpegAsync, WaitForExitAsync, TryKill, DetachAndDispose, OnFfmpegOutput, ClearRecentFfmpegOutput, FindFfmpeg, BuildSegmentArguments, BuildDefaultInput
- Responsibility: ffmpeg process lifecycle, output capture, argument construction, and executable discovery
-
FfmpegVideoRecorder.WindowCapture.cs (~160 lines, partial class)
- Contents:
TryGetCurrentProcessWindowRegion, TrySetPerMonitorDpiAwareThread, EnumerateCandidateWindows, and the nested NativeMethods class
- Responsibility: Windows-specific DPI-aware window-region detection and all P/Invoke declarations
Implementation Guidelines
- Preserve Behavior: All existing functionality must work identically after the split
- Maintain Public API: Keep all
internal symbols accessible from the rest of the assembly (they don't cross assembly boundaries here)
- Use partial classes:
FfmpegVideoRecorder should be declared partial to allow the split across .ProcessManagement.cs and .WindowCapture.cs
- Keep the nested class:
NativeMethods can stay as a private static class inside the partial declaration in WindowCapture.cs
- Test After Each Split: Run
./build.sh -test (or .\build.cmd -test) after each incremental file move
- One File at a Time: Move one group at a time to keep diffs reviewable
Acceptance Criteria
Priority: Medium
Effort: Small — the concerns are already well-separated; moving code is mostly mechanical
Expected Impact: Improved code navigability, easier per-concern code review, reduced merge conflicts on the recorder file
🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Daily File Diet workflow. · 132.9 AIC · ⌖ 12.8 AIC · ⊞ 43K · [◷]( · ◷)
Overview
The file
src/Platform/Microsoft.Testing.Extensions.VideoRecorder/FfmpegVideoRecorder.cshas grown to 723 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files.Current State
src/Platform/Microsoft.Testing.Extensions.VideoRecorder/FfmpegVideoRecorder.csStructural Analysis
The file currently contains two top-level declarations and one large nested class:
VideoSegmentstruct (~34 lines, lines 18–51) — A small data model describing a finalized recording segment and its time range. Completely self-contained and unrelated to the recorder machinery.FfmpegVideoRecorderclass (~670 lines, lines 53–723) with four distinct concern groups:Start,StopAsync,PruneSegments,ConcatAsync) — Public API for starting/stopping the continuous recorder and producing per-test clip files.BuildSegmentArguments,BuildDefaultInput) — Platform-aware construction of the ffmpeg command line (gdigrab/avfoundation/x11grab inputs, encoder settings, segment muxer flags).RunFfmpegAsync,WaitForExitAsync,TryKill,DetachAndDispose,OnFfmpegOutput,ClearRecentFfmpegOutput,FindFfmpeg) — All the plumbing for launching, monitoring, and tearing down the ffmpeg child process.TryGetCurrentProcessWindowRegion,TrySetPerMonitorDpiAwareThread,EnumerateCandidateWindows) plus the private nestedNativeMethodsclass (~36 lines of P/Invoke declarations forGetConsoleWindow,GetForegroundWindow,GetSystemMetrics,SetThreadDpiAwarenessContext,IsWindowVisible,GetWindowRect, andRECT).Refactoring Strategy
Proposed File Splits
Split the file into four focused files using C# partial classes where appropriate:
VideoSegment.cs(~35 lines)VideoSegmentreadonly struct[startSeconds, endSeconds)time rangeFfmpegVideoRecorder.cs(~300 lines, trimmed from current 670)IsAvailable,FfmpegPath,RecordingStartUtc,SegmentDirectory), and the public lifecycle methods (Start,StopAsync,PruneSegments,ConcatAsync)FfmpegVideoRecorder.ProcessManagement.cs(~150 lines, partial class)RunFfmpegAsync,WaitForExitAsync,TryKill,DetachAndDispose,OnFfmpegOutput,ClearRecentFfmpegOutput,FindFfmpeg,BuildSegmentArguments,BuildDefaultInputFfmpegVideoRecorder.WindowCapture.cs(~160 lines, partial class)TryGetCurrentProcessWindowRegion,TrySetPerMonitorDpiAwareThread,EnumerateCandidateWindows, and the nestedNativeMethodsclassImplementation Guidelines
internalsymbols accessible from the rest of the assembly (they don't cross assembly boundaries here)FfmpegVideoRecordershould be declaredpartialto allow the split across.ProcessManagement.csand.WindowCapture.csNativeMethodscan stay as aprivate static classinside the partial declaration inWindowCapture.cs./build.sh -test(or.\build.cmd -test) after each incremental file moveAcceptance Criteria
VideoSegmentmoved to its ownVideoSegment.csfileFfmpegVideoRecordersplit intopartialdeclarations across multiple filesFfmpegVideoRecorder.cs(the main partial) is under 300 linesinternalAPI surfaceBuildSegmentArguments/BuildDefaultInputstill callable from the main partialPriority: Medium
Effort: Small — the concerns are already well-separated; moving code is mostly mechanical
Expected Impact: Improved code navigability, easier per-concern code review, reduced merge conflicts on the recorder file