【问题标题】:gstreamer and QML: Drawing on a QML Windowgstreamer 和 QML:在 QML 窗口上绘图
【发布时间】:2016-07-03 09:39:38
【问题描述】:

几个月来,我一直在尝试将 gstreamer 相机输出绘制到 QML 对象上。至少在我的 ARM 系统上,没有一个 qt-gstreamer qml 组件真正与相机输出一起工作(我可以显示测试视频源),但从来没有来自相机的任何东西。

因此,我通过以下示例进入了在常规 qt 窗口上渲染的老派:

#include <glib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>

#include <QApplication>
#include <QTimer>
#include <QWidget>

int main(int argc, char *argv[])
{
    if (!g_thread_supported ())
        g_thread_init (NULL);

    gst_init (&argc, &argv);
    QApplication app(argc, argv);
    app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));

    // prepare the pipeline

    GstElement *pipeline = gst_pipeline_new ("xvoverlay");
    GstElement *src = gst_element_factory_make ("v4l2src", NULL);
    GstElement *sink = gst_element_factory_make ("xvimagesink", NULL);
    gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
    gst_element_link (src, sink);

    // prepare the ui

    QWidget window;
    window.resize(320, 240);
    window.show();

    WId xwinid = window.winId();
    gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), xwinid);

    // run the pipeline

    GstStateChangeReturn sret = gst_element_set_state (pipeline,
                                                       GST_STATE_PLAYING);
    if (sret == GST_STATE_CHANGE_FAILURE) {
        gst_element_set_state (pipeline, GST_STATE_NULL);
        gst_object_unref (pipeline);
        // Exit application
        QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit()));
    }

    int ret = app.exec();

    window.hide();
    gst_element_set_state (pipeline, GST_STATE_NULL);
    gst_object_unref (pipeline);

    return ret;
}

这里我是 QWidget 的窗口 ID,并在其中覆盖了视频。这是唯一对我有用的东西。

但是,现在我想知道,是否可以获取底层 qt 图形元素的窗口 ID。所以,例如,如果我有类似的东西:

ApplicationWindow {
    id: rootWindow
    objectName: "window"
    visible: true
    width: 800
    height: 480
    color: "#FFFFFF"    

    Rectangle {
       width: 100
       height: 100
       color: "red"
       border.color: "black"
       border.width: 5
       radius: 10
    }
}

是否可以获得底层图形窗口对象的 ID 或不存在?是否有一些组件具有自己的图形 ID,我可以在 QML 中使用,然后从我的 C++ 应用程序中查询并使用它来覆盖视频?

【问题讨论】:

  • 它不可避免地有一个QWindow,但它会绘制视频而不是整个QML窗口。所以像这样使用 QML 几乎没有意义。
  • 是的,这很难做到……我现在正在尝试一些事情,并且会更新。

标签: qt qml gstreamer


【解决方案1】:

这个难题有几个部分。首先,获取 QML 窗口的窗口 ID。 您可以从应用程序引擎中获取此信息。

QObject* m_rootObject = engine->rootObjects().first();
WId wid = -1;
if(m_rootObject) {
    QWindow *window = qobject_cast<QWindow *>(m_rootObject);
    if(window) {
        wid = window->winId();
    }
}

接下来,您需要在视频接收器上设置处理程序。我推荐使用glimagesing,因为自动的没有实现接口,而X11的是linux-only。

data.video_sink = gst_element_factory_make("glimagesink", "data.video_sink");
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (data.video_sink), wid);

现在,这将覆盖整个窗口,这可能不是您想要的。难题的最后一块:使用 QRect 属性向 QML 公开一个包装器,然后您可以按如下方式设置目标区域的边界:

Binding {
  target: videowrapper
  property: "rect"
  value: {
    var pos = mapToItem(window.contentItem, 0, 0)
    console.log(pos)
    return Qt.rect(pos.x, pos.y, placeholder.width, placeholder.height)
  }
}

然后基于该属性,您可以执行类似的操作

void VideoShow::set_bounds(int x, int y, int width, int height) {
    gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY (data.video_sink), x, y, width, height);
}

可能“子窗口”方法会更好,但这很有效。唯一的限制是它实际上是 UI 顶部的叠加层,因此任何 UI 元素都将绘制在框架下方。

【讨论】:

  • 写一个videowrapper是什么意思?我对这种解决方法非常感兴趣。请详细说明一下?
  • 我只记得这篇文章中的内容,但我确实写了另一篇文章,概述了一种更好的方法:pepijndevos.nl/2018/10/02/qtgstreamerddsandroid.html
猜你喜欢
  • 1970-01-01
  • 2012-10-25
  • 2022-08-04
  • 2017-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多