src/3rdparty/phonon/ds9/videowidget.cpp
changeset 0 1918ee327afb
child 7 f7bc934e204c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5 This library is free software: you can redistribute it and/or modify
       
     6 it under the terms of the GNU Lesser General Public License as published by
       
     7 the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9 This library is distributed in the hope that it will be useful,
       
    10 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 GNU Lesser General Public License for more details.
       
    13 
       
    14 You should have received a copy of the GNU Lesser General Public License
       
    15 along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 #include "videowidget.h"
       
    19 
       
    20 #include <QtGui/QPainter>
       
    21 #include <QtGui/QPaintEvent>
       
    22 #include <QtCore/QTimer>
       
    23 #include <QtCore/QSettings>
       
    24 
       
    25 #include "mediaobject.h"
       
    26 
       
    27 #include "videorenderer_vmr9.h"
       
    28 #include "videorenderer_soft.h"
       
    29 
       
    30 QT_BEGIN_NAMESPACE
       
    31 
       
    32 #ifndef QT_NO_PHONON_VIDEO
       
    33 
       
    34 namespace Phonon
       
    35 {
       
    36     namespace DS9
       
    37     {
       
    38         //class used internally to return the widget where the video is shown on
       
    39         class VideoWindow : public QWidget
       
    40         {
       
    41         public:
       
    42             explicit VideoWindow(QWidget *parent, VideoWidget *vw)
       
    43                 : QWidget(parent), m_node(vw), m_currentRenderer(0)
       
    44             {
       
    45                 //default background color
       
    46                 setPalette(QPalette(Qt::black));                 
       
    47                 setAttribute(Qt::WA_OpaquePaintEvent, true);
       
    48                 setAttribute(Qt::WA_NoSystemBackground, true);
       
    49                 setAttribute(Qt::WA_PaintOnScreen, true);
       
    50                 setAutoFillBackground(false);
       
    51             }
       
    52 
       
    53             QPaintEngine* paintEngine() const
       
    54             {
       
    55                 return 0;
       
    56             }
       
    57 
       
    58             bool isEmbedded() const
       
    59             {
       
    60 #if QT_VERSION >= 0x040400
       
    61                 return window()->testAttribute(Qt::WA_DontShowOnScreen);
       
    62 #else
       
    63                 return false;
       
    64 #endif
       
    65             }
       
    66 
       
    67             bool needsSoftRendering() const
       
    68             {
       
    69                 QPaintDevice *dev = QPainter::redirected(this, 0);
       
    70                 return (dev && dev != this);
       
    71             }
       
    72 
       
    73             void resizeEvent(QResizeEvent *e)
       
    74             {
       
    75                 m_node->updateVideoSize();
       
    76                 QWidget::resizeEvent(e);
       
    77             }
       
    78 
       
    79             AbstractVideoRenderer *currentRenderer() const
       
    80             {
       
    81                 return m_currentRenderer;
       
    82             }
       
    83 
       
    84             void setCurrentRenderer(AbstractVideoRenderer *renderer)
       
    85             {
       
    86                 m_currentRenderer = renderer;
       
    87                 //we disallow repaint on that widget for just a fraction of second
       
    88                 //this allows better transition between videos
       
    89                 setUpdatesEnabled(false);
       
    90                 m_flickerFreeTimer.start(20, this);
       
    91             }
       
    92 
       
    93             void timerEvent(QTimerEvent *e)
       
    94             {
       
    95                 if (e->timerId() == m_flickerFreeTimer.timerId()) {
       
    96                     m_flickerFreeTimer.stop();
       
    97                     setUpdatesEnabled(true);
       
    98                 }
       
    99                 QWidget::timerEvent(e);
       
   100             }
       
   101 
       
   102             QSize sizeHint() const
       
   103             {
       
   104                 return m_currentRenderer->sizeHint().expandedTo(QWidget::sizeHint());
       
   105             }
       
   106 
       
   107             void changeEvent(QEvent *e)
       
   108             {
       
   109                 checkCurrentRenderingMode();
       
   110                 QWidget::changeEvent(e);
       
   111             }
       
   112 
       
   113             void setVisible(bool visible)
       
   114             {
       
   115                 checkCurrentRenderingMode();
       
   116                 QWidget::setVisible(visible);
       
   117             }
       
   118 
       
   119             void paintEvent(QPaintEvent *e)
       
   120             {
       
   121                 if (!updatesEnabled())
       
   122                     return; //this avoids repaint from native events
       
   123                 checkCurrentRenderingMode();
       
   124                 m_currentRenderer->repaintCurrentFrame(this, e->rect());
       
   125             }
       
   126 
       
   127             //this code manages the activation/deactivation of the screensaver
       
   128             /*bool event(QEvent *e)
       
   129             {
       
   130                 if (e->type() == QEvent::Resize) {
       
   131                     //we disable the screensaver if the video is in fullscreen mode
       
   132                     disableScreenSaver(window()->windowState() & Qt::WindowFullScreen);
       
   133                 }
       
   134                 return QWidget::event(e);
       
   135             }*/
       
   136 
       
   137         private:
       
   138             //for fullscreen mode
       
   139             void disableScreenSaver(bool b)
       
   140             {
       
   141                 const QLatin1String screenSaverActive("ScreenSaveActive");
       
   142                 QSettings settings( QLatin1String("HKEY_CURRENT_USER\\Control Panel\\Desktop"), QSettings::NativeFormat);
       
   143                 if (b) {
       
   144                     if (m_restoreScreenSaverActive.isNull()) {
       
   145                         //we store the value to be able to restore it later
       
   146                         m_restoreScreenSaverActive = settings.value(screenSaverActive);
       
   147                         settings.setValue(screenSaverActive, QString::number(!b));
       
   148                     }
       
   149                 } else if (!m_restoreScreenSaverActive.isNull()) {
       
   150                     //we restore the previous value
       
   151                     settings.setValue(screenSaverActive, m_restoreScreenSaverActive);
       
   152                 }
       
   153             }
       
   154 
       
   155             void checkCurrentRenderingMode()
       
   156             {
       
   157                 if (!m_currentRenderer)
       
   158                     return;
       
   159 
       
   160                 if (m_currentRenderer->isNative()) {
       
   161                     if (isEmbedded()) {
       
   162                         //we need to switch to software renderer
       
   163                         m_currentRenderer = m_node->switchRendering(m_currentRenderer);
       
   164                         setAttribute(Qt::WA_PaintOnScreen, false);
       
   165                     } else if (needsSoftRendering()) {
       
   166                         m_node->performSoftRendering(m_currentRenderer->snapshot());
       
   167                     }
       
   168                 } else if (!isEmbedded()) {
       
   169                     m_currentRenderer = m_node->switchRendering(m_currentRenderer);
       
   170                     setAttribute(Qt::WA_PaintOnScreen, false);
       
   171                 }
       
   172             }
       
   173 
       
   174             VideoWidget *m_node;
       
   175             AbstractVideoRenderer *m_currentRenderer;
       
   176             QVariant m_restoreScreenSaverActive;
       
   177             QBasicTimer m_flickerFreeTimer;
       
   178         };
       
   179 
       
   180         VideoWidget::VideoWidget(QWidget *parent)
       
   181             : BackendNode(parent), m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto),
       
   182               m_scaleMode(Phonon::VideoWidget::FitInView),
       
   183               m_brightness(0.), m_contrast(0.), m_hue(0.), m_saturation(0.), m_noNativeRendererSupported(false)
       
   184               
       
   185         {
       
   186             //initialisation of the widget
       
   187             m_widget = new VideoWindow(parent, this);
       
   188 
       
   189             //initialization of the renderers
       
   190             qMemSet(m_renderers, 0, sizeof(m_renderers));
       
   191 
       
   192             for(int i = 0; i< FILTER_COUNT ;++i) {
       
   193                 //This might return a non native (ie Qt) renderer in case native is not supported
       
   194                 AbstractVideoRenderer *renderer = getRenderer(i, Native, true);
       
   195                 m_filters[i] = renderer->getFilter();
       
   196             }
       
   197 
       
   198             //by default, we take the first VideoWindow object
       
   199             setCurrentGraph(0);
       
   200         }
       
   201 
       
   202         VideoWidget::~VideoWidget()
       
   203         {
       
   204             for (int i = 0; i < 4; ++i) {
       
   205                 delete m_renderers[i];
       
   206             }
       
   207         }
       
   208 
       
   209         void VideoWidget::notifyVideoLoaded()
       
   210         {
       
   211             updateVideoSize();
       
   212             m_widget->updateGeometry();
       
   213         }
       
   214 
       
   215         AbstractVideoRenderer *VideoWidget::switchRendering(AbstractVideoRenderer *current)
       
   216         {
       
   217             const bool toNative = !current->isNative();
       
   218             if (toNative && m_noNativeRendererSupported)
       
   219                 return current; //no switch here
       
   220 
       
   221             //firt we delete the renderer
       
   222             //initialization of the widgets
       
   223             for(int i = 0; i < FILTER_COUNT; ++i) {
       
   224                 Filter oldFilter = m_filters[i];
       
   225 
       
   226                 //Let's create a software renderer
       
   227                 AbstractVideoRenderer *renderer = getRenderer(i, toNative ? Native : NonNative, true);
       
   228 
       
   229                 if (m_mediaObject) {
       
   230                     m_mediaObject->switchFilters(i, oldFilter, renderer->getFilter());
       
   231                 }
       
   232 
       
   233                 m_filters[i] = renderer->getFilter();
       
   234             }
       
   235 
       
   236             return getRenderer(mediaObject()->currentGraph()->index(), toNative ? Native: NonNative);
       
   237         }
       
   238 
       
   239         void VideoWidget::performSoftRendering(const QImage &currentImage)
       
   240         {
       
   241             const int graphIndex = mediaObject()->currentGraph()->index();
       
   242             VideoRendererSoft *r = static_cast<VideoRendererSoft*>(getRenderer(graphIndex, NonNative, true /*autocreation*/));
       
   243             r->setSnapshot(currentImage);
       
   244             r->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
       
   245             r->repaintCurrentFrame(m_widget, m_widget->rect());
       
   246 
       
   247         }
       
   248 
       
   249         void VideoWidget::setCurrentGraph(int index)
       
   250         {
       
   251             for(int i = 0; i < 2; ++i) {
       
   252                 if (AbstractVideoRenderer *renderer = getRenderer(i, Native))
       
   253                     renderer->setActive(index == i);
       
   254             }
       
   255 
       
   256             //be sure to update all the things that needs an update
       
   257             applyMixerSettings();
       
   258             updateVideoSize();
       
   259 
       
   260             AbstractVideoRenderer *r = m_widget->currentRenderer();
       
   261 
       
   262             //we determine dynamically if it is native or non native
       
   263             r = getRenderer(index, !r || r->isNative() ? Native : NonNative);
       
   264 			if (!r)
       
   265 				r = getRenderer(index, NonNative);
       
   266             m_widget->setCurrentRenderer(r);
       
   267         }
       
   268 
       
   269 
       
   270         Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
       
   271         {
       
   272             return m_aspectRatio;
       
   273         }
       
   274 
       
   275         void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio)
       
   276         {
       
   277             m_aspectRatio = aspectRatio;
       
   278             updateVideoSize();
       
   279             m_widget->update();
       
   280         }
       
   281 
       
   282         Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
       
   283         {
       
   284             return m_scaleMode;
       
   285         }
       
   286 
       
   287 
       
   288         QWidget *VideoWidget::widget()
       
   289         {
       
   290             return m_widget;
       
   291         }
       
   292 
       
   293 
       
   294         void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
       
   295         {
       
   296             m_scaleMode = scaleMode;
       
   297             updateVideoSize();
       
   298             m_widget->update();
       
   299         }
       
   300 
       
   301         void VideoWidget::setBrightness(qreal b)
       
   302         {
       
   303             m_brightness = b;
       
   304             applyMixerSettings();
       
   305         }
       
   306 
       
   307         void VideoWidget::setContrast(qreal c)
       
   308         {
       
   309             m_contrast = c;
       
   310             applyMixerSettings();
       
   311         }
       
   312 
       
   313         void VideoWidget::setHue(qreal h)
       
   314         {
       
   315             m_hue = h;
       
   316             applyMixerSettings();
       
   317         }
       
   318 
       
   319         void VideoWidget::setSaturation(qreal s)
       
   320         {
       
   321             m_saturation = s;
       
   322             applyMixerSettings();
       
   323         }
       
   324 
       
   325         qreal VideoWidget::brightness() const
       
   326         {
       
   327             return m_brightness;
       
   328         }
       
   329 
       
   330 
       
   331         qreal VideoWidget::contrast() const
       
   332         {
       
   333             return m_contrast;
       
   334         }
       
   335 
       
   336         qreal VideoWidget::hue() const
       
   337         {
       
   338             return m_hue;
       
   339         }
       
   340 
       
   341         qreal VideoWidget::saturation() const
       
   342         {
       
   343             return m_saturation;
       
   344         }
       
   345 
       
   346 
       
   347         AbstractVideoRenderer *VideoWidget::getRenderer(int graphIndex, RendererType type, bool autoCreate)
       
   348         {
       
   349             int index = graphIndex * 2 + type;
       
   350             if (m_renderers[index] == 0 && autoCreate) {
       
   351                 AbstractVideoRenderer *renderer = 0;
       
   352 				if (type == Native) {
       
   353                     renderer = new VideoRendererVMR9(m_widget);
       
   354                     if (renderer->getFilter() == 0) {
       
   355                         //instanciating the renderer might fail with error VFW_E_DDRAW_CAPS_NOT_SUITABLE (0x80040273)
       
   356                         m_noNativeRendererSupported = true;
       
   357                         delete renderer;
       
   358                         renderer = 0;
       
   359                     }
       
   360                 }
       
   361 
       
   362                 if (renderer == 0) {
       
   363                     type = NonNative;
       
   364                     index = graphIndex * 2 + type;
       
   365                     if (m_renderers[index] == 0)
       
   366                         renderer = new VideoRendererSoft(m_widget); //this always succeeds
       
   367                     else
       
   368                         renderer = m_renderers[index];
       
   369                 }
       
   370 
       
   371                 m_renderers[index] = renderer;
       
   372 
       
   373                 //be sure to update all the things that needs an update
       
   374                 applyMixerSettings();
       
   375                 updateVideoSize();
       
   376 
       
   377             }
       
   378             return m_renderers[index];
       
   379         }
       
   380 
       
   381         //this must be called whe nthe node is actually connected
       
   382         void  VideoWidget::applyMixerSettings() const
       
   383         {
       
   384             for (int i = 0; i < 4; ++i) {
       
   385                 if (AbstractVideoRenderer *renderer = m_renderers[i])
       
   386                     renderer->applyMixerSettings(m_brightness, m_contrast, m_hue, m_saturation);
       
   387             }
       
   388         }
       
   389 
       
   390         void VideoWidget::connected(BackendNode *, const InputPin&)
       
   391         {
       
   392             //in case of a connection, we simply reapply the mixer settings
       
   393             applyMixerSettings();
       
   394             updateVideoSize();
       
   395         }
       
   396 
       
   397         void VideoWidget::updateVideoSize() const
       
   398         {
       
   399             for (int i = 0; i < 4; ++i) {
       
   400                 if (AbstractVideoRenderer *renderer = m_renderers[i])
       
   401                     renderer->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
       
   402             }
       
   403         }
       
   404 
       
   405 
       
   406 
       
   407     }
       
   408 }
       
   409 
       
   410 #endif //QT_NO_PHONON_VIDEO
       
   411 
       
   412 QT_END_NAMESPACE
       
   413 
       
   414 #include "moc_videowidget.cpp"