首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在嵌入式linux上使用Gstreamer在Qt小部件中嵌入单独的视频流

在嵌入式linux上使用Gstreamer在Qt小部件中嵌入单独的视频流
EN

Stack Overflow用户
提问于 2021-04-12 08:11:55
回答 2查看 927关注 0票数 1

我在寻找任何关于这个问题的提示:

我有一个运行嵌入式的i.MX6设备和一个运行在屏幕上的基于Qt5 Widget的应用程序。我还有一个定制的SDK,我不能更改它,它只限于QT5.5.1库,我需要在iMX上构建它。因为它是嵌入式的,所以我不能在上面使用'dpkg‘或'ldconfig’之类的命令。

目标:我的目标是在QT5.5应用程序中添加一个功能,在不同的小部件中显示来自多个摄像机的实时视频流(大约4到6个)。它需要硬件加速。

没有摄像头进行测试,我使用VLC来流3个视频(它们在本地运行),我的应用程序通过RTSP读取这些流。

我尝试了什么:,我一直在学习Qt和Gstreamer,以找到一个解决方案。我尝试了许多不同的东西,使用了所有已经安装在屏幕上的有前途的视频接收器,目前正在尝试基于的解决方案。

我制作了一个用于测试的简单Qt小部件应用程序,当我在我的x86系统(Ubuntu16.04)上运行它时,它运行得很好。正如您在这些截图中所看到的:

表1

表2

流很好地集成在单独的选项卡中,我可以通过单击选项卡在它们之间切换。然而,在目标设备上运行相同的应用程序(使用不同的接收器,例如imxipuvideosink)会显示“在”窗口上方和彼此之上的所有流。它们没有嵌入到Tab小部件中,可能是因为设备不能依赖X。

为了将流嵌入到小部件中,我尝试了许多不同的方法,下面是几种方法:

  1. 自动视频链接,imxipuvideosink,imxeglviv接收器:这些是我在部署目标时用上面的例子测试的接收器,我得到的是相互重叠的未嵌入的流。
  2. 我无法得到输出。
  3. qtvideosink,qtglvideosink :根据这份文件的说法,它们需要连接“更新”和“绘制”信号。我尝试了下面的一行:QGlib::connect(sink, "update", widget, &QWidget::update);,但是它抛出了一个“不匹配函数调用.”错误,并将更新槽标记为"<未解析的重载函数类型>“。:connect也是这样。我可能在这里做错了什么。
  4. 使用这个管道:rtspsrc location=rtsp://10.0.1.1:8554/stream ! videoparse width=400 height=300 format=i420 ! videoconvert ! qwidget5videosink我得到了一个输出,但是它在x86上被破坏了,并且目标设备没有安装视频插件。

由于我一定要使用QWidget应用程序,所以使用QML的唯一方法是在基于小部件的应用程序中创建一个QQuickWidget。我将这个QQuickWidget的源代码设置为一个简单的.qml文件,并尝试如下:

  1. MediaPlayer + VideoOutput :这实际上是我希望它在两个系统上的工作方式,即视频被显示并嵌入到单独的小部件中。但是AFAIK MediaPlayer并没有从硬件加速中受益,因此一些实例在开始时崩溃,其余的则会崩溃,但是具有很强的帧抖动。因为我的SDK仅限于Qt和QtMultimedia 5.5,所以我不能使用5.12中引入的MediaPlayer的流水线定义特性
  2. Qmlgl接收器:被认为是这项工作最有希望的接收器,这个接收器只在包gstreamer1.0-qt5中可用,所以我需要在嵌入式设备上安装它,这在技术上是可能的,但很困难,也很危险。
  3. VideoSurface + VideoItem:我没有安装lib QtGStreamer 1.0。
  4. GstGLVideoItem:我没有安装lib org.freedesktop.gstreamer.GLVideoItem 1.0。
  5. 我安装了qtquick2videosink,但我不知道如何使用它。文献资料不清楚应该在哪些QML元素上使用它,而且我还没有找到任何使用示例。是VideoSurface吗?GraphicsVideoSurface?

我知道这是非常有限的,但由于这是嵌入式的,我想保持安装更多的软件包和库作为最后手段。而且,如果我必须安装一些东西,我应该按照什么顺序来尝试它们,从最有希望的到不太有希望的?任何建议或链接的例子是非常感谢的,我正在寻找一般的指导,看看我错过了什么,或知道我应该如何处理这个问题。

编辑: --我使用qwidgetvideosink搜索了更多内容,并找到了一种使其工作的方法。下面的管道是我发现的最好的结果:rtspsrc location=rtsp://10.0.1.1:8554/stream ! decodebin ! imxg2dvideotransform ! clockoverlay ! qwidget5videosink sync=false。不幸的是,这里的性能与使用MediaPlayer时一样糟糕,如果不是更糟的话。但是,至少通过这种方法,我可以定制管道。我尝试了几种不同的方法,但找不到更好的解决办法。我也想不出用更精确的插件代替解码的方法。在这方面的任何帮助也将受到感谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-09 13:32:04

我想分享一下我们在这个特殊问题上所寻求的解决方案,以防它能帮助任何有类似问题的人。

在失败了所有需要缺失librairies的解决方案(QtMultimedia、qmlgl接收器等)之后,或者只是由于未知的原因没有工作,我了解了帧缓冲器 --就我而言,它基本上只是GPU的层--以及如何在这种情况下使用它们。

事实证明,我一直在使用的linux嵌入式设备有3个帧缓冲区,它允许我们将应用程序分成一个用于视频流播放的“后台”帧缓冲区,以及一个用于覆盖显示的“前台”帧缓冲区。当我们希望背景中的视频变得可见时,覆盖层( Qt MainWindow)需要是透明的。为此,我们使用alpha混合和一个颜色键。

在测试了这个解决方案的各个部分之后,我们得到了一个启动两个管道的应用程序(因为我希望一次在屏幕上显示两个摄像头,每个摄像头都可以使用一个输入选择器切换到另一个流)。例如,管道结构如下所示:

代码语言:javascript
复制
input-selector name=selector ! decodebin ! textoverlay name=text0 ! queue !
imxg2dvideosink framebuffer=/dev/fb0 name=end0 force-aspect-ratio=false
    window-x-coord=0 window-y-coord=0 window-width=512 window-height=473
rtspsrc location=rtsp://10.0.1.1:8554/stream name=src0 ! queue name=qs_0 ! selector.sink_0
rtspsrc location=rtsp://10.0.1.1:8556/stream name=src2 ! queue name=qs_2 ! selector.sink_1
rtspsrc location=rtsp://10.0.1.1:8558/stream name=src4 ! queue name=qs_4 ! selector.sink_2

我们将framebuffer属性传递给接收器,以便它将视频发送到framebuffer 0,而应用程序本身则显示在显示在fb0顶部的framebuffer 1上。为了实现这一点,我们只需在调用应用程序可执行文件之前将QT_QPA_EGLFS_FB env变量设置为/dev/fb1,因为我们的设备使用插件运行。

对于alpha混合和颜色键控部分,我们必须在应用程序中这样做:

代码语言:javascript
复制
#include <fcntl.h>
#include <linux/mxcfb.h>
#include <sys/ioctl.h>

...

// Read overlay framebuffer fb1
int fb = 0;
fb = open("/dev/fb1", O_RDWR);
if (fb < 0)
    qWarning() << "Error, framebuffer cannot be opened";

// Enable alpha
struct mxcfb_gbl_alpha alphaStruct;
alphaStruct.enable = 1;
alphaStruct.alpha = 255;
if (ioctl(fb, MXCFB_SET_GBL_ALPHA, &alphaStruct) < 0)
    qWarning() << "Error, framebuffer alpha cannot be set";

// Set color key to pure blue
struct mxcfb_color_key colorKeyStruct;
guint32 colorKeyValue = g_ascii_strtoull("0x0000FF", NULL, 16);
colorKeyStruct.color_key = colorKeyValue;
colorKeyStruct.enable = 1;
if (ioctl(fb, MXCFB_SET_CLR_KEY, &colorKeyStruct) < 0)
    qWarning() << "Error, framebuffer color key cannot be set";

...

基本上,这将打开覆盖应用程序正在运行的框架缓冲区,在其上启用alpha,然后将一个颜色(蓝色)设置为透明颜色。因此,每个像素与这个确切的颜色值将显示的视频运行在背景中。

所以现在我们有了一个应用程序,它可以播放视频流和使用HW加速视频接收器的定制Gstreamer管道。

票数 0
EN

Stack Overflow用户

发布于 2021-06-23 20:04:02

你想要的是墨镜。这个人有一个预言家,可以传递一个窗口id。您可以基于:https://thiblahute.github.io/GStreamer-doc/gst-plugins-base-video-1.0/videooverlay.html?gi-language=c编写代码。

有关于gtk+和qt的例子。现在我看一下它,我在qt中使用了gtk+方式(与总线同步处理程序).我是用imxeglviv接收器在imx6上这样做的

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67054782

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档