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