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)
关键修复点说明
内存格式转换:
去掉了不必要的identity元素,改用nvvideoconvert将NVMM内存转换为标准系统内存的video/x-raw格式,这是v4l2sink能识别的唯一内存类型。明确Caps配置:
指定了具体的像素格式(NV12)、分辨率,确保和v4l2loopback设备支持的格式一致。如果你的设备需要I420,可将format=NV12改为format=I420。v4l2loopback设备准备:
创建虚拟设备时必须添加exclusive_caps=1参数,否则很多工具(如ffplay、cheese)会无法识别为有效摄像头:sudo modprobe v4l2loopback video_nr=6 exclusive_caps=1 card_label="DeepStream-Virtual-Cam"队列隔离:
在v4l2sink分支添加独立队列,避免主 pipeline 阻塞影响输出。
验证方法
运行代码后,可用以下命令测试虚拟设备是否有输出:
ffplay /dev/video6
或者用v4l2-ctl查看设备格式:
v4l2-ctl -d /dev/video6 --list-formats-ext
内容的提问来源于stack exchange,提问作者Roberto Carlos Cruz Rodríguez
相关产品推荐
相关产品推荐

