1/* 2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18*/ 19 20#include "config.h" 21#include "MediaPlayerPrivateQt.h" 22 23#include "Frame.h" 24#include "FrameView.h" 25#include "GraphicsContext.h" 26#include "GraphicsLayer.h" 27#include "HTMLMediaElement.h" 28#include "HTMLVideoElement.h" 29#include "Logging.h" 30#include "NetworkingContext.h" 31#include "NotImplemented.h" 32#include "RenderVideo.h" 33#include "TimeRanges.h" 34#include "Widget.h" 35 36#include <QMediaPlayerControl> 37#include <QMediaService> 38#include <QNetworkAccessManager> 39#include <QNetworkCookie> 40#include <QNetworkCookieJar> 41#include <QNetworkRequest> 42#include <QPainter> 43#include <QPoint> 44#include <QRect> 45#include <QTime> 46#include <QTimer> 47#include <QUrl> 48#include <limits> 49#include <qmediametadata.h> 50#include <qmultimedia.h> 51#include <wtf/HashSet.h> 52#include <wtf/text/CString.h> 53 54#if USE(ACCELERATED_COMPOSITING) 55#include "texmap/TextureMapper.h" 56#endif 57 58using namespace WTF; 59 60namespace WebCore { 61 62PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateQt::create(MediaPlayer* player) 63{ 64 return adoptPtr(new MediaPlayerPrivateQt(player)); 65} 66 67void MediaPlayerPrivateQt::registerMediaEngine(MediaEngineRegistrar registrar) 68{ 69 registrar(create, getSupportedTypes, supportsType, 0, 0, 0); 70} 71 72void MediaPlayerPrivateQt::getSupportedTypes(HashSet<String> &supported) 73{ 74 QStringList types = QMediaPlayer::supportedMimeTypes(); 75 76 for (int i = 0; i < types.size(); i++) { 77 QString mime = types.at(i); 78 if (mime.startsWith(QString::fromLatin1("audio/")) || mime.startsWith(QString::fromLatin1("video/"))) 79 supported.add(mime); 80 } 81} 82 83MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, const String& codec, const KURL&) 84{ 85 if (!mime.startsWith("audio/") && !mime.startsWith("video/")) 86 return MediaPlayer::IsNotSupported; 87 88 // Parse and trim codecs. 89 QString codecStr = codec; 90 QStringList codecList = codecStr.split(QLatin1Char(','), QString::SkipEmptyParts); 91 QStringList codecListTrimmed; 92 foreach (const QString& codecStrNotTrimmed, codecList) { 93 QString codecStrTrimmed = codecStrNotTrimmed.trimmed(); 94 if (!codecStrTrimmed.isEmpty()) 95 codecListTrimmed.append(codecStrTrimmed); 96 } 97 98 if (QMediaPlayer::hasSupport(mime, codecListTrimmed) >= QMultimedia::ProbablySupported) 99 return MediaPlayer::IsSupported; 100 101 return MediaPlayer::MayBeSupported; 102} 103 104MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) 105 : m_webCorePlayer(player) 106 , m_mediaPlayer(new QMediaPlayer) 107 , m_mediaPlayerControl(0) 108 , m_networkState(MediaPlayer::Empty) 109 , m_readyState(MediaPlayer::HaveNothing) 110 , m_currentSize(0, 0) 111 , m_naturalSize(RenderVideo::defaultSize()) 112 , m_isSeeking(false) 113 , m_composited(false) 114 , m_preload(MediaPlayer::Auto) 115 , m_bytesLoadedAtLastDidLoadingProgress(0) 116 , m_suppressNextPlaybackChanged(false) 117{ 118 m_mediaPlayer->setVideoOutput(this); 119 120 // Signal Handlers 121 connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), 122 this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); 123 connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), 124 this, SLOT(stateChanged(QMediaPlayer::State))); 125 connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), 126 this, SLOT(handleError(QMediaPlayer::Error))); 127 connect(m_mediaPlayer, SIGNAL(bufferStatusChanged(int)), 128 this, SLOT(bufferStatusChanged(int))); 129 connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), 130 this, SLOT(durationChanged(qint64))); 131 connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), 132 this, SLOT(positionChanged(qint64))); 133 connect(m_mediaPlayer, SIGNAL(volumeChanged(int)), 134 this, SLOT(volumeChanged(int))); 135 connect(m_mediaPlayer, SIGNAL(mutedChanged(bool)), 136 this, SLOT(mutedChanged(bool))); 137 connect(this, SIGNAL(surfaceFormatChanged(const QVideoSurfaceFormat&)), 138 this, SLOT(surfaceFormatChanged(const QVideoSurfaceFormat&))); 139 140 // Grab the player control 141 if (QMediaService* service = m_mediaPlayer->service()) { 142 m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>( 143 service->requestControl(QMediaPlayerControl_iid)); 144 } 145} 146 147MediaPlayerPrivateQt::~MediaPlayerPrivateQt() 148{ 149 m_mediaPlayer->disconnect(this); 150 m_mediaPlayer->stop(); 151 m_mediaPlayer->setMedia(QMediaContent()); 152 153 delete m_mediaPlayer; 154} 155 156bool MediaPlayerPrivateQt::hasVideo() const 157{ 158 return m_mediaPlayer->isVideoAvailable(); 159} 160 161bool MediaPlayerPrivateQt::hasAudio() const 162{ 163 return true; 164} 165 166void MediaPlayerPrivateQt::load(const String& url) 167{ 168 m_mediaUrl = url; 169 170 // QtMultimedia does not have an API to throttle loading 171 // so we handle this ourselves by delaying the load 172 if (m_preload == MediaPlayer::None) { 173 m_delayingLoad = true; 174 return; 175 } 176 177 commitLoad(url); 178} 179 180void MediaPlayerPrivateQt::commitLoad(const String& url) 181{ 182 // We are now loading 183 if (m_networkState != MediaPlayer::Loading) { 184 m_networkState = MediaPlayer::Loading; 185 m_webCorePlayer->networkStateChanged(); 186 } 187 188 // And we don't have any data yet 189 if (m_readyState != MediaPlayer::HaveNothing) { 190 m_readyState = MediaPlayer::HaveNothing; 191 m_webCorePlayer->readyStateChanged(); 192 } 193 194 KURL kUrl(ParsedURLString, url); 195 const QUrl rUrl = kUrl; 196 const QString scheme = rUrl.scheme().toLower(); 197 198 // Grab the client media element 199 HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient()); 200 201 // Construct the media content with a network request if the resource is http[s] 202 if (scheme == QString::fromLatin1("http") || scheme == QString::fromLatin1("https")) { 203 QNetworkRequest request = QNetworkRequest(rUrl); 204 205 // Grab the current document 206 Document* document = element->document(); 207 if (!document) 208 document = element->ownerDocument(); 209 210 // Grab the frame and network manager 211 Frame* frame = document ? document->frame() : 0; 212 FrameLoader* frameLoader = frame ? frame->loader() : 0; 213 QNetworkAccessManager* manager = frameLoader ? frameLoader->networkingContext()->networkAccessManager() : 0; 214 215 if (manager) { 216 // Set the cookies 217 QNetworkCookieJar* jar = manager->cookieJar(); 218 QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl); 219 220 // Don't set the header if there are no cookies. 221 // This prevents a warning from being emitted. 222 if (!cookies.isEmpty()) 223 request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies)); 224 225 // Set the refferer, but not when requesting insecure content from a secure page 226 QUrl documentUrl = QUrl(QString(document->documentURI())); 227 if (documentUrl.scheme().toLower() == QString::fromLatin1("http") || scheme == QString::fromLatin1("https")) 228 request.setRawHeader("Referer", documentUrl.toEncoded()); 229 230 // Set the user agent 231 request.setRawHeader("User-Agent", frameLoader->userAgent(rUrl).utf8().data()); 232 } 233 234 m_mediaPlayer->setMedia(QMediaContent(request)); 235 } else { 236 // Otherwise, just use the URL 237 m_mediaPlayer->setMedia(QMediaContent(rUrl)); 238 } 239 240 // Set the current volume and mute status 241 // We get these from the element, rather than the player, in case we have 242 // transitioned from a media engine which doesn't support muting, to a media 243 // engine which does. 244 m_mediaPlayer->setMuted(element->muted()); 245 m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0)); 246 247 // Don't send PlaybackChanged notification for pre-roll. 248 m_suppressNextPlaybackChanged = true; 249 250 // Setting a media source will start loading the media, but we need 251 // to pre-roll as well to get video size-hints and buffer-status 252 if (element->paused()) 253 m_mediaPlayer->pause(); 254 else 255 m_mediaPlayer->play(); 256} 257 258void MediaPlayerPrivateQt::resumeLoad() 259{ 260 m_delayingLoad = false; 261 262 if (!m_mediaUrl.isNull()) 263 commitLoad(m_mediaUrl); 264} 265 266void MediaPlayerPrivateQt::cancelLoad() 267{ 268 m_mediaPlayer->setMedia(QMediaContent()); 269 updateStates(); 270} 271 272void MediaPlayerPrivateQt::prepareToPlay() 273{ 274 if (m_mediaPlayer->media().isNull() || m_delayingLoad) 275 resumeLoad(); 276} 277 278void MediaPlayerPrivateQt::play() 279{ 280 if (m_mediaPlayer->state() != QMediaPlayer::PlayingState) 281 m_mediaPlayer->play(); 282} 283 284void MediaPlayerPrivateQt::pause() 285{ 286 if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) 287 m_mediaPlayer->pause(); 288} 289 290bool MediaPlayerPrivateQt::paused() const 291{ 292 return (m_mediaPlayer->state() != QMediaPlayer::PlayingState); 293} 294 295void MediaPlayerPrivateQt::seek(float position) 296{ 297 if (!m_mediaPlayer->isSeekable()) 298 return; 299 300 if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000)) 301 return; 302 303 m_isSeeking = true; 304 m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000)); 305} 306 307bool MediaPlayerPrivateQt::seeking() const 308{ 309 return m_isSeeking; 310} 311 312float MediaPlayerPrivateQt::duration() const 313{ 314 if (m_readyState < MediaPlayer::HaveMetadata) 315 return 0.0f; 316 317 float duration = m_mediaPlayer->duration() / 1000.0f; 318 319 // We are streaming 320 if (duration <= 0.0f) 321 duration = std::numeric_limits<float>::infinity(); 322 323 return duration; 324} 325 326float MediaPlayerPrivateQt::currentTime() const 327{ 328 return m_mediaPlayer->position() / 1000.0f; 329} 330 331PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const 332{ 333 RefPtr<TimeRanges> buffered = TimeRanges::create(); 334 335 if (!m_mediaPlayerControl) 336 return buffered; 337 338 QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges(); 339 340 foreach (const QMediaTimeInterval interval, playbackRanges.intervals()) { 341 float rangeMin = static_cast<float>(interval.start()) / 1000.0f; 342 float rangeMax = static_cast<float>(interval.end()) / 1000.0f; 343 buffered->add(rangeMin, rangeMax); 344 } 345 346 return buffered.release(); 347} 348 349float MediaPlayerPrivateQt::maxTimeSeekable() const 350{ 351 if (!m_mediaPlayerControl) 352 return 0; 353 354 return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f; 355} 356 357bool MediaPlayerPrivateQt::didLoadingProgress() const 358{ 359 unsigned bytesLoaded = 0; 360 QLatin1String bytesLoadedKey("bytes-loaded"); 361 if (m_mediaPlayer->availableMetaData().contains(bytesLoadedKey)) 362 bytesLoaded = m_mediaPlayer->metaData(bytesLoadedKey).toInt(); 363 else 364 bytesLoaded = m_mediaPlayer->bufferStatus(); 365 bool didLoadingProgress = bytesLoaded != m_bytesLoadedAtLastDidLoadingProgress; 366 m_bytesLoadedAtLastDidLoadingProgress = bytesLoaded; 367 return didLoadingProgress; 368} 369 370unsigned MediaPlayerPrivateQt::totalBytes() const 371{ 372 if (m_mediaPlayer->availableMetaData().contains(QMediaMetaData::Size)) 373 return m_mediaPlayer->metaData(QMediaMetaData::Size).toInt(); 374 375 return 100; 376} 377 378void MediaPlayerPrivateQt::setPreload(MediaPlayer::Preload preload) 379{ 380 m_preload = preload; 381 if (m_delayingLoad && m_preload != MediaPlayer::None) 382 resumeLoad(); 383} 384 385void MediaPlayerPrivateQt::setRate(float rate) 386{ 387 m_mediaPlayer->setPlaybackRate(rate); 388} 389 390void MediaPlayerPrivateQt::setVolume(float volume) 391{ 392 m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0)); 393} 394 395bool MediaPlayerPrivateQt::supportsMuting() const 396{ 397 return true; 398} 399 400void MediaPlayerPrivateQt::setMuted(bool muted) 401{ 402 m_mediaPlayer->setMuted(muted); 403} 404 405MediaPlayer::NetworkState MediaPlayerPrivateQt::networkState() const 406{ 407 return m_networkState; 408} 409 410MediaPlayer::ReadyState MediaPlayerPrivateQt::readyState() const 411{ 412 return m_readyState; 413} 414 415void MediaPlayerPrivateQt::setVisible(bool) 416{ 417} 418 419void MediaPlayerPrivateQt::mediaStatusChanged(QMediaPlayer::MediaStatus) 420{ 421 updateStates(); 422} 423 424void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error) 425{ 426 updateStates(); 427} 428 429void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State) 430{ 431 if (!m_suppressNextPlaybackChanged) 432 m_webCorePlayer->playbackStateChanged(); 433 else 434 m_suppressNextPlaybackChanged = false; 435} 436 437void MediaPlayerPrivateQt::surfaceFormatChanged(const QVideoSurfaceFormat& format) 438{ 439 QSize size = format.sizeHint(); 440 LOG(Media, "MediaPlayerPrivateQt::naturalSizeChanged(%dx%d)", 441 size.width(), size.height()); 442 443 if (!size.isValid()) 444 return; 445 446 IntSize webCoreSize = size; 447 if (webCoreSize == m_naturalSize) 448 return; 449 450 m_naturalSize = webCoreSize; 451 m_webCorePlayer->sizeChanged(); 452} 453 454void MediaPlayerPrivateQt::positionChanged(qint64) 455{ 456 // Only propagate this event if we are seeking 457 if (m_isSeeking) { 458 m_isSeeking = false; 459 m_webCorePlayer->timeChanged(); 460 } 461} 462 463void MediaPlayerPrivateQt::bufferStatusChanged(int) 464{ 465 notImplemented(); 466} 467 468void MediaPlayerPrivateQt::durationChanged(qint64) 469{ 470 m_webCorePlayer->durationChanged(); 471} 472 473void MediaPlayerPrivateQt::volumeChanged(int volume) 474{ 475 m_webCorePlayer->volumeChanged(static_cast<float>(volume) / 100.0); 476} 477 478void MediaPlayerPrivateQt::mutedChanged(bool muted) 479{ 480 m_webCorePlayer->muteChanged(muted); 481} 482 483void MediaPlayerPrivateQt::updateStates() 484{ 485 // Store the old states so that we can detect a change and raise change events 486 MediaPlayer::NetworkState oldNetworkState = m_networkState; 487 MediaPlayer::ReadyState oldReadyState = m_readyState; 488 489 QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus(); 490 QMediaPlayer::Error currentError = m_mediaPlayer->error(); 491 492 if (currentError != QMediaPlayer::NoError) { 493 m_readyState = MediaPlayer::HaveNothing; 494 if (currentError == QMediaPlayer::FormatError || currentError == QMediaPlayer::ResourceError) 495 m_networkState = MediaPlayer::FormatError; 496 else 497 m_networkState = MediaPlayer::NetworkError; 498 } else if (currentStatus == QMediaPlayer::UnknownMediaStatus 499 || currentStatus == QMediaPlayer::NoMedia) { 500 m_networkState = MediaPlayer::Idle; 501 m_readyState = MediaPlayer::HaveNothing; 502 } else if (currentStatus == QMediaPlayer::LoadingMedia) { 503 m_networkState = MediaPlayer::Loading; 504 m_readyState = MediaPlayer::HaveNothing; 505 } else if (currentStatus == QMediaPlayer::LoadedMedia) { 506 m_networkState = MediaPlayer::Loading; 507 m_readyState = MediaPlayer::HaveMetadata; 508 } else if (currentStatus == QMediaPlayer::BufferingMedia) { 509 m_networkState = MediaPlayer::Loading; 510 m_readyState = MediaPlayer::HaveFutureData; 511 } else if (currentStatus == QMediaPlayer::StalledMedia) { 512 m_networkState = MediaPlayer::Loading; 513 m_readyState = MediaPlayer::HaveCurrentData; 514 } else if (currentStatus == QMediaPlayer::BufferedMedia 515 || currentStatus == QMediaPlayer::EndOfMedia) { 516 m_networkState = MediaPlayer::Loaded; 517 m_readyState = MediaPlayer::HaveEnoughData; 518 } else if (currentStatus == QMediaPlayer::InvalidMedia) { 519 m_networkState = MediaPlayer::FormatError; 520 m_readyState = MediaPlayer::HaveNothing; 521 } 522 523 // Log the state changes and raise the state change events 524 // NB: The readyStateChanged event must come before the networkStateChanged event. 525 // Breaking this invariant will cause the resource selection algorithm for multiple 526 // sources to fail. 527 if (m_readyState != oldReadyState) 528 m_webCorePlayer->readyStateChanged(); 529 530 if (m_networkState != oldNetworkState) 531 m_webCorePlayer->networkStateChanged(); 532} 533 534void MediaPlayerPrivateQt::setSize(const IntSize& size) 535{ 536 LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)", 537 size.width(), size.height()); 538 539 if (size == m_currentSize) 540 return; 541 542 m_currentSize = size; 543} 544 545IntSize MediaPlayerPrivateQt::naturalSize() const 546{ 547 if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) { 548 LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> 0x0 (!hasVideo || !haveMetaData)"); 549 return IntSize(); 550 } 551 552 LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> %dx%d (m_naturalSize)", 553 m_naturalSize.width(), m_naturalSize.height()); 554 555 return m_naturalSize; 556} 557 558void MediaPlayerPrivateQt::removeVideoItem() 559{ 560 m_mediaPlayer->setVideoOutput(static_cast<QAbstractVideoSurface*>(0)); 561} 562 563void MediaPlayerPrivateQt::restoreVideoItem() 564{ 565 m_mediaPlayer->setVideoOutput(this); 566} 567 568// Begin QAbstractVideoSurface implementation. 569 570bool MediaPlayerPrivateQt::start(const QVideoSurfaceFormat& format) 571{ 572 m_currentVideoFrame = QVideoFrame(); 573 m_frameFormat = format; 574 575 // If the pixel format is not supported by QImage, then we return false here and the QtMultimedia back-end 576 // will re-negotiate and call us again with a better format. 577 if (QVideoFrame::imageFormatFromPixelFormat(m_frameFormat.pixelFormat()) == QImage::Format_Invalid) 578 return false; 579 580 return QAbstractVideoSurface::start(format); 581} 582 583QList<QVideoFrame::PixelFormat> MediaPlayerPrivateQt::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const 584{ 585 QList<QVideoFrame::PixelFormat> formats; 586 switch (handleType) { 587 case QAbstractVideoBuffer::QPixmapHandle: 588 case QAbstractVideoBuffer::NoHandle: 589 formats << QVideoFrame::Format_RGB32 << QVideoFrame::Format_ARGB32 << QVideoFrame::Format_RGB565; 590 break; 591 default: break; 592 } 593 return formats; 594} 595 596bool MediaPlayerPrivateQt::present(const QVideoFrame& frame) 597{ 598 m_currentVideoFrame = frame; 599 m_webCorePlayer->repaint(); 600 return true; 601} 602 603// End QAbstractVideoSurface implementation. 604 605void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect) 606{ 607#if USE(ACCELERATED_COMPOSITING) 608 if (m_composited) 609 return; 610#endif 611 paintCurrentFrameInContext(context, rect); 612} 613 614void MediaPlayerPrivateQt::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect) 615{ 616 if (context->paintingDisabled()) 617 return; 618 619 if (!m_currentVideoFrame.isValid()) 620 return; 621 622 QPainter* painter = context->platformContext(); 623 624 if (m_currentVideoFrame.handleType() == QAbstractVideoBuffer::QPixmapHandle) { 625 painter->drawPixmap(rect, m_currentVideoFrame.handle().value<QPixmap>()); 626 } else if (m_currentVideoFrame.map(QAbstractVideoBuffer::ReadOnly)) { 627 QImage image(m_currentVideoFrame.bits(), 628 m_frameFormat.frameSize().width(), 629 m_frameFormat.frameSize().height(), 630 m_currentVideoFrame.bytesPerLine(), 631 QVideoFrame::imageFormatFromPixelFormat(m_frameFormat.pixelFormat())); 632 const QRect target = rect; 633 634 if (m_frameFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop) { 635 const QTransform oldTransform = painter->transform(); 636 painter->scale(1, -1); 637 painter->translate(0, -target.bottom()); 638 painter->drawImage(QRect(target.x(), 0, target.width(), target.height()), image); 639 painter->setTransform(oldTransform); 640 } else { 641 painter->drawImage(target, image); 642 } 643 644 m_currentVideoFrame.unmap(); 645 } 646} 647 648#if USE(ACCELERATED_COMPOSITING) 649void MediaPlayerPrivateQt::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) 650{ 651} 652#endif 653 654PlatformMedia MediaPlayerPrivateQt::platformMedia() const 655{ 656 PlatformMedia pm; 657 pm.type = PlatformMedia::QtMediaPlayerType; 658 pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivateQt*>(this); 659 return pm; 660} 661 662} // namespace WebCore 663 664#include "moc_MediaPlayerPrivateQt.cpp" 665