TASK 21 slice 1 step 3: IMediaFrameSource + MediaVideoSourceManager
Refactor MediaVideoSource onto IMediaFrameSource (Key/FrameAvailable/Completed/ StartAsync/StopAsync, renaming Start->StartAsync, FrameReady->FrameAvailable), behavior preserved. Add MediaVideoSourceManager: app-wide decode-session owner refcounted by MediaPath with Func<string,IMediaFrameSource?> factory seam, Acquire/Release/ReleaseAll/GetLatestFrame, coalescing each file's frames onto the UI dispatcher onto one shared WriteableBitmap; MediaFailed + PreviewBitmapChanged. Mirrors ScreenCaptureManager (screen-capture session ownership + dispatcher coalescing), per the codebase precedent and derivative-work rule. Tests: MediaVideoSourceManagerTests (5 unit + 1 integration: single shared bitmap, coalesce-to-latest); MediaVideoSourceTests updated for renames. 10/10 media tests pass, build 0 warnings. Docs (TASKS/HANDOFF/ai.md) updated.
This commit is contained in:
+29
-21
@@ -4,35 +4,43 @@
|
||||
|
||||
**`main`**, working through TASK 21 (media source). Local commits ahead of
|
||||
`origin/main` (not yet pushed — user pushes at agreed checkpoints):
|
||||
- `a1d9751` — docs: ffmpeg decode-contract verification recipe + WSL CLR boundary
|
||||
- `8f49010` — TASK 21 Increment B: FFmpeg rawvideo video decoder -> VideoFrame
|
||||
- `f89b9f9` — docs: default-device audio assumption (README + startup log)
|
||||
- `e8ff4df` — TASK 22: global audio sync offset (positive delay at the mixer out)
|
||||
- `670fe3a` — TASK 31 (already pushed; listed for context)
|
||||
|
||||
Prior milestones pushed through `origin/main`: TASK 31 (`3bf053a..670fe3a`), plus
|
||||
the full refactor series (Commit F `3107f92`, Commit G `85893ea`).
|
||||
|
||||
## What's In Flight
|
||||
|
||||
**TASK 21 (media source) — Increment B (the decoder) implemented, uncommitted-or-pending-commit, awaiting next unit.**
|
||||
**TASK 21 (media source) — slice 1 step 3 shipped (the session-manager + interface); next open work is the VM wire-in (slice 1 step 4).**
|
||||
|
||||
Increment A (the `Source` model: `MediaSourceType`, `SourceType.MediaSource`,
|
||||
`MediaPath`/`MediaIsLooping`/`MediaVolume`/`MediaPlaybackState` + LayoutStore
|
||||
persistence) shipped earlier. This session shipped **Increment B — the decoder**:
|
||||
persistence) and Increment B (the decoder `MediaVideoSource`) shipped earlier.
|
||||
|
||||
New files:
|
||||
- `Services/RawVideoFrameReader.cs` — pure: parses a rawvideo BGRA stream into
|
||||
`VideoFrame`s (exactly W×H×4 per frame; partial reads kept across `Feed`).
|
||||
- `Services/IDecodeProcess.cs` + `Services/FfmpegDecodeProcess.cs` — binary-stdout
|
||||
subprocess seam (mirror of `IEncoderProcess`).
|
||||
- `Services/MediaVideoSource.cs` — spawns ffmpeg `-f rawvideo -pix_fmt bgra -an`,
|
||||
drains the pipe, raises `FrameReady` per frame; `Completed` on EOF.
|
||||
- `ytLive.Tests/MediaVideoSourceTests.cs` — 3 pure reader tests + 1 integration
|
||||
(fake `IDecodeProcess`+`IFfmpegLocator` through the real source loop, frames in
|
||||
order). **Verified: 4/4 pass, build 0 warnings.**
|
||||
This session:
|
||||
- Refactored `Services/MediaVideoSource.cs` onto the new
|
||||
`Services/IMediaFrameSource.cs` (`Key`, `FrameAvailable`, `Completed`,
|
||||
`StartAsync`/`StopAsync`; `Start`→`StartAsync`, `FrameReady`→`FrameAvailable`)
|
||||
— behavior preserved, `MediaVideoSourceTests` updated and passing.
|
||||
- Added `Services/MediaVideoSourceManager.cs` — app-wide decode-session
|
||||
ownership refcounted by `MediaPath`, `Func<string, IMediaFrameSource?>` factory
|
||||
seam, `AcquireAsync`/`ReleaseAsync`/`ReleaseAllAsync`/`GetLatestFrame`, frames
|
||||
coalesced onto the UI dispatcher onto one shared `WriteableBitmap` per file,
|
||||
`MediaFailed` + `PreviewBitmapChanged`. Structural mirror of `ScreenCaptureManager`.
|
||||
- Added `ytLive.Tests/MediaVideoSourceManagerTests.cs` (5 unit + 1 integration:
|
||||
single shared bitmap, coalesce-to-latest). **Verified: all 10 media tests pass
|
||||
(5 manager + 3 reader + 1 decoder integration + 1), build 0 warnings.**
|
||||
|
||||
Still open (next slices): native-FPS pacing (ffprobe probe), loop control, volume,
|
||||
the `ResolveOutputFrame` resolver case + wire into `SceneCompositor`, the file-picker
|
||||
UI, and the remaining tests.
|
||||
Next (slice 1 step 4 — VM wire-in): create `_mediaManager` in the ctor with
|
||||
`path => new MediaVideoSource(path, <W>, <H>, new FfmpegLocator(), new FfmpegDecodeProcess())`,
|
||||
subscribe `OnMediaPreviewBitmapChanged` (set `source.VideoImageSource` for every
|
||||
`IsMediaSource` with that `MediaPath`), add the `Source { IsMediaSource: true, MediaPath: not null }`
|
||||
case to `ResolveOutputFrame` (`MainViewModel.cs:447`), add `or SourceType.MediaSource`
|
||||
to `Source.DisplaySource` (Source.cs:119-121) so media previews route `VideoImageSource`,
|
||||
and dispose the manager on shutdown. Then slices 2 (native-FPS pacing) and 3 (loop).
|
||||
|
||||
**Landmine:** a stale `testhost` can lock `ytLive.Tests`'s `ytLive.dll` and break
|
||||
`dotnet build` of the test project — kill it first (`cmd.exe /c "taskkill /PID N /F"`)
|
||||
@@ -42,11 +50,11 @@ pure tests run in WSL; user verifies the GUI suites on native Windows PowerShell
|
||||
|
||||
## Next
|
||||
|
||||
1. Commit Increment B (decoder) as one work unit (scope-check + docs already
|
||||
staged in ai.md/TASKS.md/HANDOFF.md).
|
||||
2. Next slice: native-FPS pacing + wire media into `ResolveOutputFrame` and the
|
||||
compositor, per TASK 21 steps 6–7.
|
||||
3. Await user push checkpoint for the TASK 22/21 commits.
|
||||
1. Commit slice 1 step 3 (this unit): manager + `IMediaFrameSource` + tests. Commit
|
||||
is already covered by `TASKS.md`/`HANDOFF.md`; this HANDOFF is the shipping doc.
|
||||
2. Slice 1 step 4: wire `_mediaManager` into the resolver + preview routing (see above).
|
||||
3. Slice 2: native-FPS pacing (ffprobe FPS probe + per-frame pacing seam).
|
||||
4. Await user push checkpoint for the pending TASK 22/21 commits.
|
||||
|
||||
## The directive (2026-08-31, user)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user