• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
debugMediaObject(WebCore::MediaPlayerPrivate * mediaPlayer,const MediaObject & mediaObject)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 
MediaPlayerPrivate(MediaPlayer * player)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 
create(MediaPlayer * player)118 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
119 {
120     return new MediaPlayerPrivate(player);
121 }
122 
registerMediaEngine(MediaEngineRegistrar registrar)123 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
124 {
125     if (isAvailable())
126         registrar(create, getSupportedTypes, supportsType);
127 }
128 
129 
~MediaPlayerPrivate()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 
getSupportedTypes(HashSet<String> &)146 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
147 {
148     notImplemented();
149 }
150 
supportsType(const String &,const String &)151 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&)
152 {
153     // FIXME: do the real thing
154     notImplemented();
155     return MediaPlayer::IsNotSupported;
156 }
157 
hasVideo() const158 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 
hasAudio() const165 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 
load(const String & url)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 
cancelLoad()194 void MediaPlayerPrivate::cancelLoad()
195 {
196     notImplemented();
197 }
198 
199 
play()200 void MediaPlayerPrivate::play()
201 {
202     LOG(Media, "MediaPlayerPrivatePhonon::play()");
203     m_mediaObject->play();
204 }
205 
pause()206 void MediaPlayerPrivate::pause()
207 {
208     LOG(Media, "MediaPlayerPrivatePhonon::pause()");
209     m_mediaObject->pause();
210 }
211 
212 
paused() const213 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 
seek(float position)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 
seeking() const233 bool MediaPlayerPrivate::seeking() const
234 {
235     return false;
236 }
237 
duration() const238 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 
currentTime() const252 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 
buffered() const260 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
261 {
262     notImplemented();
263     return TimeRanges::create();
264 }
265 
maxTimeSeekable() const266 float MediaPlayerPrivate::maxTimeSeekable() const
267 {
268     notImplemented();
269     return 0.0f;
270 }
271 
bytesLoaded() const272 unsigned MediaPlayerPrivate::bytesLoaded() const
273 {
274     notImplemented();
275     return 0;
276 }
277 
totalBytes() const278 unsigned MediaPlayerPrivate::totalBytes() const
279 {
280     //notImplemented();
281     return 0;
282 }
283 
setRate(float)284 void MediaPlayerPrivate::setRate(float)
285 {
286     notImplemented();
287 }
288 
setVolume(float volume)289 void MediaPlayerPrivate::setVolume(float volume)
290 {
291     LOG(Media, "MediaPlayerPrivatePhonon::setVolume()");
292     m_audioOutput->setVolume(volume);
293 }
294 
setMuted(bool muted)295 void MediaPlayerPrivate::setMuted(bool muted)
296 {
297     LOG(Media, "MediaPlayerPrivatePhonon::setMuted()");
298     m_audioOutput->setMuted(muted);
299 }
300 
networkState() const301 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 
readyState() const309 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 
updateStates()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 
setVisible(bool visible)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 
setSize(const IntSize & newSize)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 
naturalSize() const387 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 
eventFilter(QObject * obj,QEvent * event)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 
paint(GraphicsContext * graphicsContect,const IntRect & rect)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 
stateChanged(Phonon::State newState,Phonon::State oldState)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 
metaDataChanged()444 void MediaPlayerPrivate::metaDataChanged()
445 {
446     LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
447     LOG_MEDIAOBJECT();
448 }
449 
seekableChanged(bool)450 void MediaPlayerPrivate::seekableChanged(bool)
451 {
452     notImplemented();
453     LOG_MEDIAOBJECT();
454 }
455 
hasVideoChanged(bool hasVideo)456 void MediaPlayerPrivate::hasVideoChanged(bool hasVideo)
457 {
458     LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false");
459 }
460 
bufferStatus(int)461 void MediaPlayerPrivate::bufferStatus(int)
462 {
463     notImplemented();
464     LOG_MEDIAOBJECT();
465 }
466 
finished()467 void MediaPlayerPrivate::finished()
468 {
469     notImplemented();
470     LOG_MEDIAOBJECT();
471 }
472 
currentSourceChanged(const Phonon::MediaSource &)473 void MediaPlayerPrivate::currentSourceChanged(const Phonon::MediaSource&)
474 {
475     notImplemented();
476     LOG_MEDIAOBJECT();
477 }
478 
aboutToFinish()479 void MediaPlayerPrivate::aboutToFinish()
480 {
481     notImplemented();
482     LOG_MEDIAOBJECT();
483 }
484 
totalTimeChanged(qint64 totalTime)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