mac-capture: Disable all SCK modes besides WindowCapture on macOS 12

SCK has too many open issues on macOS 12 to enable full functionality
on that version. Window Capture has the biggest performance uplift and
so far the least amount of quirks, so leave this variant (with the
"Beta" qualifier) for macOS versions before Ventura.
This commit is contained in:
PatTheMav 2022-11-08 14:10:01 +01:00 committed by Ryan Foster
parent 8e8148a2d5
commit 7cedd324e1
2 changed files with 98 additions and 48 deletions

View file

@ -24,4 +24,5 @@ Crop.size.height="Crop bottom"
SCK.Name="macOS Screen Capture"
SCK.Name.Beta="macOS Screen Capture (BETA)"
SCK.AudioUnavailable="Audio capture requires macOS 13 or newer."
SCK.CaptureTypeUnavailable="Selected capture type requires macOS 13 or newer."
SCK.Method="Method"

View file

@ -69,6 +69,8 @@ struct screen_capture {
NSString *application_id;
};
#pragma mark -
static void destroy_screen_stream(struct screen_capture *sc)
{
if (sc->disp) {
@ -365,33 +367,9 @@ static bool init_screen_stream(struct screen_capture *sc)
case ScreenCaptureDisplayStream: {
SCDisplay *target_display = get_target_display();
if (@available(macOS 13.0, *)) {
content_filter = [[SCContentFilter alloc]
initWithDisplay:target_display
excludingWindows:[[NSArray alloc] init]];
} else {
NSArray *excluded = [sc->shareable_content.applications
filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(
SCRunningApplication
*application,
NSDictionary<
NSString *,
id>
*_Nullable bindings
__attribute__((
unused))) {
return [application
.bundleIdentifier
isEqualToString:
@"com.apple.controlcenter"];
}]];
content_filter = [[SCContentFilter alloc]
initWithDisplay:target_display
excludingApplications:excluded
exceptingWindows:[[NSArray alloc] init]];
}
content_filter = [[SCContentFilter alloc]
initWithDisplay:target_display
excludingWindows:[[NSArray alloc] init]];
set_display_mode(sc, target_display);
} break;
@ -464,13 +442,22 @@ static bool init_screen_stream(struct screen_capture *sc)
[sc->stream_properties setShowsCursor:!sc->hide_cursor];
[sc->stream_properties setColorSpaceName:kCGColorSpaceDisplayP3];
[sc->stream_properties setPixelFormat:'l10r'];
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
if (@available(macOS 13.0, *)) {
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
[sc->stream_properties setCapturesAudio:TRUE];
[sc->stream_properties setExcludesCurrentProcessAudio:TRUE];
[sc->stream_properties setChannelCount:2];
}
#endif
} else {
if (sc->capture_type != ScreenCaptureWindowStream) {
sc->disp = NULL;
os_event_init(&sc->disp_finished, OS_EVENT_TYPE_MANUAL);
os_event_init(&sc->stream_start_completed,
OS_EVENT_TYPE_MANUAL);
return true;
}
}
sc->disp = [[SCStream alloc] initWithFilter:content_filter
configuration:sc->stream_properties
@ -491,7 +478,7 @@ static bool init_screen_stream(struct screen_capture *sc)
}
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
if (__builtin_available(macOS 13.0, *)) {
if (@available(macOS 13.0, *)) {
did_add_output = [sc->disp
addStreamOutput:sc->capture_delegate
type:SCStreamOutputTypeAudio
@ -577,8 +564,8 @@ static void *screen_capture_create(obs_data_t *settings, obs_source_t *source)
sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names");
sc->show_hidden_windows =
obs_data_get_bool(settings, "show_hidden_windows");
sc->window = obs_data_get_int(settings, "window");
sc->capture_type = obs_data_get_int(settings, "type");
sc->window = (CGWindowID)obs_data_get_int(settings, "window");
sc->capture_type = (unsigned int)obs_data_get_int(settings, "type");
os_sem_init(&sc->shareable_content_available, 1);
screen_capture_build_content_list(
@ -591,7 +578,7 @@ static void *screen_capture_create(obs_data_t *settings, obs_source_t *source)
if (!sc->effect)
goto fail;
sc->display = obs_data_get_int(settings, "display");
sc->display = (CGDirectDisplayID)obs_data_get_int(settings, "display");
sc->application_id = [[NSString alloc]
initWithUTF8String:obs_data_get_string(settings,
"application")];
@ -699,10 +686,11 @@ static void screen_capture_defaults(obs_data_t *settings)
}
}
obs_data_set_default_int(settings, "type", 0);
obs_data_set_default_int(settings, "display", initial_display);
obs_data_set_default_int(settings, "window", kCGNullWindowID);
obs_data_set_default_obj(settings, "application", NULL);
obs_data_set_default_int(settings, "type", ScreenCaptureDisplayStream);
obs_data_set_default_int(settings, "window", kCGNullWindowID);
obs_data_set_default_bool(settings, "show_cursor", true);
obs_data_set_default_bool(settings, "show_empty_names", false);
obs_data_set_default_bool(settings, "show_hidden_windows", false);
@ -713,7 +701,8 @@ static void screen_capture_update(void *data, obs_data_t *settings)
struct screen_capture *sc = data;
CGWindowID old_window_id = sc->window;
CGWindowID new_window_id = obs_data_get_int(settings, "window");
CGWindowID new_window_id =
(CGWindowID)obs_data_get_int(settings, "window");
if (new_window_id > 0 && new_window_id != old_window_id)
sc->window = new_window_id;
@ -766,6 +755,8 @@ static void screen_capture_update(void *data, obs_data_t *settings)
obs_leave_graphics();
}
#pragma mark - obs_properties
static bool build_display_list(struct screen_capture *sc,
obs_properties_t *props)
{
@ -894,7 +885,8 @@ static bool content_settings_changed(void *data, obs_properties_t *props,
{
struct screen_capture *sc = data;
unsigned int capture_type_id = obs_data_get_int(settings, "type");
unsigned int capture_type_id =
(unsigned int)obs_data_get_int(settings, "type");
obs_property_t *display_list = obs_properties_get(props, "display");
obs_property_t *window_list = obs_properties_get(props, "window");
obs_property_t *app_list = obs_properties_get(props, "application");
@ -902,6 +894,9 @@ static bool content_settings_changed(void *data, obs_properties_t *props,
obs_property_t *hidden =
obs_properties_get(props, "show_hidden_windows");
obs_property_t *capture_type_error =
obs_properties_get(props, "capture_type_info");
if (sc->capture_type != capture_type_id) {
switch (capture_type_id) {
case 0: {
@ -910,6 +905,11 @@ static bool content_settings_changed(void *data, obs_properties_t *props,
obs_property_set_visible(app_list, false);
obs_property_set_visible(empty, false);
obs_property_set_visible(hidden, false);
if (capture_type_error) {
obs_property_set_visible(capture_type_error,
true);
}
break;
}
case 1: {
@ -918,6 +918,11 @@ static bool content_settings_changed(void *data, obs_properties_t *props,
obs_property_set_visible(app_list, false);
obs_property_set_visible(empty, true);
obs_property_set_visible(hidden, true);
if (capture_type_error) {
obs_property_set_visible(capture_type_error,
false);
}
break;
}
case 2: {
@ -926,21 +931,26 @@ static bool content_settings_changed(void *data, obs_properties_t *props,
obs_property_set_visible(window_list, false);
obs_property_set_visible(empty, false);
obs_property_set_visible(hidden, true);
if (capture_type_error) {
obs_property_set_visible(capture_type_error,
true);
}
break;
}
}
}
sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names");
sc->show_hidden_windows =
obs_data_get_bool(settings, "show_hidden_windows");
screen_capture_build_content_list(
sc, capture_type_id == ScreenCaptureDisplayStream);
build_display_list(sc, props);
build_window_list(sc, props);
build_application_list(sc, props);
sc->show_empty_names = obs_data_get_bool(settings, "show_empty_names");
sc->show_hidden_windows =
obs_data_get_bool(settings, "show_hidden_windows");
return true;
}
@ -949,9 +959,11 @@ static obs_properties_t *screen_capture_properties(void *data)
struct screen_capture *sc = data;
obs_properties_t *props = obs_properties_create();
obs_property_t *capture_type = obs_properties_add_list(
props, "type", obs_module_text("SCK.Method"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(capture_type,
obs_module_text("DisplayCapture"), 0);
obs_property_list_add_int(capture_type,
@ -982,9 +994,6 @@ static obs_properties_t *screen_capture_properties(void *data)
props, "show_hidden_windows",
obs_module_text("WindowUtils.ShowHidden"));
obs_properties_add_bool(props, "show_cursor",
obs_module_text("DisplayCapture.ShowCursor"));
if (sc) {
obs_property_set_modified_callback2(
hidden, content_settings_changed, sc);
@ -1020,12 +1029,48 @@ static obs_properties_t *screen_capture_properties(void *data)
empty, content_settings_changed, sc);
}
obs_properties_add_bool(props, "show_cursor",
obs_module_text("DisplayCapture.ShowCursor"));
if (@available(macOS 13.0, *))
;
else
obs_properties_add_text(props, "audio_info",
obs_module_text("SCK.AudioUnavailable"),
OBS_TEXT_INFO);
else {
obs_property_t *audio_warning = obs_properties_add_text(
props, "audio_info",
obs_module_text("SCK.AudioUnavailable"), OBS_TEXT_INFO);
obs_property_text_set_info_type(audio_warning,
OBS_TEXT_INFO_WARNING);
obs_property_t *capture_type_error = obs_properties_add_text(
props, "capture_type_info",
obs_module_text("SCK.CaptureTypeUnavailable"),
OBS_TEXT_INFO);
obs_property_text_set_info_type(capture_type_error,
OBS_TEXT_INFO_ERROR);
if (sc) {
switch (sc->capture_type) {
case ScreenCaptureDisplayStream: {
obs_property_set_visible(capture_type_error,
true);
break;
}
case ScreenCaptureWindowStream: {
obs_property_set_visible(capture_type_error,
false);
break;
}
case ScreenCaptureApplicationStream: {
obs_property_set_visible(capture_type_error,
true);
break;
}
}
} else {
obs_property_set_visible(capture_type_error, false);
}
}
return props;
}
@ -1053,6 +1098,8 @@ enum gs_color_space screen_capture_video_get_color_space(
return GS_CS_SRGB_16F;
}
#pragma mark - obs_source_info
struct obs_source_info screen_capture_info = {
.id = "screen_capture",
.type = OBS_SOURCE_TYPE_INPUT,
@ -1077,6 +1124,8 @@ struct obs_source_info screen_capture_info = {
.video_get_color_space = screen_capture_video_get_color_space,
};
#pragma mark - ScreenCaptureDelegate
@implementation ScreenCaptureDelegate
- (void)stream:(SCStream *)stream