/* This file is part of the KDE project. Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 or 3 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "videowidget.h" #include #include #include #include #include "mediaobject.h" #include "videorenderer_vmr9.h" #include "videorenderer_soft.h" QT_BEGIN_NAMESPACE #ifndef QT_NO_PHONON_VIDEO namespace Phonon { namespace DS9 { //class used internally to return the widget where the video is shown on class VideoWindow : public QWidget { public: explicit VideoWindow(QWidget *parent, VideoWidget *vw) : QWidget(parent), m_node(vw), m_currentRenderer(0) { //default background color setPalette(QPalette(Qt::black)); setAttribute(Qt::WA_OpaquePaintEvent, true); setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_PaintOnScreen, true); setAutoFillBackground(false); } QPaintEngine* paintEngine() const { return 0; } bool isEmbedded() const { #if QT_VERSION >= 0x040400 return window()->testAttribute(Qt::WA_DontShowOnScreen); #else return false; #endif } bool needsSoftRendering() const { QPaintDevice *dev = QPainter::redirected(this, 0); return (dev && dev != this); } void resizeEvent(QResizeEvent *e) { m_node->updateVideoSize(); QWidget::resizeEvent(e); } AbstractVideoRenderer *currentRenderer() const { return m_currentRenderer; } void setCurrentRenderer(AbstractVideoRenderer *renderer) { m_currentRenderer = renderer; //we disallow repaint on that widget for just a fraction of second //this allows better transition between videos setUpdatesEnabled(false); m_flickerFreeTimer.start(20, this); } void timerEvent(QTimerEvent *e) { if (e->timerId() == m_flickerFreeTimer.timerId()) { m_flickerFreeTimer.stop(); setUpdatesEnabled(true); } QWidget::timerEvent(e); } QSize sizeHint() const { return m_currentRenderer->sizeHint().expandedTo(QWidget::sizeHint()); } void changeEvent(QEvent *e) { checkCurrentRenderingMode(); QWidget::changeEvent(e); } void setVisible(bool visible) { checkCurrentRenderingMode(); QWidget::setVisible(visible); } void paintEvent(QPaintEvent *e) { if (!updatesEnabled()) return; //this avoids repaint from native events checkCurrentRenderingMode(); m_currentRenderer->repaintCurrentFrame(this, e->rect()); } //this code manages the activation/deactivation of the screensaver /*bool event(QEvent *e) { if (e->type() == QEvent::Resize) { //we disable the screensaver if the video is in fullscreen mode disableScreenSaver(window()->windowState() & Qt::WindowFullScreen); } return QWidget::event(e); }*/ private: //for fullscreen mode void disableScreenSaver(bool b) { const QLatin1String screenSaverActive("ScreenSaveActive"); QSettings settings( QLatin1String("HKEY_CURRENT_USER\\Control Panel\\Desktop"), QSettings::NativeFormat); if (b) { if (m_restoreScreenSaverActive.isNull()) { //we store the value to be able to restore it later m_restoreScreenSaverActive = settings.value(screenSaverActive); settings.setValue(screenSaverActive, QString::number(!b)); } } else if (!m_restoreScreenSaverActive.isNull()) { //we restore the previous value settings.setValue(screenSaverActive, m_restoreScreenSaverActive); } } void checkCurrentRenderingMode() { if (!m_currentRenderer) return; if (m_currentRenderer->isNative()) { if (isEmbedded()) { //we need to switch to software renderer m_currentRenderer = m_node->switchRendering(m_currentRenderer); setAttribute(Qt::WA_PaintOnScreen, false); } else if (needsSoftRendering()) { m_node->performSoftRendering(m_currentRenderer->snapshot()); } } else if (!isEmbedded()) { m_currentRenderer = m_node->switchRendering(m_currentRenderer); setAttribute(Qt::WA_PaintOnScreen, false); } } VideoWidget *m_node; AbstractVideoRenderer *m_currentRenderer; QVariant m_restoreScreenSaverActive; QBasicTimer m_flickerFreeTimer; }; VideoWidget::VideoWidget(QWidget *parent) : BackendNode(parent), m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto), m_scaleMode(Phonon::VideoWidget::FitInView), m_brightness(0.), m_contrast(0.), m_hue(0.), m_saturation(0.), m_noNativeRendererSupported(false) { //initialisation of the widget m_widget = new VideoWindow(parent, this); //initialization of the renderers qMemSet(m_renderers, 0, sizeof(m_renderers)); for(int i = 0; i< FILTER_COUNT ;++i) { //This might return a non native (ie Qt) renderer in case native is not supported AbstractVideoRenderer *renderer = getRenderer(i, Native, true); m_filters[i] = renderer->getFilter(); } //by default, we take the first VideoWindow object setCurrentGraph(0); } VideoWidget::~VideoWidget() { for (int i = 0; i < 4; ++i) { delete m_renderers[i]; } } void VideoWidget::notifyVideoLoaded() { updateVideoSize(); m_widget->updateGeometry(); } AbstractVideoRenderer *VideoWidget::switchRendering(AbstractVideoRenderer *current) { const bool toNative = !current->isNative(); if (toNative && m_noNativeRendererSupported) return current; //no switch here if (!mediaObject()) return current; //firt we delete the renderer //initialization of the widgets for(int i = 0; i < FILTER_COUNT; ++i) { Filter oldFilter = m_filters[i]; //Let's create a software renderer AbstractVideoRenderer *renderer = getRenderer(i, toNative ? Native : NonNative, true); if (m_mediaObject) { m_mediaObject->switchFilters(i, oldFilter, renderer->getFilter()); } m_filters[i] = renderer->getFilter(); } return getRenderer(mediaObject()->currentGraph()->index(), toNative ? Native: NonNative); } void VideoWidget::performSoftRendering(const QImage ¤tImage) { const int graphIndex = mediaObject()->currentGraph()->index(); VideoRendererSoft *r = static_cast(getRenderer(graphIndex, NonNative, true /*autocreation*/)); r->setSnapshot(currentImage); r->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode); r->repaintCurrentFrame(m_widget, m_widget->rect()); } void VideoWidget::setCurrentGraph(int index) { for(int i = 0; i < 2; ++i) { if (AbstractVideoRenderer *renderer = getRenderer(i, Native)) renderer->setActive(index == i); } //be sure to update all the things that needs an update applyMixerSettings(); updateVideoSize(); AbstractVideoRenderer *r = m_widget->currentRenderer(); //we determine dynamically if it is native or non native r = getRenderer(index, !r || r->isNative() ? Native : NonNative); if (!r) r = getRenderer(index, NonNative); m_widget->setCurrentRenderer(r); } Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const { return m_aspectRatio; } void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio) { m_aspectRatio = aspectRatio; updateVideoSize(); m_widget->update(); } Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const { return m_scaleMode; } QWidget *VideoWidget::widget() { return m_widget; } void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode) { m_scaleMode = scaleMode; updateVideoSize(); m_widget->update(); } void VideoWidget::setBrightness(qreal b) { m_brightness = b; applyMixerSettings(); } void VideoWidget::setContrast(qreal c) { m_contrast = c; applyMixerSettings(); } void VideoWidget::setHue(qreal h) { m_hue = h; applyMixerSettings(); } void VideoWidget::setSaturation(qreal s) { m_saturation = s; applyMixerSettings(); } qreal VideoWidget::brightness() const { return m_brightness; } qreal VideoWidget::contrast() const { return m_contrast; } qreal VideoWidget::hue() const { return m_hue; } qreal VideoWidget::saturation() const { return m_saturation; } AbstractVideoRenderer *VideoWidget::getRenderer(int graphIndex, RendererType type, bool autoCreate) { int index = graphIndex * 2 + type; if (m_renderers[index] == 0 && autoCreate) { AbstractVideoRenderer *renderer = 0; if (type == Native) { renderer = new VideoRendererVMR9(m_widget); if (renderer->getFilter() == 0) { //instanciating the renderer might fail with error VFW_E_DDRAW_CAPS_NOT_SUITABLE (0x80040273) m_noNativeRendererSupported = true; delete renderer; renderer = 0; } } if (renderer == 0) { type = NonNative; index = graphIndex * 2 + type; if (m_renderers[index] == 0) renderer = new VideoRendererSoft(m_widget); //this always succeeds else renderer = m_renderers[index]; } m_renderers[index] = renderer; //be sure to update all the things that needs an update applyMixerSettings(); updateVideoSize(); } return m_renderers[index]; } //this must be called whe nthe node is actually connected void VideoWidget::applyMixerSettings() const { for (int i = 0; i < 4; ++i) { if (AbstractVideoRenderer *renderer = m_renderers[i]) renderer->applyMixerSettings(m_brightness, m_contrast, m_hue, m_saturation); } } void VideoWidget::connected(BackendNode *, const InputPin&) { //in case of a connection, we simply reapply the mixer settings applyMixerSettings(); updateVideoSize(); } void VideoWidget::updateVideoSize() const { for (int i = 0; i < 4; ++i) { if (AbstractVideoRenderer *renderer = m_renderers[i]) renderer->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode); } } } } #endif //QT_NO_PHONON_VIDEO QT_END_NAMESPACE #include "moc_videowidget.cpp"