使用Qt在xoverlay上绘制

时间:2012-03-18 19:22:59

标签: qt opengl

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

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,如下所示

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

}

问题是矩形会在视频下方绘制。如何将其覆盖以显示在视频上方?

1 个答案:

答案 0 :(得分:1)

我有两种方法可以解决这个问题:

尽量让你的绘画像视频的绘画一样频繁发生。

或创建一个单独的窗口小部件,其中包含一些窗口标记,强制它的z顺序高于您的视频(如您在问题中所建议的那样)。

经常重新粉刷

Qt非常聪明,根据与小部件的交互,调整大小,移动,更新调用等来决定何时重新绘制。但是Qt也将接受这些调用(在GUI线程中转换为事件)并且有时将它们合并到优化时序和处理。如果你调用repaint而不是update,那么应该尽快调用它。您可以尝试调用QApplication :: processEvents()让它更快地使用事件更改。

更高的Z订单

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

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

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

我没有在你的代码上测试过这个,但是我已经在Windows中使用了这个设置用于很多小部件并取得了巨大的成功。这是我回答的一个问题,指的是png splash screen with transparency

此外,如果您没有为窗口小部件设置几何图形或未设置其大小,则它可能不会显示,因为它只允许在其几何体内绘制。

如果您仍需要更多帮助,请告诉我。