Skip to content

Commit

Permalink
Throttling and capture tweaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbound committed Aug 27, 2021
1 parent 14291e0 commit e68c05f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 51 deletions.
2 changes: 1 addition & 1 deletion Desktop.Core/Services/Viewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void ApplyAutoQuality()
ImageQuality = Math.Min(DefaultQuality, ImageQuality + 2);
}

// Limit to 20 FPS.
// Limit FPS.
_ = TaskHelper.DelayUntil(() =>
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result.Timestamp > TimeSpan.FromMilliseconds(50),
TimeSpan.FromSeconds(5));
Expand Down
79 changes: 31 additions & 48 deletions Desktop.Win/Services/ScreenCapturerWin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,66 +82,47 @@ public Bitmap GetNextFrame()
{
lock (_screenBoundsLock)
{
Bitmap returnFrame = null;
var frameCompletedEvent = new ManualResetEventSlim();

// This is necessary to ensure SwitchToInputDesktop works. Threads
// that have hooks in the current desktop will not succeed.
var captureThread = new Thread(() =>
try
{
try
Win32Interop.SwitchToInputDesktop();

if (NeedsInit)
{
Win32Interop.SwitchToInputDesktop();
Logger.Write("Init needed in GetNextFrame.");
Init();
}

if (NeedsInit)
// Sometimes DX will result in a timeout, even when there are changes
// on the screen. I've observed this when a laptop lid is closed, or
// on some machines that aren't connected to a monitor. This will
// have it fall back to BitBlt in those cases.
// TODO: Make DX capture work with changed screen orientation.
if (_directxScreens.TryGetValue(SelectedScreen, out var dxDisplay) &&
dxDisplay.Rotation == DisplayModeRotation.Identity)
{
var (result, frame) = GetDirectXFrame();

if (result == GetDirectXFrameResult.Timeout)
{
Logger.Write("Init needed in GetNextFrame.");
Init();
NeedsInit = false;
return null;
}

// Sometimes DX will result in a timeout, even when there are changes
// on the screen. I've observed this when a laptop lid is closed, or
// on some machines that aren't connected to a monitor. This will
// have it fall back to BitBlt in those cases.
// TODO: Make DX capture work with changed screen orientation.
if (_directxScreens.TryGetValue(SelectedScreen, out var dxDisplay) &&
dxDisplay.Rotation == DisplayModeRotation.Identity)
if (result == GetDirectXFrameResult.Success)
{
var (result, frame) = GetDirectXFrame();

if (result == GetDirectXFrameResult.Timeout)
{
return;
}

if (result == GetDirectXFrameResult.Success)
{
returnFrame = frame;
return;
}
return frame;
}

returnFrame = GetBitBltFrame();

}
catch (Exception e)
{
Logger.Write(e);
NeedsInit = true;
}
finally
{
frameCompletedEvent.Set();
}
});

captureThread.SetApartmentState(ApartmentState.STA);
captureThread.Start();
return GetBitBltFrame();

frameCompletedEvent.Wait();
}
catch (Exception e)
{
Logger.Write(e);
NeedsInit = true;
}

return returnFrame;
return null;
}

}
Expand All @@ -168,6 +149,8 @@ public void Init()
InitDirectX();

ScreenChanged?.Invoke(this, CurrentScreenBounds);

NeedsInit = false;
}

public void SetSelectedScreen(string displayName)
Expand Down
5 changes: 3 additions & 2 deletions Shared/Win32/Win32Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,17 @@ public static MessageBoxResult ShowMessageBox(IntPtr owner,

public static bool SwitchToInputDesktop()
{
var inputDesktop = OpenInputDesktop();
try
{
CloseDesktop(_lastInputDesktop);
var inputDesktop = OpenInputDesktop();

if (inputDesktop == IntPtr.Zero)
{
return false;
}

var result = SetThreadDesktop(inputDesktop) && SwitchDesktop(inputDesktop);
CloseDesktop(_lastInputDesktop);
_lastInputDesktop = inputDesktop;
return result;
}
Expand Down

0 comments on commit e68c05f

Please sign in to comment.