Skip to content

[file-diet] Refactor FfmpegVideoRecorder.cs — 723 lines exceeds healthy file size #9464

Description

@Evangelink

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:

  1. 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.

  2. 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:

  1. VideoSegment.cs (~35 lines)

    • Contents: The VideoSegment readonly struct
    • Responsibility: Pure data model — a recording segment path plus its [startSeconds, endSeconds) time range
  2. 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
  3. 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
  4. 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

  1. Preserve Behavior: All existing functionality must work identically after the split
  2. Maintain Public API: Keep all internal symbols accessible from the rest of the assembly (they don't cross assembly boundaries here)
  3. Use partial classes: FfmpegVideoRecorder should be declared partial to allow the split across .ProcessManagement.cs and .WindowCapture.cs
  4. Keep the nested class: NativeMethods can stay as a private static class inside the partial declaration in WindowCapture.cs
  5. Test After Each Split: Run ./build.sh -test (or .\build.cmd -test) after each incremental file move
  6. One File at a Time: Move one group at a time to keep diffs reviewable

Acceptance Criteria

  • VideoSegment moved to its own VideoSegment.cs file
  • FfmpegVideoRecorder split into partial declarations across multiple files
  • Each new file is under 300 lines
  • FfmpegVideoRecorder.cs (the main partial) is under 300 lines
  • All existing unit and integration tests pass after refactoring
  • No breaking changes to the internal API surface
  • BuildSegmentArguments / BuildDefaultInput still callable from the main partial

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 · [◷]( · )

  • expires on Jun 28, 2026, 7:28 PM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions