0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00

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.
This commit is contained in:
PatTheMav 2024-02-15 22:06:21 +01:00 committed by Ryan Foster
parent d87cf9c7eb
commit ee28503726
3 changed files with 54 additions and 29 deletions

View File

@ -448,8 +448,11 @@
return NO; return NO;
} }
} else { } else {
int inputFormat;
CMFormatDescriptionRef formatDescription = self.deviceInput.device.activeFormat.formatDescription; 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]; colorSpace = [OBSAVCapture colorspaceFromDescription:formatDescription];
videoRange = ([OBSAVCapture isFullRangeFormat:inputFourCC]) ? VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL; videoRange = ([OBSAVCapture isFullRangeFormat:inputFourCC]) ? VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL;
} }

View File

@ -117,7 +117,7 @@ static obs_properties_t *av_capture_properties(void *capture_info_aliased)
configure_property(frame_rates, isFastPath, isFastPath, NULL, NULL); configure_property(frame_rates, isFastPath, isFastPath, NULL, NULL);
configure_property(color_space, !isFastPath, !isFastPath, NULL, NULL); configure_property(color_space, !isFastPath, !isFastPath, NULL, NULL);
configure_property(video_range, !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; return properties;

View File

@ -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_color_space = NULL;
obs_property_t *prop_video_range = 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) { if (!captureInstance.isFastPath) {
prop_input_format = obs_properties_get(properties, "input_format");
prop_color_space = obs_properties_get(properties, "color_space"); prop_color_space = obs_properties_get(properties, "color_space");
prop_video_range = obs_properties_get(properties, "video_range"); 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_video_range);
obs_property_list_clear(prop_color_space); 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 *colorSpaces = NULL;
NSMutableArray *videoRanges = NULL; NSMutableArray *videoRanges = NULL;
input_format = (int) obs_data_get_int(settings, "input_format");
inputFormats = [[NSMutableArray alloc] init];
if (!captureInstance.isFastPath) { if (!captureInstance.isFastPath) {
input_format = (int) obs_data_get_int(settings, "input_format");
color_space = (int) obs_data_get_int(settings, "color_space"); color_space = (int) obs_data_get_int(settings, "color_space");
video_range = (int) obs_data_get_int(settings, "video_range"); video_range = (int) obs_data_get_int(settings, "video_range");
inputFormats = [[NSMutableArray alloc] init];
colorSpaces = [[NSMutableArray alloc] init]; colorSpaces = [[NSMutableArray alloc] init];
videoRanges = [[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 hasFoundResolution = NO;
BOOL hasFoundFramerate = NO; BOOL hasFoundFramerate = NO;
BOOL hasFoundInputFormat = captureInstance.isFastPath; BOOL hasFoundInputFormat = NO;
BOOL hasFoundColorSpace = captureInstance.isFastPath; BOOL hasFoundColorSpace = captureInstance.isFastPath;
BOOL hasFoundVideoRange = 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) { if (!hasFoundColorSpace && device_color_space == color_space) {
hasFoundColorSpace = YES; 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); 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 // 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) { for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges.reverseObjectEnumerator) {
struct media_frames_per_second min_fps = { FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription);
.numerator = (uint32_t) clamp_Uint(range.maxFrameDuration.timescale, 0, UINT32_MAX), int device_format = [OBSAVCapture formatFromSubtype:formatSubType];
.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]) { if (input_format == device_format) {
obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps); struct media_frames_per_second min_fps = {
[frameRates addObject:range]; .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 (!hasFoundFramerate && CMTimeCompare(range.maxFrameDuration, time) >= 0 && if (![frameRates containsObject:range]) {
CMTimeCompare(range.minFrameDuration, time) <= 0) { obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps);
hasFoundFramerate = YES; [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 // Add currently selected values in disabled state if they are not supported by the device
size_t index; size_t index;
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 (!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);
}
if (!hasFoundVideoRange) { if (!hasFoundVideoRange) {
int device_range; int device_range;
const char *range_description; const char *range_description;