initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / qt / MediaPlayerPrivateQt.cpp
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 "NetworkingContext.h"
30 #include "NotImplemented.h"
31 #include "RenderVideo.h"
32 #include "TimeRanges.h"
33 #include "Widget.h"
34 #include "qwebframe.h"
35 #include "qwebpage.h"
36
37 #include <QGraphicsScene>
38 #include <QGraphicsVideoItem>
39 #include <QMediaPlayerControl>
40 #include <QMediaService>
41 #include <QNetworkAccessManager>
42 #include <QNetworkCookieJar>
43 #include <QNetworkRequest>
44 #include <QPainter>
45 #include <QPoint>
46 #include <QRect>
47 #include <QStyleOptionGraphicsItem>
48 #include <QTime>
49 #include <QTimer>
50 #include <QUrl>
51 #include <limits>
52 #include <wtf/HashSet.h>
53 #include <wtf/text/CString.h>
54
55 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
56 #include "texmap/TextureMapper.h"
57 #endif
58
59 using namespace WTF;
60
61 namespace WebCore {
62
63 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateQt::create(MediaPlayer* player)
64 {
65     return adoptPtr(new MediaPlayerPrivateQt(player));
66 }
67
68 void MediaPlayerPrivateQt::registerMediaEngine(MediaEngineRegistrar registrar)
69 {
70     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
71 }
72
73 void MediaPlayerPrivateQt::getSupportedTypes(HashSet<String> &supported)
74 {
75     QStringList types = QMediaPlayer::supportedMimeTypes();
76
77     for (int i = 0; i < types.size(); i++) {
78         QString mime = types.at(i);
79         if (mime.startsWith(QString::fromLatin1("audio/")) || mime.startsWith(QString::fromLatin1("video/")))
80             supported.add(mime);
81     }
82 }
83
84 MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, const String& codec)
85 {
86     if (!mime.startsWith("audio/") && !mime.startsWith("video/"))
87         return MediaPlayer::IsNotSupported;
88
89     // Parse and trim codecs.
90     QString codecStr = codec;
91     QStringList codecList = codecStr.split(QLatin1Char(','), QString::SkipEmptyParts);
92     QStringList codecListTrimmed;
93     foreach (const QString& codecStrNotTrimmed, codecList) {
94         QString codecStrTrimmed = codecStrNotTrimmed.trimmed();
95         if (!codecStrTrimmed.isEmpty())
96             codecListTrimmed.append(codecStrTrimmed);
97     }
98
99     if (QMediaPlayer::hasSupport(mime, codecListTrimmed) >= QtMultimediaKit::ProbablySupported)
100         return MediaPlayer::IsSupported;
101
102     return MediaPlayer::MayBeSupported;
103 }
104
105 MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
106     : m_webCorePlayer(player)
107     , m_mediaPlayer(new QMediaPlayer)
108     , m_mediaPlayerControl(0)
109     , m_videoItem(new QGraphicsVideoItem)
110     , m_videoScene(new QGraphicsScene)
111     , m_networkState(MediaPlayer::Empty)
112     , m_readyState(MediaPlayer::HaveNothing)
113     , m_currentSize(0, 0)
114     , m_naturalSize(RenderVideo::defaultSize())
115     , m_isVisible(false)
116     , m_isSeeking(false)
117     , m_composited(false)
118     , m_preload(MediaPlayer::Auto)
119     , m_suppressNextPlaybackChanged(false)
120 {
121     m_mediaPlayer->setVideoOutput(m_videoItem);
122     m_videoScene->addItem(m_videoItem);
123
124     // Signal Handlers
125     connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
126             this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
127     connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),
128             this, SLOT(stateChanged(QMediaPlayer::State)));
129     connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)),
130             this, SLOT(handleError(QMediaPlayer::Error)));
131     connect(m_mediaPlayer, SIGNAL(bufferStatusChanged(int)),
132             this, SLOT(bufferStatusChanged(int)));
133     connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)),
134             this, SLOT(durationChanged(qint64)));
135     connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)),
136             this, SLOT(positionChanged(qint64)));
137     connect(m_mediaPlayer, SIGNAL(volumeChanged(int)),
138             this, SLOT(volumeChanged(int)));
139     connect(m_mediaPlayer, SIGNAL(mutedChanged(bool)),
140             this, SLOT(mutedChanged(bool)));
141     connect(m_videoScene, SIGNAL(changed(QList<QRectF>)),
142             this, SLOT(repaint()));
143     connect(m_videoItem, SIGNAL(nativeSizeChanged(QSizeF)),
144            this, SLOT(nativeSizeChanged(QSizeF)));
145
146     // Grab the player control
147     if (QMediaService* service = m_mediaPlayer->service()) {
148         m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>(
149                 service->requestControl(QMediaPlayerControl_iid));
150     }
151 }
152
153 MediaPlayerPrivateQt::~MediaPlayerPrivateQt()
154 {
155     m_mediaPlayer->disconnect(this);
156     m_mediaPlayer->stop();
157     m_mediaPlayer->setMedia(QMediaContent());
158
159     delete m_mediaPlayer;
160     delete m_videoScene;
161 }
162
163 bool MediaPlayerPrivateQt::hasVideo() const
164 {
165     return m_mediaPlayer->isVideoAvailable();
166 }
167
168 bool MediaPlayerPrivateQt::hasAudio() const
169 {
170     return true;
171 }
172
173 void MediaPlayerPrivateQt::load(const String& url)
174 {
175     m_mediaUrl = url;
176
177     // QtMultimedia does not have an API to throttle loading
178     // so we handle this ourselves by delaying the load
179     if (m_preload == MediaPlayer::None) {
180         m_delayingLoad = true;
181         return;
182     }
183
184     commitLoad(url);
185 }
186
187 void MediaPlayerPrivateQt::commitLoad(const String& url)
188 {
189     // We are now loading
190     if (m_networkState != MediaPlayer::Loading) {
191         m_networkState = MediaPlayer::Loading;
192         m_webCorePlayer->networkStateChanged();
193     }
194
195     // And we don't have any data yet
196     if (m_readyState != MediaPlayer::HaveNothing) {
197         m_readyState = MediaPlayer::HaveNothing;
198         m_webCorePlayer->readyStateChanged();
199     }
200
201     KURL kUrl(ParsedURLString, url);
202     const QUrl rUrl = kUrl;
203     const QString scheme = rUrl.scheme().toLower();
204
205     // Grab the client media element
206     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
207
208     // Construct the media content with a network request if the resource is http[s]
209     if (scheme == QString::fromLatin1("http") || scheme == QString::fromLatin1("https")) {
210         QNetworkRequest request = QNetworkRequest(rUrl);
211
212         // Grab the current document
213         Document* document = element->document();
214         if (!document)
215             document = element->ownerDocument();
216
217         // Grab the frame and network manager
218         Frame* frame = document ? document->frame() : 0;
219         FrameLoader* frameLoader = frame ? frame->loader() : 0;
220         QNetworkAccessManager* manager = frameLoader ? frameLoader->networkingContext()->networkAccessManager() : 0;
221
222         if (manager) {
223             // Set the cookies
224             QNetworkCookieJar* jar = manager->cookieJar();
225             QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl);
226
227             // Don't set the header if there are no cookies.
228             // This prevents a warning from being emitted.
229             if (!cookies.isEmpty())
230                 request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
231
232             // Set the refferer, but not when requesting insecure content from a secure page
233             QUrl documentUrl = QUrl(QString(document->documentURI()));
234             if (documentUrl.scheme().toLower() == QString::fromLatin1("http") || scheme == QString::fromLatin1("https"))
235                 request.setRawHeader("Referer", documentUrl.toEncoded());
236
237             // Set the user agent
238             request.setRawHeader("User-Agent", frameLoader->userAgent(rUrl).utf8().data());
239         }
240
241         m_mediaPlayer->setMedia(QMediaContent(request));
242     } else {
243         // Otherwise, just use the URL
244         m_mediaPlayer->setMedia(QMediaContent(rUrl));
245     }
246
247     // Set the current volume and mute status
248     // We get these from the element, rather than the player, in case we have
249     // transitioned from a media engine which doesn't support muting, to a media
250     // engine which does.
251     m_mediaPlayer->setMuted(element->muted());
252     m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0));
253
254     // Don't send PlaybackChanged notification for pre-roll.
255     m_suppressNextPlaybackChanged = true;
256
257     // Setting a media source will start loading the media, but we need
258     // to pre-roll as well to get video size-hints and buffer-status
259     if (element->paused())
260         m_mediaPlayer->pause();
261     else
262         m_mediaPlayer->play();
263 }
264
265 void MediaPlayerPrivateQt::resumeLoad()
266 {
267     m_delayingLoad = false;
268
269     if (!m_mediaUrl.isNull())
270         commitLoad(m_mediaUrl);
271 }
272
273 void MediaPlayerPrivateQt::cancelLoad()
274 {
275     m_mediaPlayer->setMedia(QMediaContent());
276     updateStates();
277 }
278
279 void MediaPlayerPrivateQt::prepareToPlay()
280 {
281     if (m_mediaPlayer->media().isNull() || m_delayingLoad)
282         resumeLoad();
283 }
284
285 void MediaPlayerPrivateQt::play()
286 {
287     if (m_mediaPlayer->state() != QMediaPlayer::PlayingState)
288         m_mediaPlayer->play();
289 }
290
291 void MediaPlayerPrivateQt::pause()
292 {
293     if (m_mediaPlayer->state() == QMediaPlayer::PlayingState)
294         m_mediaPlayer->pause();
295 }
296
297 bool MediaPlayerPrivateQt::paused() const
298 {
299     return (m_mediaPlayer->state() != QMediaPlayer::PlayingState);
300 }
301
302 void MediaPlayerPrivateQt::seek(float position)
303 {
304     if (!m_mediaPlayer->isSeekable())
305         return;
306
307     if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000))
308         return;
309
310     m_isSeeking = true;
311     m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000));
312 }
313
314 bool MediaPlayerPrivateQt::seeking() const
315 {
316     return m_isSeeking;
317 }
318
319 float MediaPlayerPrivateQt::duration() const
320 {
321     if (m_readyState < MediaPlayer::HaveMetadata)
322         return 0.0f;
323
324     float duration = m_mediaPlayer->duration() / 1000.0f;
325
326     // We are streaming
327     if (duration <= 0.0f)
328         duration = std::numeric_limits<float>::infinity();
329
330     return duration;
331 }
332
333 float MediaPlayerPrivateQt::currentTime() const
334 {
335     return m_mediaPlayer->position() / 1000.0f;
336 }
337
338 PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const
339 {
340     RefPtr<TimeRanges> buffered = TimeRanges::create();
341
342     if (!m_mediaPlayerControl)
343         return buffered;
344
345     QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges();
346
347     foreach (const QMediaTimeInterval interval, playbackRanges.intervals()) {
348         float rangeMin = static_cast<float>(interval.start()) / 1000.0f;
349         float rangeMax = static_cast<float>(interval.end()) / 1000.0f;
350         buffered->add(rangeMin, rangeMax);
351     }
352
353     return buffered.release();
354 }
355
356 float MediaPlayerPrivateQt::maxTimeSeekable() const
357 {
358     if (!m_mediaPlayerControl)
359         return 0;
360
361     return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f;
362 }
363
364 unsigned MediaPlayerPrivateQt::bytesLoaded() const
365 {
366     QLatin1String bytesLoadedKey("bytes-loaded");
367     if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey))
368         return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt();
369
370     return m_mediaPlayer->bufferStatus();
371 }
372
373 unsigned MediaPlayerPrivateQt::totalBytes() const
374 {
375     if (m_mediaPlayer->availableMetaData().contains(QtMultimediaKit::Size))
376         return m_mediaPlayer->metaData(QtMultimediaKit::Size).toInt();
377
378     return 100;
379 }
380
381 void MediaPlayerPrivateQt::setPreload(MediaPlayer::Preload preload)
382 {
383     m_preload = preload;
384     if (m_delayingLoad && m_preload != MediaPlayer::None)
385         resumeLoad();
386 }
387
388 void MediaPlayerPrivateQt::setRate(float rate)
389 {
390     m_mediaPlayer->setPlaybackRate(rate);
391 }
392
393 void MediaPlayerPrivateQt::setVolume(float volume)
394 {
395     m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0));
396 }
397
398 bool MediaPlayerPrivateQt::supportsMuting() const
399 {
400     return true;
401 }
402
403 void MediaPlayerPrivateQt::setMuted(bool muted)
404 {
405     m_mediaPlayer->setMuted(muted);
406 }
407
408 MediaPlayer::NetworkState MediaPlayerPrivateQt::networkState() const
409 {
410     return m_networkState;
411 }
412
413 MediaPlayer::ReadyState MediaPlayerPrivateQt::readyState() const
414 {
415     return m_readyState;
416 }
417
418 void MediaPlayerPrivateQt::setVisible(bool visible)
419 {
420     m_isVisible = visible;
421 }
422
423 void MediaPlayerPrivateQt::mediaStatusChanged(QMediaPlayer::MediaStatus)
424 {
425     updateStates();
426 }
427
428 void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error)
429 {
430     updateStates();
431 }
432
433 void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State)
434 {
435     if (!m_suppressNextPlaybackChanged)
436         m_webCorePlayer->playbackStateChanged();
437     else
438         m_suppressNextPlaybackChanged = false;
439 }
440
441 void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF& size)
442 {
443     LOG(Media, "MediaPlayerPrivateQt::naturalSizeChanged(%dx%d)",
444             size.toSize().width(), size.toSize().height());
445
446     if (!size.isValid())
447         return;
448
449     m_naturalSize = size.toSize();
450     m_webCorePlayer->sizeChanged();
451 }
452
453 void MediaPlayerPrivateQt::positionChanged(qint64)
454 {
455     // Only propagate this event if we are seeking
456     if (m_isSeeking) {
457         m_isSeeking = false;
458         m_webCorePlayer->timeChanged();
459     }
460 }
461
462 void MediaPlayerPrivateQt::bufferStatusChanged(int)
463 {
464     notImplemented();
465 }
466
467 void MediaPlayerPrivateQt::durationChanged(qint64)
468 {
469     m_webCorePlayer->durationChanged();
470 }
471
472 void MediaPlayerPrivateQt::volumeChanged(int volume)
473 {
474     m_webCorePlayer->volumeChanged(static_cast<float>(volume) / 100.0);
475 }
476
477 void MediaPlayerPrivateQt::mutedChanged(bool muted)
478 {
479     m_webCorePlayer->muteChanged(muted);
480 }
481
482 void MediaPlayerPrivateQt::updateStates()
483 {
484     // Store the old states so that we can detect a change and raise change events
485     MediaPlayer::NetworkState oldNetworkState = m_networkState;
486     MediaPlayer::ReadyState oldReadyState = m_readyState;
487
488     QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus();
489     QMediaPlayer::Error currentError = m_mediaPlayer->error();
490
491     if (currentError != QMediaPlayer::NoError) {
492         m_readyState = MediaPlayer::HaveNothing;
493         if (currentError == QMediaPlayer::FormatError || currentError == QMediaPlayer::ResourceError)
494             m_networkState = MediaPlayer::FormatError;
495         else
496             m_networkState = MediaPlayer::NetworkError;
497     } else if (currentStatus == QMediaPlayer::UnknownMediaStatus
498                || currentStatus == QMediaPlayer::NoMedia) {
499         m_networkState = MediaPlayer::Idle;
500         m_readyState = MediaPlayer::HaveNothing;
501     } else if (currentStatus == QMediaPlayer::LoadingMedia) {
502         m_networkState = MediaPlayer::Loading;
503         m_readyState = MediaPlayer::HaveNothing;
504     } else if (currentStatus == QMediaPlayer::LoadedMedia) {
505         m_networkState = MediaPlayer::Loading;
506         m_readyState = MediaPlayer::HaveMetadata;
507     } else if (currentStatus == QMediaPlayer::BufferingMedia) {
508         m_networkState = MediaPlayer::Loading;
509         m_readyState = MediaPlayer::HaveFutureData;
510     } else if (currentStatus == QMediaPlayer::StalledMedia) {
511         m_networkState = MediaPlayer::Loading;
512         m_readyState = MediaPlayer::HaveCurrentData;
513     } else if (currentStatus == QMediaPlayer::BufferedMedia
514                || currentStatus == QMediaPlayer::EndOfMedia) {
515         m_networkState = MediaPlayer::Loaded;
516         m_readyState = MediaPlayer::HaveEnoughData;
517     } else if (currentStatus == QMediaPlayer::InvalidMedia) {
518         m_networkState = MediaPlayer::FormatError;
519         m_readyState = MediaPlayer::HaveNothing;
520     }
521
522     // Log the state changes and raise the state change events
523     // NB: The readyStateChanged event must come before the networkStateChanged event.
524     // Breaking this invariant will cause the resource selection algorithm for multiple
525     // sources to fail.
526     if (m_readyState != oldReadyState)
527         m_webCorePlayer->readyStateChanged();
528
529     if (m_networkState != oldNetworkState)
530         m_webCorePlayer->networkStateChanged();
531 }
532
533 void MediaPlayerPrivateQt::setSize(const IntSize& size)
534 {
535     LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)",
536             size.width(), size.height());
537
538     if (size == m_currentSize)
539         return;
540
541     m_currentSize = size;
542     m_videoItem->setSize(QSizeF(QSize(size)));
543 }
544
545 IntSize 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
558 void MediaPlayerPrivateQt::removeVideoItem()
559 {
560     m_oldNaturalSize = m_naturalSize;
561     m_mediaPlayer->setVideoOutput(static_cast<QGraphicsVideoItem*>(0));
562     m_videoScene->removeItem(m_videoItem);
563 }
564
565 void MediaPlayerPrivateQt::restoreVideoItem()
566 {
567     m_mediaPlayer->setVideoOutput(m_videoItem);
568     m_videoScene->addItem(m_videoItem);
569     // FIXME: a qtmobility bug, need to reset the size when restore the videoitem, otherwise the size is 0
570     // http://bugreports.qt.nokia.com/browse/QTMOBILITY-971
571     nativeSizeChanged(QSize(m_oldNaturalSize));
572 }
573
574 void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect)
575 {
576 #if USE(ACCELERATED_COMPOSITING)
577     if (m_composited)
578         return;
579 #endif
580     if (context->paintingDisabled())
581         return;
582
583     if (!m_isVisible)
584         return;
585
586     QPainter* painter = context->platformContext();
587     m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect());
588 }
589
590 void MediaPlayerPrivateQt::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
591 {
592     if (context->paintingDisabled())
593         return;
594
595     if (!m_isVisible)
596         return;
597
598     // Grab the painter and widget
599     QPainter* painter = context->platformContext();
600
601     // Render the video, using the item as it might not be in the scene
602     m_videoItem->paint(painter, 0, 0);
603 }
604
605 void MediaPlayerPrivateQt::repaint()
606 {
607     m_webCorePlayer->repaint();
608
609 }
610
611 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
612 void MediaPlayerPrivateQt::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, BitmapTexture*) const
613 {
614         GraphicsContext* context = textureMapper->graphicsContext();
615         QPainter* painter = context->platformContext();
616         painter->save();
617         painter->setTransform(matrix);
618         painter->setOpacity(opacity);
619         m_videoScene->render(painter, QRectF(targetRect), m_videoItem->sceneBoundingRect());
620         painter->restore();
621 }
622 #endif
623
624 PlatformMedia MediaPlayerPrivateQt::platformMedia() const
625 {
626     PlatformMedia pm;
627     pm.type = PlatformMedia::QtMediaPlayerType;
628     pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivateQt*>(this);
629     return pm;
630 }
631
632 } // namespace WebCore
633
634 #include "moc_MediaPlayerPrivateQt.cpp"