TASK 21 slice 1 step 4: wire media into resolver + preview routing

Wire the MediaVideoSourceManager into the live pipeline (new partial
ViewModels/MainViewModel.Media.cs mirrors Webcam/Background partials):
readonly _mediaManager assigned in the core ctor (decode at 1920x1080 master,
dispatcher-coalesced preview), OnMediaPreviewBitmapChanged adopts the shared
bitmap onto every IsMediaSource with a matching MediaPath, a
Source { IsMediaSource, MediaPath } case in ResolveOutputFrame feeds
GetLatestFrame, and the manager is disposed on shutdown.

Source.DisplaySource now routes VideoImageSource for MediaSource (Source.cs),
so media previews/canvas show decoded video.

Compositor needs no change: BlitContent UniformToFill-scales any frame to the
element rect. Decoder/manager/seam derived-work mirrors ScreenCaptureManager
(citation in commit for slice-step-3).

Test (one unit for this change, mirroring the live-capture case):
Source_DisplaySource_IsVideoImageSource_WhenMediaSource. 14/14 media +
DisplaySource tests pass, build 0 warnings. Docs (TASKS/HANDOFF/ai.md) updated.
This commit is contained in:
2026-08-31 19:32:41 -07:00
parent 480ead0fc7
commit 071ec8be0c
7 changed files with 85 additions and 16 deletions
+20 -12
View File
@@ -34,13 +34,21 @@ This session:
single shared bitmap, coalesce-to-latest). **Verified: all 10 media tests pass
(5 manager + 3 reader + 1 decoder integration + 1), build 0 warnings.**
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).
Slice 1 step 4 (wire-in) shipped: `_mediaManager` wired in the core ctor
(`path => new MediaVideoSource(path, 1920, 1080, new FfmpegLocator(), new FfmpegDecodeProcess())`,
dispatched preview), `OnMediaPreviewBitmapChanged` sets `VideoImageSource` on every
`IsMediaSource` with a matching `MediaPath`, a `Source { IsMediaSource, MediaPath }`
case in `ResolveOutputFrame` feeds `_mediaManager.GetLatestFrame`, `Source.DisplaySource`
routes `VideoImageSource` for `MediaSource`, and the manager is disposed on shutdown.
Lives in the new `ViewModels/MainViewModel.Media.cs` partial. **Verified: 14/14
media + DisplaySource tests pass, build 0 warnings.**
Next (slice 1 step 4's remaining open end): no session acquisition yet — nothing
`AcquireAsync`s a media path, so no frames flow until the UI picker (a later slice)
starts a session on add and releases on remove.
Next (slice 2): native-FPS pacing (ffprobe FPS probe + per-frame pacing seam).
Slice 3: loop control (restart decode on `Completed` when `MediaIsLooping`).
**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"`)
@@ -50,11 +58,11 @@ pure tests run in WSL; user verifies the GUI suites on native Windows PowerShell
## Next
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.
1. Commit slice 1 step 4 (this unit): resolver/preview wire-in + `Source.DisplaySource` media branch + tests.
2. Slice 2: native-FPS pacing (ffprobe FPS probe + per-frame pacing seam).
3. Slice 3: loop control (restart decode on `Completed` when `MediaIsLooping`).
4. UI picker slice: acquire/release media sessions on add/remove (the remaining slice-1-step-4 open end).
5. Await user push checkpoint for the pending TASK 22/21 commits.
## The directive (2026-08-31, user)