mac-avcapture: Fix frame rate collection for camera device formats

Some devices will report different framerate ranges for formats that
are identical apart from color primaries. Without taking these into
account, only framerates for one color primary variant would be used
to populate the framerate dropdown in the property view of the camera
source.

Checking for a difference in color primaries when iterating over all
available formats for a device thus requires checking for this
variation and adding the additional frame rate range as well.
This commit is contained in:
PatTheMav
2024-02-24 03:33:04 +01:00
committed by Lain
parent 409bd12db3
commit 745f87f21f
2 changed files with 30 additions and 18 deletions
+1
View File
@@ -197,6 +197,7 @@
[self.deviceInput.device unlockForConfiguration];
self.deviceInput = nil;
self.isDeviceLocked = NO;
self.presetFormat = nil;
}
if (!device) {
+29 -18
View File
@@ -338,6 +338,8 @@ bool properties_update_config(OBSAVCapture *capture, obs_properties_t *propertie
BOOL hasFoundColorSpace = capture.isFastPath;
BOOL hasFoundVideoRange = capture.isFastPath;
CFPropertyListRef priorColorPrimary = @"";
if (device) {
// Iterate over all formats reported by the device and gather them for property lists
for (AVCaptureDeviceFormat *format in device.formats) {
@@ -419,29 +421,38 @@ bool properties_update_config(OBSAVCapture *capture, obs_properties_t *propertie
}
// Only iterate over available framerates if input format, color space, and resolution are matching
if (hasFoundInputFormat && hasFoundColorSpace && hasFoundResolution && !hasFoundFramerate) {
for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges.reverseObjectEnumerator) {
FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription);
int device_format = [OBSAVCapture formatFromSubtype:formatSubType];
if (hasFoundInputFormat && hasFoundColorSpace && hasFoundResolution) {
CFPropertyListRef colorPrimary = CMFormatDescriptionGetExtension(
format.formatDescription, kCMFormatDescriptionExtension_ColorPrimaries);
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)};
CFComparisonResult isColorPrimaryMatch = CFStringCompare(colorPrimary, priorColorPrimary, 0);
if (![frameRates containsObject:range]) {
obs_property_frame_rate_fps_range_add(prop_framerate, min_fps, max_fps);
[frameRates addObject:range];
}
if (isColorPrimaryMatch != kCFCompareEqualTo || !hasFoundFramerate) {
for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges.reverseObjectEnumerator) {
FourCharCode formatSubType = CMFormatDescriptionGetMediaSubType(format.formatDescription);
int device_format = [OBSAVCapture formatFromSubtype:formatSubType];
if (!hasFoundFramerate && CMTimeCompare(range.maxFrameDuration, time) >= 0 &&
CMTimeCompare(range.minFrameDuration, time) <= 0) {
hasFoundFramerate = YES;
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;
}
}
}
priorColorPrimary = colorPrimary;
}
}
}