c01206fb8a
The ~30Hz CapturePreviewAsync PNG poll capped real cadence at ~20Hz (35–165ms full-HD encode+decode), so a 60fps widget still juddered at ~1/6 speed. Replaced polling with frame-driven capture of the composition controller's root visual — the mechanism WebView2CompositionControl and Flutter's webview_windows use (graphics_context.cc captures the root surface_ visual via CreateGraphicsCaptureItemFromVisual; reference: github.com/microsoft/Windows.UI.Composition.WinUI / flutter-internal webview_windows). Frames now arrive at the renderer's own pace; capture memory is epoch'd ring reuse + one crop-sized shared WriteableBitmap. New Services/WebCaptureFrameSource.cs owns GraphicsCaptureItem + free- threaded Direct3D11CaptureFramePool + session (Straight alpha readback, per-frame FindContentBounds → CropBounds). WebView2Manager reworked around per-session composition controllers + one UI-thread Compositor created via the CoreMessaging CreateDispatcherQueueController P/Invoke (the 19041 projection lacks CreateOnCurrentThread); internal seam ctor (Dispatcher, Func<string,IScreenCaptureSource>?) for hermetic tests. CaptureScheduler.cs deleted; the three SetCaptureInterval cadence hooks removed; InitWebView2() moved from MainWindow ctor to Loaded (a parent HWND must exist for the composition controller); the hidden WebViewHostPanel overlay deleted. TransparentBackgroundScript unchanged. Tests: WebView2ManagerTests reworked — 4 control-size + scheduler tests dropped, FindContentBounds tests moved to WebCaptureFrameSource, ONE integration test (Frames_PublishCroppedPreview_And_CoalesceToLatest_CarryingCropBounds) drives the seam with a FakeWebSource + background-STA DispatcherPump. Suite 293/293, 0 warnings. NOTE: composition path NOT yet verified on a device — the take is the next step. Web work committed locally only (no push per standing rule). Docs same-commit: ai.md Slice 14 + supersede marker on Slice 11, HANDOFF, MyMistakes (CoreMessaging DQ + namespace-landmine recipe), TASK 17, Controls/ViewModels/Services indexes.
45 lines
1.5 KiB
C#
45 lines
1.5 KiB
C#
using System.Linq;
|
|
using System.Windows.Media.Imaging;
|
|
using ytLive.Models;
|
|
using ytLive.Services;
|
|
using ytLive.ViewModels;
|
|
|
|
namespace ytLive.ViewModels;
|
|
|
|
public partial class MainViewModel
|
|
{
|
|
private void RegisterLoadedWebSources()
|
|
{
|
|
if (_webView2Manager == null) return;
|
|
|
|
foreach (var source in Scenes.SelectMany(s => s.Elements).OfType<Source>()
|
|
.Where(s => s.Type == SourceType.WebSource))
|
|
{
|
|
_webView2Manager.Register(source);
|
|
source.PropertyChanged += (_, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(Source.WebUri))
|
|
_webView2Manager.OnWebUriChanged(source);
|
|
};
|
|
}
|
|
}
|
|
|
|
// Runs on the main window's Loaded handler (MainWindow.xaml.cs): the
|
|
// composition controller needs the window HWND as its parent, which does not
|
|
// exist in the ctor. Web sources register then — no frames are expected before
|
|
// the window is shown anyway.
|
|
public void InitWebView2()
|
|
{
|
|
_webView2Manager = new WebView2Manager(System.Windows.Application.Current.Dispatcher);
|
|
_webView2Manager.PreviewBitmapChanged += OnWebView2PreviewBitmapChanged;
|
|
RegisterLoadedWebSources();
|
|
}
|
|
|
|
private void OnWebView2PreviewBitmapChanged(string sourceId, WriteableBitmap bitmap)
|
|
{
|
|
foreach (var scene in Scenes)
|
|
foreach (var el in scene.Elements.OfType<Source>().Where(s => s.Id == sourceId))
|
|
el.VideoImageSource = bitmap;
|
|
}
|
|
}
|