PR #25425 opened by oppianmatt
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25425
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25425.patch

configure_video_device() selects a frame-rate range only when the requested
rate equals that range's maxFrameRate. Some devices advertise one continuous
range per format instead of one range per rate. The MacBook Pro FaceTime HD
camera on macOS 26.5.1 can list "1280x720@[15.000000 30.000000]fps", and then
-framerate 15 fails with "Selected framerate (15.000000) is not supported by
the device" although 15 is inside the advertised range.

Keep the exact max match first, so existing behaviour is unchanged. Failing
that, accept a range that contains the requested rate, and set both
activeVideoMinFrameDuration and activeVideoMaxFrameDuration to the requested
rate rather than to the range's minimum duration.

Tested on that camera at 1280x720 nv12, 10 s each: -framerate 15 now opens
and delivers 150 frames (15.0 fps); -framerate 30 delivers 298-299 frames, as
before.

Signed-off-by: Matthew Jacobi <[email protected]>



>From 94d5bbc0c106796e67d3076c224751f55d919467 Mon Sep 17 00:00:00 2001
From: Matthew Jacobi <[email protected]>
Date: Sat, 24 Oct 2026 21:46:56 +0200
Subject: [PATCH] avdevice/avfoundation: accept a frame rate inside a
 continuous range

configure_video_device() selects a frame-rate range only when the requested
rate equals that range's maxFrameRate. Some devices advertise one continuous
range per format instead of one range per rate. The MacBook Pro FaceTime HD
camera on macOS 26.5.1 can list "1280x720@[15.000000 30.000000]fps", and then
-framerate 15 fails with "Selected framerate (15.000000) is not supported by
the device" although 15 is inside the advertised range.

Keep the exact max match first, so existing behaviour is unchanged. Failing
that, accept a range that contains the requested rate, and set both
activeVideoMinFrameDuration and activeVideoMaxFrameDuration to the requested
rate rather than to the range's minimum duration.

Tested on that camera at 1280x720 nv12, 10 s each: -framerate 15 now opens
and delivers 150 frames (15.0 fps); -framerate 30 delivers 298-299 frames, as
before.

Signed-off-by: Matthew Jacobi <[email protected]>
---
 libavdevice/avfoundation.m | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index 8b7e728279e..68dcd1ee38c 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -397,6 +397,7 @@ static int configure_video_device(AVFormatContext *s, 
AVCaptureDevice *video_dev
     NSObject *matching_size_format = nil;
     NSObject *selected_range = nil;
     NSObject *selected_format = nil;
+    int inside_range = 0;
 
     // try to configure format by formats list
     // might raise an exception if no format list is given
@@ -415,14 +416,25 @@ static int configure_video_device(AVFormatContext *s, 
AVCaptureDevice *video_dev
                 matching_size_format = format;
 
                 for (range in [format 
valueForKey:@"videoSupportedFrameRateRanges"]) {
+                    double min_framerate;
                     double max_framerate;
 
+                    [[range valueForKey:@"minFrameRate"] 
getValue:&min_framerate];
                     [[range valueForKey:@"maxFrameRate"] 
getValue:&max_framerate];
                     if (fabs (framerate - max_framerate) < 0.01) {
                         selected_format = format;
                         selected_range = range;
+                        inside_range = 0;
                         break;
                     }
+                    // A device may advertise one continuous range (e.g. [15 
30])
+                    // instead of one range per rate; any rate inside it is 
valid.
+                    if (!selected_range &&
+                        framerate > min_framerate - 0.01 && framerate < 
max_framerate + 0.01) {
+                        selected_format = format;
+                        selected_range = range;
+                        inside_range = 1;
+                    }
                 }
             }
         }
@@ -449,9 +461,13 @@ static int configure_video_device(AVFormatContext *s, 
AVCaptureDevice *video_dev
                 [video_device setValue:selected_format forKey:@"activeFormat"];
             }
             if (selected_range) {
-                NSValue *min_frame_duration = [selected_range 
valueForKey:@"minFrameDuration"];
-                [video_device setValue:min_frame_duration 
forKey:@"activeVideoMinFrameDuration"];
-                [video_device setValue:min_frame_duration 
forKey:@"activeVideoMaxFrameDuration"];
+                NSValue *frame_duration = [selected_range 
valueForKey:@"minFrameDuration"];
+                if (inside_range) {
+                    CMTime requested = CMTimeMake(ctx->framerate.den, 
ctx->framerate.num);
+                    frame_duration = [NSValue valueWithCMTime:requested];
+                }
+                [video_device setValue:frame_duration 
forKey:@"activeVideoMinFrameDuration"];
+                [video_device setValue:frame_duration 
forKey:@"activeVideoMaxFrameDuration"];
             }
         } else {
             av_log(s, AV_LOG_ERROR, "Could not lock device for 
configuration.\n");
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to