Webcam grab: SharedReadOnly mode, VideoPreview/VideoRecord source fallback, name the blocking app in the error (NVIDIA Broadcast finding)
This commit is contained in:
@@ -43,14 +43,21 @@ public sealed class MediaCaptureFrameSource : ICameraFrameSource
|
|||||||
VideoDeviceId = _deviceId,
|
VideoDeviceId = _deviceId,
|
||||||
StreamingCaptureMode = StreamingCaptureMode.Video,
|
StreamingCaptureMode = StreamingCaptureMode.Video,
|
||||||
MemoryPreference = MediaCaptureMemoryPreference.Cpu,
|
MemoryPreference = MediaCaptureMemoryPreference.Cpu,
|
||||||
|
SharingMode = MediaCaptureSharingMode.SharedReadOnly,
|
||||||
};
|
};
|
||||||
await capture.InitializeAsync(settings);
|
await capture.InitializeAsync(settings);
|
||||||
|
|
||||||
var colorSource = capture.FrameSources
|
var colorSource = capture.FrameSources.Values
|
||||||
.FirstOrDefault(pair => pair.Value.Info.MediaStreamType == MediaStreamType.VideoPreview)
|
.OrderBy(s => s.Info.MediaStreamType == MediaStreamType.VideoPreview ? 0 : 1)
|
||||||
.Value;
|
.FirstOrDefault(s => s.Info.MediaStreamType is MediaStreamType.VideoPreview or MediaStreamType.VideoRecord);
|
||||||
if (colorSource == null)
|
if (colorSource == null)
|
||||||
throw new InvalidOperationException($"No video preview source on camera '{_deviceId}'.");
|
{
|
||||||
|
var kinds = string.Join(", ", capture.FrameSources.Values
|
||||||
|
.Select(s => s.Info.MediaStreamType).Distinct());
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Camera '{_deviceId}' exposes no video source (found: {kinds}). " +
|
||||||
|
"It may be locked by another app (e.g. NVIDIA Broadcast).");
|
||||||
|
}
|
||||||
|
|
||||||
reader = await capture.CreateFrameReaderAsync(colorSource, MediaEncodingSubtypes.Bgra8);
|
reader = await capture.CreateFrameReaderAsync(colorSource, MediaEncodingSubtypes.Bgra8);
|
||||||
reader.FrameArrived += OnFrameArrived;
|
reader.FrameArrived += OnFrameArrived;
|
||||||
|
|||||||
@@ -84,10 +84,19 @@ C# / WPF (.NET 8) following MVVM:
|
|||||||
- **Seam-first:** everything above the WinRT layer speaks only `VideoFrame` (normalized tightly-packed
|
- **Seam-first:** everything above the WinRT layer speaks only `VideoFrame` (normalized tightly-packed
|
||||||
BGRA8) + `CameraDeviceInfo`/`ICameraEnumerator`/`ICameraFrameSource` interfaces. Tests inject fakes;
|
BGRA8) + `CameraDeviceInfo`/`ICameraEnumerator`/`ICameraFrameSource` interfaces. Tests inject fakes;
|
||||||
screen capture and background removal later feed the same seam.
|
screen capture and background removal later feed the same seam.
|
||||||
- **CPU-first:** `MediaCaptureInitializationSettings { MemoryPreference = Cpu, StreamingCaptureMode = Video }`,
|
- **CPU-first:** `MediaCaptureInitializationSettings { MemoryPreference = Cpu, StreamingCaptureMode = Video,
|
||||||
frames pulled via `CreateFrameReaderAsync(colorSource, MediaEncodingSubtypes.Bgra8)` — the pipeline does
|
SharingMode = SharedReadOnly }`, frames pulled via
|
||||||
any format conversion, so every `FrameArrived` yields a ready BGRA8 `SoftwareBitmap` (bytes read via
|
`CreateFrameReaderAsync(colorSource, MediaEncodingSubtypes.Bgra8)` — the pipeline does any format
|
||||||
|
conversion, so every `FrameArrived` yields a ready BGRA8 `SoftwareBitmap` (bytes read via
|
||||||
`WindowsRuntimeMarshal.TryGetDataUnsafe`, not marshalled copies).
|
`WindowsRuntimeMarshal.TryGetDataUnsafe`, not marshalled copies).
|
||||||
|
- **Source pick, not first hit:** the frame reader is bound to the first source that is `VideoPreview`
|
||||||
|
(preferred) or `VideoRecord`, not blindly the first preview source. If a camera exposes neither, the
|
||||||
|
failure names the device and the stream types it *does* expose. `SharedReadOnly` lets the capture
|
||||||
|
coexist with other apps that share the camera.
|
||||||
|
- **Known failure: NVIDIA Broadcast** — it opens the physical webcam exclusively, so `InitializeAsync`
|
||||||
|
fails with "camera in use" (or, if init slips through, the device exposes no preview source). Fix:
|
||||||
|
quit Broadcast while streaming, or pick its virtual "NVIDIA Broadcast" device from the picker and the
|
||||||
|
app captures the processed feed. This is a real-device finding (Logitech `VID_046D&PID_082D`).
|
||||||
- **TFM:** `net8.0-windows10.0.19041.0` (app + tests) pulls the WinRT projection from the SDK reference
|
- **TFM:** `net8.0-windows10.0.19041.0` (app + tests) pulls the WinRT projection from the SDK reference
|
||||||
packs — no NuGet package, no capability manifest (unpackaged desktop app works; the Windows privacy
|
packs — no NuGet package, no capability manifest (unpackaged desktop app works; the Windows privacy
|
||||||
camera toggle still applies). `EnableWindowsTargeting` keeps WSL builds working.
|
camera toggle still applies). `EnableWindowsTargeting` keeps WSL builds working.
|
||||||
|
|||||||
Reference in New Issue
Block a user