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