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