597浏览
查看: 597|回复: 0

[官方资料] NVIDIA Jetson Nano 2GB 系列文章(36):加入USB输入与RTSP输出

[复制链接]
本文以上一期 Python 版的 deepstream-test1为基础,在输入与输出添加功能的两个扩展应用:deepstream-teat1-usbcamdeepstream-teat1-rtsp-out 中,分别将输入源从视频文件变成 USB 摄像头,以及将输出从显示屏变成 RTSP 视频流。接下去同样从代码内容来看看这两个部分需要进行怎样的修改。

  • 将输入源从视频文件修改成 USB 摄像头
  • 文件路径:
  • /sources/deepstream_python_apps/apps的deepstream-test1-usbcam/deepstream_test_1_usb.py
  • 范例功能:将 deepstream-test1 的视频文件输入改成 USB 摄像头
  • 插件流:v4l2src --> videoconvert--> nvvideoconvert --> nvstreammux --> nvinfer --> nvvideoconvert --> nvdsosd --> nvegltransform --> nveglglessink

  • 修改重点:
  • 将原本数据源插件从 filesrc 改成 v4l2src
  • 将原本格式转换插件从 h264 相关的,改成符合 USB 摄像头原始数据格式相关的

现在进去看看 deepstream_test_1_usb.py 与前面 deepstream_test_1.py 有那些修改的地方。

首先在创建阶段的修改,原本用 H264 视频文件输入的部分,需要以下四个元件:

  1. source = Gst.ElementFactory.make("filesrc", "file-source")
  2. h264parser = Gst.ElementFactory.make("h264parse", "h264-parser")
  3. decoder = Gst.ElementFactory.make("nvv4l2decoder", "nvv4l2-decoder")
  4. streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer")
复制代码

如今要改成USB摄像头输入时,就需要把输入的元件改成以下六个元件:
  1. source = Gst.ElementFactory.make("v4l2src","usb-cam-source")
  2. caps_v4l2src = Gst.ElementFactory.make("capsfilter","v4l2src_caps")
  3. vidconvsrc = Gst.ElementFactory.make("videoconvert","convertor_src1")
  4. nvvidconvsrc=Gst.ElementFactory.make("nvvideoconvert","convertor_src2")
  5. caps_vidconvsrc = Gst.ElementFactory.make("capsfilter","nvmm_caps")
  6. streammux = Gst.ElementFactory.make("nvstreammux","Stream-muxer")
复制代码

这里面的第 3~4 行添加 videoconvert->nvvideoconvert 的元件,最主要是因为 nvvideoconvert 并不支持所有原始格式,例如某些品牌 USB 摄像头常用的 YUYV 这种格式,但是我们需要获得 nvvideoconvert 所能支持的摄像头原始格式,于是 GStreamer 的 videoconvert 就能起到调节的作用。

Videoconvert 插件确保提供支持原始格式的超集,然后再由 nvvideoconvert 插件调用 NvBufSurface API 将传入的原始缓冲区,转换格式存到 NVMM Mem 里。

接下去在设置 caps_v4l2src 与 caps_vidconvsrc 元件参数的部分,并将输入源设定为程式所接受的第一个参数指,最后还设置“sync=false”以避免在显示接收器处出现延迟帧下降,其他设定指与 test1 的内容一致:

  1. caps_v4l2src.set_property('caps',Gst.Caps.from_string("video/x-raw, framerate=30/1"))
  2. caps_vidconvsrc.set_property('caps', \ Gst.Caps.from_string("video/x-raw(memory:NVMM)"))
  3. source.set_property('device',args[1])
  4. 。。。。
  5. sink.set_property('sync',False)
复制代码

后面的元件添加、元件连接、创建事件循环、播放并收听事件等部分的代码,则与 deepstream_test_1.py 是一致的,甚至 osd_sink_pad_buffer_probe 的代码也是完全一样的,这表示我们只要简单地将输入阶段的插件进行合适的替换,就能修改输入源的变更,十分简单。

请先将 USB 摄像头连接到设备上,然后执行以代码:

  1. cd<deepstream< span="">根目录>/sources/deepstream_python_apps/app
  2. cd deepstream-test1-usbcam
  3. python3 deepstream_test_1_usb.py
复制代码

下面截屏就是打开 USB 摄像头,对着屏幕上播放的视频进行识别的结果:

qw2.jpg

总的来说,大约就修改不到 10 行的内容,就将原本视频文件输入的功能改成 USB 输入的方式,里面最关键的重点就在于需要加入 videoconvert 这个插件,来适应各个摄像头硬件厂家所支持的原始格式。

您可以照此自行尝试将输入源修改成 CSI 摄像头或 IP 摄像头输入,或者可以在多种输入源中任选一种作为输入的方式。

  • 将输出从显示屏转成 RTSP 视频流
  • 文件路径:/sources/deepstream_python_apps/apps的deepstream-test1-rtsp-out/deepstream_test1_rtsp_out.py
  • 范例功能:将 deepstream-test1 的输出透过 RTSP 协议转向其他电脑
  • 修改重点:在 nvdsosd 之后添加将格式转成符合 RSTP 协议的 H264 格式,主要如下:
                      nvvideoconvert:将视频颜色格式从 RGBA 转换成 I420
                      CapsFilter:对数据实施限制(无数据修改)
                      nvv4l2h264enc:将 I420 格式的原始数据转成 H264 编码
                      RtpH264Pay:将 H264 编码的有效负载转换为 RFC 3984 格式的 RTP 数据包
                      UDPSink:向网络发送 UDP 数据包,当 rtph264pay 数据包与 RTP 有效负载配对时,就会生成 RTP 视频流。

这是一种实用性非常高的应用,很多时候部署在边缘端的 AIOT 计算设备,无法在机器上直接安装显示器去监控现场的状况,这时候用 RTSP 协议发出视频流,我们可以在其他设备上透过 VLC 之类的视频播放器,观看边缘设备上的识别结果,过程中可能会有些许的延迟,但总体来说确实非常方便部署的技术。

由于本实验需要用到 gst-rtsp-server 库,因此需要先进行以下的安装:

  1. sudo apt update
  2. sudo apt-get install libgstrtspserver-1.0-0 gstreamer1.0-rtsp
  3. sudo apt-get install libgirepository1.0-dev
  4. sudo apt-get install gobject-introspection gir1.2-gst-rtsp-server-1.0
复制代码

这个项目的输入部分还是使用 deepstream-test1 的 H264 视频文件,唯一改变的地方就是输出的方式,也就是在 deepstream_test_1.py 管道流 nvdsosd 之前的代码可以不做更动,重点在后面的部分。

在 deepstream_test1_rtsp_out.py 里面,从第 179 行(nvdsosd 之后)才开始产生变化,这里开始添加一些插件元件:

  1. nvvidconv_postosd = Gst.ElementFactory.make("nvvideoconvert", "convertor_postosd")
  2. # 创建caps过滤器
  3. caps = Gst.ElementFactory.make("capsfilter", "filter")
  4. caps.set_property("caps",   Gst.Caps.from_string("video/x-raw(memory:NVMM), format=I420"))
  5. # 根据输入参数选择使用的编码器,预设为H264
  6. if codec == "H264":
  7.     encoder =   Gst.ElementFactory.make("nvv4l2h264enc",   "encoder")
  8. elif codec == "H265":
  9.     encoder =   Gst.ElementFactory.make("nvv4l2h265enc",   "encoder")
  10. encoder.set_property('bitrate', bitrate)
  11. # 如果是在 Jetson 设备上,执行下面的设定
  12. if is_aarch64():
  13.       encoder.set_property('preset-level', 1)
  14.       encoder.set_property('insert-sps-pps', 1)
  15.       encoder.set_property('bufapi-version', 1)
  16.       
  17. # 使有效负载将视频编码为RTP数据包
  18. if codec == "H264":
  19.    rtppay =   Gst.ElementFactory.make("rtph264pay", "rtppay")
  20. elif codec == "H265":
  21.    rtppay =   Gst.ElementFactory.make("rtph265pay", "rtppay")
  22.    
  23. # 建立 UDP 接收器
  24. updsink_port_num = 5400
  25. sink = Gst.ElementFactory.make("udpsink",   "udpsink")
  26. # 设定接收器的值
  27. sink.set_property('host', '224.224.255.255')
  28. sink.set_property('port', updsink_port_num)
  29. sink.set_property('async', False)
  30. sink.set_property('sync', 1)
复制代码


接下去就是按照 file-source -> h264-parser -> nvh264-decoder -> nvinfer -> nvvidconv -> nvosd -> nvvidconv_postosd -> caps -> encoder -> rtppay -> udpsink  顺序,将元件依序进行连接。

以上部分的操作逻辑与先前所说的都是一致的,最后只剩一个部分,就是在代码第 276~286 行,需要调用 Gstreamer 的 gst-rtsp-server 库的 GstRtspServer 对象,细节请自行参考 https://github.com/GStreamer/gst-rtsp-server

  1. # Start streaming
  2. rtsp_port_num = 8554  # 设定端口值
  3. server = GstRtspServer.RTSPServer.new()
  4. server.props.service = "%d" % rtsp_port_num
  5. server.attach(None)
  6. factory = GstRtspServer.RTSPMediaFactory.new()
  7. factory.set_launch( "( udpsrc name=pay0 port=%d buffer-size=524288   caps="application/x-rtp, media=video, clock-rate=90000,   encoding-name=(string)%s, payload=96 " )" % (updsink_port_num,   codec))
  8. factory.set_shared(True)
  9. server.get_mount_points().add_factory("/ds-test",   factory)  # 设定加载点
复制代码

最后面的 mount_points 设定为“/ds-test”,因此将来在其他设备上要读取 RTSP 视频流的完整地址就是“rtsp://:8554/ds-test”,到此就完成将推理计算的结果透过 RTSP 服务向外推送的工作。

最后关于 osd_sink_pad_buffer_probe 的部分,与 deepstream_test_1.py 的内容完全一样,就不重复说明,至于代码最后面有个“def parse_args():”的部分,只是为了解析程式读入的指令参数,很容易就能看懂,这里也不浪费篇幅去讲解。

现在是否可以准备执行这个应用呢?当然是可以的,只不过好像还没有准备好“接收视频”的环境!这个其实也很简单,请找到与本台边缘设备(Jetson Nano 2GB)在相同网段的另一台电脑,可以是 Windows、MacOS、Ubuntu 操作系统,只要能安装 VLC 这个播放软件就可以。

假设是使用 USB 线连接 Jetson Nano 2GB 与 PC 的状态,这时在 PC 上可以透过“192.168.55.1”这个 IP 访问到 Jetson Nano 2GB。现在可以先打开 VLC,选择“打开网路串流”后,输入“rtsp://192.168.55.1:8554/ds-test”(如下图)

qw3.jpg

然后在Jetson Nano 2GB上执行一下指令:

  1. # 在DeepStream设备(如Jetson   Nano 2GB)
  2. cd<deepstream< span="">根目录>/sources/deepstream_python_apps/apps
  3. cd deepstream-test1-rtsp-out
  4. ln -s   ../../../../samples/streams/sample_720p.h264 sample_720.h264
  5. python3   deepstream_test_1_usb.py -i sample_720.h264
复制代码

执行前:下图左是用 Nomachine 连接到 Jetson Nano 2GB 的显示,下图右是在 PC 上打开 VLC 之后的画面。

qw4.jpg

执行后:下图左可以看到 Jetson Nano 2GB 正在执行推理计算,并且将视频流送出,下图右是在 PC 的 VLC 按下“播放”键之后的画面。

qw5.jpg

这样就完成这个 deepstream-test1-rtsp-out 的范例,建议大家能多花时间将代码修改的部分好好再咀嚼一番。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail