19#include "videowidget.h"
20#include "../videooverlay.h"
21#include "../pipeline.h"
23#include "../message.h"
24#include "../../QGlib/connect.h"
25#include "../../QGlib/Signal"
26#include <QtCore/QDebug>
27#include <QtCore/QMutex>
28#include <QtCore/QThread>
29#include <QtGui/QPainter>
30#include <QtGui/QPaintEvent>
31#include <QtGui/QResizeEvent>
33#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
34# include <QtWidgets/QApplication>
35# include <QtWidgets/QHBoxLayout>
37# include <QtGui/QApplication>
38# include <QtGui/QHBoxLayout>
41#ifndef QTGSTREAMER_UI_NO_OPENGL
42# include <QtOpenGL/QGLWidget>
51 static AbstractRenderer *create(
const ElementPtr & sink, QWidget *videoWidget);
53 virtual ~AbstractRenderer() {}
54 virtual ElementPtr videoSink()
const = 0;
58class VideoOverlayRenderer :
public QObject,
public AbstractRenderer
61 VideoOverlayRenderer(QWidget *parent)
64 m_windowId = widget()->winId();
65#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
66 QApplication::syncX();
69 widget()->installEventFilter(
this);
70 widget()->setAttribute(Qt::WA_NoSystemBackground,
true);
71 widget()->setAttribute(Qt::WA_PaintOnScreen,
true);
75 virtual ~VideoOverlayRenderer()
78 m_sink->setWindowHandle(0);
80 widget()->removeEventFilter(
this);
81 widget()->setAttribute(Qt::WA_NoSystemBackground,
false);
82 widget()->setAttribute(Qt::WA_PaintOnScreen,
false);
86 void setVideoSink(
const VideoOverlayPtr & sink)
88 QMutexLocker l(&m_sinkMutex);
90 m_sink->setWindowHandle(0);
94 m_sink->setWindowHandle(m_windowId);
98 virtual ElementPtr videoSink()
const
100 QMutexLocker l(&m_sinkMutex);
101 return m_sink.dynamicCast<Element>();
105 virtual bool eventFilter(QObject *filteredObject, QEvent *event)
107 if (filteredObject == parent() && event->type() == QEvent::Paint) {
108 QMutexLocker l(&m_sinkMutex);
109 State currentState = m_sink ? m_sink.dynamicCast<Element>()->currentState() : StateNull;
111 if (currentState == StatePlaying || currentState == StatePaused) {
114 QPainter p(widget());
115 p.fillRect(widget()->rect(), Qt::black);
119 return QObject::eventFilter(filteredObject, event);
124 inline QWidget *widget() {
return static_cast<QWidget*
>(parent()); }
126 mutable QMutex m_sinkMutex;
127 VideoOverlayPtr m_sink;
131class QtVideoSinkRenderer :
public QObject,
public AbstractRenderer
134 QtVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
135 : QObject(parent), m_sink(sink)
137 QGlib::connect(sink,
"update",
this, &QtVideoSinkRenderer::onUpdate);
138 parent->installEventFilter(
this);
139 parent->setAttribute(Qt::WA_OpaquePaintEvent,
true);
142 virtual ~QtVideoSinkRenderer()
144 widget()->removeEventFilter(
this);
145 widget()->setAttribute(Qt::WA_OpaquePaintEvent,
false);
148 virtual ElementPtr videoSink()
const {
return m_sink; }
151 virtual bool eventFilter(QObject *filteredObject, QEvent *event)
153 if (filteredObject == parent() && event->type() == QEvent::Paint) {
154 QPainter painter(widget());
155 QRect targetArea = widget()->rect();
156 QGlib::emit<void>(m_sink,
"paint", (
void*) &painter,
157 (qreal) targetArea.x(), (qreal) targetArea.y(),
158 (qreal) targetArea.width(), (qreal) targetArea.height());
161 return QObject::eventFilter(filteredObject, event);
166 inline QWidget *widget() {
return static_cast<QWidget*
>(parent()); }
167 void onUpdate() { widget()->update(); }
173#ifndef QTGSTREAMER_UI_NO_OPENGL
175class QtGLVideoSinkRenderer :
public AbstractRenderer
178 QtGLVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
180 m_layout =
new QHBoxLayout(parent);
181 m_glWidget =
new QGLWidget(parent);
182 m_layout->setContentsMargins(0, 0, 0, 0);
183 m_layout->addWidget(m_glWidget);
184 parent->setLayout(m_layout);
186 m_renderer =
new QtVideoSinkRenderer(sink, m_glWidget);
188 m_glWidget->makeCurrent();
189 sink->setProperty(
"glcontext", (
void*) QGLContext::currentContext());
190 m_glWidget->doneCurrent();
193 virtual ~QtGLVideoSinkRenderer()
200 virtual ElementPtr videoSink()
const {
return m_renderer->videoSink(); }
203 QtVideoSinkRenderer *m_renderer;
204 QHBoxLayout *m_layout;
205 QGLWidget *m_glWidget;
211class QWidgetVideoSinkRenderer :
public AbstractRenderer
214 QWidgetVideoSinkRenderer(
const ElementPtr & sink, QWidget *parent)
218 m_sink->setProperty<
void*>(
"widget", parent);
221 virtual ~QWidgetVideoSinkRenderer()
223 m_sink->setProperty<
void*>(
"widget", NULL);
226 virtual ElementPtr videoSink()
const {
return m_sink; }
233class PipelineWatch :
public QObject,
public AbstractRenderer
236 PipelineWatch(
const PipelinePtr & pipeline, QWidget *parent)
237 : QObject(parent), m_renderer(new VideoOverlayRenderer(parent)), m_pipeline(pipeline)
239 pipeline->bus()->enableSyncMessageEmission();
241 this, &PipelineWatch::onBusSyncMessage);
244 virtual ~PipelineWatch()
246 m_pipeline->bus()->disableSyncMessageEmission();
250 virtual ElementPtr videoSink()
const {
return m_renderer->videoSink(); }
252 void releaseSink() { m_renderer->setVideoSink(VideoOverlayPtr()); }
255 void onBusSyncMessage(
const MessagePtr & msg)
257 switch (msg->type()) {
259 if (VideoOverlay::isPrepareWindowHandleMessage(msg)) {
260 VideoOverlayPtr overlay = msg->source().
dynamicCast<VideoOverlay>();
261 m_renderer->setVideoSink(overlay);
264 case MessageStateChanged:
266 if (msg.staticCast<StateChangedMessage>()->newState() == StateNull &&
267 msg->source() == m_renderer->videoSink())
277 VideoOverlayRenderer *m_renderer;
278 PipelinePtr m_pipeline;
282AbstractRenderer *AbstractRenderer::create(
const ElementPtr & sink, QWidget *videoWidget)
284 VideoOverlayPtr overlay = sink.
dynamicCast<VideoOverlay>();
286 VideoOverlayRenderer *r =
new VideoOverlayRenderer(videoWidget);
287 r->setVideoSink(overlay);
291 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQtVideoSink"
292#
if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
296 return new QtVideoSinkRenderer(sink, videoWidget);
299#ifndef QTGSTREAMER_UI_NO_OPENGL
300 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQtGLVideoSink"
301#
if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
305 return new QtGLVideoSinkRenderer(sink, videoWidget);
309 if (QGlib::Type::fromInstance(sink).name() == QLatin1String(
"GstQWidgetVideoSink"
310#
if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
314 return new QWidgetVideoSinkRenderer(sink, videoWidget);
321VideoWidget::VideoWidget(QWidget *parent, Qt::WindowFlags f)
322 : QWidget(parent, f), d(NULL)
326VideoWidget::~VideoWidget()
343 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
346 d = AbstractRenderer::create(sink,
this);
349 qCritical() <<
"QGst::Ui::VideoWidget: Could not construct a renderer for the specified element";
353void VideoWidget::releaseVideoSink()
355 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
358 PipelineWatch *pw =
dynamic_cast<PipelineWatch*
>(d);
375 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
378 d =
new PipelineWatch(pipeline,
this);
381void VideoWidget::stopPipelineWatch()
383 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
385 if (
dynamic_cast<PipelineWatch*
>(d)) {
391void VideoWidget::paintEvent(QPaintEvent *event)
394 p.fillRect(event->rect(), Qt::black);
RefPointer< X > dynamicCast() const
bool connect(void *instance, const char *detailedSignal, T *receiver, R(T::*slot)(Args...), ConnectFlags flags=0)
Wrappers for GStreamer classes.