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.
3.8 KiB
HANDOFF — Session State
Branch / Commit State
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 boundary8f49010— TASK 21 Increment B: FFmpeg rawvideo video decoder -> VideoFramef89b9f9— docs: default-device audio assumption (README + startup log)e8ff4df— TASK 22: global audio sync offset (positive delay at the mixer out)
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) — 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) and Increment B (the decoder MediaVideoSource) shipped earlier.
This session:
- Refactored
Services/MediaVideoSource.csonto the newServices/IMediaFrameSource.cs(Key,FrameAvailable,Completed,StartAsync/StopAsync;Start→StartAsync,FrameReady→FrameAvailable) — behavior preserved,MediaVideoSourceTestsupdated and passing. - Added
Services/MediaVideoSourceManager.cs— app-wide decode-session ownership refcounted byMediaPath,Func<string, IMediaFrameSource?>factory seam,AcquireAsync/ReleaseAsync/ReleaseAllAsync/GetLatestFrame, frames coalesced onto the UI dispatcher onto one sharedWriteableBitmapper file,MediaFailed+PreviewBitmapChanged. Structural mirror ofScreenCaptureManager. - 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.
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")
on MSB3027. Full-suite vstest hangs headless (RealAppHost/WASAPI) — only filtered
pure tests run in WSL; user verifies the GUI suites on native Windows PowerShell
(which may also hang if WASAPI startup blocks — pre-existing, not this change).
Next
- Commit slice 1 step 3 (this unit): manager +
IMediaFrameSource+ tests. Commit is already covered byTASKS.md/HANDOFF.md; this HANDOFF is the shipping doc. - Slice 1 step 4: wire
_mediaManagerinto the resolver + preview routing (see above). - Slice 2: native-FPS pacing (ffprobe FPS probe + per-frame pacing seam).
- Await user push checkpoint for the pending TASK 22/21 commits.
The directive (2026-08-31, user)
Rewrite the project into functional components to aid AI retrieval —
Services/ChatOverlayLayer.cs / SceneGraph.cs style (owner-state extraction),
not line-count chasing. Audio assumption is now an explicit contract (README
"Audio Assumption"): the app uses system defaults, never fights Windows device
locking, and does not debug user audio issues — OS's problem, not ours.