From 27439467ced44eecea16cd06b50c5bd4afe863db Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 23 Feb 2026 21:01:45 -0800 Subject: [PATCH] camera: Don't try to fake entire range for FRMIVAL_TYPE_CONTINUOUS V4L2 is able to advertise that a video device is able to display any frame interval within a continuous range. SDL does not allow advertising this and only exposes discrete frame intervals. To work around this, SDL attempted to generate a subset of the range with a fixed interval. Unfortunately, the way this was accomplish is inherently broken and led to attempting to allocate a very large number of formats per resolution and colorspace. With the Magewell Pro Capture HDMI, which can expose FRMSIZE_TYPE_CONTINUOUS as well, this can expose a truly astronomical number of formats, exceeding 1 PB of RAM. This will lead to an OOM kill for any process that tries to initialize the camera subsystem. This patch just tests to see if some common frame rates are within the contiuous range and expose those. SDL still does not handle FRMSIZE_TYPE_CONTINUOUS in a graceful way so it still uses over a gigabyte of RAM for each possible combination of sizes, but with this patch it no longer leads to an OOM kill. The API will need amending for proper support for both continuous frame sizes and frame intervals. (cherry picked from commit ab6dd970ac8a427c1aafb5f2f66ac6cce8fc4bf4) --- src/camera/v4l2/SDL_camera_v4l2.c | 46 ++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/camera/v4l2/SDL_camera_v4l2.c b/src/camera/v4l2/SDL_camera_v4l2.c index e1ee5eaa1b..938f5a3b86 100644 --- a/src/camera/v4l2/SDL_camera_v4l2.c +++ b/src/camera/v4l2/SDL_camera_v4l2.c @@ -698,7 +698,7 @@ static bool AddCameraFormat(const int fd, CameraFormatAddData *data, SDL_PixelFo return false; // Probably out of memory; we'll go with what we have, if anything. } frmivalenum.index++; // set up for the next one. - } else if ((frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) || (frmivalenum.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) { + } else if (frmivalenum.type == V4L2_FRMIVAL_TYPE_STEPWISE) { int d = frmivalenum.stepwise.min.denominator; // !!! FIXME: should we step by the numerator...? for (int n = (int) frmivalenum.stepwise.min.numerator; n <= (int) frmivalenum.stepwise.max.numerator; n += (int) frmivalenum.stepwise.step.numerator) { @@ -713,6 +713,50 @@ static bool AddCameraFormat(const int fd, CameraFormatAddData *data, SDL_PixelFo d += (int) frmivalenum.stepwise.step.denominator; } break; + } else if (frmivalenum.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { + // FIXME: The current API does not enable exposing continuous ranges, so for now let's expose some common values that are within the range + const int min_numer = frmivalenum.stepwise.min.numerator; + const int min_denom = frmivalenum.stepwise.min.denominator; + const int max_numer = frmivalenum.stepwise.max.numerator; + const int max_denom = frmivalenum.stepwise.max.denominator; + const float minrate = (float) min_numer / (float) min_denom; + const float maxrate = (float) max_numer / (float) max_denom; + if (minrate <= 1.001 / 24 && maxrate >= 1.001 / 24) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 24000, 1001)) { + return false; + } + } + if (minrate <= 1.000 / 24 && maxrate >= 1.000 / 24) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 24000, 1000)) { + return false; + } + } + if (minrate <= 1.001 / 30 && maxrate >= 1.001 / 30) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 30000, 1001)) { + return false; + } + } + if (minrate <= 1.000 / 30 && maxrate >= 1.000 / 30) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 30000, 1000)) { + return false; + } + } + if (minrate <= 1.000 / 50 && maxrate >= 1.000 / 50) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 50000, 1000)) { + return false; + } + } + if (minrate <= 1.001 / 60 && maxrate >= 1.001 / 60) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 60000, 1001)) { + return false; + } + } + if (minrate <= 1.000 / 60 && maxrate >= 1.000 / 60) { + if (!SDL_AddCameraFormat(data, sdlfmt, colorspace, w, h, 60000, 1000)) { + return false; + } + } + break; } }