@@ -152,6 +152,8 @@ def screen_capture_backend():
152152 return openshot .SCREEN_CAPTURE_WAYLAND
153153 if sys .platform .startswith ("win" ) and hasattr (openshot , "SCREEN_CAPTURE_WINDOWS_GDI" ):
154154 return openshot .SCREEN_CAPTURE_WINDOWS_GDI
155+ if sys .platform == "darwin" and hasattr (openshot , "SCREEN_CAPTURE_MAC_AVFOUNDATION" ):
156+ return openshot .SCREEN_CAPTURE_MAC_AVFOUNDATION
155157 if hasattr (openshot , "SCREEN_CAPTURE_X11" ):
156158 return openshot .SCREEN_CAPTURE_X11
157159 return auto_backend
@@ -177,6 +179,8 @@ def screen_capture_backend_supported(backend=None):
177179 return False
178180 if sys .platform .startswith ("win" ):
179181 return selected_backend == getattr (openshot , "SCREEN_CAPTURE_WINDOWS_GDI" , object ())
182+ if sys .platform == "darwin" :
183+ return selected_backend == getattr (openshot , "SCREEN_CAPTURE_MAC_AVFOUNDATION" , object ())
180184 return selected_backend == getattr (openshot , "SCREEN_CAPTURE_X11" , object ())
181185
182186
@@ -190,6 +194,11 @@ def screen_capture_backend_is_windows(backend=None):
190194 return selected_backend == getattr (openshot , "SCREEN_CAPTURE_WINDOWS_GDI" , object ())
191195
192196
197+ def screen_capture_backend_is_mac (backend = None ):
198+ selected_backend = screen_capture_backend () if backend is None else backend
199+ return selected_backend == getattr (openshot , "SCREEN_CAPTURE_MAC_AVFOUNDATION" , object ())
200+
201+
193202def camera_capture_backend ():
194203 default_backend = getattr (getattr (openshot , "CameraCaptureReader" , None ), "DefaultBackend" , None )
195204 if callable (default_backend ):
@@ -199,6 +208,8 @@ def camera_capture_backend():
199208 log .debug ("Unable to query default camera capture backend" , exc_info = True )
200209 if sys .platform .startswith ("win" ) and hasattr (openshot , "CAMERA_CAPTURE_WINDOWS_DSHOW" ):
201210 return openshot .CAMERA_CAPTURE_WINDOWS_DSHOW
211+ if sys .platform == "darwin" and hasattr (openshot , "CAMERA_CAPTURE_MAC_AVFOUNDATION" ):
212+ return openshot .CAMERA_CAPTURE_MAC_AVFOUNDATION
202213 if hasattr (openshot , "CAMERA_CAPTURE_V4L2" ):
203214 return openshot .CAMERA_CAPTURE_V4L2
204215 return getattr (openshot , "CAMERA_CAPTURE_AUTO" , None )
@@ -209,6 +220,11 @@ def camera_capture_backend_is_windows(backend=None):
209220 return selected_backend == getattr (openshot , "CAMERA_CAPTURE_WINDOWS_DSHOW" , object ())
210221
211222
223+ def camera_capture_backend_is_mac (backend = None ):
224+ selected_backend = camera_capture_backend () if backend is None else backend
225+ return selected_backend == getattr (openshot , "CAMERA_CAPTURE_MAC_AVFOUNDATION" , object ())
226+
227+
212228class LiveRecordingThumbnailCache :
213229 """Save coarse thumbnail-grid frames while a live video recording is written."""
214230
@@ -734,8 +750,13 @@ def __init__(self, window, parent=None):
734750 self .screen_status_label .setWordWrap (True )
735751 self .screen_section .body_layout .addWidget (self .screen_status_label )
736752
753+ default_screen_display = os .environ .get ("DISPLAY" , ":0.0" )
754+ if sys .platform .startswith ("win" ):
755+ default_screen_display = "desktop"
756+ elif sys .platform == "darwin" :
757+ default_screen_display = "1:none"
737758 self .screen_display_edit = QLineEdit (
738- "desktop" if sys . platform . startswith ( "win" ) else os . environ . get ( "DISPLAY" , ":0.0" ) ,
759+ default_screen_display ,
739760 self .screen_section ,
740761 )
741762 self .screen_x_spin = QSpinBox (self .screen_section )
@@ -933,11 +954,14 @@ def _camera_backend_available(self):
933954 ) or (
934955 backend == getattr (openshot , "CAMERA_CAPTURE_WINDOWS_DSHOW" , object ())
935956 and sys .platform .startswith ("win" )
957+ ) or (
958+ backend == getattr (openshot , "CAMERA_CAPTURE_MAC_AVFOUNDATION" , object ())
959+ and sys .platform == "darwin"
936960 )
937961
938962 def _selected_camera_device (self ):
939963 device = self .camera_combo .currentData () if hasattr (self , "camera_combo" ) else None
940- if device and (camera_capture_backend_is_windows () or os .path .exists (device )):
964+ if device and (camera_capture_backend_is_windows () or camera_capture_backend_is_mac () or os .path .exists (device )):
941965 return device
942966 return ""
943967
@@ -967,6 +991,7 @@ def _sync_source_availability(self):
967991 def _sync_screen_backend_ui (self ):
968992 _ = get_app ()._tr
969993 wayland = screen_capture_backend_is_wayland ()
994+ mac_screen = screen_capture_backend_is_mac ()
970995 self .screen_mode_widget .setVisible (not wayland )
971996 self .screen_display_label .setVisible (not wayland )
972997 self .screen_display_edit .setVisible (not wayland )
@@ -977,12 +1002,16 @@ def _sync_screen_backend_ui(self):
9771002 self .screen_size_label .setVisible (not wayland )
9781003 self .screen_width_spin .setVisible (not wayland )
9791004 self .screen_height_spin .setVisible (not wayland )
980- self .window_button .setEnabled (not wayland )
1005+ self .window_button .setEnabled (not wayland and not mac_screen )
1006+ self .region_button .setEnabled (not wayland and not mac_screen )
9811007 self .screen_hide_label .setVisible (not wayland )
9821008 self .hide_openshot_combo .setVisible (not wayland )
9831009 if wayland :
9841010 self .screen_status_label .setText (_ ("Your desktop will ask what to share when recording starts." ))
9851011 self ._screen_window_id = ""
1012+ elif mac_screen :
1013+ self .screen_status_label .setText (_ ("macOS screen recording uses the selected AVFoundation display device." ))
1014+ self ._screen_window_id = ""
9861015 elif screen_capture_backend_is_windows ():
9871016 self .screen_status_label .setText (_ ("Windows screen recording uses full screen or numeric region bounds." ))
9881017
@@ -1047,6 +1076,11 @@ def _select_window(self):
10471076 if screen_capture_backend_is_wayland ():
10481077 self .screen_status_label .setText (get_app ()._tr ("Your desktop will ask what to share when recording starts." ))
10491078 return
1079+ if screen_capture_backend_is_mac ():
1080+ self .full_screen_button .setChecked (True )
1081+ self .window_button .setChecked (False )
1082+ self .screen_status_label .setText (get_app ()._tr ("Window selection is not available for macOS AVFoundation recording." ))
1083+ return
10501084 self .window_button .setChecked (True )
10511085 self .full_screen_button .setChecked (False )
10521086 self .region_button .setChecked (False )
@@ -1068,6 +1102,11 @@ def _select_region(self):
10681102 if screen_capture_backend_is_wayland ():
10691103 self .screen_status_label .setText (get_app ()._tr ("Region selection is not available for Wayland screen recording." ))
10701104 return
1105+ if screen_capture_backend_is_mac ():
1106+ self .full_screen_button .setChecked (True )
1107+ self .region_button .setChecked (False )
1108+ self .screen_status_label .setText (get_app ()._tr ("Region selection is not available for macOS AVFoundation recording." ))
1109+ return
10711110 self .region_button .setChecked (True )
10721111 self .full_screen_button .setChecked (False )
10731112 self .window_button .setChecked (False )
@@ -1250,7 +1289,7 @@ def refresh_cameras(self):
12501289 self .camera_combo .blockSignals (True )
12511290 self .camera_combo .clear ()
12521291 devices = []
1253- if camera_capture_backend_is_windows ():
1292+ if camera_capture_backend_is_windows () or camera_capture_backend_is_mac () :
12541293 try :
12551294 get_devices = getattr (openshot .CameraCaptureReader , "GetDeviceNames" , None )
12561295 if callable (get_devices ):
@@ -1369,7 +1408,7 @@ def _probe_camera_modes(self, device):
13691408 (640 , 360 ): {30 },
13701409 }
13711410 self ._camera_mode_formats = {}
1372- if camera_capture_backend_is_windows ():
1411+ if camera_capture_backend_is_windows () or camera_capture_backend_is_mac () :
13731412 return fallback
13741413 try :
13751414 result = subprocess .run (
@@ -1545,9 +1584,9 @@ def _recording_start_validation_error(self):
15451584 device = self .camera_combo .currentData ()
15461585 if not device :
15471586 return _ ("No webcam device was found." )
1548- if not camera_capture_backend_is_windows () and not os .path .exists (device ):
1587+ if not ( camera_capture_backend_is_windows () or camera_capture_backend_is_mac () ) and not os .path .exists (device ):
15491588 return _ ("Webcam device was not found: %s" ) % device
1550- if not camera_capture_backend_is_windows () and not os .access (device , os .R_OK ):
1589+ if not ( camera_capture_backend_is_windows () or camera_capture_backend_is_mac () ) and not os .access (device , os .R_OK ):
15511590 return _ ("Webcam device is not accessible: %s" ) % device
15521591 return ""
15531592
@@ -1737,6 +1776,7 @@ def _build_video_jobs(self):
17371776 screen_width = self ._safe_even_dimension (self .screen_width_spin .value ())
17381777 screen_height = self ._safe_even_dimension (self .screen_height_spin .value ())
17391778 windows_screen = screen_capture_backend_is_windows (screen_backend )
1779+ mac_screen = screen_capture_backend_is_mac (screen_backend )
17401780 if wayland_screen :
17411781 root_x , root_y , root_width , root_height = 0 , 0 , None , None
17421782 else :
@@ -1756,9 +1796,12 @@ def _build_video_jobs(self):
17561796 screen_height = self ._safe_even_dimension (min (screen_height , root_bottom - screen_y ))
17571797 settings = openshot .ScreenCaptureSettings ()
17581798 settings .backend = screen_backend
1759- settings .display = (
1760- "desktop" if windows_screen else self .screen_display_edit .text ().strip () or os .environ .get ("DISPLAY" , ":0.0" )
1761- )
1799+ if windows_screen :
1800+ settings .display = "desktop"
1801+ elif mac_screen :
1802+ settings .display = self .screen_display_edit .text ().strip () or "1:none"
1803+ else :
1804+ settings .display = self .screen_display_edit .text ().strip () or os .environ .get ("DISPLAY" , ":0.0" )
17621805 settings .x = screen_x
17631806 settings .y = screen_y
17641807 settings .width = screen_width
@@ -1801,7 +1844,7 @@ def _build_video_jobs(self):
18011844 settings .height = self ._safe_even_dimension (camera_size [1 ])
18021845 settings .fps = camera_fps
18031846 input_format = self ._camera_mode_formats .get ((settings .width , settings .height , int (camera_fps .num )))
1804- if camera_capture_backend_is_windows (settings .backend ):
1847+ if camera_capture_backend_is_windows (settings .backend ) or camera_capture_backend_is_mac ( settings . backend ) :
18051848 settings .options ["use_device_defaults" ] = "1"
18061849 elif input_format :
18071850 settings .options ["input_format" ] = input_format
0 commit comments