19 #include "videowidget.h"
20 #include "../xoverlay.h"
21 #include "../pipeline.h"
23 #include "../message.h"
24 #include "../../QGlib/connect.h"
25 #include "../../QGlib/signal.h"
26 #include <QtCore/QDebug>
27 #include <QtCore/QMutex>
28 #include <QtCore/QThread>
29 #include <QtGui/QPainter>
30 #include <QtGui/QPaintEvent>
31 #include <QtGui/QResizeEvent>
32 #include <QtGui/QApplication>
33 #include <QtGui/QHBoxLayout>
35 #ifndef QTGSTREAMER_UI_NO_OPENGL
36 # include <QtOpenGL/QGLWidget>
42 class AbstractRenderer
45 static AbstractRenderer *create(
const ElementPtr & sink, QWidget *videoWidget);
47 virtual ~AbstractRenderer() {}
48 virtual ElementPtr videoSink()
const = 0;
52 class XOverlayRenderer :
public QObject,
public AbstractRenderer
55 XOverlayRenderer(QWidget *parent)
58 m_windowId = widget()->winId();
59 QApplication::syncX();
61 widget()->installEventFilter(
this);
62 widget()->setAttribute(Qt::WA_NoSystemBackground,
true);
63 widget()->setAttribute(Qt::WA_PaintOnScreen,
true);
67 virtual ~XOverlayRenderer()
70 m_sink->setWindowHandle(0);
72 widget()->removeEventFilter(
this);
73 widget()->setAttribute(Qt::WA_NoSystemBackground,
false);
74 widget()->setAttribute(Qt::WA_PaintOnScreen,
false);
78 void setVideoSink(
const XOverlayPtr & sink)
80 QMutexLocker l(&m_sinkMutex);
82 m_sink->setWindowHandle(0);
86 m_sink->setWindowHandle(m_windowId);
90 virtual ElementPtr videoSink()
const
92 QMutexLocker l(&m_sinkMutex);
93 return m_sink.dynamicCast<Element>();
97 virtual bool eventFilter(QObject *filteredObject, QEvent *event)
99 if (filteredObject == parent() && event->type() == QEvent::Paint) {
100 QMutexLocker l(&m_sinkMutex);
101 State currentState = m_sink ? m_sink.dynamicCast<Element>()->currentState() : StateNull;
103 if (currentState == StatePlaying || currentState == StatePaused) {
106 QPainter p(widget());
107 p.fillRect(widget()->rect(), Qt::black);
111 return QObject::eventFilter(filteredObject, event);
116 inline QWidget *widget() {
return static_cast<QWidget*
>(parent()); }
118 mutable QMutex m_sinkMutex;
123 class QtVideoSinkRenderer :
public QObject,
public AbstractRenderer
126 QtVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
127 : QObject(parent), m_sink(sink)
129 QGlib::connect(sink,
"update",
this, &QtVideoSinkRenderer::onUpdate);
130 parent->installEventFilter(
this);
131 parent->setAttribute(Qt::WA_OpaquePaintEvent,
true);
134 virtual ~QtVideoSinkRenderer()
136 widget()->removeEventFilter(
this);
137 widget()->setAttribute(Qt::WA_OpaquePaintEvent,
false);
140 virtual ElementPtr videoSink()
const {
return m_sink; }
143 virtual bool eventFilter(QObject *filteredObject, QEvent *event)
145 if (filteredObject == parent() && event->type() == QEvent::Paint) {
146 QPainter painter(widget());
147 QRect targetArea = widget()->rect();
148 QGlib::emit<void>(m_sink,
"paint", (
void*) &painter,
149 (qreal) targetArea.x(), (qreal) targetArea.y(),
150 (qreal) targetArea.width(), (qreal) targetArea.height());
153 return QObject::eventFilter(filteredObject, event);
158 inline QWidget *widget() {
return static_cast<QWidget*
>(parent()); }
159 void onUpdate() { widget()->update(); }
165 #ifndef QTGSTREAMER_UI_NO_OPENGL
167 class QtGLVideoSinkRenderer :
public AbstractRenderer
170 QtGLVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
172 m_layout =
new QHBoxLayout(parent);
173 m_glWidget =
new QGLWidget(parent);
174 m_layout->setContentsMargins(0, 0, 0, 0);
175 m_layout->addWidget(m_glWidget);
176 parent->setLayout(m_layout);
178 m_renderer =
new QtVideoSinkRenderer(sink, m_glWidget);
180 m_glWidget->makeCurrent();
181 sink->setProperty(
"glcontext", (
void*) QGLContext::currentContext());
182 m_glWidget->doneCurrent();
185 virtual ~QtGLVideoSinkRenderer()
192 virtual ElementPtr videoSink()
const {
return m_renderer->videoSink(); }
195 QtVideoSinkRenderer *m_renderer;
196 QHBoxLayout *m_layout;
197 QGLWidget *m_glWidget;
200 #endif // QTGSTREAMER_UI_NO_OPENGL
203 class QWidgetVideoSinkRenderer :
public AbstractRenderer
206 QWidgetVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
210 m_sink->setProperty<
void*>(
"widget", parent);
213 virtual ~QWidgetVideoSinkRenderer()
215 m_sink->setProperty<
void*>(
"widget", NULL);
218 virtual ElementPtr videoSink()
const {
return m_sink; }
225 class PipelineWatch :
public QObject,
public AbstractRenderer
228 PipelineWatch(
const PipelinePtr & pipeline, QWidget *parent)
229 : QObject(parent), m_renderer(new XOverlayRenderer(parent)), m_pipeline(pipeline)
231 pipeline->bus()->enableSyncMessageEmission();
233 this, &PipelineWatch::onBusSyncMessage);
236 virtual ~PipelineWatch()
238 m_pipeline->bus()->disableSyncMessageEmission();
242 virtual ElementPtr videoSink()
const {
return m_renderer->videoSink(); }
244 void releaseSink() { m_renderer->setVideoSink(XOverlayPtr()); }
247 void onBusSyncMessage(
const MessagePtr & msg)
249 switch (msg->type()) {
251 if (msg->internalStructure()->name() == QLatin1String(
"prepare-xwindow-id")) {
252 XOverlayPtr overlay = msg->source().
dynamicCast<XOverlay>();
253 m_renderer->setVideoSink(overlay);
256 case MessageStateChanged:
258 if (msg.staticCast<StateChangedMessage>()->newState() == StateNull &&
259 msg->source() == m_renderer->videoSink())
269 XOverlayRenderer *m_renderer;
270 PipelinePtr m_pipeline;
274 AbstractRenderer *AbstractRenderer::create(
const ElementPtr & sink, QWidget *videoWidget)
276 XOverlayPtr overlay = sink.
dynamicCast<XOverlay>();
278 XOverlayRenderer *r =
new XOverlayRenderer(videoWidget);
279 r->setVideoSink(overlay);
283 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQtVideoSink")) {
284 return new QtVideoSinkRenderer(sink, videoWidget);
287 #ifndef QTGSTREAMER_UI_NO_OPENGL
288 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQtGLVideoSink")) {
289 return new QtGLVideoSinkRenderer(sink, videoWidget);
293 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQWidgetVideoSink")) {
294 return new QWidgetVideoSinkRenderer(sink, videoWidget);
301 VideoWidget::VideoWidget(QWidget *parent, Qt::WindowFlags f)
302 : QWidget(parent, f), d(NULL)
306 VideoWidget::~VideoWidget()
323 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
326 d = AbstractRenderer::create(sink,
this);
329 qCritical() <<
"QGst::Ui::VideoWidget: Could not construct a renderer for the specified element";
335 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
338 PipelineWatch *pw =
dynamic_cast<PipelineWatch*
>(d);
355 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
358 d =
new PipelineWatch(pipeline,
this);
363 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
365 if (dynamic_cast<PipelineWatch*>(d)) {
371 void VideoWidget::paintEvent(QPaintEvent *event)
374 p.fillRect(event->rect(), Qt::black);