使用Qt在xoverlay上绘制 [英] Draw on top of xoverlay using Qt

查看:410
本文介绍了使用Qt在xoverlay上绘制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在使用Xoverlay渲染的视频流之上绘制一些UI.我正在使用gstreamer播放视频,并使用xoverlay在xvimagesink上呈现它. 我的小部件继承自QGLWidget,我希望使用QPainter绘制2D元素 我已完成以下操作:

I wish to draw some UI on top of video stream that is rendered using Xoverlay. I am using gstreamer to play the video and render it on xvimagesink using xoverlay. My widget inherits from QGLWidget and I wish to draw 2D elements using QPainter I have done the following:

VideoPlayer::VideoPlayer(QWidget *parent) :
QGLWidget(parent)
{
    setAutoFillBackground(false);
    QString fname = QFileDialog::getOpenFileName(0,tr("Open video"),tr("/"));
    GstElement *pipeline,*source,*decoder,*q,*converter,*resampler,*audiosink,*videosink;
    GstBus *bus;
    pipeline = gst_pipeline_new("my-player");
    source = gst_element_factory_make("filesrc","source");
    decoder = gst_element_factory_make("decodebin2","decoder");
    q = gst_element_factory_make("queue","q");
    converter = gst_element_factory_make("audioconvert","converter");
    resampler = gst_element_factory_make("audioresample","resampler");
    audiosink = gst_element_factory_make("autoaudiosink","audio-sink");

    videosink = gst_element_factory_make("xvimagesink","video-sink");

    //Set the bin properties
    g_object_set(G_OBJECT(source),"location",fname.toAscii().constData(),NULL);
    g_object_set(G_OBJECT(decoder),"name","decoder");

    gst_bin_add_many(GST_BIN(pipeline),source,decoder,q,converter,resampler,audiosink,videosink,NULL);
    gst_element_link(source,decoder);
    gst_element_link_many(q,converter,resampler,audiosink,NULL);
    //gst_element_link(decoder,q);
    g_signal_connect(decoder,"pad-added",G_CALLBACK(on_pad_added),videosink);
    g_signal_connect(decoder,"pad-added",G_CALLBACK(on_pad_added),q);


    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    gst_bus_add_watch(bus,bus_call,NULL);
    gst_object_unref(bus);


    if (GST_IS_X_OVERLAY (videosink))
    {
        unsigned long win_id=winId();
        QApplication::syncX();
        gst_x_overlay_set_xwindow_id (GST_X_OVERLAY(videosink),win_id);
    }


    gst_element_set_state(pipeline,GST_STATE_PLAYING);
}

然后我重新实现paintEvent,

Then I reimplement paintEvent as follows

void VideoPlayer::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    painter.save();
    painter.setPen(QColor(255,0,0,140));
    painter.drawRect(QRectF(50,50,100,100));
    painter.restore();

}

问题是该矩形在视频下方绘制.我该如何对其进行过度覆盖以使其在视频上方显示?

The problem is that the rectangle gets painted below the video. How do I overpaint it so that it shows above the video?

推荐答案

我有两种解决方法:

尝试使绘画与视频绘画一样频繁.

Try to have your painting happen as frequently as the video's painting.

或创建带有某些Window标志的单独的小部件,以使其在z顺序上高于视频(如您在问题中所建议的).

Or create a separate widget with some Window flags that forces it to be higher in z order than your video (like you suggested in your question).

Qt非常聪明,可以根据与小部件的交互,调整大小,移动,更新调用等来决定何时重新绘制.但是Qt也会接受这些调用(在GUI线程中变成事件),有时将它们合并为针对时序和处理进行优化.如果您调用重绘而不是更新,则应尽快调用它.而且,您可以尝试调用QApplication :: processEvents()以使其更快地使用事件更改.

Qt is pretty smart about deciding when to repaint based on interactions with widgets, resizing, moving, update calls, etc. But Qt will also take those calls (which get turned into events in the GUI thread) and sometimes merge them to optimize for timing and processing. If you call repaint instead of update, then it should get called sooner. And you can try calling QApplication::processEvents() to have it use event changes sooner.

无论您想在视频顶部绘画什么,都可以变成小部件并移至视频顶部.如果您可以确保此叠加层的标志使其优于视频,则可以使该叠加层位于顶部.操作系统的窗口系统应确保一个窗口位于另一个窗口之上.

Whatever you are trying to paint on top of the video can get turned into a widget and moved on top of the video. You can make this overlay stay on top if you make sure that its flags make it superior to the video. The windowing system for the OS should make sure that one is above the other.

这应该像将您的VideoOverlay小部件(不是播放器,而是由播放器在堆上创建的单独的无父母小部件),将其大小调整为位于视频顶部(甚至将其连接到)一样简单.为播放器调整大小事件,并将其窗口标志设置为Qt :: WindowStaysOnTop.您还需要将背景设置为透明和无框架等.您可能还需要使其对鼠标事件透明.

This should be as simple as taking your VideoOverlay widget (not the player, but a separate parentless widget that gets created on the heap by your player), resizing it to be on top of the video (and maybe even connnecting it to the resize event for your player, and set it's window flags to be Qt::WindowStaysOnTop. You also will need to set the background transparent, and frameless, etc. You may also need to make it transparent to mouse events.

videoOverlay->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
videoOverlay->setAttribute(Qt::WA_TranslucentBackground);

我尚未在您的代码上对此进行测试,但是我已将该设置用于Windows中的许多小部件,并取得了巨大的成功.这是我不久前回答的一个问题,它涉及到 png初始屏幕透明度.

I haven't tested this on your code, but I have used this setup for a number of widgets in Windows with great success. Here is a question that I answered a while back that refers to a png splash screen with transparency.

如果您的小部件没有设置几何图形或未设置其大小,则由于只允许在其几何图形内部绘画,因此可能不会显示.

Also if you don't have a set geometry for your widget or its size isn't set, then it might not show up because it is only allowed to paint inside its geometry.

让我知道您是否仍然需要更多帮助.

Let me know if you are still need more help.

这篇关于使用Qt在xoverlay上绘制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆