QtGStreamer 0.10.1
|
00001 /* 00002 Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> 00003 Copyright (C) 2011 Collabora Ltd. 00004 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> 00005 00006 This library is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU Lesser General Public License as published 00008 by the Free Software Foundation; either version 2.1 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU Lesser General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 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(); //create a new X window (if we are on X11 with alien widgets) 00053 QApplication::syncX(); //inform other applications about the new window (on X11) 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 //GValue of G_TYPE_POINTER can only be set as void* in the bindings 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 //release the sink when it goes back to null state 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 } //namespace Ui 00282 } //namespace QGst