Reputation: 115
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);
}
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?
Upvotes: 3
Views: 2607
Reputation: 19112
There are two ways that I would go about this:
Try to have your painting happen as frequently as the video's painting.
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 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.
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);
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.
Upvotes: 1