From fe08a773ab4b94d716a23c525e8e21e76fa00034 Mon Sep 17 00:00:00 2001 From: derrod Date: Wed, 14 Feb 2024 04:53:40 +0100 Subject: [PATCH 01/19] win-capture: Fix leak in wasapi reroute proc call --- plugins/win-capture/audio-helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/win-capture/audio-helpers.c b/plugins/win-capture/audio-helpers.c index 276d96971b9bd0..dab320bab0ed5d 100644 --- a/plugins/win-capture/audio-helpers.c +++ b/plugins/win-capture/audio-helpers.c @@ -22,10 +22,10 @@ static inline void reroute_wasapi_source(obs_source_t *wasapi, obs_source_t *target) { proc_handler_t *ph = obs_source_get_proc_handler(wasapi); - calldata_t *cd = calldata_create(); - calldata_set_ptr(cd, "target", target); - proc_handler_call(ph, "reroute_audio", cd); - calldata_free(cd); + calldata_t cd = {0}; + calldata_set_ptr(&cd, "target", target); + proc_handler_call(ph, "reroute_audio", &cd); + calldata_free(&cd); } void setup_audio_source(obs_source_t *parent, obs_source_t **child, From 4f5d65271246a37c5609de9e30185184a75a060d Mon Sep 17 00:00:00 2001 From: test Date: Thu, 15 Feb 2024 04:32:28 +0900 Subject: [PATCH 02/19] UI: Fix locale key for fragmented tooltip --- UI/data/locale/en-US.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index a32d0bce3a6f92..9c3f387779133c 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -962,8 +962,8 @@ Basic.Settings.Output.Format.TS="MPEG-TS (.ts)" Basic.Settings.Output.Format.HLS="HLS (.m3u8 + .ts)" Basic.Settings.Output.Format.fMP4="Fragmented MP4 (.mp4)" Basic.Settings.Output.Format.fMOV="Fragmented MOV (.mov)" -Basic.Settings.Output.Format.TT.fmov="Fragmented MOV writes the recording in chunks and does not require the same finalization as traditional MOV files.\nThis ensures the file remains playable even if writing to disk is interrupted, for example, as a result of a BSOD or power loss.\n\nThis may not be compatible with all players and editors. Use File โ†’ Remux Recordings to convert the file into a more compatible format if necessary." -Basic.Settings.Output.Format.TT.fmp4="Fragmented MP4 writes the recording in chunks and does not require the same finalization as traditional MP4 files.\nThis ensures the file remains playable even if writing to disk is interrupted, for example, as a result of a BSOD or power loss.\n\nThis may not be compatible with all players and editors. Use File โ†’ Remux Recordings to convert the file into a more compatible format if necessary." +Basic.Settings.Output.Format.TT.fragmented_mov="Fragmented MOV writes the recording in chunks and does not require the same finalization as traditional MOV files.\nThis ensures the file remains playable even if writing to disk is interrupted, for example, as a result of a BSOD or power loss.\n\nThis may not be compatible with all players and editors. Use File โ†’ Remux Recordings to convert the file into a more compatible format if necessary." +Basic.Settings.Output.Format.TT.fragmented_mp4="Fragmented MP4 writes the recording in chunks and does not require the same finalization as traditional MP4 files.\nThis ensures the file remains playable even if writing to disk is interrupted, for example, as a result of a BSOD or power loss.\n\nThis may not be compatible with all players and editors. Use File โ†’ Remux Recordings to convert the file into a more compatible format if necessary." Basic.Settings.Output.Encoder.Video="Video Encoder" Basic.Settings.Output.Encoder.Audio="Audio Encoder" Basic.Settings.Output.SelectDirectory="Select Recording Directory" From d87cf9c7eb2eb5e63b1a3118b74261013ddd52fb Mon Sep 17 00:00:00 2001 From: derrod Date: Sun, 18 Feb 2024 00:11:11 +0100 Subject: [PATCH 03/19] win-capture: Disable audio source when game capture unhooks --- plugins/win-capture/game-capture.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/win-capture/game-capture.c b/plugins/win-capture/game-capture.c index 2015475b090efd..66cdef2869f01a 100644 --- a/plugins/win-capture/game-capture.c +++ b/plugins/win-capture/game-capture.c @@ -380,6 +380,10 @@ static void stop_capture(struct game_capture *gc) calldata_set_ptr(&data, "source", gc->source); signal_handler_signal(sh, "unhooked", &data); calldata_free(&data); + + // Also update audio source to stop capturing + if (gc->audio_source) + reconfigure_audio_source(gc->audio_source, NULL); } gc->copy_texture = NULL; From ee2850372669427c12551ed7397729b8babaef43 Mon Sep 17 00:00:00 2001 From: PatTheMav Date: Thu, 15 Feb 2024 22:06:21 +0100 Subject: [PATCH 04/19] mac-avcapture: Add color format selection for capture card source Some devices do not support all color formats at all resolutions, but the capture card source automatically uses an available color format and compares it against the available format for a specific resolution. Without being able to change this format, some resolutions do not work as CMIO will not be able to find a compatible format. Thus the color format needs to be manually selected for capture card sources as well. --- plugins/mac-avcapture/OBSAVCapture.m | 5 +- plugins/mac-avcapture/plugin-main.m | 2 +- plugins/mac-avcapture/plugin-properties.m | 78 +++++++++++++++-------- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/plugins/mac-avcapture/OBSAVCapture.m b/plugins/mac-avcapture/OBSAVCapture.m index 0543fdcafafd77..df1a03e6cf5b69 100644 --- a/plugins/mac-avcapture/OBSAVCapture.m +++ b/plugins/mac-avcapture/OBSAVCapture.m @@ -448,8 +448,11 @@ - (BOOL)configureSession:(NSError *__autoreleasing *)error return NO; } } else { + int inputFormat; CMFormatDescriptionRef formatDescription = self.deviceInput.device.activeFormat.formatDescription; - inputFourCC = CMFormatDescriptionGetMediaSubType(formatDescription); + inputFormat = (int) obs_data_get_int(self.captureInfo->settings, "input_format"); + inputFourCC = [OBSAVCapture fourCharCodeFromFormat:inputFormat withRange:VIDEO_RANGE_DEFAULT]; + colorSpace = [OBSAVCapture colorspaceFromDescription:formatDescription]; videoRange = ([OBSAVCapture isFullRangeFormat:inputFourCC]) ? VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL; } diff --git a/plugins/mac-avcapture/plugin-main.m b/plugins/mac-avcapture/plugin-main.m index d0f38f143e4262..37611be54b0f39 100644 --- a/plugins/mac-avcapture/plugin-main.m +++ b/plugins/mac-avcapture/plugin-main.m @@ -117,7 +117,7 @@ static void av_fast_capture_set_defaults(obs_data_t *settings) configure_property(frame_rates, isFastPath, isFastPath, NULL, NULL); configure_property(color_space, !isFastPath, !isFastPath, NULL, NULL); configure_property(video_range, !isFastPath, !isFastPath, NULL, NULL); - configure_property(input_format, !isFastPath, !isFastPath, NULL, NULL); + configure_property(input_format, true, true, NULL, NULL); } return properties; diff --git a/plugins/mac-avcapture/plugin-properties.m b/plugins/mac-avcapture/plugin-properties.m index f7422e6e0ff97f..ea9050dd16f7a1 100644 --- a/plugins/mac-avcapture/plugin-properties.m +++ b/plugins/mac-avcapture/plugin-properties.m @@ -289,12 +289,13 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope obs_property_t *prop_color_space = NULL; obs_property_t *prop_video_range = NULL; + prop_input_format = obs_properties_get(properties, "input_format"); + obs_property_list_clear(prop_input_format); + if (!captureInstance.isFastPath) { - prop_input_format = obs_properties_get(properties, "input_format"); prop_color_space = obs_properties_get(properties, "color_space"); prop_video_range = obs_properties_get(properties, "video_range"); - obs_property_list_clear(prop_input_format); obs_property_list_clear(prop_video_range); obs_property_list_clear(prop_color_space); } @@ -320,12 +321,13 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope NSMutableArray *colorSpaces = NULL; NSMutableArray *videoRanges = NULL; + input_format = (int) obs_data_get_int(settings, "input_format"); + inputFormats = [[NSMutableArray alloc] init]; + if (!captureInstance.isFastPath) { - input_format = (int) obs_data_get_int(settings, "input_format"); color_space = (int) obs_data_get_int(settings, "color_space"); video_range = (int) obs_data_get_int(settings, "video_range"); - inputFormats = [[NSMutableArray alloc] init]; colorSpaces = [[NSMutableArray alloc] init]; videoRanges = [[NSMutableArray alloc] init]; } @@ -335,7 +337,7 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope BOOL hasFoundResolution = NO; BOOL hasFoundFramerate = NO; - BOOL hasFoundInputFormat = captureInstance.isFastPath; + BOOL hasFoundInputFormat = NO; BOOL hasFoundColorSpace = captureInstance.isFastPath; BOOL hasFoundVideoRange = captureInstance.isFastPath; @@ -388,6 +390,20 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope if (!hasFoundColorSpace && device_color_space == color_space) { hasFoundColorSpace = YES; } + } else { + FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription); + + NSString *formatDescription = [OBSAVCapture stringFromSubType:formatSubType]; + int device_format = [OBSAVCapture formatFromSubtype:formatSubType]; + + if (!hasFoundInputFormat && input_format == device_format) { + hasFoundInputFormat = YES; + } + + if (![inputFormats containsObject:@(formatSubType)]) { + obs_property_list_add_int(prop_input_format, formatDescription.UTF8String, device_format); + [inputFormats addObject:@(formatSubType)]; + } } CMVideoDimensions formatDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription); @@ -406,23 +422,28 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope } // Only iterate over available framerates if input format, color space, and resolution are matching - if (hasFoundInputFormat && hasFoundColorSpace && hasFoundResolution) { + if (hasFoundInputFormat && hasFoundColorSpace && hasFoundResolution && !hasFoundFramerate) { for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges.reverseObjectEnumerator) { - struct media_frames_per_second min_fps = { - .numerator = (uint32_t) clamp_Uint(range.maxFrameDuration.timescale, 0, UINT32_MAX), - .denominator = (uint32_t) clamp_Uint(range.maxFrameDuration.value, 0, UINT32_MAX)}; - struct media_frames_per_second max_fps = { - .numerator = (uint32_t) clamp_Uint(range.minFrameDuration.timescale, 0, UINT32_MAX), - .denominator = (uint32_t) clamp_Uint(range.minFrameDuration.value, 0, UINT32_MAX)}; - - if (![frameRates containsObject:range]) { - obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps); - [frameRates addObject:range]; - } - - if (!hasFoundFramerate && CMTimeCompare(range.maxFrameDuration, time) >= 0 && - CMTimeCompare(range.minFrameDuration, time) <= 0) { - hasFoundFramerate = YES; + FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription); + int device_format = [OBSAVCapture formatFromSubtype:formatSubType]; + + if (input_format == device_format) { + struct media_frames_per_second min_fps = { + .numerator = (uint32_t) clamp_Uint(range.maxFrameDuration.timescale, 0, UINT32_MAX), + .denominator = (uint32_t) clamp_Uint(range.maxFrameDuration.value, 0, UINT32_MAX)}; + struct media_frames_per_second max_fps = { + .numerator = (uint32_t) clamp_Uint(range.minFrameDuration.timescale, 0, UINT32_MAX), + .denominator = (uint32_t) clamp_Uint(range.minFrameDuration.value, 0, UINT32_MAX)}; + + if (![frameRates containsObject:range]) { + obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps); + [frameRates addObject:range]; + } + + if (!hasFoundFramerate && CMTimeCompare(range.maxFrameDuration, time) >= 0 && + CMTimeCompare(range.minFrameDuration, time) <= 0) { + hasFoundFramerate = YES; + } } } } @@ -443,15 +464,16 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope // Add currently selected values in disabled state if they are not supported by the device size_t index; - if (!captureInstance.isFastPath) { - FourCharCode formatSubType = [OBSAVCapture fourCharCodeFromFormat:input_format withRange:video_range]; - if (!hasFoundInputFormat) { - NSString *formatDescription = [OBSAVCapture stringFromSubType:formatSubType]; - index = obs_property_list_add_int(prop_input_format, formatDescription.UTF8String, input_format); - obs_property_list_item_disable(prop_input_format, index, true); - } + FourCharCode formatSubType = [OBSAVCapture fourCharCodeFromFormat:input_format withRange:video_range]; + if (!hasFoundInputFormat) { + NSString *formatDescription = [OBSAVCapture stringFromSubType:formatSubType]; + index = obs_property_list_add_int(prop_input_format, formatDescription.UTF8String, input_format); + obs_property_list_item_disable(prop_input_format, index, true); + } + + if (!captureInstance.isFastPath) { if (!hasFoundVideoRange) { int device_range; const char *range_description; From 5a7478d5623d6c6e6a893b15d42a562553fcc3d4 Mon Sep 17 00:00:00 2001 From: PatTheMav Date: Thu, 15 Feb 2024 19:28:56 +0100 Subject: [PATCH 05/19] mac-capture: Limit number of copied audio channels to libobs limits OBS handles up to 8 channels of audio, which requires the CoreAudio input callback to omit/ignore any audio data from channels above that count and also report a maximum amount of 8 channels to match the speaker setup given to swresample by libobs. --- plugins/mac-capture/mac-audio.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/plugins/mac-capture/mac-audio.c b/plugins/mac-capture/mac-audio.c index 27ba6a54bcb2d6..6ba6c957d56bc2 100644 --- a/plugins/mac-capture/mac-audio.c +++ b/plugins/mac-capture/mac-audio.c @@ -467,11 +467,16 @@ static OSStatus input_callback(void *data, if (!ca_success(stat, ca, "input_callback", "audio retrieval")) return noErr; - for (UInt32 i = 0; i < ca->buf_list->mNumberBuffers; i++) - audio.data[i] = ca->buf_list->mBuffers[i].mData; + for (UInt32 i = 0; i < ca->buf_list->mNumberBuffers; i++) { + if (i < MAX_AUDIO_CHANNELS) { + audio.data[i] = ca->buf_list->mBuffers[i].mData; + } + } audio.frames = frames; - audio.speakers = ca->buf_list->mNumberBuffers; + audio.speakers = (ca->buf_list->mNumberBuffers > MAX_AUDIO_CHANNELS) + ? MAX_AUDIO_CHANNELS + : ca->buf_list->mNumberBuffers; audio.format = ca->format; audio.samples_per_sec = ca->sample_rate; static double factor = 0.; @@ -863,10 +868,10 @@ static void coreaudio_destroy(void *data) static void coreaudio_set_channels(struct coreaudio_data *ca, obs_data_t *settings) { - ca->channel_map = bzalloc(sizeof(SInt32) * MAX_AV_PLANES); + ca->channel_map = bzalloc(sizeof(SInt32) * MAX_AUDIO_CHANNELS); char *device_config_name = sanitize_device_name(ca->device_uid); - for (uint8_t i = 0; i < MAX_AV_PLANES; i++) { + for (uint8_t i = 0; i < MAX_AUDIO_CHANNELS; i++) { char setting_name[128]; snprintf(setting_name, 128, "output-%s-%i", device_config_name, i + 1); From 50a19c5219022735054dc23316116729bac8dcde Mon Sep 17 00:00:00 2001 From: PatTheMav Date: Thu, 15 Feb 2024 20:38:58 +0100 Subject: [PATCH 06/19] mac-capture: Fix crash in device reconnect handler The uninit function prematurely released the memory allocated for the channel map setting, which exists in the scope of source life cycle (compared to channel names which are valid during the life cycle of a configured device). Splitting up the clean-up for both (memory for channel names is released when the device is uninitialized, memory for channel map setting is released when the source is removed) ensures that the memory is released but pointers don't become unexpectedly invalid. --- plugins/mac-capture/mac-audio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/mac-capture/mac-audio.c b/plugins/mac-capture/mac-audio.c index 6ba6c957d56bc2..4e3f51411d9d51 100644 --- a/plugins/mac-capture/mac-audio.c +++ b/plugins/mac-capture/mac-audio.c @@ -816,11 +816,6 @@ static void coreaudio_uninit(struct coreaudio_data *ca) bfree(ca->channel_names); ca->channel_names = NULL; } - - if (ca->channel_map) { - bfree(ca->channel_map); - ca->channel_map = NULL; - } } /* ------------------------------------------------------------------------- */ @@ -859,6 +854,12 @@ static void coreaudio_destroy(void *data) coreaudio_shutdown(ca); os_event_destroy(ca->exit_event); + + if (ca->channel_map) { + bfree(ca->channel_map); + ca->channel_map = NULL; + } + bfree(ca->device_name); bfree(ca->device_uid); bfree(ca); From fd65a1404c228340ed53bbb4137db5180a1e8a6e Mon Sep 17 00:00:00 2001 From: Florian Zwoch Date: Fri, 9 Feb 2024 13:40:54 +0100 Subject: [PATCH 07/19] UI: Fill audio meter background each update (#9842) Since the widget is marked as opaque we need to draw each pixel or else we may end up with unpainted pixels. On Wayland this will result in artifacts in the audio meter as transparent pixels will pick up colors from the underlaying desktop instead. --- UI/volume-control.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp index 9303f78dc8d2a3..88477300f9788d 100644 --- a/UI/volume-control.cpp +++ b/UI/volume-control.cpp @@ -1417,6 +1417,10 @@ void VolumeMeter::paintEvent(QPaintEvent *event) QPainter painter(this); + // Paint window background color (as widget is opaque) + QColor background = palette().color(QPalette::ColorRole::Window); + painter.fillRect(event->region().boundingRect(), background); + if (vertical) height -= METER_PADDING * 2; @@ -1426,11 +1430,6 @@ void VolumeMeter::paintEvent(QPaintEvent *event) if (needLayoutChange()) doLayout(); - // Paint window background color (as widget is opaque) - QColor background = - palette().color(QPalette::ColorRole::Window); - painter.fillRect(widgetRect, background); - if (vertical) { paintVTicks(painter, displayNrAudioChannels * From a63714c8f1bc0eba25a5b73a44126fab03422962 Mon Sep 17 00:00:00 2001 From: shiina424 Date: Tue, 20 Feb 2024 23:47:05 +0900 Subject: [PATCH 08/19] win-capture: Add line break for capture audio tooltip --- plugins/win-capture/data/locale/en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/win-capture/data/locale/en-US.ini b/plugins/win-capture/data/locale/en-US.ini index 4d5c5415581b17..237b4726c9f9b7 100644 --- a/plugins/win-capture/data/locale/en-US.ini +++ b/plugins/win-capture/data/locale/en-US.ini @@ -40,7 +40,7 @@ GameCapture.Rgb10a2Space.Srgb="sRGB" GameCapture.Rgb10a2Space.2100PQ="Rec. 2100 (PQ)" Mode="Mode" CaptureAudio="Capture Audio (BETA)" -CaptureAudio.TT="When enabled, creates an \"Application Audio Capture\" source that automatically updates to the currently captured window/application. Note that if Desktop Audio is configured, this could result in doubled audio." +CaptureAudio.TT="When enabled, creates an \"Application Audio Capture\" source that automatically updates to the currently captured window/application.\nNote that if Desktop Audio is configured, this could result in doubled audio." AudioSuffix="Audio" # Generic compatibility messages From 03c42e5b9300a45b3d46e900aba08596a223b43f Mon Sep 17 00:00:00 2001 From: PatTheMav Date: Tue, 20 Feb 2024 20:15:19 +0100 Subject: [PATCH 09/19] mac-avcapture: Fix crash issues on Intel-based Macs and older macOS Fixes several possible crash issues that might occur on Intel-based Macs and older macOS versions: On modern macOS versions (13+) allocated memory is zero-allocated by default which makes NULL pointer checks work correctly after allocation. On older macOS versions this is not the case, so the OBSAVCaptureInfo struct needs to be zero-allocated to ensure the guards in the tick and render functions bail out correctly. On Intel-based Macs and/or older macOS versions passing a reference to the OBSAVCapture instance inside the OBSAVCapture struct can lead to a crash because of a possible circular reference that cannot be resolved at runtime. Passing only a reference of the OBSAVCapture to libobs and incrementing the retain count at source creation (decrementing in when the source is destroyed) avoids this issue entirely. --- plugins/mac-avcapture/OBSAVCapture.h | 1 - plugins/mac-avcapture/plugin-main.m | 66 ++++++++++++----------- plugins/mac-avcapture/plugin-properties.h | 30 +++++------ plugins/mac-avcapture/plugin-properties.m | 61 ++++++++++----------- 4 files changed, 78 insertions(+), 80 deletions(-) diff --git a/plugins/mac-avcapture/OBSAVCapture.h b/plugins/mac-avcapture/OBSAVCapture.h index 7b2152fa4fb127..1144fa56c44d21 100644 --- a/plugins/mac-avcapture/OBSAVCapture.h +++ b/plugins/mac-avcapture/OBSAVCapture.h @@ -36,7 +36,6 @@ typedef enum : NSUInteger { /// C struct for interaction with obs-module functions typedef struct av_capture { - id capture; IOSurfaceRef previousSurface; IOSurfaceRef currentSurface; OBSAVCaptureTexture *texture; diff --git a/plugins/mac-avcapture/plugin-main.m b/plugins/mac-avcapture/plugin-main.m index 37611be54b0f39..a15821d447650e 100644 --- a/plugins/mac-avcapture/plugin-main.m +++ b/plugins/mac-avcapture/plugin-main.m @@ -16,7 +16,7 @@ static void *av_capture_create(obs_data_t *settings, obs_source_t *source) { - OBSAVCaptureInfo *capture_data = bmalloc(sizeof(OBSAVCaptureInfo)); + OBSAVCaptureInfo *capture_data = bzalloc(sizeof(OBSAVCaptureInfo)); capture_data->isFastPath = false; capture_data->settings = settings; capture_data->source = source; @@ -25,14 +25,12 @@ OBSAVCapture *capture = [[OBSAVCapture alloc] initWithCaptureInfo:capture_data]; - capture_data->capture = capture; - - return capture_data; + return (void *) CFBridgingRetain(capture); } static void *av_fast_capture_create(obs_data_t *settings, obs_source_t *source) { - OBSAVCaptureInfo *capture_info = bmalloc(sizeof(OBSAVCaptureInfo)); + OBSAVCaptureInfo *capture_info = bzalloc(sizeof(OBSAVCaptureInfo)); capture_info->isFastPath = true; capture_info->settings = settings; capture_info->source = source; @@ -47,17 +45,15 @@ OBSAVCapture *capture = [[OBSAVCapture alloc] initWithCaptureInfo:capture_info]; - capture_info->capture = capture; - - return capture_info; + return (void *) CFBridgingRetain(capture); } -static const char *av_capture_get_name(void *capture_info_aliased __unused) +static const char *av_capture_get_name(void *av_capture __unused) { return obs_module_text("AVCapture"); } -static const char *av_fast_capture_get_name(void *capture_info_aliased __unused) +static const char *av_fast_capture_get_name(void *av_capture __unused) { return obs_module_text("AVCapture_Fast"); } @@ -79,9 +75,10 @@ static void av_fast_capture_set_defaults(obs_data_t *settings) obs_data_set_default_bool(settings, "enable_audio", true); } -static obs_properties_t *av_capture_properties(void *capture_info_aliased) +static obs_properties_t *av_capture_properties(void *av_capture) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + OBSAVCaptureInfo *capture_info = capture.captureInfo; obs_properties_t *properties = obs_properties_create(); @@ -106,11 +103,11 @@ static void av_fast_capture_set_defaults(obs_data_t *settings) bool isFastPath = capture_info->isFastPath; // Add Property Visibility and Callbacks - configure_property(device_list, true, true, properties_changed, capture_info); + configure_property(device_list, true, true, properties_changed, capture); configure_property(use_preset, !isFastPath, !isFastPath, (!isFastPath) ? properties_changed_use_preset : NULL, - capture_info); + capture); configure_property(preset_list, !isFastPath, !isFastPath, (!isFastPath) ? properties_changed_preset : NULL, - capture_info); + capture); configure_property(resolutions, isFastPath, isFastPath, NULL, NULL); configure_property(use_buffering, !isFastPath, !isFastPath, NULL, NULL); @@ -123,18 +120,18 @@ static void av_fast_capture_set_defaults(obs_data_t *settings) return properties; } -static void av_capture_update(void *capture_info_aliased, obs_data_t *settings) +static void av_capture_update(void *av_capture, obs_data_t *settings) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; - OBSAVCapture *capture = capture_info->capture; - capture_info->settings = settings; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + capture.captureInfo->settings = settings; [capture updateSessionwithError:NULL]; } -static void av_fast_capture_tick(void *capture_info_aliased, float seconds __unused) +static void av_fast_capture_tick(void *av_capture, float seconds __unused) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + OBSAVCaptureInfo *capture_info = capture.captureInfo; if (!capture_info->currentSurface) { return; @@ -174,9 +171,10 @@ static void av_fast_capture_tick(void *capture_info_aliased, float seconds __unu } } -static void av_fast_capture_render(void *capture_info_aliased, gs_effect_t *effect __unused) +static void av_fast_capture_render(void *av_capture, gs_effect_t *effect __unused) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + OBSAVCaptureInfo *capture_info = capture.captureInfo; if (!capture_info->texture) { return; @@ -203,33 +201,36 @@ static void av_fast_capture_render(void *capture_info_aliased, gs_effect_t *effe gs_enable_framebuffer_srgb(previous); } -static UInt32 av_fast_capture_get_width(void *capture_info_aliased) +static UInt32 av_fast_capture_get_width(void *av_capture) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + OBSAVCaptureInfo *capture_info = capture.captureInfo; CGSize frameSize = capture_info->frameSize.size; return (UInt32) frameSize.width; } -static UInt32 av_fast_capture_get_height(void *capture_info_aliased) +static UInt32 av_fast_capture_get_height(void *av_capture) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); + OBSAVCaptureInfo *capture_info = capture.captureInfo; CGSize frameSize = capture_info->frameSize.size; return (UInt32) frameSize.height; } -static void av_capture_destroy(void *capture_info_aliased) +static void av_capture_destroy(void *av_capture) { - OBSAVCaptureInfo *capture_info = capture_info_aliased; + OBSAVCapture *capture = (__bridge OBSAVCapture *) (av_capture); - if (!capture_info) { + if (!capture) { return; } - OBSAVCapture *capture = capture_info->capture; + OBSAVCaptureInfo *capture_info = capture.captureInfo; + [capture stopCaptureSession]; [capture.deviceInput.device unlockForConfiguration]; @@ -251,8 +252,9 @@ static void av_capture_destroy(void *capture_info_aliased) capture_info->sampleBufferDescription = NULL; } - capture_info->capture = NULL; bfree(capture_info); + + CFBridgingRelease((__bridge CFTypeRef _Nullable)(capture)); } #pragma mark - OBS Module API diff --git a/plugins/mac-avcapture/plugin-properties.h b/plugins/mac-avcapture/plugin-properties.h index 951be4acbf9850..323c2e15b323fe 100644 --- a/plugins/mac-avcapture/plugin-properties.h +++ b/plugins/mac-avcapture/plugin-properties.h @@ -15,54 +15,54 @@ /// - enable: Whether the source property should be enabled (user-changeable) /// - visible: Whether the source property should be visible /// - callback: Pointer to a function that will be called if this property has been modified or the properties are reloaded -/// - callback_data: Optional payload data for the callback function -void configure_property(obs_property_t *property, bool enable, bool visible, void *callback, void *callback_data); +/// - capture: Optional reference to ``OBSAVCapture`` instance +void configure_property(obs_property_t *property, bool enable, bool visible, void *callback, OBSAVCapture *capture); /// Generic callback handler for changed properties. Will update all properties of an OBSAVCapture source at once /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source (``OBSAVcaptureInfo``) +/// - capture: Pointer to ``OBSAVCapture`` instance /// - properties: Pointer to properties struct associated with the source /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_changed(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, obs_property_t *property, +bool properties_changed(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property, obs_data_t *settings); /// Callback handler for preset changes. /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source +/// - capture: Pointer to ``OBSAVCapture`` instance /// - properties: Pointer to properties struct associated with the source /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_changed_preset(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, obs_property_t *property, +bool properties_changed_preset(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property, obs_data_t *settings); /// Callback handler for changing preset usage for an OBSAVCapture source. Switches between preset-based configuration and manual configuration /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source +/// - capture: Pointer to ``OBSAVCapture`` instance /// - properties: Pointer to properties struct associated with the source /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_changed_use_preset(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, - obs_property_t *property, obs_data_t *settings); +bool properties_changed_use_preset(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property, + obs_data_t *settings); /// Updates preset property with description-value-pairs of presets supported by the currently selected device /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source +/// - capture: Pointer to ``OBSAVCapture`` instance /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_update_preset(OBSAVCaptureInfo *captureInfo, obs_property_t *property, obs_data_t *settings); +bool properties_update_preset(OBSAVCapture *capture, obs_property_t *property, obs_data_t *settings); /// Updates device property with description-value-pairs of devices available via CoreMediaIO /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source +/// - capture: Pointer to ``OBSAVCapture`` instance /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_update_device(OBSAVCaptureInfo *captureInfo, obs_property_t *property, obs_data_t *settings); +bool properties_update_device(OBSAVCapture *capture, obs_property_t *property, obs_data_t *settings); /// Updates available values for all properties required in manual device configuration. /// @@ -77,8 +77,8 @@ bool properties_update_device(OBSAVCaptureInfo *captureInfo, obs_property_t *pro /// Frame rate ranges will be limited to ranges only available for a specific combination of resolution and color format. /// /// - Parameters: -/// - captureInfo: Pointer to capture info struct associated with the source +/// - capture: Pointer to ``OBSAVCapture`` instance /// - property: Pointer to the property that the callback is attached to /// - settings: Pointer to settings associated with the source /// - Returns: Always returns true -bool properties_update_config(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, obs_data_t *settings); +bool properties_update_config(OBSAVCapture *capture, obs_properties_t *properties, obs_data_t *settings); diff --git a/plugins/mac-avcapture/plugin-properties.m b/plugins/mac-avcapture/plugin-properties.m index ea9050dd16f7a1..4aed2eda980293 100644 --- a/plugins/mac-avcapture/plugin-properties.m +++ b/plugins/mac-avcapture/plugin-properties.m @@ -10,50 +10,50 @@ extern const char *av_capture_get_text(const char *text_id); -void configure_property(obs_property_t *property, bool enable, bool visible, void *callback, void *callback_data) +void configure_property(obs_property_t *property, bool enable, bool visible, void *callback, OBSAVCapture *capture) { if (property) { obs_property_set_enabled(property, enable); obs_property_set_visible(property, visible); if (callback) { - obs_property_set_modified_callback2(property, callback, callback_data); + obs_property_set_modified_callback2(property, callback, (__bridge void *) (capture)); } } } -bool properties_changed(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, obs_property_t *property __unused, +bool properties_changed(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property __unused, obs_data_t *settings) { + OBSAVCaptureInfo *captureInfo = capture.captureInfo; + obs_property_t *prop_use_preset = obs_properties_get(properties, "use_preset"); obs_property_t *prop_device = obs_properties_get(properties, "device"); obs_property_t *prop_presets = obs_properties_get(properties, "preset"); obs_property_set_enabled(prop_use_preset, !captureInfo->isFastPath); - if (captureInfo && captureInfo->capture && settings) { - properties_update_device(captureInfo, prop_device, settings); + if (captureInfo && settings) { + properties_update_device(capture, prop_device, settings); bool use_preset = (settings ? obs_data_get_bool(settings, "use_preset") : true); if (use_preset) { - properties_update_preset(captureInfo, prop_presets, settings); + properties_update_preset(capture, prop_presets, settings); } else { - properties_update_config(captureInfo, properties, settings); + properties_update_config(capture, properties, settings); } } return true; } -bool properties_changed_preset(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties __unused, - obs_property_t *property, obs_data_t *settings) +bool properties_changed_preset(OBSAVCapture *capture, obs_properties_t *properties __unused, obs_property_t *property, + obs_data_t *settings) { bool use_preset = obs_data_get_bool(settings, "use_preset"); - if (captureInfo && captureInfo->capture && settings && use_preset) { - OBSAVCapture *capture = captureInfo->capture; - + if (capture && settings && use_preset) { NSArray *presetKeys = [capture.presetList keysSortedByValueUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { NSNumber *obj1Resolution; @@ -123,7 +123,7 @@ bool properties_changed_preset(OBSAVCaptureInfo *captureInfo, obs_properties_t * } } -bool properties_changed_use_preset(OBSAVCaptureInfo *captureInfo, obs_properties_t *properties, +bool properties_changed_use_preset(OBSAVCapture *capture, obs_properties_t *properties, obs_property_t *property __unused, obs_data_t *settings) { bool use_preset = obs_data_get_bool(settings, "use_preset"); @@ -132,7 +132,7 @@ bool properties_changed_use_preset(OBSAVCaptureInfo *captureInfo, obs_properties obs_property_set_visible(preset_list, use_preset); if (use_preset) { - properties_changed_preset(captureInfo, properties, preset_list, settings); + properties_changed_preset(capture, properties, preset_list, settings); } const char *update_properties[5] = {"resolution", "frame_rate", "color_space", "video_range", "input_format"}; @@ -151,12 +151,10 @@ bool properties_changed_use_preset(OBSAVCaptureInfo *captureInfo, obs_properties return true; } -bool properties_update_preset(OBSAVCaptureInfo *captureInfo, obs_property_t *property, obs_data_t *settings) +bool properties_update_preset(OBSAVCapture *capture, obs_property_t *property, obs_data_t *settings) { - OBSAVCapture *captureInstance = captureInfo->capture; - - NSArray *presetKeys = [captureInstance.presetList - keysSortedByValueUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { + NSArray *presetKeys = + [capture.presetList keysSortedByValueUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { NSNumber *obj1Resolution; NSNumber *obj2Resolution; if ([obj1 isEqualToString:@"High"]) { @@ -202,7 +200,7 @@ bool properties_update_preset(OBSAVCaptureInfo *captureInfo, obs_property_t *pro if (device) { for (NSString *presetName in presetKeys) { - NSString *presetDescription = captureInstance.presetList[presetName]; + NSString *presetDescription = capture.presetList[presetName]; if ([device supportsAVCaptureSessionPreset:presetName]) { obs_property_list_add_string(property, presetDescription.UTF8String, presetName.UTF8String); @@ -213,7 +211,7 @@ bool properties_update_preset(OBSAVCaptureInfo *captureInfo, obs_property_t *pro } }; } else if (deviceUUID.length) { - size_t index = obs_property_list_add_string(property, captureInstance.presetList[currentPreset].UTF8String, + size_t index = obs_property_list_add_string(property, capture.presetList[currentPreset].UTF8String, currentPreset.UTF8String); obs_property_list_item_disable(property, index, true); } @@ -221,7 +219,7 @@ bool properties_update_preset(OBSAVCaptureInfo *captureInfo, obs_property_t *pro return true; } -bool properties_update_device(OBSAVCaptureInfo *captureInfo __unused, obs_property_t *property, obs_data_t *settings) +bool properties_update_device(OBSAVCapture *capture __unused, obs_property_t *property, obs_data_t *settings) { obs_property_list_clear(property); @@ -273,9 +271,8 @@ bool properties_update_device(OBSAVCaptureInfo *captureInfo __unused, obs_proper return true; } -bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *properties, obs_data_t *settings) +bool properties_update_config(OBSAVCapture *capture, obs_properties_t *properties, obs_data_t *settings) { - OBSAVCapture *captureInstance = capture->capture; AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:[OBSAVCapture stringFromSettings:settings withSetting:@"device"]]; @@ -292,7 +289,7 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope prop_input_format = obs_properties_get(properties, "input_format"); obs_property_list_clear(prop_input_format); - if (!captureInstance.isFastPath) { + if (!capture.isFastPath) { prop_color_space = obs_properties_get(properties, "color_space"); prop_video_range = obs_properties_get(properties, "video_range"); @@ -303,12 +300,12 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope CMVideoDimensions resolution = [OBSAVCapture dimensionsFromSettings:settings]; if (resolution.width == 0 || resolution.height == 0) { - [captureInstance AVCaptureLog:LOG_DEBUG withFormat:@"No valid resolution found in settings"]; + [capture AVCaptureLog:LOG_DEBUG withFormat:@"No valid resolution found in settings"]; } struct media_frames_per_second fps; if (!obs_data_get_frames_per_second(settings, "frame_rate", &fps, NULL)) { - [captureInstance AVCaptureLog:LOG_DEBUG withFormat:@"No valid framerate found in settings"]; + [capture AVCaptureLog:LOG_DEBUG withFormat:@"No valid framerate found in settings"]; } CMTime time = {.value = fps.denominator, .timescale = fps.numerator, .flags = 1}; @@ -324,7 +321,7 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope input_format = (int) obs_data_get_int(settings, "input_format"); inputFormats = [[NSMutableArray alloc] init]; - if (!captureInstance.isFastPath) { + if (!capture.isFastPath) { color_space = (int) obs_data_get_int(settings, "color_space"); video_range = (int) obs_data_get_int(settings, "video_range"); @@ -338,13 +335,13 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope BOOL hasFoundResolution = NO; BOOL hasFoundFramerate = NO; BOOL hasFoundInputFormat = NO; - BOOL hasFoundColorSpace = captureInstance.isFastPath; - BOOL hasFoundVideoRange = captureInstance.isFastPath; + BOOL hasFoundColorSpace = capture.isFastPath; + BOOL hasFoundVideoRange = capture.isFastPath; if (device) { // Iterate over all formats reported by the device and gather them for property lists for (AVCaptureDeviceFormat *format in device.formats) { - if (!captureInstance.isFastPath) { + if (!capture.isFastPath) { FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription); NSString *formatDescription = [OBSAVCapture stringFromSubType:formatSubType]; @@ -473,7 +470,7 @@ bool properties_update_config(OBSAVCaptureInfo *capture, obs_properties_t *prope obs_property_list_item_disable(prop_input_format, index, true); } - if (!captureInstance.isFastPath) { + if (!capture.isFastPath) { if (!hasFoundVideoRange) { int device_range; const char *range_description; From 66d210cf1ba01c4035b59c4fb9b839d7e70cf6f7 Mon Sep 17 00:00:00 2001 From: test Date: Wed, 21 Feb 2024 05:23:16 +0900 Subject: [PATCH 10/19] UI: Fix problem with Yes/No message box buttons not translated --- UI/window-basic-main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index c7aea63010dbad..0850cdc18f17e4 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -9532,7 +9532,7 @@ void OBSBasic::on_resetDocks_triggered(bool force) !force) #endif { - QMessageBox::StandardButton button = QMessageBox::question( + QMessageBox::StandardButton button = OBSMessageBox::question( this, QTStr("ResetUIWarning.Title"), QTStr("ResetUIWarning.Text")); From f275080abb714e9e921fe73dfc9efd56a9d993cf Mon Sep 17 00:00:00 2001 From: Exeldro Date: Mon, 19 Feb 2024 22:19:33 +0100 Subject: [PATCH 11/19] libobs: Fix crop to bounds ABI break --- UI/window-basic-main.cpp | 14 +++++++------ UI/window-basic-preview.cpp | 10 ++++----- UI/window-basic-source-select.cpp | 2 +- UI/window-basic-transform.cpp | 6 +++--- libobs/obs-scene.c | 35 +++++++++++++++++++++++++++++-- libobs/obs.h | 5 ++++- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 0850cdc18f17e4..5cd8f8de254fe6 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -8666,7 +8666,7 @@ void OBSBasic::on_actionCopyTransform_triggered() { OBSSceneItem item = GetCurrentSceneItem(); - obs_sceneitem_get_info(item, &copiedTransformInfo); + obs_sceneitem_get_info2(item, &copiedTransformInfo); obs_sceneitem_get_crop(item, &copiedCropInfo); ui->actionPasteTransform->setEnabled(true); @@ -8697,7 +8697,7 @@ void OBSBasic::on_actionPasteTransform_triggered() OBSBasic *main = reinterpret_cast(data); obs_sceneitem_defer_update_begin(item); - obs_sceneitem_set_info(item, &main->copiedTransformInfo); + obs_sceneitem_set_info2(item, &main->copiedTransformInfo); obs_sceneitem_set_crop(item, &main->copiedCropInfo); obs_sceneitem_defer_update_end(item); @@ -8735,8 +8735,9 @@ static bool reset_tr(obs_scene_t * /* scene */, obs_sceneitem_t *item, void *) info.alignment = OBS_ALIGN_TOP | OBS_ALIGN_LEFT; info.bounds_type = OBS_BOUNDS_NONE; info.bounds_alignment = OBS_ALIGN_CENTER; + info.crop_to_bounds = false; vec2_set(&info.bounds, 0.0f, 0.0f); - obs_sceneitem_set_info(item, &info); + obs_sceneitem_set_info2(item, &info); obs_sceneitem_crop crop = {}; obs_sceneitem_set_crop(item, &crop); @@ -8979,8 +8980,9 @@ static bool CenterAlignSelectedItems(obs_scene_t * /* scene */, float(ovi.base_height)); itemInfo.bounds_type = boundsType; itemInfo.bounds_alignment = OBS_ALIGN_CENTER; + itemInfo.crop_to_bounds = obs_sceneitem_get_bounds_crop(item); - obs_sceneitem_set_info(item, &itemInfo); + obs_sceneitem_set_info2(item, &itemInfo); return true; } @@ -9034,7 +9036,7 @@ void OBSBasic::CenterSelectedSceneItems(const CenterType ¢erType) for (int x = 0; x < selectedItems.count(); x++) { OBSSceneItem item = ui->sources->Get(selectedItems[x].row()); obs_transform_info oti; - obs_sceneitem_get_info(item, &oti); + obs_sceneitem_get_info2(item, &oti); obs_source_t *source = obs_sceneitem_get_source(item); float width = float(obs_source_get_width(source)) * oti.scale.x; @@ -10021,7 +10023,7 @@ void OBSBasic::on_actionCopySource_triggered() SourceCopyInfo copyInfo; copyInfo.weak_source = OBSGetWeakRef(source); - obs_sceneitem_get_info(item, ©Info.transform); + obs_sceneitem_get_info2(item, ©Info.transform); obs_sceneitem_get_crop(item, ©Info.crop); copyInfo.blend_method = obs_sceneitem_get_blending_method(item); copyInfo.blend_mode = obs_sceneitem_get_blending_mode(item); diff --git a/UI/window-basic-preview.cpp b/UI/window-basic-preview.cpp index 8f3c79d3e87d73..588c7421283fe1 100644 --- a/UI/window-basic-preview.cpp +++ b/UI/window-basic-preview.cpp @@ -1969,7 +1969,7 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *, obs_sceneitem_t *item, GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "DrawSelectedOverflow"); obs_transform_info info; - obs_sceneitem_get_info(item, &info); + obs_sceneitem_get_info2(item, &info); gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT); gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image"); @@ -2013,7 +2013,7 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *, obs_sceneitem_t *item, matrix4 mat; obs_transform_info groupInfo; obs_sceneitem_get_draw_transform(item, &mat); - obs_sceneitem_get_info(item, &groupInfo); + obs_sceneitem_get_info2(item, &groupInfo); prev->groupRot = groupInfo.rot; @@ -2095,7 +2095,7 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *, obs_sceneitem_t *item, boxScale.y *= curTransform.y.y; obs_transform_info info; - obs_sceneitem_get_info(item, &info); + obs_sceneitem_get_info2(item, &info); gs_matrix_push(); gs_matrix_mul(&boxTransform); @@ -2523,7 +2523,7 @@ void OBSBasicPreview::DrawSpacingHelpers() obs_sceneitem_get_box_transform(item, &boxTransform); obs_transform_info oti; - obs_sceneitem_get_info(item, &oti); + obs_sceneitem_get_info2(item, &oti); obs_video_info ovi; obs_get_video_info(&ovi); @@ -2545,7 +2545,7 @@ void OBSBasicPreview::DrawSpacingHelpers() if (parentGroup) { obs_transform_info groupOti; - obs_sceneitem_get_info(parentGroup, &groupOti); + obs_sceneitem_get_info2(parentGroup, &groupOti); //Correct the scene item rotation angle rot = oti.rot + groupOti.rot; diff --git a/UI/window-basic-source-select.cpp b/UI/window-basic-source-select.cpp index 62e0e303844709..a500e3a72144e1 100644 --- a/UI/window-basic-source-select.cpp +++ b/UI/window-basic-source-select.cpp @@ -122,7 +122,7 @@ static void AddSource(void *_data, obs_scene_t *scene) sceneitem = obs_scene_add(scene, data->source); if (data->transform != nullptr) - obs_sceneitem_set_info(sceneitem, data->transform); + obs_sceneitem_set_info2(sceneitem, data->transform); if (data->crop != nullptr) obs_sceneitem_set_crop(sceneitem, data->crop); if (data->blend_method != nullptr) diff --git a/UI/window-basic-transform.cpp b/UI/window-basic-transform.cpp index 06d139e3c67ac0..f0add7ec3d1cb3 100644 --- a/UI/window-basic-transform.cpp +++ b/UI/window-basic-transform.cpp @@ -267,7 +267,7 @@ void OBSBasicTransform::RefreshControls() obs_transform_info osi; obs_sceneitem_crop crop; - obs_sceneitem_get_info(item, &osi); + obs_sceneitem_get_info2(item, &osi); obs_sceneitem_get_crop(item, &crop); obs_source_t *source = obs_sceneitem_get_source(item); @@ -347,7 +347,7 @@ void OBSBasicTransform::OnControlChanged() double height = double(source_cy); obs_transform_info oti; - obs_sceneitem_get_info(item, &oti); + obs_sceneitem_get_info2(item, &oti); /* do not scale a source if it has 0 width/height */ if (source_cx != 0 && source_cy != 0) { @@ -367,7 +367,7 @@ void OBSBasicTransform::OnControlChanged() oti.crop_to_bounds = ui->cropToBounds->isChecked(); ignoreTransformSignal = true; - obs_sceneitem_set_info(item, &oti); + obs_sceneitem_set_info2(item, &oti); ignoreTransformSignal = false; } diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index ee0aca2723667e..b8bf01f52537f6 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -2406,7 +2406,7 @@ bool save_transform_states(obs_scene_t *scene, obs_sceneitem_t *item, struct obs_transform_info info; struct obs_sceneitem_crop crop; - obs_sceneitem_get_info(item, &info); + obs_sceneitem_get_info2(item, &info); obs_sceneitem_get_crop(item, &crop); struct vec2 pos = info.pos; @@ -2518,7 +2518,7 @@ void load_transform_states(obs_data_t *temp, void *vp_scene) obs_sceneitem_defer_update_begin(item); - obs_sceneitem_set_info(item, &info); + obs_sceneitem_set_info2(item, &info); obs_sceneitem_set_crop(item, &crop); obs_sceneitem_defer_update_end(item); @@ -2827,6 +2827,20 @@ void obs_sceneitem_get_bounds(const obs_sceneitem_t *item, struct vec2 *bounds) void obs_sceneitem_get_info(const obs_sceneitem_t *item, struct obs_transform_info *info) +{ + if (item && info) { + info->pos = item->pos; + info->rot = item->rot; + info->scale = item->scale; + info->alignment = item->align; + info->bounds_type = item->bounds_type; + info->bounds_alignment = item->bounds_align; + info->bounds = item->bounds; + } +} + +void obs_sceneitem_get_info2(const obs_sceneitem_t *item, + struct obs_transform_info *info) { if (item && info) { info->pos = item->pos; @@ -2842,6 +2856,23 @@ void obs_sceneitem_get_info(const obs_sceneitem_t *item, void obs_sceneitem_set_info(obs_sceneitem_t *item, const struct obs_transform_info *info) +{ + if (item && info) { + item->pos = info->pos; + item->rot = info->rot; + if (isfinite(info->scale.x) && isfinite(info->scale.y)) { + item->scale = info->scale; + } + item->align = info->alignment; + item->bounds_type = info->bounds_type; + item->bounds_align = info->bounds_alignment; + item->bounds = info->bounds; + do_update_transform(item); + } +} + +void obs_sceneitem_set_info2(obs_sceneitem_t *item, + const struct obs_transform_info *info) { if (item && info) { item->pos = info->pos; diff --git a/libobs/obs.h b/libobs/obs.h index bde6fd6acdc7c4..73889e9a21eb8a 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -1885,11 +1885,14 @@ EXPORT uint32_t obs_sceneitem_get_bounds_alignment(const obs_sceneitem_t *item); EXPORT bool obs_sceneitem_get_bounds_crop(const obs_sceneitem_t *item); EXPORT void obs_sceneitem_get_bounds(const obs_sceneitem_t *item, struct vec2 *bounds); - EXPORT void obs_sceneitem_get_info(const obs_sceneitem_t *item, struct obs_transform_info *info); EXPORT void obs_sceneitem_set_info(obs_sceneitem_t *item, const struct obs_transform_info *info); +EXPORT void obs_sceneitem_get_info2(const obs_sceneitem_t *item, + struct obs_transform_info *info); +EXPORT void obs_sceneitem_set_info2(obs_sceneitem_t *item, + const struct obs_transform_info *info); EXPORT void obs_sceneitem_get_draw_transform(const obs_sceneitem_t *item, struct matrix4 *transform); From 806c72fc662c2476d79edbd837b073187af33411 Mon Sep 17 00:00:00 2001 From: Exeldro Date: Tue, 20 Feb 2024 20:58:52 -0600 Subject: [PATCH 12/19] libobs: Save crop to bounds when saving transform states (Lain note: Splitting parent commit. This was probably unintentionally not taken into account in the origin crop_to_bounds PR.) --- libobs/obs-scene.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index b8bf01f52537f6..9b51956aeadd7b 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -2415,6 +2415,7 @@ bool save_transform_states(obs_scene_t *scene, obs_sceneitem_t *item, uint32_t alignment = info.alignment; uint32_t bounds_type = info.bounds_type; uint32_t bounds_alignment = info.bounds_alignment; + bool crop_to_bounds = info.crop_to_bounds; struct vec2 bounds = info.bounds; obs_data_set_int(temp, "id", obs_sceneitem_get_id(item)); @@ -2425,6 +2426,7 @@ bool save_transform_states(obs_scene_t *scene, obs_sceneitem_t *item, obs_data_set_int(temp, "bounds_type", bounds_type); obs_data_set_vec2(temp, "bounds", &bounds); obs_data_set_int(temp, "bounds_alignment", bounds_alignment); + obs_data_set_bool(temp, "crop_to_bounds", crop_to_bounds); obs_data_set_int(temp, "top", crop.top); obs_data_set_int(temp, "bottom", crop.bottom); obs_data_set_int(temp, "left", crop.left); @@ -2511,6 +2513,7 @@ void load_transform_states(obs_data_t *temp, void *vp_scene) info.bounds_alignment = (uint32_t)obs_data_get_int(temp, "bounds_alignment"); obs_data_get_vec2(temp, "bounds", &info.bounds); + info.crop_to_bounds = obs_data_get_bool(temp, "crop_to_bounds"); crop.top = (int)obs_data_get_int(temp, "top"); crop.bottom = (int)obs_data_get_int(temp, "bottom"); crop.left = (int)obs_data_get_int(temp, "left"); From cf1c5962ffe19e9cf431098cfdc799b20b2ac2f8 Mon Sep 17 00:00:00 2001 From: Lain Date: Tue, 20 Feb 2024 21:38:18 -0600 Subject: [PATCH 13/19] obs-websocket: Update version to 5.4.1 Fixes future deprecation warnings --- plugins/obs-websocket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-websocket b/plugins/obs-websocket index 9ee6e2ff2af2e5..4a647c526291ab 160000 --- a/plugins/obs-websocket +++ b/plugins/obs-websocket @@ -1 +1 @@ -Subproject commit 9ee6e2ff2af2e5d70f58b6378b269d407616679e +Subproject commit 4a647c526291abe986955f95e4d9dbb51cb9448c From 4b138f674f982c1b85487ff0cf6e3cabd27a76b4 Mon Sep 17 00:00:00 2001 From: Lain Date: Tue, 20 Feb 2024 21:39:56 -0600 Subject: [PATCH 14/19] libobs: Deprecate scene item transform API In order to support crop_to_bounds, deprecates: obs_sceneitem_set_info obs_sceneitem_get_info In favor of: obs_sceneitem_set_info2 obs_sceneitem_get_info2 --- libobs/obs.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libobs/obs.h b/libobs/obs.h index 73889e9a21eb8a..4ed9d8613dea2d 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -1885,10 +1885,12 @@ EXPORT uint32_t obs_sceneitem_get_bounds_alignment(const obs_sceneitem_t *item); EXPORT bool obs_sceneitem_get_bounds_crop(const obs_sceneitem_t *item); EXPORT void obs_sceneitem_get_bounds(const obs_sceneitem_t *item, struct vec2 *bounds); -EXPORT void obs_sceneitem_get_info(const obs_sceneitem_t *item, - struct obs_transform_info *info); -EXPORT void obs_sceneitem_set_info(obs_sceneitem_t *item, - const struct obs_transform_info *info); +OBS_DEPRECATED EXPORT void +obs_sceneitem_get_info(const obs_sceneitem_t *item, + struct obs_transform_info *info); +OBS_DEPRECATED EXPORT void +obs_sceneitem_set_info(obs_sceneitem_t *item, + const struct obs_transform_info *info); EXPORT void obs_sceneitem_get_info2(const obs_sceneitem_t *item, struct obs_transform_info *info); EXPORT void obs_sceneitem_set_info2(obs_sceneitem_t *item, From 33043a0c3eddd14a4eea8aaf1201e1ee5f8bd718 Mon Sep 17 00:00:00 2001 From: Lain Date: Wed, 21 Feb 2024 11:22:59 -0600 Subject: [PATCH 15/19] obs-websocket: Update to version 5.4.2 Fixes a versioning issue --- plugins/obs-websocket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/obs-websocket b/plugins/obs-websocket index 4a647c526291ab..d5077fca03a471 160000 --- a/plugins/obs-websocket +++ b/plugins/obs-websocket @@ -1 +1 @@ -Subproject commit 4a647c526291abe986955f95e4d9dbb51cb9448c +Subproject commit d5077fca03a47144f7c0eb81b5d3278186e31d59 From 8438c08ced0bde410df69f7b496043940817c89d Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 21 Feb 2024 15:12:51 -0300 Subject: [PATCH 16/19] CI: Switch to flathub-infra actions They contain a more recent commit with a fix for a flatpak-builder regression. --- .github/workflows/build-project.yaml | 2 +- .github/workflows/publish.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-project.yaml b/.github/workflows/build-project.yaml index 1c7d61de400645..cf6d621a804278 100644 --- a/.github/workflows/build-project.yaml +++ b/.github/workflows/build-project.yaml @@ -288,7 +288,7 @@ jobs: path: build-aux/com.obsproject.Studio.json - name: Build Flatpak Manifest ๐Ÿงพ - uses: flatpak/flatpak-github-actions/flatpak-builder@0ab9dd6a6afa6fe7e292db0325171660bf5b6fdf + uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8 with: build-bundle: ${{ fromJSON(needs.check-event.outputs.package) }} bundle: obs-studio-flatpak-${{ needs.check-event.outputs.commitHash }}.flatpak diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 37983a4229bb7e..6d81aa6871f024 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -104,7 +104,7 @@ jobs: path: build-aux/com.obsproject.Studio.json - name: Build Flatpak Manifest - uses: flatpak/flatpak-github-actions/flatpak-builder@0ab9dd6a6afa6fe7e292db0325171660bf5b6fdf + uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8 with: bundle: obs-studio-${{ steps.setup.outputs.commitHash }}.flatpak manifest-path: ${{ github.workspace }}/build-aux/com.obsproject.Studio.json @@ -139,7 +139,7 @@ jobs: path: repo - name: Publish to Flathub Beta - uses: flatpak/flatpak-github-actions/flat-manager@0ab9dd6a6afa6fe7e292db0325171660bf5b6fdf + uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8 if: ${{ matrix.branch == 'beta' }} with: flat-manager-url: https://hub.flathub.org/ @@ -148,7 +148,7 @@ jobs: build-log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - name: Publish to Flathub - uses: flatpak/flatpak-github-actions/flat-manager@0ab9dd6a6afa6fe7e292db0325171660bf5b6fdf + uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8 if: ${{ matrix.branch == 'stable' }} with: flat-manager-url: https://hub.flathub.org/ From 48b5affc5b676d8c127f31399bf480098a5f201d Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 21 Feb 2024 16:52:34 -0300 Subject: [PATCH 17/19] CI: Update Flathub screenshots URL This is what Flathub uses now. It's an implementation detail that will eventually be hidden away in a Flathub-specific publish action. But for now, we still publish directly, and we have to adapt. --- .github/workflows/build-project.yaml | 2 +- .github/workflows/publish.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-project.yaml b/.github/workflows/build-project.yaml index cf6d621a804278..a9dd34194bd6f5 100644 --- a/.github/workflows/build-project.yaml +++ b/.github/workflows/build-project.yaml @@ -296,7 +296,7 @@ jobs: cache: ${{ fromJSON(steps.setup.outputs.cacheHit) || (github.event_name == 'push' && github.ref_name == 'master')}} restore-cache: ${{ fromJSON(steps.setup.outputs.cacheHit) }} cache-key: ${{ steps.setup.outputs.cacheKey }} - mirror-screenshots-url: https://dl.flathub.org/repo/screenshots + mirror-screenshots-url: https://dl.flathub.org/media - name: Validate build directory uses: ./.github/actions/flatpak-builder-lint diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 6d81aa6871f024..fc98164f1094df 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -110,7 +110,7 @@ jobs: manifest-path: ${{ github.workspace }}/build-aux/com.obsproject.Studio.json cache: ${{ fromJSON(steps.setup.outputs.cacheHit) }} cache-key: ${{ steps.setup.outputs.cacheKey }} - mirror-screenshots-url: https://dl.flathub.org/repo/screenshots + mirror-screenshots-url: https://dl.flathub.org/media branch: ${{ matrix.branch }} - name: Validate AppStream From 7a35ae2cb658c1d4ca929b40987d5512d88f9187 Mon Sep 17 00:00:00 2001 From: Ryan Foster Date: Tue, 13 Feb 2024 15:48:17 -0500 Subject: [PATCH 18/19] UI: Fix Remux window only being usable once The beginInsertRows/endInsertRows calls seem to signal that the rowCount has changed, and that views should adjust accordingly. The isProcessing boolean changes the returned value of RemuxQueueModel::rowCount, which seems to cause the empty row in the table model to disappear permanently. I still don't know why it used to work this way and no longer does. --- UI/window-remux.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/UI/window-remux.cpp b/UI/window-remux.cpp index 1603a9e9612636..62ded65ac04608 100644 --- a/UI/window-remux.cpp +++ b/UI/window-remux.cpp @@ -585,14 +585,12 @@ void RemuxQueueModel::endProcessing() } // Signal that the insertion point exists again. - + isProcessing = false; if (!autoRemux) { beginInsertRows(QModelIndex(), queue.length(), queue.length()); endInsertRows(); } - isProcessing = false; - emit dataChanged(index(0, RemuxEntryColumn::State), index(queue.length(), RemuxEntryColumn::State)); } From ba4f17e1143dd769f55bce6b1595c6704aa7a44d Mon Sep 17 00:00:00 2001 From: Ryan Foster Date: Tue, 20 Feb 2024 18:15:59 -0500 Subject: [PATCH 19/19] CI: Update deps to 2024-02-20 release Notable changes: * deps.ffmpeg: Force classic linker for AppleClang 15.0.0+ * CI: Update macOS jobs to use macOS 14 runners * deps.ffmpeg: Enable runtime CPU detection for AOM to fix ARM64 crashes * deps.ffmpeg: Update zlib to 1.3.1 * deps.ffmpeg: Update aom to 3.8.1 * deps.ffmpeg: Update mbedTLS to 3.4.1 * deps.qt: Update Qt6 to 6.6.2 for Windows * deps.qt: Update Qt6 to 6.6.2 for macOS * deps.qt: Restore native dialogs on macOS --- buildspec.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/buildspec.json b/buildspec.json index 080a78db3ce4bf..e14c8ef18ad634 100644 --- a/buildspec.json +++ b/buildspec.json @@ -1,25 +1,25 @@ { "dependencies": { "prebuilt": { - "version": "2024-01-27", + "version": "2024-02-20", "baseUrl": "https://github.com/obsproject/obs-deps/releases/download", "label": "Pre-Built obs-deps", "hashes": { - "macos-universal": "57a13557f7528e58743c4712dc25eb1c4558d36eeaca6f5361fe1f6cbfabe229", - "windows-x64": "d371f8cc81859b5321b66dcef00a207abbdff7373c722b761852cbc95664b4c9", - "windows-x86": "66a72428f404c69d6abac0b36fc89bb2ae4a8a6cb3bd14816a35b5ceb95d8769" + "macos-universal": "a9f1697f411c981be787af3a408015981c746ca9ab2832c05f0b36ce17a93d92", + "windows-x64": "2c4ef55724a98dd0db35bf0b7fe5a12540d26afcc1e2e6ca26145763074ae207", + "windows-x86": "f3cf8977fced8809aca6770b546c9d5bc9dd8ee3689d85bba5ea91208f3629b9" } }, "qt6": { - "version": "2024-01-27", + "version": "2024-02-20", "baseUrl": "https://github.com/obsproject/obs-deps/releases/download", "label": "Pre-Built Qt6", "hashes": { - "macos-universal": "86f6418c3e454b3979947fdba183aa7303ca9d7729c7056435bd023d466cf93a", - "windows-x64": "7a15c4b494bfe2df51cad16e7cbcfcc2b5b69b55839dd584c622214038c7d44c" + "macos-universal": "5d91472dc1750c085a0d3b9ab6100661ddea8335399f4cd43500e632b167ccc6", + "windows-x64": "da26946a473a1fcb8378d90202f1b6b0a2329e87978bee13c996dfd0ef1555fe" }, "debugSymbols": { - "windows-x64": "ddf356ce20a4946f7522253b5da44ce7fe29398bb55ff74467431fb31e8ec645" + "windows-x64": "f004f83f77630eece6abe5996234b11738cee4aeec6e0ef49f6b1eee14eb4a68" } }, "cef": {