util/src/3rdparty/phonon/ds9/videowidget.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     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             if (!mediaObject())
       
   222                 return current;
       
   223 
       
   224             //firt we delete the renderer
       
   225             //initialization of the widgets
       
   226             for(int i = 0; i < FILTER_COUNT; ++i) {
       
   227                 Filter oldFilter = m_filters[i];
       
   228 
       
   229                 //Let's create a software renderer
       
   230                 AbstractVideoRenderer *renderer = getRenderer(i, toNative ? Native : NonNative, true);
       
   231 
       
   232                 if (m_mediaObject) {
       
   233                     m_mediaObject->switchFilters(i, oldFilter, renderer->getFilter());
       
   234                 }
       
   235 
       
   236                 m_filters[i] = renderer->getFilter();
       
   237             }
       
   238 
       
   239             return getRenderer(mediaObject()->currentGraph()->index(), toNative ? Native: NonNative);
       
   240         }
       
   241 
       
   242         void VideoWidget::performSoftRendering(const QImage &currentImage)
       
   243         {
       
   244             const int graphIndex = mediaObject()->currentGraph()->index();
       
   245             VideoRendererSoft *r = static_cast<VideoRendererSoft*>(getRenderer(graphIndex, NonNative, true /*autocreation*/));
       
   246             r->setSnapshot(currentImage);
       
   247             r->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
       
   248             r->repaintCurrentFrame(m_widget, m_widget->rect());
       
   249 
       
   250         }
       
   251 
       
   252         void VideoWidget::setCurrentGraph(int index)
       
   253         {
       
   254             for(int i = 0; i < 2; ++i) {
       
   255                 if (AbstractVideoRenderer *renderer = getRenderer(i, Native))
       
   256                     renderer->setActive(index == i);
       
   257             }
       
   258 
       
   259             //be sure to update all the things that needs an update
       
   260             applyMixerSettings();
       
   261             updateVideoSize();
       
   262 
       
   263             AbstractVideoRenderer *r = m_widget->currentRenderer();
       
   264 
       
   265             //we determine dynamically if it is native or non native
       
   266             r = getRenderer(index, !r || r->isNative() ? Native : NonNative);
       
   267 			if (!r)
       
   268 				r = getRenderer(index, NonNative);
       
   269             m_widget->setCurrentRenderer(r);
       
   270         }
       
   271 
       
   272 
       
   273         Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
       
   274         {
       
   275             return m_aspectRatio;
       
   276         }
       
   277 
       
   278         void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio)
       
   279         {
       
   280             m_aspectRatio = aspectRatio;
       
   281             updateVideoSize();
       
   282             m_widget->update();
       
   283         }
       
   284 
       
   285         Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
       
   286         {
       
   287             return m_scaleMode;
       
   288         }
       
   289 
       
   290 
       
   291         QWidget *VideoWidget::widget()
       
   292         {
       
   293             return m_widget;
       
   294         }
       
   295 
       
   296 
       
   297         void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
       
   298         {
       
   299             m_scaleMode = scaleMode;
       
   300             updateVideoSize();
       
   301             m_widget->update();
       
   302         }
       
   303 
       
   304         void VideoWidget::setBrightness(qreal b)
       
   305         {
       
   306             m_brightness = b;
       
   307             applyMixerSettings();
       
   308         }
       
   309 
       
   310         void VideoWidget::setContrast(qreal c)
       
   311         {
       
   312             m_contrast = c;
       
   313             applyMixerSettings();
       
   314         }
       
   315 
       
   316         void VideoWidget::setHue(qreal h)
       
   317         {
       
   318             m_hue = h;
       
   319             applyMixerSettings();
       
   320         }
       
   321 
       
   322         void VideoWidget::setSaturation(qreal s)
       
   323         {
       
   324             m_saturation = s;
       
   325             applyMixerSettings();
       
   326         }
       
   327 
       
   328         qreal VideoWidget::brightness() const
       
   329         {
       
   330             return m_brightness;
       
   331         }
       
   332 
       
   333 
       
   334         qreal VideoWidget::contrast() const
       
   335         {
       
   336             return m_contrast;
       
   337         }
       
   338 
       
   339         qreal VideoWidget::hue() const
       
   340         {
       
   341             return m_hue;
       
   342         }
       
   343 
       
   344         qreal VideoWidget::saturation() const
       
   345         {
       
   346             return m_saturation;
       
   347         }
       
   348 
       
   349 
       
   350         AbstractVideoRenderer *VideoWidget::getRenderer(int graphIndex, RendererType type, bool autoCreate)
       
   351         {
       
   352             int index = graphIndex * 2 + type;
       
   353             if (m_renderers[index] == 0 && autoCreate) {
       
   354                 AbstractVideoRenderer *renderer = 0;
       
   355 				if (type == Native) {
       
   356                     renderer = new VideoRendererVMR9(m_widget);
       
   357                     if (renderer->getFilter() == 0) {
       
   358                         //instanciating the renderer might fail with error VFW_E_DDRAW_CAPS_NOT_SUITABLE (0x80040273)
       
   359                         m_noNativeRendererSupported = true;
       
   360                         delete renderer;
       
   361                         renderer = 0;
       
   362                     }
       
   363                 }
       
   364 
       
   365                 if (renderer == 0) {
       
   366                     type = NonNative;
       
   367                     index = graphIndex * 2 + type;
       
   368                     if (m_renderers[index] == 0)
       
   369                         renderer = new VideoRendererSoft(m_widget); //this always succeeds
       
   370                     else
       
   371                         renderer = m_renderers[index];
       
   372                 }
       
   373 
       
   374                 m_renderers[index] = renderer;
       
   375 
       
   376                 //be sure to update all the things that needs an update
       
   377                 applyMixerSettings();
       
   378                 updateVideoSize();
       
   379 
       
   380             }
       
   381             return m_renderers[index];
       
   382         }
       
   383 
       
   384         //this must be called whe nthe node is actually connected
       
   385         void  VideoWidget::applyMixerSettings() const
       
   386         {
       
   387             for (int i = 0; i < 4; ++i) {
       
   388                 if (AbstractVideoRenderer *renderer = m_renderers[i])
       
   389                     renderer->applyMixerSettings(m_brightness, m_contrast, m_hue, m_saturation);
       
   390             }
       
   391         }
       
   392 
       
   393         void VideoWidget::connected(BackendNode *, const InputPin&)
       
   394         {
       
   395             //in case of a connection, we simply reapply the mixer settings
       
   396             applyMixerSettings();
       
   397             updateVideoSize();
       
   398         }
       
   399 
       
   400         void VideoWidget::updateVideoSize() const
       
   401         {
       
   402             for (int i = 0; i < 4; ++i) {
       
   403                 if (AbstractVideoRenderer *renderer = m_renderers[i])
       
   404                     renderer->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
       
   405             }
       
   406         }
       
   407 
       
   408 
       
   409 
       
   410     }
       
   411 }
       
   412 
       
   413 #endif //QT_NO_PHONON_VIDEO
       
   414 
       
   415 QT_END_NAMESPACE
       
   416 
       
   417 #include "moc_videowidget.cpp"