Skip to content

Commit

Permalink
mac-avcapture: Fix frame rate collection for camera device formats
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
PatTheMav authored and Lain-B committed Feb 24, 2024
1 parent 409bd12 commit 745f87f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
1 change: 1 addition & 0 deletions plugins/mac-avcapture/OBSAVCapture.m
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ - (BOOL)switchCaptureDevice:(NSString *)uuid withError:(NSError *__autoreleasing
[self.deviceInput.device unlockForConfiguration];
self.deviceInput = nil;
self.isDeviceLocked = NO;
self.presetFormat = nil;
}

if (!device) {
Expand Down
53 changes: 32 additions & 21 deletions plugins/mac-avcapture/plugin-properties.m
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
}
Expand Down

0 comments on commit 745f87f

Please sign in to comment.