--- a/libavutil/hwcontext_v4l2request.c +++ b/libavutil/hwcontext_v4l2request.c @@ -19,12 +19,13 @@ #include "config.h" #include #include #include #include +#include #include #include #include #include @@ -690,12 +691,125 @@ } udev_enumerate_unref(enumerate); return ret; } +/* + * Brute-force fallback used when libudev's scan fails (e.g. inside firefox's + * RDD sandbox where Mozilla's broker rejects fd-relative openat used by + * systemd's chase() symlink resolver). Iterates /dev/video[0..63], picks the + * one whose major/minor matches the requested devnum. + */ +static char *v4l2request_devnum_to_video_path_brute(dev_t devnum) +{ + char path[32]; + struct stat st; + for (int i = 0; i < 64; i++) { + snprintf(path, sizeof(path), "/dev/video%d", i); + if (stat(path, &st) < 0) + continue; + if (st.st_rdev == devnum) + return av_strdup(path); + } + return NULL; +} + +/* Brute-force version of v4l2request_probe_video_devices: replaces the + * udev_device_new_from_devnum + udev_device_get_devnode flow with + * stat()-based major/minor matching against /dev/video[0..63]. */ +static int v4l2request_probe_video_devices_brute(AVHWFramesContext *hwfc, + uint32_t pixelformat, + uint32_t buffersize) +{ + AVV4L2RequestFramesContext *fctx = hwfc->hwctx; + AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; + struct media_device_info device_info; + struct media_v2_topology topology = {0}; + struct media_v2_interface *interfaces; + char *path; + dev_t devnum; + int ret; + + if (ioctl(fctxi->media_fd, MEDIA_IOC_DEVICE_INFO, &device_info) < 0) + return AVERROR(errno); + + if (ioctl(fctxi->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) + return AVERROR(errno); + + if (!topology.num_interfaces) + return AVERROR(ENOENT); + + interfaces = av_calloc(topology.num_interfaces, + sizeof(struct media_v2_interface)); + if (!interfaces) + return AVERROR(ENOMEM); + + topology.ptr_interfaces = (__u64)(uintptr_t)interfaces; + if (ioctl(fctxi->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) { + ret = AVERROR(errno); + goto fail; + } + + ret = AVERROR(ENOENT); + for (unsigned i = 0; i < topology.num_interfaces; i++) { + if (interfaces[i].intf_type != MEDIA_INTF_T_V4L_VIDEO) + continue; + + devnum = makedev(interfaces[i].devnode.major, + interfaces[i].devnode.minor); + path = v4l2request_devnum_to_video_path_brute(devnum); + if (!path) + continue; + + ret = v4l2request_probe_video_device(hwfc, path, pixelformat, buffersize); + if (!ret) { + av_log(hwfc, AV_LOG_INFO, + "Using V4L2 media driver %s (brute-force) for %s\n", + device_info.driver, av_fourcc2str(pixelformat)); + av_free(path); + break; + } + av_free(path); + } + +fail: + av_free(interfaces); + return ret; +} + +/* Brute-force fallback for v4l2request_probe_media_devices(). Iterates + * /dev/media[0..15], opens each, probes via topology+stat. */ +static int v4l2request_probe_media_devices_brute(AVHWFramesContext *hwfc, + uint32_t pixelformat, + uint32_t buffersize) +{ + AVV4L2RequestFramesContext *fctx = hwfc->hwctx; + AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; + char path[32]; + int ret = AVERROR(ENOENT); + + for (int i = 0; i < 16; i++) { + snprintf(path, sizeof(path), "/dev/media%d", i); + + fctxi->media_fd = open(path, O_RDWR); + if (fctxi->media_fd < 0) + continue; + + ret = v4l2request_probe_video_devices_brute(hwfc, pixelformat, + buffersize); + if (!ret) + return 0; + + close(fctxi->media_fd); + fctxi->media_fd = -1; + } + + return ret; +} + static int v4l2request_open_decoder(AVHWFramesContext *hwfc) { AVV4L2RequestFramesContext *fctx = hwfc->hwctx; uint32_t buffersize; struct udev *udev; int ret; @@ -712,12 +826,23 @@ buffersize = FFMAX(hwfc->width * hwfc->height * 3 / 2, 256 * 1024); // Probe all media devices (auto-detection) ret = v4l2request_probe_media_devices(hwfc, udev, fctx->pixelformat, buffersize); + // Brute-force fallback when libudev fails. Firefox-fourier hits this + // because Mozilla's RDD sandbox blocks fd-relative openat used by + // systemd's chase() symlink resolver inside udev_enumerate_scan_devices. + if (ret < 0) { + av_log(hwfc, AV_LOG_INFO, + "libudev probe failed (%d), falling back to brute-force /dev/media*\n", + ret); + ret = v4l2request_probe_media_devices_brute(hwfc, fctx->pixelformat, + buffersize); + } + udev_unref(udev); return ret; } static AVBufferRef *v4l2request_v4l2_buffer_alloc(AVHWFramesContext *hwfc, struct v4l2_format *format)