docs: rewrite HANDOFF for clean session end (fully pushed, project-wide read, no-suggestions note)
This commit is contained in:
+52
-74
@@ -2,89 +2,54 @@
|
|||||||
|
|
||||||
## Branch / Commit State
|
## Branch / Commit State
|
||||||
|
|
||||||
**`main`**, working through TASK 21 (media source). Local commits ahead of
|
**`main`**, clean working tree, **fully pushed to `origin/main`** (nothing pending).
|
||||||
`origin/main` (not yet pushed — user pushes at agreed checkpoints):
|
Last work boundary: `097dd0d` (docs: hand off TASK 21 UI picker slice). No uncommitted
|
||||||
|
work; no local commits ahead of origin.
|
||||||
|
|
||||||
|
Recent commit series (all pushed, before this session's end):
|
||||||
|
- `097dd0d` — docs: hand off TASK 21 UI picker slice (acquisition + loop wiring spec)
|
||||||
|
- `881addb` — TASK 21 slice 3: loop control in MediaVideoSource (process factory + Loop flag)
|
||||||
|
- `a2219be` — TASK 21 slice 2b: native-FPS pacing in MediaVideoSource (probe -> delay seam)
|
||||||
|
- `8fa7842` — TASK 21 slice 2a: native-FPS probe seam (ffprobe parse + derive sibling)
|
||||||
|
- `071ec8b` — TASK 21 slice 1 step 4: wire media into resolver + preview routing
|
||||||
|
- `480ead0` — TASK 21 slice 1 step 3: IMediaFrameSource + MediaVideoSourceManager
|
||||||
- `a1d9751` — docs: ffmpeg decode-contract verification recipe + WSL CLR boundary
|
- `a1d9751` — docs: ffmpeg decode-contract verification recipe + WSL CLR boundary
|
||||||
- `8f49010` — TASK 21 Increment B: FFmpeg rawvideo video decoder -> VideoFrame
|
- `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)
|
|
||||||
|
|
||||||
Prior milestones pushed through `origin/main`: TASK 31 (`3bf053a..670fe3a`), plus
|
## Why the session ended
|
||||||
the full refactor series (Commit F `3107f92`, Commit G `85893ea`).
|
|
||||||
|
User ready for a break after a substantial day. No mid-flight work — everything is
|
||||||
|
committed and pushed. This is a clean stopping point.
|
||||||
|
|
||||||
## What's In Flight
|
## What's In Flight
|
||||||
|
|
||||||
**TASK 21 (media source) — all headless-testable decoder/mechanism slices shipped (slice 1 + 2a + 2b + 3); the remaining UI-picker (acquisition) slice is handed off below — it is a GUI feature to build + verify on native Windows.**
|
Nothing actively mid-flight. The last TASK 21 work unit (the **UI picker / acquisition
|
||||||
|
slice**) is **handed off**, not in progress — spec reproduced in the section below.
|
||||||
|
It is a GUI feature that must be built + verified natively on Windows.
|
||||||
|
|
||||||
Increment A (the `Source` model: `MediaSourceType`, `SourceType.MediaSource`,
|
## Project-wide code-complete picture (2026-08-31, user's framing)
|
||||||
`MediaPath`/`MediaIsLooping`/`MediaVolume`/`MediaPlaybackState` + LayoutStore
|
|
||||||
persistence) and Increment B (the decoder `MediaVideoSource`) shipped earlier.
|
|
||||||
|
|
||||||
This session:
|
The user revisited the ongoing "how code-complete are we" question. Current agreed read:
|
||||||
- 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.**
|
|
||||||
|
|
||||||
Slice 1 step 4 (wire-in) shipped: `_mediaManager` wired in the core ctor
|
- **Feature/code completeness ≈ 88–92%**, after removing from consideration:
|
||||||
(`path => new MediaVideoSource(path, 1920, 1080, new FfmpegLocator(), new FfmpegDecodeProcess())`,
|
- **TASK 13 = MARCOM, not code** (social media launch kit) — does not count against code-complete.
|
||||||
dispatched preview), `OnMediaPreviewBitmapChanged` sets `VideoImageSource` on every
|
- **TASK 10 (monetization / Polar billing / Velopack distribution + updater) — deliberately
|
||||||
`IsMediaSource` with a matching `MediaPath`, a `Source { IsMediaSource, MediaPath }`
|
parked by the user until it is the dead-last thing to do.** Not a blocker for feature completion.
|
||||||
case in `ResolveOutputFrame` feeds `_mediaManager.GetLatestFrame`, `Source.DisplaySource`
|
- Remaining real code before feature-complete:
|
||||||
routes `VideoImageSource` for `MediaSource`, and the manager is disposed on shutdown.
|
- **TASK 21 UI picker** slice (the handoff below) — the one genuinely open feature unit.
|
||||||
Lives in the new `ViewModels/MainViewModel.Media.cs` partial. **Verified: 14/14
|
- **TASK 9** — visibility picker (drop the always-Private lock, let user pick
|
||||||
media + DisplaySource tests pass, build 0 warnings.**
|
Private/Unlisted/Public) + a couple stream-management items.
|
||||||
|
- **TASK 4** — background removal (excluded by design) + a few capture-pipeline items.
|
||||||
|
- **Biggest actual risk is not code — it is the missing native-Windows verification pass.**
|
||||||
|
Real ffmpeg media decode/loop/pacing, recording, and the GUI suites have only ever run
|
||||||
|
headless in WSL or against fakes. Crossing-the-line "works on Windows" readiness is lower
|
||||||
|
than the code-complete number would suggest until that pass happens.
|
||||||
|
|
||||||
Next (slice 1 step 4's remaining open end): no session acquisition yet — nothing
|
## @ User note — no suggestions for the time being
|
||||||
`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.
|
|
||||||
|
|
||||||
Slice 2a shipped: the native-FPS **probe seam** (not yet wired into pacing).
|
The user asked to **stop with forward-looking suggestions** (they read as distracting). Do
|
||||||
`Services/FfmpegFrameRateParser.cs` (pure — prefers `avg_frame_rate=` then
|
not volunteer next-step options or "what's next" lists unless the user asks. Answer what is
|
||||||
`r_frame_rate=`, rational `N`/`N/M`, unknown→null), `Services/FrameRateProbe.cs`
|
asked; stay quiet on roadmap unless prompted.
|
||||||
(`IFrameRateProbe` + `FfmpegFrameRateProbe` — derives sibling `ffprobe.exe` from
|
|
||||||
the located ffmpeg dir, reuses the `IDecodeProcess` seam for the ffprobe
|
|
||||||
subprocess text, null if ffprobe absent), and `FfmpegLocator.ProbeFileName`
|
|
||||||
(`ffprobe.exe`) + conditional extraction alongside ffmpeg.exe. Tests:
|
|
||||||
`ytLive.Tests/FfmpegFrameRateParserTests.cs` (6 pure units + 1 probe integration
|
|
||||||
via fake locator/process); `FfmpegLocatorTests` still green — 15/15 pass, build
|
|
||||||
0 warnings. Slice 2b shipped too: `MediaVideoSource` now takes optional
|
|
||||||
`IFrameRateProbe?` + `Func<TimeSpan,CancellationToken,Task>? delay` seams,
|
|
||||||
probes FPS once in `RunAsync`, and paces each emitted frame by 1/fps (unknown/
|
|
||||||
absent probe → no pacing). New test `MediaVideoSource_PacesFramesByProbedFps`
|
|
||||||
(fake probe + recording delay, one delay per frame ≈1ms). Media tests 5/5,
|
|
||||||
build 0 warnings.
|
|
||||||
|
|
||||||
Next (slice 3): loop control — SHIPPED. `MediaVideoSource` takes a
|
|
||||||
`Func<IDecodeProcess>` process factory (a single `Process` can't be re-`Start()`ed,
|
|
||||||
so each loop pass creates a fresh decoder) and wraps the decode in a
|
|
||||||
`do…while (Looping)` restart, keyed on the new `IMediaFrameSource.Looping` flag;
|
|
||||||
Production wiring in `MainViewModel` (media factory) now passes the factory AND
|
|
||||||
`FfmpegFrameRateProbe` (closing the slice-2b gap where production had no probe →
|
|
||||||
no pacing). Loop test `MediaVideoSource_LoopsUntilLoopDisabled` (single frame
|
|
||||||
re-emits, `Completed` only when loop cleared) — media tests 12/12 (6 source + 6
|
|
||||||
manager), build 0 warnings. Open: wiring `Source.MediaIsLooping` into
|
|
||||||
`IMediaFrameSource.Looping` needs a manager-level per-path loop provider — lands
|
|
||||||
with the UI picker (acquisition) slice.
|
|
||||||
|
|
||||||
**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
|
|
||||||
|
|
||||||
1. **(Handed off) UI picker slice** — the last TASK 21 work unit. GUI feature; build + verify natively on Windows.
|
|
||||||
2. Await user push checkpoint for the pending commits (TASK 22 + TASK 21 slices below).
|
|
||||||
|
|
||||||
## UI picker slice — handoff spec (2026-08-31)
|
## UI picker slice — handoff spec (2026-08-31)
|
||||||
|
|
||||||
@@ -108,10 +73,23 @@ but a media Source has no way to start a session. Deliverables, in order:
|
|||||||
|
|
||||||
**Design notes to preserve:** `ResolveOutputFrame` reads `_mediaManager.GetLatestFrame(MediaPath)`;
|
**Design notes to preserve:** `ResolveOutputFrame` reads `_mediaManager.GetLatestFrame(MediaPath)`;
|
||||||
`OnMediaPreviewBitmapChanged` adopts the shared `WriteableBitmap` per path; `MediaFailed` →
|
`OnMediaPreviewBitmapChanged` adopts the shared `WriteableBitmap` per path; `MediaFailed` →
|
||||||
`OnMediaFailed` (currently `Debug.WriteLine`, surface in UI). Composer scales any frame size.
|
`OnMediaFailed` (currently `Debug.WriteLine`, surface in UI). Composer scales any frame size
|
||||||
Tmpl: the real-ffmpeg decode/loop/restart path is only exercised natively on Windows — first
|
(media renders through the generic `frameFor(element)` path — no compositor change needed).
|
||||||
|
The real-ffmpeg decode/loop/restart path is only exercised natively on Windows — first
|
||||||
GUI smoke test should add a short mp4, confirm it plays and previews, then crash further.
|
GUI smoke test should add a short mp4, confirm it plays and previews, then crash further.
|
||||||
|
|
||||||
|
## 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).
|
||||||
|
- **WSL can only run the Windows-bound dotnet CLR shim** — it cannot spawn Linux ffmpeg/ffprobe
|
||||||
|
(Win32Exception 193). Verify ffmpeg contracts via shell/python; leave CLR→real-ffmpeg to the
|
||||||
|
native Windows suite. Linux static ffmpeg/ffprobe 7.0.2 live at
|
||||||
|
`/tmp/opencode/ffmpeg-7.0.2-amd64-static/`; `/tmp/opencode/clip.mp4` = 640x360 30fps 1s.
|
||||||
|
|
||||||
## The directive (2026-08-31, user)
|
## The directive (2026-08-31, user)
|
||||||
|
|
||||||
Rewrite the project into functional components to aid AI retrieval —
|
Rewrite the project into functional components to aid AI retrieval —
|
||||||
|
|||||||
Reference in New Issue
Block a user