You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

V4L2 loopback设备作为QML Camera源时缓冲区分配失败问题求助

问题:Qt Camera组件配合v4l2loopback设备时频繁出现"Failed to allocate a buffer"错误

系统信息

  • NVIDIA Jetson Xavier NX (aarch64)
  • Qt 5.15 (qmake)
  • 在Ubuntu 22.04上通过Qt Creator进行交叉编译

问题场景

我用QML的Camera和VideoOutput组件配合v4l2loopback设备工作:该设备既是GStreamer管线的v4l2sink,又是QML Camera组件的视频源。每隔几秒就会收到报错:

CameraBin error: "Failed to allocate a buffer"

GStreamer管线的视频由Camera QML组件捕获,相关QML代码如下(Loader组件liveViewLoader未包含):

import QtQuick 2.0
import QtMultimedia 5.15

Item
{
    /*
     * If the video stream does not exist on creation, the camera will never work.
     * The Component + Loader circumvents this by reloading the camera components after a timeout has occured.
     * The video device itself has to exist before the start, though.
     */
    id:             wrappingItem
    anchors.fill:   parent

    property string videoDeviceFile: "/dev/video2"
    Timer
    {
        id:         cameraTimeoutTimer
        interval:   1000 /* in ms */
        running:    false
        repeat:     false
        onTriggered:
        {
            liveViewLoader.restart();
        }
    }

    Component
    {
        id: liveViewComponent
        Item
        {
            height: wrappingItem.height
            width:  wrappingItem.width

            id: liveViewComponentItem

            Camera
            {
                id:             camera
                captureMode:    Camera.CaptureStillImage
                deviceId:       wrappingItem.videoDeviceFile
                onCameraStatusChanged:
                {
                    console.log("Live view camera state changed to", camera.cameraStatus)
                    var liveViewRunning = (camera.cameraStatus == Camera.ActiveStatus);
                    // If the camera changed state, but it's not running, set a timeout to restart the camera via the Loader.
                    cameraTimeoutTimer.start();
                    if ( liveViewRunning )
                    {
                        cameraTimeoutTimer.stop();
                    }
                }

                Component.onCompleted:
                {
                    checkAndHandleCameraAvailability();
                }
            }

            VideoOutput
            {
                id:             videoOutputArea
                source:         camera
                anchors.fill:   parent
                flushMode:      VideoOutput.EmptyFrame
                focus:          visible
            }

            function checkAndHandleCameraAvailability()
            {
                // If the selected camera is not available, the camera will automatically select a different camera that's available on the system. This is a workaround to disable that behavior.
                camera.deviceId = wrappingItem.videoDeviceFile

                let videoDeviceIsAvailable = (camera.deviceId === wrappingItem.videoDeviceFile);
                if (videoDeviceIsAvailable)
                    return;

                console.log("Camera is currently using video device", camera.deviceId)
                console.log("AvlStreamHandler.videoDeviceFile: ", AvlStreamHandler.videoDeviceFile)
                console.log("Video device", wrappingItem.videoDeviceFile, "is not available.")
                liveViewLoader.stop();
            }
        }
    }
}

可能的原因及解决方法

1. v4l2loopback设备缓冲区配置不足

v4l2loopback默认的缓冲区数量、大小无法满足Qt Camera和GStreamer同时读写的需求,导致分配失败。

  • 解决方法:加载v4l2loopback模块时手动指定缓冲区参数:
    sudo modprobe v4l2loopback video_nr=2 max_buffers=32 buffer_size=4194304
    
    其中video_nr=2对应你的/dev/video2,max_buffers设为更大值,buffer_size根据视频分辨率调整(比如1080P的YUV420帧约2.7MB,设为4MB足够)。

2. Qt Camera捕获模式与场景不匹配

你设置了captureMode: Camera.CaptureStillImage,但当前场景是视频流传输,静态捕获模式的缓冲区分配逻辑会与视频流场景冲突。

  • 解决方法:将捕获模式改为Camera.CaptureVideo:
    Camera
    {
        id:             camera
        captureMode:    Camera.CaptureVideo  // 修改此处
        deviceId:       wrappingItem.videoDeviceFile
        // 其余代码保持不变
    }
    

3. GStreamer管线与Qt Camera的缓冲区竞争

两者同时操作v4l2loopback设备时,会出现缓冲区抢占,导致某一方无法分配到资源。

  • 解决方法:
    • 给GStreamer的v4l2sink添加sync=false参数,减少缓冲区阻塞:
      管线末尾改为... ! v4l2sink device=/dev/video2 sync=false
    • 强制Qt Camera的视频格式与GStreamer输出一致:
      在Camera组件中添加格式配置:
      Camera
      {
          // ...
          imageProcessing {
              captureResolution: Qt.size(1920, 1080) // 匹配GStreamer输出分辨率
              pixelFormat: "YUV420P" // 匹配GStreamer输出像素格式
          }
      }
      

4. Jetson平台CMA内存不足

Jetson Xavier NX的连续内存分配器(CMA)内存不足,无法分配视频设备所需的连续缓冲区。

  • 解决方法:
    • 查看当前CMA配置:cat /proc/cmdline | grep cma
    • 修改/boot/extlinux/extlinux.conf,在启动参数中添加cma=512M,重启设备生效。

5. Qt Multimedia的GStreamer后端缓冲区配置不足

Qt 5.15的Multimedia模块基于GStreamer,默认缓冲区设置无法满足高负载场景。

  • 解决方法:
    • 在应用启动前设置环境变量:
      export GST_BUFFER_POOL_MAX_BUFFERS=32 && ./your_app
      
    • 或在main.cpp中添加代码设置:
      qputenv("GST_BUFFER_POOL_MAX_BUFFERS", "32");
      qputenv("GST_VIDEO_SINK_MAX_BUFFERS", "16");
      

内容的提问来源于stack exchange,提问作者Bruno Kempf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:20:05