浏览代码

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.
PatTheMav 1 年之前
父节点
当前提交
745f87f21f
共有 2 个文件被更改,包括 33 次插入21 次删除
  1. 1 0
      plugins/mac-avcapture/OBSAVCapture.m
  2. 32 21
      plugins/mac-avcapture/plugin-properties.m

+ 1 - 0
plugins/mac-avcapture/OBSAVCapture.m

@@ -197,6 +197,7 @@
         [self.deviceInput.device unlockForConfiguration];
         self.deviceInput = nil;
         self.isDeviceLocked = NO;
+        self.presetFormat = nil;
     }
 
     if (!device) {

+ 32 - 21
plugins/mac-avcapture/plugin-properties.m

@@ -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 (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;
+            if (hasFoundInputFormat && hasFoundColorSpace && hasFoundResolution) {
+                CFPropertyListRef colorPrimary = CMFormatDescriptionGetExtension(
+                    format.formatDescription, kCMFormatDescriptionExtension_ColorPrimaries);
+
+                CFComparisonResult isColorPrimaryMatch = CFStringCompare(colorPrimary, priorColorPrimary, 0);
+
+                if (isColorPrimaryMatch != kCFCompareEqualTo || !hasFoundFramerate) {
+                    for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges.reverseObjectEnumerator) {
+                        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;
+                            }
                         }
                     }
+
+                    priorColorPrimary = colorPrimary;
                 }
             }
         }