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

DeepStream结合v4l2sink写入虚拟V4L2设备失败求助

DeepStream + v4l2sink 无法输出到虚拟V4L2设备:问题修复与可运行示例

首先,你的代码没有报错但无法读取V4L2设备,核心问题是内存类型不兼容和Caps格式配置错误——v4l2sink无法直接处理DeepStream默认的NVMM硬件加速内存,必须转换为标准系统内存的raw视频格式,同时要匹配虚拟设备支持的像素格式。

修复后的可运行代码

以下是调整后的完整代码,重点修改了create_v4l2sink_branch函数,同时补充了关键配置说明:

import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
import math
import sys
# 注意:确保common.utils和其他依赖模块路径正确
import common.utils as DS_UTILS
import pyds
from common.bus_call import bus_call
from common.FPS import PERF_DATA
from common.is_aarch_64 import is_aarch64
from gi.repository import GLib, Gst, GstRtspServer

CODEC="H264"
BITRATE=4000000
MAX_DISPLAY_LEN = 64
MUXER_OUTPUT_WIDTH = 1920
MUXER_OUTPUT_HEIGHT = 1080
MUXER_BATCH_TIMEOUT_USEC = 400000
TILED_OUTPUT_WIDTH = 1920
TILED_OUTPUT_HEIGHT = 1080
GST_CAPS_FEATURES_NVMM = "memory:NVMM"
OSD_PROCESS_MODE = 0
OSD_DISPLAY_TEXT = 1
MUX_SYNC_INPUTS = 0

ds_loop=None
perf_data = None

def terminate_pipeline(u_data):
    global ds_loop
    # 可根据需要添加停止逻辑
    return True 

def create_v4l2sink_branch(pipeline, gst_elem, index, output_video_device):
    # 1. 队列用于隔离上下游,避免阻塞
    queue = DS_UTILS.create_gst_element("queue", f"v4l2-queue-{index}")
    pipeline.add(queue)
    gst_elem.link(queue)

    # 2. NVMM转系统内存:nvvideoconvert负责硬件转码格式转换
    nvvidconv = DS_UTILS.create_gst_element("nvvideoconvert", f"v4l2-convertor-{index}")    
    pipeline.add(nvvidconv)
    queue.link(nvvidconv)

    # 3. Caps Filter:明确指定输出为系统内存的NV12格式(v4l2loopback普遍支持)
    caps = DS_UTILS.create_gst_element("capsfilter", f"v4l2-filter-{index}")
    caps.set_property(
        "caps", 
        Gst.Caps.from_string(f"video/x-raw, format=NV12, width={MUXER_OUTPUT_WIDTH}, height={MUXER_OUTPUT_HEIGHT}")
    )
    pipeline.add(caps)
    nvvidconv.link(caps)

    # 4. v4l2sink:输出到虚拟设备
    sink = DS_UTILS.create_gst_element("v4l2sink", f"v4l2sink-{index}")
    sink.set_property('device', output_video_device)
    sink.set_property("sync", False)  # 关闭同步避免延迟
    sink.set_property("async", True)  # 异步提升性能
    pipeline.add(sink)

    caps.link(sink)

def run_pipeline(rtsp_v4l2_pairs):
    # Check input arguments
    number_sources = len(rtsp_v4l2_pairs)
    perf_data = PERF_DATA(number_sources)

    # Standard GStreamer initialization
    Gst.init(None)

    # Create gstreamer elements */
    # Create Pipeline element that will form a connection of other elements
    print("Creating Pipeline")
    pipeline = Gst.Pipeline()
    is_live = False
    if not pipeline:
        sys.stderr.write(" Unable to create Pipeline \n")
        return 

    # Create nvstreammux instance to form batches from one or more sources.
    streammux = DS_UTILS.create_gst_element("nvstreammux", "Stream-muxer")
    pipeline.add(streammux)
    for i in range(number_sources):
        uri_name = rtsp_v4l2_pairs[i][0]
        print("  Creating source_bin {} --> {}".format(i, uri_name))
        is_live = uri_name.find("rtsp://") == 0
        source_bin = DS_UTILS.create_source_bin(i, uri_name)

        pipeline.add(source_bin)
        padname = "sink_%u" % i
        sinkpad = streammux.get_request_pad(padname)
        if not sinkpad:
            sys.stderr.write("Unable to create sink pad bin \n")
        srcpad = source_bin.get_static_pad("src")
        if not srcpad:
            sys.stderr.write("Unable to create src pad bin \n")
        srcpad.link(sinkpad)

    # streammux setup 
    if is_live:
        print("  At least one of the sources is live")
        streammux.set_property('live-source', 1)   
    streammux.set_property('width', MUXER_OUTPUT_WIDTH)
    streammux.set_property('height', MUXER_OUTPUT_HEIGHT)
    streammux.set_property('batch-size', number_sources)
    streammux.set_property("batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC)

    queue = DS_UTILS.create_gst_element("queue", "queue1")
    pipeline.add(queue)
    nvstreamdemux = DS_UTILS.create_gst_element("nvstreamdemux", "nvstreamdemux")
    pipeline.add(nvstreamdemux)

    # linking
    streammux.link(queue)
    queue.link(nvstreamdemux)

    for i in range(number_sources):
        queue = DS_UTILS.create_gst_element("queue", f"queue{2+i}")
        pipeline.add(queue)

        demuxsrcpad = nvstreamdemux.get_request_pad(f"src_{i}")
        if not demuxsrcpad:
            sys.stderr.write("Unable to create demux src pad \n")

        queuesinkpad = queue.get_static_pad("sink")
        if not queuesinkpad:
            sys.stderr.write("Unable to create queue sink pad \n")
        demuxsrcpad.link(queuesinkpad)

        # 替换为修复后的v4l2sink分支
        create_v4l2sink_branch(pipeline=pipeline, gst_elem=queue, index=i, output_video_device=rtsp_v4l2_pairs[i][1])

    # for terminate the pipeline 
    GLib.timeout_add_seconds(1, terminate_pipeline, 0)
    # display FPS 
    GLib.timeout_add(5000, perf_data.perf_print_callback)

    # create an event loop and feed gstreamer bus mesages to it
    loop = GLib.MainLoop()
    ds_loop = loop
    bus = pipeline.get_bus()
    bus.add_signal_watch()
    bus.connect("message", bus_call, loop)
 

    print("Starting pipeline")
    # start play back and listen to events      
    pipeline.set_state(Gst.State.PLAYING)
    try:
        loop.run()
    except:
        pass
    # cleanup
    print("Pipeline ended")
    pipeline.set_state(Gst.State.NULL)

if __name__ == '__main__':
    # RTSP流与虚拟V4L2设备的映射
    pairs = [
        ("rtsp://192.168.1.88:554/22", "/dev/video6")
    ]
    
    # 先确保v4l2loopback设备已创建:
    # sudo modprobe v4l2loopback video_nr=6 exclusive_caps=1 card_label="DeepStream-Virtual-Cam"
    run_pipeline(rtsp_v4l2_pairs=pairs)

关键修复点说明

  1. 内存格式转换:
    去掉了不必要的identity元素,改用nvvideoconvert将NVMM内存转换为标准系统内存的video/x-raw格式,这是v4l2sink能识别的唯一内存类型。

  2. 明确Caps配置:
    指定了具体的像素格式(NV12)、分辨率,确保和v4l2loopback设备支持的格式一致。如果你的设备需要I420,可将format=NV12改为format=I420。

  3. v4l2loopback设备准备:
    创建虚拟设备时必须添加exclusive_caps=1参数,否则很多工具(如ffplay、cheese)会无法识别为有效摄像头:

    sudo modprobe v4l2loopback video_nr=6 exclusive_caps=1 card_label="DeepStream-Virtual-Cam"
    
  4. 队列隔离:
    在v4l2sink分支添加独立队列,避免主 pipeline 阻塞影响输出。

验证方法

运行代码后,可用以下命令测试虚拟设备是否有输出:

ffplay /dev/video6

或者用v4l2-ctl查看设备格式:

v4l2-ctl -d /dev/video6 --list-formats-ext

内容的提问来源于stack exchange,提问作者Roberto Carlos Cruz Rodríguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:02:24