Skip to content

Commit a83dc8e

Browse files
authored
Merge pull request #72 from grandixximo/cursor/fix-webcam-tab-performance-and-ui-glitches-1590
Fix webcam tab performance and UI glitches
2 parents dcbee54 + 26d8dcf commit a83dc8e

4 files changed

Lines changed: 97 additions & 15 deletions

File tree

src/Captura.Base/Services/IWebcamCapture.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public interface IWebcamCapture : IDisposable
1414

1515
void UpdatePreview(IWindow Window, Rectangle Location);
1616

17+
// Control preview window visibility without tearing down the camera graph
18+
void SetPreviewVisibility(bool IsVisible);
19+
1720
string GetCameraProperties();
1821
}
1922
}

src/Captura.Windows/Webcam/CaptureWebcam.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class CaptureWebcam : ISampleGrabberCB, IDisposable
1313
#region Fields
1414
readonly Filter _videoDevice;
1515
readonly IntPtr _previewWindow;
16+
IntPtr _currentOwner;
1617
readonly DummyForm _form;
1718
readonly Action _onClick;
1819
readonly object _lock = new object();
@@ -50,6 +51,7 @@ public CaptureWebcam(Filter VideoDevice, Action OnClick, IntPtr PreviewWindow)
5051
_form.Click += (s, e) => OnClick?.Invoke();
5152

5253
_previewWindow = PreviewWindow != IntPtr.Zero ? PreviewWindow : _form.Handle;
54+
_currentOwner = _previewWindow;
5355

5456
BuildGraph();
5557
}
@@ -502,6 +504,7 @@ void SetupVideoWindow()
502504
_videoWindow = null;
503505
return;
504506
}
507+
_currentOwner = _previewWindow;
505508
}
506509
catch
507510
{
@@ -555,6 +558,48 @@ public void OnPreviewWindowResize(int X, int Y, int Width, int Height)
555558
}
556559
}
557560

561+
public void SetPreviewVisibility(bool isVisible)
562+
{
563+
lock (_lock)
564+
{
565+
if (_videoWindow == null)
566+
return;
567+
568+
try
569+
{
570+
_videoWindow.put_Visible(isVisible ? OABool.True : OABool.False);
571+
}
572+
catch { }
573+
}
574+
}
575+
576+
public void UpdatePreviewWindow(IntPtr ownerHandle, Rectangle location)
577+
{
578+
lock (_lock)
579+
{
580+
if (_videoWindow != null)
581+
{
582+
try
583+
{
584+
if (ownerHandle != IntPtr.Zero && _currentOwner != ownerHandle)
585+
{
586+
// Switch owner without rebuilding the graph
587+
_videoWindow.put_Visible(OABool.False);
588+
_videoWindow.put_Owner(ownerHandle);
589+
_currentOwner = ownerHandle;
590+
_videoWindow.put_Visible(OABool.True);
591+
}
592+
593+
_videoWindow.SetWindowPosition(location.X, location.Y, location.Width, location.Height);
594+
}
595+
catch
596+
{
597+
// Ignore errors
598+
}
599+
}
600+
}
601+
}
602+
558603
#endregion
559604

560605
#region Frame Capture

src/Captura.Windows/Webcam/WebcamCapture.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,22 @@ public void UpdatePreview(IWindow Window, Rectangle Location)
9494
{
9595
try
9696
{
97-
if (Window != null && _lastWin != Window.Handle)
97+
// Lazily create capture when first preview is requested
98+
if (_captureWebcam == null)
9899
{
99-
// Recreate capture with new window handle
100-
_captureWebcam?.StopPreview();
101-
_captureWebcam?.Dispose();
102-
103-
_captureWebcam = new CaptureWebcam(_filter, _onClick, Window.Handle);
100+
var handle = Window?.Handle ?? IntPtr.Zero;
101+
_captureWebcam = new CaptureWebcam(_filter, _onClick, handle);
104102
_captureWebcam.StartPreview();
105-
103+
_lastWin = handle;
104+
}
105+
else if (Window != null && _lastWin != Window.Handle)
106+
{
107+
// Switch owner handle without rebuilding the graph
108+
_captureWebcam.UpdatePreviewWindow(Window.Handle, Location);
106109
_lastWin = Window.Handle;
107110
}
108111

112+
// Always update window position
109113
_captureWebcam?.OnPreviewWindowResize(Location.X, Location.Y, Location.Width, Location.Height);
110114
}
111115
catch (COMException ex)
@@ -119,6 +123,21 @@ public void UpdatePreview(IWindow Window, Rectangle Location)
119123
});
120124
}
121125

126+
public void SetPreviewVisibility(bool isVisible)
127+
{
128+
if (_disposed)
129+
return;
130+
131+
_syncContext.Run(() =>
132+
{
133+
try
134+
{
135+
_captureWebcam?.SetPreviewVisibility(isVisible);
136+
}
137+
catch { }
138+
});
139+
}
140+
122141
void HandleCameraException(Exception exception, string context)
123142
{
124143
// Common DirectShow/Windows error codes

src/Captura/Pages/WebcamPlacementPreviewPage.xaml.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ async Task UpdateBackground()
7171
IReadOnlyReactiveProperty<IWebcamCapture> _webcamCapture;
7272
bool _setupComplete;
7373
bool _isReleasing;
74+
bool _acquired;
7475

7576
public void SetupPreview()
7677
{
@@ -81,24 +82,25 @@ public void SetupPreview()
8182

8283
IsVisibleChanged += (S, E) =>
8384
{
84-
if (IsVisible && _webcamCapture == null && !_isReleasing)
85+
if (IsVisible && !_isReleasing)
8586
{
86-
_webcamCapture = _webcamModel.InitCapture();
87+
if (_webcamCapture == null)
88+
{
89+
_webcamCapture = _webcamModel.InitCapture();
90+
_acquired = true;
91+
}
8792

8893
if (_webcamCapture.Value is { } capture)
8994
{
9095
_reactor.WebcamSize.OnNext(new WSize(capture.Width, capture.Height));
91-
96+
_webcamCapture.Value.SetPreviewVisibility(true);
9297
UpdateWebcamPreview();
9398
}
9499
}
95100
else if (!IsVisible && _webcamCapture != null && !_isReleasing)
96101
{
97-
// Release webcam when page becomes not visible
98-
_isReleasing = true;
99-
_webcamModel.ReleaseCapture();
100-
_webcamCapture = null;
101-
_isReleasing = false;
102+
// Hide preview when page is not visible but keep camera running to avoid flicker
103+
try { _webcamCapture.Value?.SetPreviewVisibility(false); } catch { }
102104
}
103105
};
104106

@@ -127,6 +129,19 @@ void OnRegionChange()
127129
.AddTo(_subscriptions);
128130

129131
UpdateWebcamPreview();
132+
133+
Unloaded += (s, e) =>
134+
{
135+
// Cleanup when page is unloaded
136+
if (_acquired && _webcamCapture != null)
137+
{
138+
_isReleasing = true;
139+
_webcamModel.ReleaseCapture();
140+
_webcamCapture = null;
141+
_acquired = false;
142+
_isReleasing = false;
143+
}
144+
};
130145
}
131146

132147

0 commit comments

Comments
 (0)