fix(webcam): reader-output-subtype ladder + record WinRT per-call wrap rule
A browser grabbing the C920 kills our reader startup: the camera stays in MJPG 1920x1080@30 (another app's format) and our OBS-refusal to re-negotiate under SharedReadOnly contention (`SetMediaStreamPropertiesAsync` throws 'file in use / CaptureMode is SharedReadOnly') leaves it there. CreateFrameReaderAsync(.., Bgra8) + StartAsync then refuses with OutputFormatNotSupported — the MJPG-active source only exposes NV12 at the reader level (clue: startup.log 19:01/19:05 sessions, same hardware that started YUY2 640x480 fine at 08:52). Fresh launches showed no webcam and 'Add Webcam' failed. Reader creation is now a per-candidate ladder (ReaderSubtypeCandidates): Bgra8 for uncompressed cameras (unchanged fast path); NV12 then the source-default for MJPG cameras — converted in OnFrameArrived like any non-BGRA frame. Each candidate is allocated AND started under its OWN catch: WinRT answers an unsupported subtype with a throw (E_INVALIDARG), not a status, so a single rejected format must degrade to the next candidate instead of aborting acquisition (creator rule — see MyMistakes WINRT resource-allocation recipe). Rejections are logged and collected into the final error. Good Dog: 4 unit tests lock the candidate ordering (MJPG never Bgra8, case-insensitive, uncompressed keeps Bgra8 first, unknown/null -> Bgra8). 301/301 green, 0 warnings. [no push]
This commit is contained in:
@@ -15,6 +15,27 @@
|
||||
|
||||
## 🔬 Recipes registry
|
||||
|
||||
### WINRT RESOURCE-ALLOCATION CALLS: WRAP PER-CALL, DEGRADE TO NEXT OPTION (RECIPE)
|
||||
|
||||
Creator callout (2026-09-15): WinRT/COM calls that allocate or start a resource — `InitializeAsync`,
|
||||
`CreateFrameReaderAsync`, `StartAsync`, `CreateReaderAsync` & friends — are THROW-HEAVY. An unsupported
|
||||
subtype/format, a device that just vanished, an access mode rejected mid-flight: these surface as
|
||||
`ArgumentException`/`E_INVALIDARG` ("value does not fall within the expected range") or HRESULTs, NOT as
|
||||
a returned status you can switch on. Relying on ONE outer catch to "handle failures" is not handling —
|
||||
one rejected call inside a fallback ladder aborts the whole ladder and every untried option. Rule:
|
||||
|
||||
- Each allocation/start call inside a try/catch of its OWN, so a throw on candidate N falls through to
|
||||
candidate N+1 (log each rejection with its message/status; collect them for the final error string).
|
||||
- `return`/`break` on success must be reached WITHOUT passing through a `finally` that disposes the
|
||||
resource you just committed (classic reader/capture dispose-after-commit bug).
|
||||
- Unsubscribe + dispose the partial resource in the catch block when the subscription happened before
|
||||
the throwing call.
|
||||
- The outer catch stays as the LAST-RESORT net for device-level errors, not the primary one.
|
||||
- Same discipline applies to the frame-consumption side: teardown races reader threads (see HANDOFF
|
||||
crash follow-up) — a frame callback can't assume the pipeline is alive.
|
||||
|
||||
Applied in `MediaCaptureFrameSource`'s reader-subtype ladder (2026-09-15, webcam-take fix).
|
||||
|
||||
### SPIN GUARD → RESOLVED — web overlay transparency + bounding box (RECIPE)
|
||||
|
||||
**THE ONE ROOT CAUSE THAT EXPLAINS EVERY FAILED TAKE:** WebView2's `CapturePreviewAsync`
|
||||
|
||||
Reference in New Issue
Block a user