00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "videowidget.h"
00020 #include "../xoverlay.h"
00021 #include "../pipeline.h"
00022 #include "../bus.h"
00023 #include "../message.h"
00024 #include "../../QGlib/connect.h"
00025 #include <QtCore/QDebug>
00026 #include <QtCore/QMutex>
00027 #include <QtCore/QThread>
00028 #include <QtGui/QPainter>
00029 #include <QtGui/QPaintEvent>
00030 #include <QtGui/QResizeEvent>
00031 #include <QtGui/QApplication>
00032
00033 namespace QGst {
00034 namespace Ui {
00035
00036 class AbstractRenderer
00037 {
00038 public:
00039 static AbstractRenderer *create(const ElementPtr & sink, QWidget *videoWidget);
00040
00041 virtual ~AbstractRenderer() {}
00042 virtual ElementPtr videoSink() const = 0;
00043 };
00044
00045
00046 class XOverlayRenderer : public QObject, public AbstractRenderer
00047 {
00048 public:
00049 XOverlayRenderer(QWidget *parent)
00050 : QObject(parent)
00051 {
00052 m_windowId = widget()->winId();
00053 QApplication::syncX();
00054
00055 widget()->installEventFilter(this);
00056 widget()->setAttribute(Qt::WA_NoSystemBackground, true);
00057 widget()->setAttribute(Qt::WA_PaintOnScreen, true);
00058 widget()->update();
00059 }
00060
00061 virtual ~XOverlayRenderer()
00062 {
00063 if (m_sink) {
00064 m_sink->setWindowHandle(0);
00065 }
00066 widget()->removeEventFilter(this);
00067 widget()->setAttribute(Qt::WA_NoSystemBackground, false);
00068 widget()->setAttribute(Qt::WA_PaintOnScreen, false);
00069 widget()->update();
00070 }
00071
00072 void setVideoSink(const XOverlayPtr & sink)
00073 {
00074 QMutexLocker l(&m_sinkMutex);
00075 if (m_sink) {
00076 m_sink->setWindowHandle(0);
00077 }
00078 m_sink = sink;
00079 if (m_sink) {
00080 m_sink->setWindowHandle(m_windowId);
00081 }
00082 }
00083
00084 virtual ElementPtr videoSink() const
00085 {
00086 QMutexLocker l(&m_sinkMutex);
00087 return m_sink.dynamicCast<Element>();
00088 }
00089
00090 protected:
00091 virtual bool eventFilter(QObject *filteredObject, QEvent *event)
00092 {
00093 if (filteredObject == parent() && event->type() == QEvent::Paint) {
00094 QMutexLocker l(&m_sinkMutex);
00095 State currentState = m_sink ? m_sink.dynamicCast<Element>()->currentState() : StateNull;
00096
00097 if (currentState == StatePlaying || currentState == StatePaused) {
00098 m_sink->expose();
00099 } else {
00100 QPainter p(widget());
00101 p.fillRect(widget()->rect(), Qt::black);
00102 }
00103 return true;
00104 } else {
00105 return QObject::eventFilter(filteredObject, event);
00106 }
00107 }
00108
00109 private:
00110 inline QWidget *widget() { return static_cast<QWidget*>(parent()); }
00111 WId m_windowId;
00112 mutable QMutex m_sinkMutex;
00113 XOverlayPtr m_sink;
00114 };
00115
00116
00117 class QWidgetVideoSinkRenderer : public AbstractRenderer
00118 {
00119 public:
00120 QWidgetVideoSinkRenderer(const ElementPtr & sink, QWidget *parent)
00121 : m_sink(sink)
00122 {
00123
00124 m_sink->setProperty<void*>("widget", parent);
00125 }
00126
00127 virtual ~QWidgetVideoSinkRenderer()
00128 {
00129 m_sink->setProperty<void*>("widget", NULL);
00130 }
00131
00132 virtual ElementPtr videoSink() const { return m_sink; }
00133
00134 private:
00135 ElementPtr m_sink;
00136 };
00137
00138
00139 class PipelineWatch : public QObject, public AbstractRenderer
00140 {
00141 public:
00142 PipelineWatch(const PipelinePtr & pipeline, QWidget *parent)
00143 : QObject(parent), m_renderer(new XOverlayRenderer(parent)), m_pipeline(pipeline)
00144 {
00145 pipeline->bus()->enableSyncMessageEmission();
00146 QGlib::connect(pipeline->bus(), "sync-message",
00147 this, &PipelineWatch::onBusSyncMessage);
00148 }
00149
00150 virtual ~PipelineWatch()
00151 {
00152 m_pipeline->bus()->disableSyncMessageEmission();
00153 delete m_renderer;
00154 }
00155
00156 virtual ElementPtr videoSink() const { return m_renderer->videoSink(); }
00157
00158 void releaseSink() { m_renderer->setVideoSink(XOverlayPtr()); }
00159
00160 private:
00161 void onBusSyncMessage(const MessagePtr & msg)
00162 {
00163 switch (msg->type()) {
00164 case MessageElement:
00165 if (msg->internalStructure()->name() == QLatin1String("prepare-xwindow-id")) {
00166 XOverlayPtr overlay = msg->source().dynamicCast<XOverlay>();
00167 m_renderer->setVideoSink(overlay);
00168 }
00169 break;
00170 case MessageStateChanged:
00171
00172 if (msg.staticCast<StateChangedMessage>()->newState() == StateNull &&
00173 msg->source() == m_renderer->videoSink())
00174 {
00175 releaseSink();
00176 }
00177 default:
00178 break;
00179 }
00180 }
00181
00182 private:
00183 XOverlayRenderer *m_renderer;
00184 PipelinePtr m_pipeline;
00185 };
00186
00187
00188 AbstractRenderer *AbstractRenderer::create(const ElementPtr & sink, QWidget *videoWidget)
00189 {
00190 XOverlayPtr overlay = sink.dynamicCast<XOverlay>();
00191 if (overlay) {
00192 XOverlayRenderer *r = new XOverlayRenderer(videoWidget);
00193 r->setVideoSink(overlay);
00194 return r;
00195 }
00196
00197 if (QGlib::Type::fromInstance(sink).name() == QLatin1String("GstQWidgetVideoSink")) {
00198 return new QWidgetVideoSinkRenderer(sink, videoWidget);
00199 }
00200
00201 return NULL;
00202 }
00203
00204
00205 VideoWidget::VideoWidget(QWidget *parent, Qt::WindowFlags f)
00206 : QWidget(parent, f), d(NULL)
00207 {
00208 }
00209
00210 VideoWidget::~VideoWidget()
00211 {
00212 delete d;
00213 }
00214
00215 ElementPtr VideoWidget::videoSink() const
00216 {
00217 return d ? d->videoSink() : ElementPtr();
00218 }
00219
00220 void VideoWidget::setVideoSink(const ElementPtr & sink)
00221 {
00222 if (!sink) {
00223 releaseVideoSink();
00224 return;
00225 }
00226
00227 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
00228 Q_ASSERT(d == NULL);
00229
00230 d = AbstractRenderer::create(sink, this);
00231
00232 if (!d) {
00233 qCritical() << "QGst::Ui::VideoWidget: Could not construct a renderer for the specified element";
00234 }
00235 }
00236
00237 void VideoWidget::releaseVideoSink()
00238 {
00239 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
00240
00241 if (d) {
00242 PipelineWatch *pw = dynamic_cast<PipelineWatch*>(d);
00243 if (pw) {
00244 pw->releaseSink();
00245 } else {
00246 delete d;
00247 d = NULL;
00248 }
00249 }
00250 }
00251
00252 void VideoWidget::watchPipeline(const PipelinePtr & pipeline)
00253 {
00254 if (!pipeline) {
00255 stopPipelineWatch();
00256 return;
00257 }
00258
00259 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
00260 Q_ASSERT(d == NULL);
00261
00262 d = new PipelineWatch(pipeline, this);
00263 }
00264
00265 void VideoWidget::stopPipelineWatch()
00266 {
00267 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
00268
00269 if (dynamic_cast<PipelineWatch*>(d)) {
00270 delete d;
00271 d = NULL;
00272 }
00273 }
00274
00275 void VideoWidget::paintEvent(QPaintEvent *event)
00276 {
00277 QPainter p(this);
00278 p.fillRect(event->rect(), Qt::black);
00279 }
00280
00281 }
00282 }