【目的】
硬件平台的视频流混合,方便讲2条视频流或者多条视频流混合输出为一条视频流,输出可以以RTSP形式输出,也可以直接显示LCD,也可以通过qmlglsink给qt的UI显示。
【意义】
使用基于G2D的硬件视频流混合,比纯软件混合(比如gstreamer的videomixer)占用CPU资源要少的多。
【硬件平台】
Imx6q-arm的硬件平台,video0和video1两个摄像头输入,其中video0是红外摄像头,DVP接IPU;video1是OV摄像头,MIPI接IPU;
【系统平台】
kernel4.9.88 + linux文件系统。
【多媒体框架软件】
gstreamer1.0 (1.12.2) + imx_plugin
其中imx_plugin为nxp最新的plug-imx编译出来的,支持zero-copy和imxg2dcompositor特性;
我使用的plug-imx源码地址为:https://github.com/freescale/gstreamer-imx/
其readme.md里面明确说明了其硬件支持的新特性。
【问题抛出-imxg2dcompositor使用局限性】
在板子上使用该元件来做硬件视频融合,如果摄像头为标准摄像头,比如2个都为可见光标准输出格式的摄像头,则可以直接使用,只要摄像头输出格式满足imxg2dcompositor的输入格式需求;
但在本人的需求中,红外摄像头数据是自定义数据格式,每帧数据包含了gray8图像数据和温度数据,这样的场景就需要通过自己写gstreamer元件来实现红外摄像头的图像数据和温度数据分离,图像数据的格式转换后输出;
【自己写gstreamer元件】
1、gstreamer提供了appsrc/appsink可以避免自己写gstreamer元件,特别是涉及元件sinkpad和srcpad数据格式不一致的问题,很麻烦自己写元件;如果是通常处理,不涉及imxg2dcompositor,完全可以使用appsrc/appsink来实现对帧数据处理;
2、imxg2dcompositor元件很特殊,基于GPU的视频融合,对输入视频源需要连续物理地址,所以需要使用gstreamer元件的meta属性来实现连续物理地址,而不能通过gst_buffer_new_allocate()方式来创建虚拟地址连续,物理地址不连续的gstbuffer空间,一般在appsink里面的回调里面是通过gst_buffer_new_allocate()函数来创建gstbuffer空间来转储处理后的帧数据,以push给appsrc。
3、本人自己写的元件名字:hzncchytransform
因为要在元件的帧处理中给加上伪彩色,所以添加了一个element properties属性:pseudo-color
pseudo-color : Pseudo color to choose
flags: readable, writable
Enum "ImxIpuBlitterPseudoColor" Default: 0, "backwrite"
(0): backwrite - backwrite
(1): pseudo_color1 - pseudo_color1
(2): pseudo_color1 - pseudo_color1
(3): pseudo_color1 - pseudo_color1
(4): pseudo_color1 - pseudo_color1
(5): pseudo_color1 - pseudo_color1
(6): pseudo_color1 - pseudo_color1
因为还要处理温度数据,所以使用了tee的方式来分离温度数据。
上面的为不同伪彩色。
4、使用pipeline:
gst-launch-1.0 \
imxg2dcompositor name=c background-color=0x000000 border-alpha=0 \
sink_0::xpos=0 sink_0::ypos=0 sink_0::width=640 sink_0::height=480 sink_0::zorder=55 sink_0::fill_color=0xff00ff00 sink_0::alpha=0.7 sink_0::rotation=0 \
sink_1::xpos=0 sink_1::ypos=0 sink_1::width=640 sink_1::height=480 ! \
queue2 ! "video/x-raw, width=640, height=480,format=RGBA" ! overlaysink\
imxv4l2videosrc device=/dev/video0 ! tee name=t ! queue ! hzncchytransform pseudo-color=1 ! video/x-raw, width=384, height=288, format=RGBA,pixel-aspect-ratio=1/1 ! c.sink_0 t. ! queue ! fakesink \
imxv4l2videosrc device=/dev/video1 ! c.sink_1
直接显示在LCD上面,2个视频输出的alpha,以及相对位移,大小都可以通过sink属性来调整;
整个视频流路径如下:
5、使用qt:
(1)、qt使用的pipeline:
gst-launch-1.0 \
imxg2dcompositor name=c background-color=0x000000 border-alpha=0 \
sink_0::xpos=0 sink_0::ypos=0 sink_0::width=640 sink_0::height=480 sink_0::zorder=55 sink_0::fill_color=0xff00ff00 sink_0::alpha=0.7 sink_0::rotation=0 \
sink_1::xpos=0 sink_1::ypos=0 sink_1::width=640 sink_1::height=480 ! \
queue2 ! "video/x-raw, width=640, height=480,format=RGBA" ! glupload ! qmlglsink sync=false \
imxv4l2videosrc device=/dev/video0 ! tee name=t ! queue ! hzncchytransform pseudo-color=1 ! video/x-raw, width=384, height=288, format=RGBA,pixel-aspect-ratio=1/1 ! c.sink_0 t. ! queue ! fakesink \
imxv4l2videosrc device=/dev/video1 ! c.sink_1
(2)、问题2-为何不用2个pipeline对应于qt-qml的2个GstGLVideoItem?
在qt的qtquick中使用2个GstGLVideoItem控件,每个用来对应一个qmlglsink,显示一个摄像头的数据流。这种方式本人也尝试过,结果如下:
在qt的qtquick只使用1个GstGLVideoItem来显示视频流,完全没有问题,且不会有qt的软转码导致CPU资源高问题;
在qt的qtquick中同时使用2个GstGLVideoItem来显示2个视频流,会有明显的视频延时和画面卡顿(估计是qt的gst提供的GstGLVideoItem刷新问题,最后通过模拟鼠标拖动事件来解决,但是CPU占用率很高)
所以本人将2个摄像头数据在硬件层面混合后,通过1个GstGLVideoItem来显示在qt界面,可以解决上面的视频延时和画面卡顿问题。
6、效率对比:
(1)、videomixer:该方式纯软件处理视频流,且不支持appsrc/appsink,且延时非常大;
(2)、自定义元件hzncchytransform:该方式占用CPU非常低,1个core不到20%,如果加上伪彩色数添加,1个core的cpu占用率会高一些。
7、元件hzncchytransform源码:
https://github.com/tttg/hzncctransform.git