简体   繁体   English

gstreamer和QML:在QML窗口上绘图

[英]gstreamer and QML: Drawing on a QML Window

I have been trying to draw a gstreamer camera output onto a QML object for months now. 几个月来,我一直在尝试将gstreamer摄像机输出绘制到QML对象上。 At least on my ARM system none of the qt-gstreamer qml components really worked with the camera output (I can show the test video source) but never anything from the camera. 至少在我的ARM系统上,所有qt-gstreamer qml组件都无法真正与摄像机输出配合使用(我可以显示测试视频源),但摄像机无法提供任何支持。

So, I went to the old school of rendering onto a regular qt window with the following example: 因此,我通过以下示例进入了在常规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;
}

Here I am window ID of the QWidget and overlaying the video in it. 在这里,我是QWidget的窗口ID,并在其中叠加了视频。 This is the only thing that ever worked for me. 这是对我唯一有效的方法。

However, now I wonder, if it is possible to get the window ID of an underlying qt graphical element. 但是,现在我想知道,是否有可能获得基础qt图形元素的窗口ID。 So, for example if I have something like: 因此,例如,如果我有类似的内容:

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
    }
}

Is it possible to get the ID of the underlying graphical window object or does that not exist? 是否可以获得底层图形窗口对象的ID或不存在? is there some component which has its own graphical ID that I can use in QML and then query from my C++ app and use it to overlay the video? 是否有一些具有自己的图形ID的组件可以在QML中使用,然后从我的C ++应用程序查询并使用它来覆盖视频?

There are a few pieces to this puzzle. 这个难题有几部分。 First, getting the window ID of the QML window. 首先,获取QML窗口的窗口ID。 You can get this from the application engine. 您可以从应用程序引擎获得此信息。

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

Next, you need to set the handler on the video sink. 接下来,您需要在视频接收器上设置处理程序。 I recommend using glimagesing , because the automatic one does not implement the interface, and the X11 one is linux-only. 我建议使用glimagesing ,因为自动接口不会实现该接口,而X11接口仅适用于Linux。

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

Now, this will overlay the entire window, which is probably not what you want. 现在,这将覆盖整个窗口,可能不是您想要的。 The final piece of the puzzle: Expose a wrapper to QML with a QRect property, then you can set the bounds of the target area as follows: 难题的最后一部分:使用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)
  }
}

And then based on that property, you can do something like 然后基于该属性,您可以执行以下操作

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);
}

Probably the "subwindow" approach would be better, but this works. 也许“子窗口”方法会更好,但这是可行的。 Only limitation is that it's literally an overlay on top of the UI, so any UI elements will draw below the frame. 唯一的限制是它实际上是在UI顶部的覆盖,因此所有UI元素都将绘制在框架下方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM