Home | History | Annotate | Download | only in qt
      1 /*
      2     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      3     Copyright (C) 2009 Apple Inc. All rights reserved.
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public License
     16     along with this library; see the file COPYING.LIB.  If not, write to
     17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18     Boston, MA 02110-1301, USA.
     19 */
     20 
     21 #include "config.h"
     22 #include "MediaPlayerPrivatePhonon.h"
     23 
     24 #include <limits>
     25 
     26 #include "CString.h"
     27 #include "FrameView.h"
     28 #include "GraphicsContext.h"
     29 #include "NotImplemented.h"
     30 #include "TimeRanges.h"
     31 #include "Widget.h"
     32 #include <wtf/HashSet.h>
     33 
     34 #include <QDebug>
     35 #include <QPainter>
     36 #include <QWidget>
     37 #include <QMetaEnum>
     38 #include <QUrl>
     39 #include <QEvent>
     40 
     41 #include <phonon/path.h>
     42 #include <phonon/audiooutput.h>
     43 #include <phonon/mediaobject.h>
     44 #include <phonon/videowidget.h>
     45 
     46 using namespace Phonon;
     47 
     48 #define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData()))
     49 
     50 #if !LOG_DISABLED
     51 static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject)
     52 {
     53     QByteArray byteArray;
     54     QTextStream stream(&byteArray);
     55 
     56     const QMetaObject* metaObj = mediaPlayer->metaObject();
     57     QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
     58 
     59     stream << "debugMediaObject -> Phonon::MediaObject(";
     60     stream << "State: " << phononStates.valueToKey(mediaObject.state());
     61     stream << " | Current time: " << mediaObject.currentTime();
     62     stream << " | Remaining time: " << mediaObject.remainingTime();
     63     stream << " | Total time: " << mediaObject.totalTime();
     64     stream << " | Meta-data: ";
     65     QMultiMap<QString, QString> map = mediaObject.metaData();
     66     for (QMap<QString, QString>::const_iterator it = map.constBegin();
     67         it != map.constEnd(); ++it) {
     68         stream << "(" << it.key() << ", " << it.value() << ")";
     69     }
     70     stream << " | Has video: " << mediaObject.hasVideo();
     71     stream << " | Is seekable: " << mediaObject.isSeekable();
     72     stream << ")";
     73 
     74     stream.flush();
     75 
     76     return byteArray;
     77 }
     78 #endif
     79 
     80 using namespace WTF;
     81 
     82 namespace WebCore {
     83 
     84 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
     85     : m_player(player)
     86     , m_networkState(MediaPlayer::Empty)
     87     , m_readyState(MediaPlayer::HaveNothing)
     88     , m_mediaObject(new MediaObject())
     89     , m_videoWidget(new VideoWidget(0))
     90     , m_audioOutput(new AudioOutput())
     91     , m_isVisible(false)
     92 {
     93     // Hint to Phonon to disable overlay painting
     94     m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
     95     m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false);
     96 
     97     createPath(m_mediaObject, m_videoWidget);
     98     createPath(m_mediaObject, m_audioOutput);
     99 
    100     // Make sure we get updates for each frame
    101     m_videoWidget->installEventFilter(this);
    102     foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget))
    103         widget->installEventFilter(this);
    104 
    105     connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
    106             this, SLOT(stateChanged(Phonon::State,Phonon::State)));
    107     connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
    108     connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
    109     connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool)));
    110     connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int)));
    111     connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished()));
    112     connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
    113             this, SLOT(currentSourceChanged(Phonon::MediaSource)));
    114     connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
    115     connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
    116 }
    117 
    118 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
    119 {
    120     return new MediaPlayerPrivate(player);
    121 }
    122 
    123 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
    124 {
    125     if (isAvailable())
    126         registrar(create, getSupportedTypes, supportsType);
    127 }
    128 
    129 
    130 MediaPlayerPrivate::~MediaPlayerPrivate()
    131 {
    132     LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
    133     m_videoWidget->close();
    134     delete m_videoWidget;
    135     m_videoWidget = 0;
    136 
    137     LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting audiooutput");
    138     delete m_audioOutput;
    139     m_audioOutput = 0;
    140 
    141     LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting mediaobject");
    142     delete m_mediaObject;
    143     m_mediaObject = 0;
    144 }
    145 
    146 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
    147 {
    148     notImplemented();
    149 }
    150 
    151 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&)
    152 {
    153     // FIXME: do the real thing
    154     notImplemented();
    155     return MediaPlayer::IsNotSupported;
    156 }
    157 
    158 bool MediaPlayerPrivate::hasVideo() const
    159 {
    160     bool hasVideo = m_mediaObject->hasVideo();
    161     LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false");
    162     return hasVideo;
    163 }
    164 
    165 bool MediaPlayerPrivate::hasAudio() const
    166 {
    167     // FIXME: Phonon::MediaObject does not have such a hasAudio() function
    168     bool hasAudio = true;
    169     LOG(Media, "MediaPlayerPrivatePhonon::hasAudio() -> %s", hasAudio ? "true" : "false");
    170     return hasAudio;
    171 }
    172 
    173 void MediaPlayerPrivate::load(const String& url)
    174 {
    175     LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
    176 
    177     // We are now loading
    178     if (m_networkState != MediaPlayer::Loading) {
    179         m_networkState = MediaPlayer::Loading;
    180         m_player->networkStateChanged();
    181     }
    182 
    183     // And we don't have any data yet
    184     if (m_readyState != MediaPlayer::HaveNothing) {
    185         m_readyState = MediaPlayer::HaveNothing;
    186         m_player->readyStateChanged();
    187     }
    188 
    189     m_mediaObject->setCurrentSource(QUrl(url));
    190     m_audioOutput->setVolume(m_player->volume());
    191     setVisible(m_player->visible());
    192 }
    193 
    194 void MediaPlayerPrivate::cancelLoad()
    195 {
    196     notImplemented();
    197 }
    198 
    199 
    200 void MediaPlayerPrivate::play()
    201 {
    202     LOG(Media, "MediaPlayerPrivatePhonon::play()");
    203     m_mediaObject->play();
    204 }
    205 
    206 void MediaPlayerPrivate::pause()
    207 {
    208     LOG(Media, "MediaPlayerPrivatePhonon::pause()");
    209     m_mediaObject->pause();
    210 }
    211 
    212 
    213 bool MediaPlayerPrivate::paused() const
    214 {
    215     bool paused = m_mediaObject->state() == Phonon::PausedState;
    216     LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false");
    217     return paused;
    218 }
    219 
    220 void MediaPlayerPrivate::seek(float position)
    221 {
    222     LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position);
    223 
    224     if (!m_mediaObject->isSeekable())
    225         return;
    226 
    227     if (position > duration())
    228         position = duration();
    229 
    230     m_mediaObject->seek(position * 1000.0f);
    231 }
    232 
    233 bool MediaPlayerPrivate::seeking() const
    234 {
    235     return false;
    236 }
    237 
    238 float MediaPlayerPrivate::duration() const
    239 {
    240     if (m_readyState < MediaPlayer::HaveMetadata)
    241         return 0.0f;
    242 
    243     float duration = m_mediaObject->totalTime() / 1000.0f;
    244 
    245     if (duration == 0.0f) // We are streaming
    246         duration = std::numeric_limits<float>::infinity();
    247 
    248     LOG(Media, "MediaPlayerPrivatePhonon::duration() --> %f", duration);
    249     return duration;
    250 }
    251 
    252 float MediaPlayerPrivate::currentTime() const
    253 {
    254     float currentTime = m_mediaObject->currentTime() / 1000.0f;
    255 
    256     LOG(Media, "MediaPlayerPrivatePhonon::currentTime() --> %f", currentTime);
    257     return currentTime;
    258 }
    259 
    260 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
    261 {
    262     notImplemented();
    263     return TimeRanges::create();
    264 }
    265 
    266 float MediaPlayerPrivate::maxTimeSeekable() const
    267 {
    268     notImplemented();
    269     return 0.0f;
    270 }
    271 
    272 unsigned MediaPlayerPrivate::bytesLoaded() const
    273 {
    274     notImplemented();
    275     return 0;
    276 }
    277 
    278 unsigned MediaPlayerPrivate::totalBytes() const
    279 {
    280     //notImplemented();
    281     return 0;
    282 }
    283 
    284 void MediaPlayerPrivate::setRate(float)
    285 {
    286     notImplemented();
    287 }
    288 
    289 void MediaPlayerPrivate::setVolume(float volume)
    290 {
    291     LOG(Media, "MediaPlayerPrivatePhonon::setVolume()");
    292     m_audioOutput->setVolume(volume);
    293 }
    294 
    295 void MediaPlayerPrivate::setMuted(bool muted)
    296 {
    297     LOG(Media, "MediaPlayerPrivatePhonon::setMuted()");
    298     m_audioOutput->setMuted(muted);
    299 }
    300 
    301 MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
    302 {
    303     const QMetaObject* metaObj = this->metaObject();
    304     QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
    305     LOG(Media, "MediaPlayerPrivatePhonon::networkState() --> %s", networkStates.valueToKey(m_networkState));
    306     return m_networkState;
    307 }
    308 
    309 MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
    310 {
    311     const QMetaObject* metaObj = this->metaObject();
    312     QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
    313     LOG(Media, "MediaPlayerPrivatePhonon::readyState() --> %s", readyStates.valueToKey(m_readyState));
    314     return m_readyState;
    315 }
    316 
    317 void MediaPlayerPrivate::updateStates()
    318 {
    319     MediaPlayer::NetworkState oldNetworkState = m_networkState;
    320     MediaPlayer::ReadyState oldReadyState = m_readyState;
    321 
    322     Phonon::State phononState = m_mediaObject->state();
    323 
    324     if (phononState == Phonon::StoppedState) {
    325         if (m_readyState < MediaPlayer::HaveMetadata) {
    326             m_networkState = MediaPlayer::Loading; // FIXME: should this be MediaPlayer::Idle?
    327             m_readyState = MediaPlayer::HaveMetadata;
    328             m_mediaObject->pause();
    329         }
    330     } else if (phononState == Phonon::PausedState) {
    331         m_networkState = MediaPlayer::Loaded;
    332         m_readyState = MediaPlayer::HaveEnoughData;
    333     } else if (phononState == Phonon::ErrorState) {
    334          if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
    335              // FIXME: is it possile to differentiate between different types of errors
    336              m_networkState = MediaPlayer::NetworkError;
    337              m_readyState = MediaPlayer::HaveNothing;
    338              cancelLoad();
    339          } else
    340              m_mediaObject->pause();
    341     }
    342 
    343     if (seeking())
    344         m_readyState = MediaPlayer::HaveNothing;
    345 
    346     if (m_networkState != oldNetworkState) {
    347         const QMetaObject* metaObj = this->metaObject();
    348         QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
    349         LOG(Media, "Network state changed from '%s' to '%s'",
    350                 networkStates.valueToKey(oldNetworkState),
    351                 networkStates.valueToKey(m_networkState));
    352         m_player->networkStateChanged();
    353     }
    354 
    355     if (m_readyState != oldReadyState) {
    356         const QMetaObject* metaObj = this->metaObject();
    357         QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
    358         LOG(Media, "Ready state changed from '%s' to '%s'",
    359                 readyStates.valueToKey(oldReadyState),
    360                 readyStates.valueToKey(m_readyState));
    361         m_player->readyStateChanged();
    362     }
    363 }
    364 
    365 void MediaPlayerPrivate::setVisible(bool visible)
    366 {
    367     m_isVisible = visible;
    368     LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false");
    369 
    370     m_videoWidget->setVisible(m_isVisible);
    371 }
    372 
    373 void MediaPlayerPrivate::setSize(const IntSize& newSize)
    374 {
    375     if (!m_videoWidget)
    376         return;
    377 
    378     LOG(Media, "MediaPlayerPrivatePhonon::setSize(%d,%d)",
    379                 newSize.width(), newSize.height());
    380 
    381     QRect currentRect = m_videoWidget->rect();
    382 
    383     if (newSize.width() != currentRect.width() || newSize.height() != currentRect.height())
    384         m_videoWidget->resize(newSize.width(), newSize.height());
    385 }
    386 
    387 IntSize MediaPlayerPrivate::naturalSize() const
    388 {
    389     if (!hasVideo()) {
    390         LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
    391                     0, 0);
    392         return IntSize();
    393     }
    394 
    395     if (m_readyState < MediaPlayer::HaveMetadata) {
    396         LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
    397                            0, 0);
    398         return IntSize();
    399     }
    400 
    401     QSize videoSize = m_videoWidget->sizeHint();
    402     IntSize naturalSize(videoSize.width(), videoSize.height());
    403     LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
    404             naturalSize.width(), naturalSize.height());
    405     return naturalSize;
    406 }
    407 
    408 bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event)
    409 {
    410     if (event->type() == QEvent::UpdateRequest)
    411         m_player->repaint();
    412 
    413     return QObject::eventFilter(obj, event);
    414 }
    415 
    416 void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& rect)
    417 {
    418     if (graphicsContect->paintingDisabled())
    419         return;
    420 
    421     if (!m_isVisible)
    422         return;
    423 
    424     QPainter* painter = graphicsContect->platformContext();
    425 
    426     painter->fillRect(rect, Qt::black);
    427 
    428     m_videoWidget->render(painter, QPoint(rect.x(), rect.y()),
    429             QRegion(0, 0, rect.width(), rect.height()));
    430 }
    431 
    432 // ====================== Phonon::MediaObject signals ======================
    433 
    434 void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldState)
    435 {
    436     const QMetaObject* metaObj = this->metaObject();
    437     QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
    438     LOG(Media, "MediaPlayerPrivatePhonon::stateChanged(newState=%s, oldState=%s)",
    439             phononStates.valueToKey(newState), phononStates.valueToKey(oldState));
    440 
    441     updateStates();
    442 }
    443 
    444 void MediaPlayerPrivate::metaDataChanged()
    445 {
    446     LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
    447     LOG_MEDIAOBJECT();
    448 }
    449 
    450 void MediaPlayerPrivate::seekableChanged(bool)
    451 {
    452     notImplemented();
    453     LOG_MEDIAOBJECT();
    454 }
    455 
    456 void MediaPlayerPrivate::hasVideoChanged(bool hasVideo)
    457 {
    458     LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false");
    459 }
    460 
    461 void MediaPlayerPrivate::bufferStatus(int)
    462 {
    463     notImplemented();
    464     LOG_MEDIAOBJECT();
    465 }
    466 
    467 void MediaPlayerPrivate::finished()
    468 {
    469     notImplemented();
    470     LOG_MEDIAOBJECT();
    471 }
    472 
    473 void MediaPlayerPrivate::currentSourceChanged(const Phonon::MediaSource&)
    474 {
    475     notImplemented();
    476     LOG_MEDIAOBJECT();
    477 }
    478 
    479 void MediaPlayerPrivate::aboutToFinish()
    480 {
    481     notImplemented();
    482     LOG_MEDIAOBJECT();
    483 }
    484 
    485 void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime)
    486 {
    487     LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%lld)", totalTime);
    488     LOG_MEDIAOBJECT();
    489 }
    490 
    491 } // namespace WebCore
    492 
    493 #include "moc_MediaPlayerPrivatePhonon.cpp"
    494