Files
LlamaCasty/Services/FfmpegDecodeProcess.cs
gramps 8f490102ee TASK 21 Increment B: FFmpeg rawvideo video decoder -> VideoFrame
Adds the codec-agnostic decoder half of the media source. Spawns ffmpeg
with -f rawvideo -pix_fmt bgra (reusing the already-shipped ffmpeg via
IFfmpegLocator) and drains the raw BGRA stdout pipe into VideoFrames.

- Services/RawVideoFrameReader.cs: pure rawvideo BGRA stream -> frames
  (partial reads kept across Feed; no ffmpeg needed to test)
- Services/IDecodeProcess.cs + FfmpegDecodeProcess.cs: binary-stdout
  subprocess seam, mirror of the encoder's IEncoderProcess
- Services/MediaVideoSource.cs: owns the decode, raises FrameReady/Completed
- MediaVideoSourceTests: 3 pure reader + 1 integration (fake decode
  process through the real source loop, frames in order)

Reference (external scan): ffmpeg rawvideo pipe decode is the canonical
codec-agnostic frame feeds pattern (ffmpeg docs -f rawvideo; how OBS/media
pipelines push frames to a compositor). Verified: 4/4 tests, build 0 warnings.
Native-FPS pacing + resolver/compositor wiring are the next slice.
2026-08-31 18:57:29 -07:00

37 lines
1.1 KiB
C#

using System.Diagnostics;
using System.IO;
namespace ytLive.Services;
/// <summary>
/// The real <see cref="IDecodeProcess"/>: a <see cref="Process"/> with stdout
/// redirected as raw bytes for reading <c>rawvideo</c> frames. Constructed by
/// <see cref="MediaVideoSource"/> for the media-file decoder subprocess.
/// </summary>
public sealed class FfmpegDecodeProcess : IDecodeProcess
{
private readonly Process _process;
public FfmpegDecodeProcess() => _process = new Process { EnableRaisingEvents = true };
public void Start(ProcessStartInfo startInfo)
{
_process.StartInfo = startInfo;
_process.Start();
}
public Stream StandardOutput => _process.StandardOutput.BaseStream;
public bool HasExited => _process.HasExited;
public int ExitCode => _process.ExitCode;
public void Kill()
{
if (!_process.HasExited) _process.Kill();
}
public Task WaitForExitAsync(CancellationToken cancellationToken = default)
=> _process.WaitForExitAsync(cancellationToken);
public void Dispose() => _process.Dispose();
}