Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/capture/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

<!-- version list -->

## Unreleased

### Fixes

- Full-screen video startup sizes the stream from Quartz display-mode
pixel metadata instead of taking a screenshot, so a slow framebuffer
read in a macOS VM guest no longer blows the writer startup budget.
Darwin screen-dimension and pixel-ratio probes prefer the same Quartz
path and only fall back to a grab when metadata is unavailable
([#1883](https://github.com/OpenAdaptAI/OpenAdapt/issues/1883)).


## v1.3.0 (2026-10-17)

_This release uses the MIT License._
Expand Down
145 changes: 83 additions & 62 deletions packages/capture/openadapt_capture/platform/darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,38 @@ class DarwinPlatform:
display information, and accessibility checking.
"""

@staticmethod
def _main_display_pixel_size() -> tuple[int, int]:
"""Physical pixel size of the main display via Quartz (no framebuffer read).

``CGDisplayPixelsWide`` / ``High`` follow the looking-glass size on
scaled Retina modes; ``CGDisplayModeGetPixelWidth`` / ``Height`` are
the framebuffer dimensions that match ``mss`` / ``ImageGrab`` grabs.
"""
import Quartz

main_display = Quartz.CGMainDisplayID()
mode = Quartz.CGDisplayCopyDisplayMode(main_display)
if mode is None:
raise DisplayMetricsUnavailable(
"Quartz did not report a display mode for the main display"
)
width = int(Quartz.CGDisplayModeGetPixelWidth(mode))
height = int(Quartz.CGDisplayModeGetPixelHeight(mode))
if width <= 0 or height <= 0:
raise DisplayMetricsUnavailable(
"Quartz reported a non-positive main-display pixel size: "
f"{width}x{height}"
)
return width, height

@staticmethod
def get_screen_dimensions() -> tuple[int, int]:
"""Get screen dimensions in physical pixels.

On Retina displays, this returns the actual pixel dimensions,
not the scaled logical dimensions.
not the scaled logical dimensions. Prefers Quartz mode metadata so
callers (video startup) never wait on a full-screen framebuffer read.

Returns:
Tuple of (width, height) in physical pixels.
Expand All @@ -37,89 +63,84 @@ def get_screen_dimensions() -> tuple[int, int]:
DisplayMetricsUnavailable: If the screen could not be measured.
"""
try:
from PIL import ImageGrab
screenshot = ImageGrab.grab()
return screenshot.size
except Exception as grab_exc:
# Fallback using Quartz
return DarwinPlatform._main_display_pixel_size()
except DisplayMetricsUnavailable:
raise
except Exception as quartz_exc:
try:
import Quartz
from PIL import ImageGrab

main_display = Quartz.CGMainDisplayID()
width = Quartz.CGDisplayPixelsWide(main_display)
height = Quartz.CGDisplayPixelsHigh(main_display)
return (width, height)
except Exception as quartz_exc:
screenshot = ImageGrab.grab()
if screenshot.size[0] > 0 and screenshot.size[1] > 0:
return screenshot.size
raise DisplayMetricsUnavailable(
"ImageGrab returned a non-positive screen size: "
f"{screenshot.size}"
)
except DisplayMetricsUnavailable:
raise
except Exception as grab_exc:
raise DisplayMetricsUnavailable(
"Could not measure macOS screen dimensions: "
f"ImageGrab failed ({grab_exc}) and Quartz failed "
f"({quartz_exc})"
) from quartz_exc
f"Quartz failed ({quartz_exc}) and ImageGrab failed "
f"({grab_exc})"
) from grab_exc

@staticmethod
def get_display_pixel_ratio() -> float:
"""Get the display pixel ratio for Retina displays.

Returns 2.0 for Retina displays, 1.0 for standard displays.
Prefers Quartz mode metadata so recording startup never waits on a
full-screen framebuffer read.

Returns:
Pixel ratio (physical pixels / logical pixels).
"""
try:
import mss
from PIL import ImageGrab

# Get physical dimensions from screenshot
screenshot = ImageGrab.grab()
physical_width = screenshot.size[0]

# Get logical dimensions from mss
with mss.mss() as sct:
# monitors[1] is typically the primary monitor
monitor = sct.monitors[1] if len(sct.monitors) > 1 else sct.monitors[0]
logical_width = monitor["width"]

if logical_width > 0:
return physical_width / logical_width
import Quartz

raise DisplayMetricsUnavailable(
"macOS reported a non-positive logical display width; "
"the pixel ratio could not be measured"
)
except ImportError as import_exc:
# Try using Quartz directly
main_display = Quartz.CGMainDisplayID()
mode = Quartz.CGDisplayCopyDisplayMode(main_display)
if mode is None:
raise DisplayMetricsUnavailable(
"Quartz did not report a display mode for the main display"
)
physical_width = float(Quartz.CGDisplayModeGetPixelWidth(mode))
logical_width = float(Quartz.CGDisplayModeGetWidth(mode))
if logical_width <= 0 or physical_width <= 0:
raise DisplayMetricsUnavailable(
"Quartz reported a non-positive display width while "
f"measuring pixel ratio: physical={physical_width} "
f"logical={logical_width}"
)
return physical_width / logical_width
except DisplayMetricsUnavailable:
raise
except Exception as quartz_exc:
try:
import Quartz

main_display = Quartz.CGMainDisplayID()

# Get physical dimensions
physical_width = Quartz.CGDisplayPixelsWide(main_display)

# Get logical dimensions using display mode
mode = Quartz.CGDisplayCopyDisplayMode(main_display)
if mode:
logical_width = Quartz.CGDisplayModeGetWidth(mode)
if logical_width > 0:
return physical_width / logical_width

import mss
from PIL import ImageGrab

screenshot = ImageGrab.grab()
physical_width = screenshot.size[0]
with mss.mss() as sct:
monitor = sct.monitors[1] if len(sct.monitors) > 1 else sct.monitors[0]
logical_width = monitor["width"]
if logical_width > 0 and physical_width > 0:
return physical_width / logical_width
raise DisplayMetricsUnavailable(
"Quartz did not report a usable display mode; "
"the pixel ratio could not be measured"
"macOS reported a non-positive display width while "
"measuring pixel ratio from a screenshot fallback"
)
except DisplayMetricsUnavailable:
raise
except Exception as quartz_exc:
except Exception as grab_exc:
raise DisplayMetricsUnavailable(
"Could not measure the macOS pixel ratio: mss/PIL missing "
f"({import_exc}) and Quartz failed ({quartz_exc})"
) from quartz_exc
except DisplayMetricsUnavailable:
raise
except Exception as exc:
raise DisplayMetricsUnavailable(
f"Could not measure the macOS pixel ratio: {exc}"
) from exc
"Could not measure the macOS pixel ratio: "
f"Quartz failed ({quartz_exc}) and the screenshot "
f"fallback failed ({grab_exc})"
) from grab_exc

@staticmethod
def is_accessibility_enabled() -> bool | None:
Expand Down
10 changes: 8 additions & 2 deletions packages/capture/openadapt_capture/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1710,8 +1710,14 @@ def video_pre_callback(
if frame_size is not None:
monitor_width, monitor_height = frame_size
else:
# TODO XXX replace with utils.get_monitor_dims() once fixed
monitor_width, monitor_height = utils.take_screenshot().size
# Physical pixels of the main display, without a framebuffer read.
# take_screenshot().size matches on a single display, but the grab
# can stall for tens of seconds in a macOS VM guest and blow the
# writer startup budget (#1883). get_monitor_dims() stays logical.
try:
monitor_width, monitor_height = platform.get_screen_dimensions()
except platform.DisplayMetricsUnavailable:
monitor_width, monitor_height = utils.take_screenshot().size
video_container, video_stream, video_start_timestamp = video.initialize_video_writer(
video_file_path,
monitor_width,
Expand Down
Loading
Loading