dccee69d615f520f4b1dde963923e743a64577f5
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / MediaPlayerPrivateGStreamer.cpp
1 /*
2  * Copyright (C) 2007, 2009 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Collabora Ltd.  All rights reserved.
4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5  * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
6  * Copyright (C) 2009, 2010 Igalia S.L
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * aint with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25 #include "MediaPlayerPrivateGStreamer.h"
26
27 #if ENABLE(VIDEO) && USE(GSTREAMER)
28
29 #include "ColorSpace.h"
30 #include "Document.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "GStreamerGWorld.h"
34 #include "GStreamerUtilities.h"
35 #include "GStreamerVersioning.h"
36 #include "GraphicsContext.h"
37 #include "GraphicsTypes.h"
38 #include "ImageGStreamer.h"
39 #include "ImageOrientation.h"
40 #include "IntRect.h"
41 #include "KURL.h"
42 #include "Logging.h"
43 #include "MIMETypeRegistry.h"
44 #include "MediaPlayer.h"
45 #include "NotImplemented.h"
46 #include "SecurityOrigin.h"
47 #include "TimeRanges.h"
48 #include "VideoSinkGStreamer.h"
49 #include "WebKitWebSourceGStreamer.h"
50 #include <gst/gst.h>
51 #include <gst/video/video.h>
52 #include <limits>
53 #include <math.h>
54 #include <wtf/gobject/GOwnPtr.h>
55 #include <wtf/text/CString.h>
56
57 #ifdef GST_API_VERSION_1
58 #include <gst/audio/streamvolume.h>
59 #else
60 #include <gst/interfaces/streamvolume.h>
61 #endif
62
63 // GstPlayFlags flags from playbin2. It is the policy of GStreamer to
64 // not publicly expose element-specific enums. That's why this
65 // GstPlayFlags enum has been copied here.
66 typedef enum {
67     GST_PLAY_FLAG_VIDEO         = 0x00000001,
68     GST_PLAY_FLAG_AUDIO         = 0x00000002,
69     GST_PLAY_FLAG_TEXT          = 0x00000004,
70     GST_PLAY_FLAG_VIS           = 0x00000008,
71     GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
72     GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
73     GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
74     GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
75     GST_PLAY_FLAG_BUFFERING     = 0x000000100
76 } GstPlayFlags;
77
78 #ifdef GST_API_VERSION_1
79 static const char* gPlaybinName = "playbin";
80 #else
81 static const char* gPlaybinName = "playbin2";
82 #endif
83
84 GST_DEBUG_CATEGORY_STATIC(webkit_media_player_debug);
85 #define GST_CAT_DEFAULT webkit_media_player_debug
86
87 using namespace std;
88
89 namespace WebCore {
90
91 static int greatestCommonDivisor(int a, int b)
92 {
93     while (b) {
94         int temp = a;
95         a = b;
96         b = temp % b;
97     }
98
99     return ABS(a);
100 }
101
102 static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
103 {
104     return player->handleMessage(message);
105 }
106
107 static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
108 {
109     player->sourceChanged();
110 }
111
112 static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
113 {
114     // This is called when playbin receives the notify::volume signal.
115     player->volumeChanged();
116 }
117
118 static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
119 {
120     // This is the callback of the timeout source created in ::volumeChanged.
121     player->notifyPlayerOfVolumeChange();
122     return FALSE;
123 }
124
125 static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
126 {
127     // This is called when playbin receives the notify::mute signal.
128     player->muteChanged();
129 }
130
131 static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
132 {
133     // This is the callback of the timeout source created in ::muteChanged.
134     player->notifyPlayerOfMute();
135     return FALSE;
136 }
137
138 static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
139 {
140     player->videoChanged();
141 }
142
143 static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
144 {
145     player->videoChanged();
146 }
147
148 static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
149 {
150     player->audioChanged();
151 }
152
153 static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
154 {
155     // This is the callback of the timeout source created in ::audioChanged.
156     player->notifyPlayerOfAudio();
157     return FALSE;
158 }
159
160 static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
161 {
162     // This is the callback of the timeout source created in ::videoChanged.
163     player->notifyPlayerOfVideo();
164     return FALSE;
165 }
166
167 static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate)
168 {
169     playerPrivate->triggerRepaint(buffer);
170 }
171
172 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
173 {
174     return adoptPtr(new MediaPlayerPrivateGStreamer(player));
175 }
176
177 void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
178 {
179     if (isAvailable())
180         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
181 }
182
183 bool initializeGStreamerAndRegisterWebKitElements()
184 {
185     if (!initializeGStreamer())
186         return false;
187
188     GRefPtr<GstElementFactory> srcFactory = gst_element_factory_find("webkitwebsrc");
189     if (!srcFactory) {
190         GST_DEBUG_CATEGORY_INIT(webkit_media_player_debug, "webkitmediaplayer", 0, "WebKit media player");
191         return gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC);
192     }
193
194     return true;
195 }
196
197 bool MediaPlayerPrivateGStreamer::isAvailable()
198 {
199     if (!initializeGStreamerAndRegisterWebKitElements())
200         return false;
201
202     GRefPtr<GstElementFactory> factory = gst_element_factory_find(gPlaybinName);
203     return factory;
204 }
205
206 MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
207     : m_player(player)
208     , m_playBin(0)
209     , m_webkitVideoSink(0)
210     , m_fpsSink(0)
211     , m_source(0)
212     , m_seekTime(0)
213     , m_changingRate(false)
214     , m_endTime(numeric_limits<float>::infinity())
215     , m_isEndReached(false)
216     , m_networkState(MediaPlayer::Empty)
217     , m_readyState(MediaPlayer::HaveNothing)
218     , m_isStreaming(false)
219     , m_size(IntSize())
220     , m_buffer(0)
221     , m_mediaLocations(0)
222     , m_mediaLocationCurrentIndex(0)
223     , m_resetPipeline(false)
224     , m_paused(true)
225     , m_seeking(false)
226     , m_buffering(false)
227     , m_playbackRate(1)
228     , m_errorOccured(false)
229     , m_mediaDuration(0)
230     , m_startedBuffering(false)
231     , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
232     , m_maxTimeLoaded(0)
233     , m_bufferingPercentage(0)
234     , m_preload(MediaPlayer::Auto)
235     , m_delayingLoad(false)
236     , m_mediaDurationKnown(true)
237     , m_maxTimeLoadedAtLastDidLoadingProgress(0)
238     , m_volumeTimerHandler(0)
239     , m_muteTimerHandler(0)
240     , m_hasVideo(false)
241     , m_hasAudio(false)
242     , m_audioTimerHandler(0)
243     , m_videoTimerHandler(0)
244     , m_webkitAudioSink(0)
245     , m_totalBytes(-1)
246     , m_originalPreloadWasAutoAndWasOverridden(false)
247 {
248     if (initializeGStreamerAndRegisterWebKitElements())
249         createGSTPlayBin();
250 }
251
252 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
253 {
254     if (m_fillTimer.isActive())
255         m_fillTimer.stop();
256
257     if (m_buffer)
258         gst_buffer_unref(m_buffer);
259     m_buffer = 0;
260
261     if (m_mediaLocations) {
262         gst_structure_free(m_mediaLocations);
263         m_mediaLocations = 0;
264     }
265
266 #ifndef GST_API_VERSION_1
267     if (m_videoSinkBin) {
268         gst_object_unref(m_videoSinkBin);
269         m_videoSinkBin = 0;
270     }
271 #endif
272
273     if (m_playBin) {
274         gst_element_set_state(m_playBin, GST_STATE_NULL);
275         gst_object_unref(GST_OBJECT(m_playBin));
276         m_playBin = 0;
277     }
278
279     m_player = 0;
280
281     if (m_muteTimerHandler)
282         g_source_remove(m_muteTimerHandler);
283
284     if (m_volumeTimerHandler)
285         g_source_remove(m_volumeTimerHandler);
286
287     if (m_videoTimerHandler)
288         g_source_remove(m_videoTimerHandler);
289
290     if (m_audioTimerHandler)
291         g_source_remove(m_audioTimerHandler);
292 }
293
294 void MediaPlayerPrivateGStreamer::load(const String& url)
295 {
296
297     KURL kurl(KURL(), url);
298     String cleanUrl(url);
299
300     // Clean out everything after file:// url path.
301     if (kurl.isLocalFile())
302         cleanUrl = cleanUrl.substring(0, kurl.pathEnd());
303
304     m_url = KURL(KURL(), cleanUrl);
305     g_object_set(m_playBin, "uri", cleanUrl.utf8().data(), NULL);
306
307     LOG_MEDIA_MESSAGE("Load %s", cleanUrl.utf8().data());
308
309     if (m_preload == MediaPlayer::None) {
310         LOG_MEDIA_MESSAGE("Delaying load.");
311         m_delayingLoad = true;
312     }
313
314     // Reset network and ready states. Those will be set properly once
315     // the pipeline pre-rolled.
316     m_networkState = MediaPlayer::Loading;
317     m_player->networkStateChanged();
318     m_readyState = MediaPlayer::HaveNothing;
319     m_player->readyStateChanged();
320     m_volumeAndMuteInitialized = false;
321
322     // GStreamer needs to have the pipeline set to a paused state to
323     // start providing anything useful.
324     gst_element_set_state(m_playBin, GST_STATE_PAUSED);
325
326     if (!m_delayingLoad)
327         commitLoad();
328 }
329
330 void MediaPlayerPrivateGStreamer::commitLoad()
331 {
332     ASSERT(!m_delayingLoad);
333     LOG_MEDIA_MESSAGE("Committing load.");
334     updateStates();
335 }
336
337 float MediaPlayerPrivateGStreamer::playbackPosition() const
338 {
339     if (m_isEndReached) {
340         // Position queries on a null pipeline return 0. If we're at
341         // the end of the stream the pipeline is null but we want to
342         // report either the seek time or the duration because this is
343         // what the Media element spec expects us to do.
344         if (m_seeking)
345             return m_seekTime;
346         if (m_mediaDuration)
347             return m_mediaDuration;
348     }
349
350     float ret = 0.0f;
351
352     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
353     if (!gst_element_query(m_playBin, query)) {
354         LOG_MEDIA_MESSAGE("Position query failed...");
355         gst_query_unref(query);
356         return ret;
357     }
358
359     gint64 position;
360     gst_query_parse_position(query, 0, &position);
361
362     // Position is available only if the pipeline is not in GST_STATE_NULL or
363     // GST_STATE_READY state.
364     if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
365         ret = static_cast<double>(position) / GST_SECOND;
366
367     LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
368
369     gst_query_unref(query);
370
371     return ret;
372 }
373
374 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
375 {
376     ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
377
378     GstState currentState;
379     GstState pending;
380
381     gst_element_get_state(m_playBin, &currentState, &pending, 0);
382     LOG_MEDIA_MESSAGE("Current state: %s, pending: %s", gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
383     if (currentState == newState || pending == newState)
384         return true;
385
386     GstStateChangeReturn setStateResult = gst_element_set_state(m_playBin, newState);
387     GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
388     if (currentState != pausedOrPlaying && setStateResult == GST_STATE_CHANGE_FAILURE) {
389         loadingFailed(MediaPlayer::Empty);
390         return false;
391     }
392     return true;
393 }
394
395 void MediaPlayerPrivateGStreamer::prepareToPlay()
396 {
397     m_isEndReached = false;
398     m_seeking = false;
399
400     if (m_delayingLoad) {
401         m_delayingLoad = false;
402         commitLoad();
403     }
404 }
405
406 void MediaPlayerPrivateGStreamer::play()
407 {
408     if (changePipelineState(GST_STATE_PLAYING)) {
409         m_isEndReached = false;
410         LOG_MEDIA_MESSAGE("Play");
411     }
412 }
413
414 void MediaPlayerPrivateGStreamer::pause()
415 {
416     if (m_isEndReached)
417         return;
418
419     if (changePipelineState(GST_STATE_PAUSED))
420         LOG_MEDIA_MESSAGE("Pause");
421 }
422
423 float MediaPlayerPrivateGStreamer::duration() const
424 {
425     if (!m_playBin)
426         return 0.0f;
427
428     if (m_errorOccured)
429         return 0.0f;
430
431     // Media duration query failed already, don't attempt new useless queries.
432     if (!m_mediaDurationKnown)
433         return numeric_limits<float>::infinity();
434
435     if (m_mediaDuration)
436         return m_mediaDuration;
437
438     GstFormat timeFormat = GST_FORMAT_TIME;
439     gint64 timeLength = 0;
440
441 #ifdef GST_API_VERSION_1
442     bool failure = !gst_element_query_duration(m_playBin, timeFormat, &timeLength) || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
443 #else
444     bool failure = !gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
445 #endif
446     if (failure) {
447         LOG_MEDIA_MESSAGE("Time duration query failed for %s", m_url.string().utf8().data());
448         return numeric_limits<float>::infinity();
449     }
450
451     LOG_MEDIA_MESSAGE("Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
452
453     return static_cast<double>(timeLength) / GST_SECOND;
454     // FIXME: handle 3.14.9.5 properly
455 }
456
457 float MediaPlayerPrivateGStreamer::currentTime() const
458 {
459     if (!m_playBin)
460         return 0.0f;
461
462     if (m_errorOccured)
463         return 0.0f;
464
465     if (m_seeking)
466         return m_seekTime;
467
468     // Workaround for
469     // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer
470     // 0.10.35 basesink reports wrong duration in case of EOS and
471     // negative playback rate. There's no upstream accepted patch for
472     // this bug yet, hence this temporary workaround.
473     if (m_isEndReached && m_playbackRate < 0)
474         return 0.0f;
475
476     return playbackPosition();
477
478 }
479
480 void MediaPlayerPrivateGStreamer::seek(float time)
481 {
482     if (!m_playBin)
483         return;
484
485     if (m_errorOccured)
486         return;
487
488     LOG_MEDIA_MESSAGE("Seek attempt to %f secs", time);
489
490     // Avoid useless seeking.
491     if (time == currentTime())
492         return;
493
494     // Extract the integer part of the time (seconds) and the
495     // fractional part (microseconds). Attempt to round the
496     // microseconds so no floating point precision is lost and we can
497     // perform an accurate seek.
498     float seconds;
499     float microSeconds = modf(time, &seconds) * 1000000;
500     GTimeVal timeValue;
501     timeValue.tv_sec = static_cast<glong>(seconds);
502     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
503
504     GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
505     LOG_MEDIA_MESSAGE("Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
506
507     if (!gst_element_seek(m_playBin, m_player->rate(),
508             GST_FORMAT_TIME,
509             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
510             GST_SEEK_TYPE_SET, clockTime,
511             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
512         LOG_MEDIA_MESSAGE("Seek to %f failed", time);
513     else {
514         m_seeking = true;
515         m_seekTime = time;
516     }
517 }
518
519 bool MediaPlayerPrivateGStreamer::paused() const
520 {
521     if (m_isEndReached) {
522         LOG_MEDIA_MESSAGE("Ignoring pause at EOS");
523         return true;
524     }
525
526     GstState state;
527     gst_element_get_state(m_playBin, &state, 0, 0);
528     return state == GST_STATE_PAUSED;
529 }
530
531 bool MediaPlayerPrivateGStreamer::seeking() const
532 {
533     return m_seeking;
534 }
535
536 // Returns the size of the video
537 IntSize MediaPlayerPrivateGStreamer::naturalSize() const
538 {
539     if (!hasVideo())
540         return IntSize();
541
542     if (!m_videoSize.isEmpty())
543         return m_videoSize;
544
545     GRefPtr<GstCaps> caps = webkitGstGetPadCaps(m_videoSinkPad.get());
546     if (!caps)
547         return IntSize();
548
549
550     // TODO: handle possible clean aperture data. See
551     // https://bugzilla.gnome.org/show_bug.cgi?id=596571
552     // TODO: handle possible transformation matrix. See
553     // https://bugzilla.gnome.org/show_bug.cgi?id=596326
554
555     // Get the video PAR and original size, if this fails the
556     // video-sink has likely not yet negotiated its caps.
557     int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride;
558     IntSize originalSize;
559     GstVideoFormat format;
560     if (!getVideoSizeAndFormatFromCaps(caps.get(), originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
561         return IntSize();
562
563     LOG_MEDIA_MESSAGE("Original video size: %dx%d", originalSize.width(), originalSize.height());
564     LOG_MEDIA_MESSAGE("Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
565
566     // Calculate DAR based on PAR and video size.
567     int displayWidth = originalSize.width() * pixelAspectRatioNumerator;
568     int displayHeight = originalSize.height() * pixelAspectRatioDenominator;
569
570     // Divide display width and height by their GCD to avoid possible overflows.
571     int displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
572     displayWidth /= displayAspectRatioGCD;
573     displayHeight /= displayAspectRatioGCD;
574
575     // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
576     guint64 width = 0, height = 0;
577     if (!(originalSize.height() % displayHeight)) {
578         LOG_MEDIA_MESSAGE("Keeping video original height");
579         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
580         height = static_cast<guint64>(originalSize.height());
581     } else if (!(originalSize.width() % displayWidth)) {
582         LOG_MEDIA_MESSAGE("Keeping video original width");
583         height = gst_util_uint64_scale_int(originalSize.width(), displayHeight, displayWidth);
584         width = static_cast<guint64>(originalSize.width());
585     } else {
586         LOG_MEDIA_MESSAGE("Approximating while keeping original video height");
587         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
588         height = static_cast<guint64>(originalSize.height());
589     }
590
591     LOG_MEDIA_MESSAGE("Natural size: %" G_GUINT64_FORMAT "x%" G_GUINT64_FORMAT, width, height);
592     m_videoSize = IntSize(static_cast<int>(width), static_cast<int>(height));
593     return m_videoSize;
594 }
595
596 void MediaPlayerPrivateGStreamer::videoChanged()
597 {
598     if (m_videoTimerHandler)
599         g_source_remove(m_videoTimerHandler);
600     m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this);
601 }
602
603 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
604 {
605     m_videoTimerHandler = 0;
606
607     gint videoTracks = 0;
608     if (m_playBin)
609         g_object_get(m_playBin, "n-video", &videoTracks, NULL);
610
611     m_hasVideo = videoTracks > 0;
612
613     m_videoSize = IntSize();
614
615     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
616 }
617
618 void MediaPlayerPrivateGStreamer::audioChanged()
619 {
620     if (m_audioTimerHandler)
621         g_source_remove(m_audioTimerHandler);
622     m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this);
623 }
624
625 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
626 {
627     m_audioTimerHandler = 0;
628
629     gint audioTracks = 0;
630     if (m_playBin)
631         g_object_get(m_playBin, "n-audio", &audioTracks, NULL);
632     m_hasAudio = audioTracks > 0;
633     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
634 }
635
636 void MediaPlayerPrivateGStreamer::setVolume(float volume)
637 {
638     if (!m_playBin)
639         return;
640
641     gst_stream_volume_set_volume(GST_STREAM_VOLUME(m_playBin), GST_STREAM_VOLUME_FORMAT_CUBIC,
642                                  static_cast<double>(volume));
643 }
644
645 void MediaPlayerPrivateGStreamer::notifyPlayerOfVolumeChange()
646 {
647     m_volumeTimerHandler = 0;
648
649     if (!m_player || !m_playBin)
650         return;
651     double volume;
652     volume = gst_stream_volume_get_volume(GST_STREAM_VOLUME(m_playBin), GST_STREAM_VOLUME_FORMAT_CUBIC);
653     // get_volume() can return values superior to 1.0 if the user
654     // applies software user gain via third party application (GNOME
655     // volume control for instance).
656     volume = CLAMP(volume, 0.0, 1.0);
657     m_player->volumeChanged(static_cast<float>(volume));
658 }
659
660 void MediaPlayerPrivateGStreamer::volumeChanged()
661 {
662     if (m_volumeTimerHandler)
663         g_source_remove(m_volumeTimerHandler);
664     m_volumeTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVolumeChangeTimeoutCallback), this);
665 }
666
667 void MediaPlayerPrivateGStreamer::setRate(float rate)
668 {
669     // Avoid useless playback rate update.
670     if (m_playbackRate == rate)
671         return;
672
673     GstState state;
674     GstState pending;
675
676     gst_element_get_state(m_playBin, &state, &pending, 0);
677     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
678         || (pending == GST_STATE_PAUSED))
679         return;
680
681     if (isLiveStream())
682         return;
683
684     m_playbackRate = rate;
685     m_changingRate = true;
686
687     if (!rate) {
688         gst_element_set_state(m_playBin, GST_STATE_PAUSED);
689         return;
690     }
691
692     float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND);
693     GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
694     gint64 start, end;
695     bool mute = false;
696
697     LOG_MEDIA_MESSAGE("Set Rate to %f", rate);
698     if (rate > 0) {
699         // Mute the sound if the playback rate is too extreme.
700         // TODO: in other cases we should perform pitch adjustments.
701         mute = (bool) (rate < 0.8 || rate > 2);
702         start = currentPosition;
703         end = GST_CLOCK_TIME_NONE;
704     } else {
705         start = 0;
706         mute = true;
707
708         // If we are at beginning of media, start from the end to
709         // avoid immediate EOS.
710         if (currentPosition <= 0)
711             end = static_cast<gint64>(duration() * GST_SECOND);
712         else
713             end = currentPosition;
714     }
715
716     LOG_MEDIA_MESSAGE("Need to mute audio: %d", (int) mute);
717
718     if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags,
719                           GST_SEEK_TYPE_SET, start,
720                           GST_SEEK_TYPE_SET, end))
721         LOG_MEDIA_MESSAGE("Set rate to %f failed", rate);
722     else
723         g_object_set(m_playBin, "mute", mute, NULL);
724 }
725
726 MediaPlayer::NetworkState MediaPlayerPrivateGStreamer::networkState() const
727 {
728     return m_networkState;
729 }
730
731 MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const
732 {
733     return m_readyState;
734 }
735
736 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
737 {
738     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
739     if (m_errorOccured || isLiveStream())
740         return timeRanges.release();
741
742 #if GST_CHECK_VERSION(0, 10, 31)
743     float mediaDuration(duration());
744     if (!mediaDuration || isinf(mediaDuration))
745         return timeRanges.release();
746
747     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
748
749     if (!gst_element_query(m_playBin, query)) {
750         gst_query_unref(query);
751         return timeRanges.release();
752     }
753
754     gint64 rangeStart = 0, rangeStop = 0;
755     for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
756         if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
757             timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100),
758                             static_cast<float>((rangeStop * mediaDuration) / 100));
759     }
760
761     // Fallback to the more general maxTimeLoaded() if no range has
762     // been found.
763     if (!timeRanges->length())
764         if (float loaded = maxTimeLoaded())
765             timeRanges->add(0, loaded);
766
767     gst_query_unref(query);
768 #else
769     float loaded = maxTimeLoaded();
770     if (!m_errorOccured && !isLiveStream() && loaded > 0)
771         timeRanges->add(0, loaded);
772 #endif
773     return timeRanges.release();
774 }
775
776 gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
777 {
778     GOwnPtr<GError> err;
779     GOwnPtr<gchar> debug;
780     MediaPlayer::NetworkState error;
781     bool issueError = true;
782     bool attemptNextLocation = false;
783     const GstStructure* structure = gst_message_get_structure(message);
784
785     if (structure) {
786         const gchar* messageTypeName = gst_structure_get_name(structure);
787
788         // Redirect messages are sent from elements, like qtdemux, to
789         // notify of the new location(s) of the media.
790         if (!g_strcmp0(messageTypeName, "redirect")) {
791             mediaLocationChanged(message);
792             return TRUE;
793         }
794     }
795
796     LOG_MEDIA_MESSAGE("Message received from element %s", GST_MESSAGE_SRC_NAME(message));
797     switch (GST_MESSAGE_TYPE(message)) {
798     case GST_MESSAGE_ERROR:
799         if (m_resetPipeline)
800             break;
801         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
802         LOG_MEDIA_MESSAGE("Error %d: %s (url=%s)", err->code, err->message, m_url.string().utf8().data());
803
804         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin), GST_DEBUG_GRAPH_SHOW_ALL, "webkit-video.error");
805
806         error = MediaPlayer::Empty;
807         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
808             || err->code == GST_STREAM_ERROR_WRONG_TYPE
809             || err->code == GST_STREAM_ERROR_FAILED
810             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
811             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
812             error = MediaPlayer::FormatError;
813         else if (err->domain == GST_STREAM_ERROR) {
814             // Let the mediaPlayerClient handle the stream error, in
815             // this case the HTMLMediaElement will emit a stalled
816             // event.
817             if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) {
818                 LOG_MEDIA_MESSAGE("Decode error, let the Media element emit a stalled event.");
819                 break;
820             }
821             error = MediaPlayer::DecodeError;
822             attemptNextLocation = true;
823         } else if (err->domain == GST_RESOURCE_ERROR)
824             error = MediaPlayer::NetworkError;
825
826         if (attemptNextLocation)
827             issueError = !loadNextLocation();
828         if (issueError)
829             loadingFailed(error);
830         break;
831     case GST_MESSAGE_EOS:
832         LOG_MEDIA_MESSAGE("End of Stream");
833         didEnd();
834         break;
835     case GST_MESSAGE_STATE_CHANGED:
836         // Ignore state changes if load is delayed (preload=none). The
837         // player state will be updated once commitLoad() is called.
838         if (m_delayingLoad) {
839             LOG_MEDIA_MESSAGE("Media load has been delayed. Ignoring state changes for now");
840             break;
841         }
842
843         // Ignore state changes from internal elements. They are
844         // forwarded to playbin2 anyway.
845         if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin)) {
846             updateStates();
847
848             // Construct a filename for the graphviz dot file output.
849             GstState oldState, newState;
850             gst_message_parse_state_changed(message, &oldState, &newState, 0);
851
852             CString dotFileName = String::format("webkit-video.%s_%s",
853                                                  gst_element_state_get_name(oldState),
854                                                  gst_element_state_get_name(newState)).utf8();
855
856             GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
857         }
858         break;
859     case GST_MESSAGE_BUFFERING:
860         processBufferingStats(message);
861         break;
862 #ifdef GST_API_VERSION_1
863     case GST_MESSAGE_DURATION_CHANGED:
864 #else
865     case GST_MESSAGE_DURATION:
866 #endif
867         LOG_MEDIA_MESSAGE("Duration changed");
868         durationChanged();
869         break;
870     default:
871         LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
872                     GST_MESSAGE_TYPE_NAME(message));
873         break;
874     }
875     return TRUE;
876 }
877
878 void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
879 {
880     // This is the immediate buffering that needs to happen so we have
881     // enough to play right now.
882     m_buffering = true;
883     const GstStructure *structure = gst_message_get_structure(message);
884     gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
885
886     LOG_MEDIA_MESSAGE("[Buffering] Buffering: %d%%.", m_bufferingPercentage);
887
888     GstBufferingMode mode;
889     gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
890     if (mode != GST_BUFFERING_DOWNLOAD) {
891         updateStates();
892         return;
893     }
894
895     // This is on-disk buffering, that allows us to download much more
896     // than needed for right now.
897     if (!m_startedBuffering) {
898         LOG_MEDIA_MESSAGE("[Buffering] Starting on-disk buffering.");
899
900         m_startedBuffering = true;
901
902         if (m_fillTimer.isActive())
903             m_fillTimer.stop();
904
905         m_fillTimer.startRepeating(0.2);
906     }
907 }
908
909 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
910 {
911     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
912
913     if (!gst_element_query(m_playBin, query)) {
914         gst_query_unref(query);
915         return;
916     }
917
918     gint64 start, stop;
919     gdouble fillStatus = 100.0;
920
921     gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
922     gst_query_unref(query);
923
924     if (stop != -1)
925         fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
926
927     LOG_MEDIA_MESSAGE("[Buffering] Download buffer filled up to %f%%", fillStatus);
928
929     if (!m_mediaDuration)
930         durationChanged();
931
932     // Update maxTimeLoaded only if the media duration is
933     // available. Otherwise we can't compute it.
934     if (m_mediaDuration) {
935         if (fillStatus == 100.0)
936             m_maxTimeLoaded = m_mediaDuration;
937         else
938             m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
939         LOG_MEDIA_MESSAGE("[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
940     }
941
942     if (fillStatus != 100.0) {
943         updateStates();
944         return;
945     }
946
947     // Media is now fully loaded. It will play even if network
948     // connection is cut. Buffering is done, remove the fill source
949     // from the main loop.
950     m_fillTimer.stop();
951     m_startedBuffering = false;
952     updateStates();
953 }
954
955 float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
956 {
957     if (m_errorOccured)
958         return 0.0f;
959
960     LOG_MEDIA_MESSAGE("maxTimeSeekable");
961     // infinite duration means live stream
962     if (isinf(duration()))
963         return 0.0f;
964
965     return duration();
966 }
967
968 float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
969 {
970     if (m_errorOccured)
971         return 0.0f;
972
973     float loaded = m_maxTimeLoaded;
974     if (!loaded && !m_fillTimer.isActive())
975         loaded = duration();
976     LOG_MEDIA_MESSAGE("maxTimeLoaded: %f", loaded);
977     return loaded;
978 }
979
980 bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
981 {
982     if (!m_playBin || !m_mediaDuration || !totalBytes())
983         return false;
984     float currentMaxTimeLoaded = maxTimeLoaded();
985     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
986     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
987     LOG_MEDIA_MESSAGE("didLoadingProgress: %d", didLoadingProgress);
988     return didLoadingProgress;
989 }
990
991 unsigned MediaPlayerPrivateGStreamer::totalBytes() const
992 {
993     if (m_errorOccured)
994         return 0;
995
996     if (m_totalBytes != -1)
997         return m_totalBytes;
998
999     if (!m_source)
1000         return 0;
1001
1002     GstFormat fmt = GST_FORMAT_BYTES;
1003     gint64 length = 0;
1004 #ifdef GST_API_VERSION_1
1005     if (gst_element_query_duration(m_source.get(), fmt, &length)) {
1006 #else
1007     if (gst_element_query_duration(m_source.get(), &fmt, &length)) {
1008 #endif
1009         LOG_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1010         m_totalBytes = static_cast<unsigned>(length);
1011         m_isStreaming = !length;
1012         return m_totalBytes;
1013     }
1014
1015     // Fall back to querying the source pads manually.
1016     // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
1017     GstIterator* iter = gst_element_iterate_src_pads(m_source.get());
1018     bool done = false;
1019     while (!done) {
1020 #ifdef GST_API_VERSION_1
1021         GValue item = G_VALUE_INIT;
1022         switch (gst_iterator_next(iter, &item)) {
1023         case GST_ITERATOR_OK: {
1024             GstPad* pad = static_cast<GstPad*>(g_value_get_object(&item));
1025             gint64 padLength = 0;
1026             if (gst_pad_query_duration(pad, fmt, &padLength) && padLength > length)
1027                 length = padLength;
1028             break;
1029         }
1030 #else
1031         gpointer data;
1032
1033         switch (gst_iterator_next(iter, &data)) {
1034         case GST_ITERATOR_OK: {
1035             GRefPtr<GstPad> pad = adoptGRef(GST_PAD_CAST(data));
1036             gint64 padLength = 0;
1037             if (gst_pad_query_duration(pad.get(), &fmt, &padLength) && padLength > length)
1038                 length = padLength;
1039             break;
1040         }
1041 #endif
1042         case GST_ITERATOR_RESYNC:
1043             gst_iterator_resync(iter);
1044             break;
1045         case GST_ITERATOR_ERROR:
1046             // Fall through.
1047         case GST_ITERATOR_DONE:
1048             done = true;
1049             break;
1050         }
1051
1052 #ifdef GST_API_VERSION_1
1053         g_value_unset(&item);
1054 #endif
1055     }
1056
1057     gst_iterator_free(iter);
1058
1059     LOG_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1060     m_totalBytes = static_cast<unsigned>(length);
1061     m_isStreaming = !length;
1062     return m_totalBytes;
1063 }
1064
1065 unsigned MediaPlayerPrivateGStreamer::decodedFrameCount() const
1066 {
1067     guint64 decodedFrames = 0;
1068     if (m_fpsSink)
1069         g_object_get(m_fpsSink, "frames-rendered", &decodedFrames, NULL);
1070     return static_cast<unsigned>(decodedFrames);
1071 }
1072
1073 unsigned MediaPlayerPrivateGStreamer::droppedFrameCount() const
1074 {
1075     guint64 framesDropped = 0;
1076     if (m_fpsSink)
1077         g_object_get(m_fpsSink, "frames-dropped", &framesDropped, NULL);
1078     return static_cast<unsigned>(framesDropped);
1079 }
1080
1081 unsigned MediaPlayerPrivateGStreamer::audioDecodedByteCount() const
1082 {
1083     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1084     gint64 position = 0;
1085
1086     if (m_webkitAudioSink && gst_element_query(m_webkitAudioSink.get(), query))
1087         gst_query_parse_position(query, 0, &position);
1088
1089     gst_query_unref(query);
1090     return static_cast<unsigned>(position);
1091 }
1092
1093 unsigned MediaPlayerPrivateGStreamer::videoDecodedByteCount() const
1094 {
1095     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1096     gint64 position = 0;
1097
1098     if (gst_element_query(m_webkitVideoSink, query))
1099         gst_query_parse_position(query, 0, &position);
1100
1101     gst_query_unref(query);
1102     return static_cast<unsigned>(position);
1103 }
1104
1105 void MediaPlayerPrivateGStreamer::updateAudioSink()
1106 {
1107     if (!m_playBin)
1108         return;
1109
1110     GstElement* sinkPtr = 0;
1111
1112     g_object_get(m_playBin, "audio-sink", &sinkPtr, NULL);
1113     m_webkitAudioSink = adoptGRef(sinkPtr);
1114
1115 }
1116
1117
1118 void MediaPlayerPrivateGStreamer::sourceChanged()
1119 {
1120     GstElement* srcPtr = 0;
1121
1122     g_object_get(m_playBin, "source", &srcPtr, NULL);
1123     m_source = adoptGRef(srcPtr);
1124
1125     if (WEBKIT_IS_WEB_SRC(m_source.get()))
1126         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
1127 }
1128
1129 void MediaPlayerPrivateGStreamer::cancelLoad()
1130 {
1131     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
1132         return;
1133
1134     if (m_playBin)
1135         gst_element_set_state(m_playBin, GST_STATE_NULL);
1136 }
1137
1138 void MediaPlayerPrivateGStreamer::updateStates()
1139 {
1140     if (!m_playBin)
1141         return;
1142
1143     if (m_errorOccured)
1144         return;
1145
1146     MediaPlayer::NetworkState oldNetworkState = m_networkState;
1147     MediaPlayer::ReadyState oldReadyState = m_readyState;
1148     GstState state;
1149     GstState pending;
1150
1151     GstStateChangeReturn ret = gst_element_get_state(m_playBin,
1152         &state, &pending, 250 * GST_NSECOND);
1153
1154     bool shouldUpdateAfterSeek = false;
1155     switch (ret) {
1156     case GST_STATE_CHANGE_SUCCESS:
1157         LOG_MEDIA_MESSAGE("State: %s, pending: %s",
1158             gst_element_state_get_name(state),
1159             gst_element_state_get_name(pending));
1160
1161         m_resetPipeline = state <= GST_STATE_READY;
1162
1163         // Try to figure out ready and network states.
1164         if (state == GST_STATE_READY) {
1165             m_readyState = MediaPlayer::HaveMetadata;
1166             m_networkState = MediaPlayer::Empty;
1167             // Cache the duration without emiting the durationchange
1168             // event because it's taken care of by the media element
1169             // in this precise case.
1170             if (!m_isEndReached)
1171                 cacheDuration();
1172         } else if ((state == GST_STATE_NULL) || (maxTimeLoaded() == duration())) {
1173             m_networkState = MediaPlayer::Loaded;
1174             m_readyState = MediaPlayer::HaveEnoughData;
1175         } else {
1176             m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
1177             m_networkState = MediaPlayer::Loading;
1178         }
1179
1180         if (m_buffering && state != GST_STATE_READY) {
1181             m_readyState = MediaPlayer::HaveCurrentData;
1182             m_networkState = MediaPlayer::Loading;
1183         }
1184
1185         // Now let's try to get the states in more detail using
1186         // information from GStreamer, while we sync states where
1187         // needed.
1188         if (state == GST_STATE_PAUSED) {
1189             if (!m_webkitAudioSink)
1190                 updateAudioSink();
1191
1192             if (!m_volumeAndMuteInitialized) {
1193                 notifyPlayerOfVolumeChange();
1194                 notifyPlayerOfMute();
1195                 m_volumeAndMuteInitialized = true;
1196             }
1197
1198             if (m_buffering && m_bufferingPercentage == 100) {
1199                 m_buffering = false;
1200                 m_bufferingPercentage = 0;
1201                 m_readyState = MediaPlayer::HaveEnoughData;
1202
1203                 LOG_MEDIA_MESSAGE("[Buffering] Complete.");
1204
1205                 if (!m_paused) {
1206                     LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
1207                     gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1208                 }
1209             } else if (!m_buffering && (currentTime() < duration())) {
1210                 m_paused = true;
1211             }
1212         } else if (state == GST_STATE_PLAYING) {
1213             m_readyState = MediaPlayer::HaveEnoughData;
1214             m_paused = false;
1215
1216             if (m_buffering && !isLiveStream()) {
1217                 m_readyState = MediaPlayer::HaveCurrentData;
1218                 m_networkState = MediaPlayer::Loading;
1219
1220                 LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
1221
1222                 gst_element_set_state(m_playBin, GST_STATE_PAUSED);
1223             }
1224         } else
1225             m_paused = true;
1226
1227         // Is on-disk buffering in progress?
1228         if (m_fillTimer.isActive())
1229             m_networkState = MediaPlayer::Loading;
1230
1231         if (m_changingRate) {
1232             m_player->rateChanged();
1233             m_changingRate = false;
1234         }
1235
1236         if (m_seeking) {
1237             shouldUpdateAfterSeek = true;
1238             m_seeking = false;
1239         }
1240
1241         break;
1242     case GST_STATE_CHANGE_ASYNC:
1243         LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s",
1244             gst_element_state_get_name(state),
1245             gst_element_state_get_name(pending));
1246         // Change in progress
1247
1248         // On-disk buffering was attempted but the media is live. This
1249         // can't work so disable on-disk buffering and reset the
1250         // pipeline.
1251         if (state == GST_STATE_READY && isLiveStream() && m_preload == MediaPlayer::Auto) {
1252             setPreload(MediaPlayer::None);
1253             gst_element_set_state(m_playBin, GST_STATE_NULL);
1254             gst_element_set_state(m_playBin, GST_STATE_PAUSED);
1255         }
1256
1257         // A live stream was paused, reset the pipeline.
1258         if (state == GST_STATE_PAUSED && pending == GST_STATE_PLAYING && isLiveStream()) {
1259             gst_element_set_state(m_playBin, GST_STATE_NULL);
1260             gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1261         }
1262
1263         if (!isLiveStream() && !m_buffering)
1264             return;
1265
1266         if (m_seeking) {
1267             shouldUpdateAfterSeek = true;
1268             m_seeking = false;
1269         }
1270         break;
1271     case GST_STATE_CHANGE_FAILURE:
1272         LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s",
1273             gst_element_state_get_name(state),
1274             gst_element_state_get_name(pending));
1275         // Change failed
1276         return;
1277     case GST_STATE_CHANGE_NO_PREROLL:
1278         LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s",
1279             gst_element_state_get_name(state),
1280             gst_element_state_get_name(pending));
1281
1282         if (state == GST_STATE_READY)
1283             m_readyState = MediaPlayer::HaveNothing;
1284         else if (state == GST_STATE_PAUSED) {
1285             m_readyState = MediaPlayer::HaveEnoughData;
1286             m_paused = true;
1287             // Live pipelines go in PAUSED without prerolling.
1288             m_isStreaming = true;
1289         } else if (state == GST_STATE_PLAYING)
1290             m_paused = false;
1291
1292         if (m_seeking) {
1293             shouldUpdateAfterSeek = true;
1294             m_seeking = false;
1295             if (!m_paused)
1296                 gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1297         } else if (!m_paused)
1298             gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1299
1300         m_networkState = MediaPlayer::Loading;
1301         break;
1302     default:
1303         LOG_MEDIA_MESSAGE("Else : %d", ret);
1304         break;
1305     }
1306
1307     if (seeking())
1308         m_readyState = MediaPlayer::HaveNothing;
1309
1310     if (shouldUpdateAfterSeek)
1311         timeChanged();
1312
1313     if (m_networkState != oldNetworkState) {
1314         LOG_MEDIA_MESSAGE("Network State Changed from %u to %u",
1315             oldNetworkState, m_networkState);
1316         m_player->networkStateChanged();
1317     }
1318     if (m_readyState != oldReadyState) {
1319         LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u",
1320             oldReadyState, m_readyState);
1321         m_player->readyStateChanged();
1322     }
1323 }
1324
1325 void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
1326 {
1327     if (m_mediaLocations)
1328         gst_structure_free(m_mediaLocations);
1329
1330     const GstStructure* structure = gst_message_get_structure(message);
1331     if (structure) {
1332         // This structure can contain:
1333         // - both a new-location string and embedded locations structure
1334         // - or only a new-location string.
1335         m_mediaLocations = gst_structure_copy(structure);
1336         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1337
1338         if (locations)
1339             m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
1340
1341         loadNextLocation();
1342     }
1343 }
1344
1345 bool MediaPlayerPrivateGStreamer::loadNextLocation()
1346 {
1347     if (!m_mediaLocations)
1348         return false;
1349
1350     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1351     const gchar* newLocation = 0;
1352
1353     if (!locations) {
1354         // Fallback on new-location string.
1355         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
1356         if (!newLocation)
1357             return false;
1358     }
1359
1360     if (!newLocation) {
1361         if (m_mediaLocationCurrentIndex < 0) {
1362             m_mediaLocations = 0;
1363             return false;
1364         }
1365
1366         const GValue* location = gst_value_list_get_value(locations,
1367                                                           m_mediaLocationCurrentIndex);
1368         const GstStructure* structure = gst_value_get_structure(location);
1369
1370         if (!structure) {
1371             m_mediaLocationCurrentIndex--;
1372             return false;
1373         }
1374
1375         newLocation = gst_structure_get_string(structure, "new-location");
1376     }
1377
1378     if (newLocation) {
1379         // Found a candidate. new-location is not always an absolute url
1380         // though. We need to take the base of the current url and
1381         // append the value of new-location to it.
1382
1383         gchar* currentLocation = 0;
1384         g_object_get(m_playBin, "uri", &currentLocation, NULL);
1385
1386         KURL currentUrl(KURL(), currentLocation);
1387         g_free(currentLocation);
1388
1389         KURL newUrl;
1390
1391         if (gst_uri_is_valid(newLocation))
1392             newUrl = KURL(KURL(), newLocation);
1393         else
1394             newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
1395
1396         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
1397         if (securityOrigin->canRequest(newUrl)) {
1398             LOG_MEDIA_MESSAGE("New media url: %s", newUrl.string().utf8().data());
1399
1400             // Reset player states.
1401             m_networkState = MediaPlayer::Loading;
1402             m_player->networkStateChanged();
1403             m_readyState = MediaPlayer::HaveNothing;
1404             m_player->readyStateChanged();
1405
1406             // Reset pipeline state.
1407             m_resetPipeline = true;
1408             gst_element_set_state(m_playBin, GST_STATE_READY);
1409
1410             GstState state;
1411             gst_element_get_state(m_playBin, &state, 0, 0);
1412             if (state <= GST_STATE_READY) {
1413                 // Set the new uri and start playing.
1414                 g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
1415                 gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1416                 return true;
1417             }
1418         }
1419     }
1420     m_mediaLocationCurrentIndex--;
1421     return false;
1422
1423 }
1424
1425 void MediaPlayerPrivateGStreamer::loadStateChanged()
1426 {
1427     updateStates();
1428 }
1429
1430 void MediaPlayerPrivateGStreamer::sizeChanged()
1431 {
1432     notImplemented();
1433 }
1434
1435 void MediaPlayerPrivateGStreamer::timeChanged()
1436 {
1437     updateStates();
1438     m_player->timeChanged();
1439 }
1440
1441 void MediaPlayerPrivateGStreamer::didEnd()
1442 {
1443     // Synchronize position and duration values to not confuse the
1444     // HTMLMediaElement. In some cases like reverse playback the
1445     // position is not always reported as 0 for instance.
1446     float now = currentTime();
1447     if (now > 0 && now <= duration() && m_mediaDuration != now) {
1448         m_mediaDurationKnown = true;
1449         m_mediaDuration = now;
1450         m_player->durationChanged();
1451     }
1452
1453     m_isEndReached = true;
1454     timeChanged();
1455
1456     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
1457         m_paused = true;
1458         gst_element_set_state(m_playBin, GST_STATE_NULL);
1459     }
1460 }
1461
1462 void MediaPlayerPrivateGStreamer::cacheDuration()
1463 {
1464     // Reset cached media duration
1465     m_mediaDuration = 0;
1466
1467     // And re-cache it if possible.
1468     GstState state;
1469     gst_element_get_state(m_playBin, &state, 0, 0);
1470     float newDuration = duration();
1471
1472     if (state <= GST_STATE_READY) {
1473         // Don't set m_mediaDurationKnown yet if the pipeline is not
1474         // paused. This allows duration() query to fail at least once
1475         // before playback starts and duration becomes known.
1476         if (!isinf(newDuration))
1477             m_mediaDuration = newDuration;
1478     } else {
1479         m_mediaDurationKnown = !isinf(newDuration);
1480         if (m_mediaDurationKnown)
1481             m_mediaDuration = newDuration;
1482     }
1483
1484     if (!isinf(newDuration))
1485         m_mediaDuration = newDuration;
1486 }
1487
1488 void MediaPlayerPrivateGStreamer::durationChanged()
1489 {
1490     float previousDuration = m_mediaDuration;
1491
1492     cacheDuration();
1493     // Avoid emiting durationchanged in the case where the previous
1494     // duration was 0 because that case is already handled by the
1495     // HTMLMediaElement.
1496     if (previousDuration && m_mediaDuration != previousDuration)
1497         m_player->durationChanged();
1498
1499     if (m_preload == MediaPlayer::None && m_originalPreloadWasAutoAndWasOverridden) {
1500         m_totalBytes = -1;
1501         if (totalBytes() && !isLiveStream()) {
1502             setPreload(MediaPlayer::Auto);
1503             gst_element_set_state(m_playBin, GST_STATE_NULL);
1504             gst_element_set_state(m_playBin, GST_STATE_PAUSED);
1505         }
1506     }
1507 }
1508
1509 bool MediaPlayerPrivateGStreamer::supportsMuting() const
1510 {
1511     return true;
1512 }
1513
1514 void MediaPlayerPrivateGStreamer::setMuted(bool muted)
1515 {
1516     if (!m_playBin)
1517         return;
1518
1519     g_object_set(m_playBin, "mute", muted, NULL);
1520 }
1521
1522 void MediaPlayerPrivateGStreamer::notifyPlayerOfMute()
1523 {
1524     m_muteTimerHandler = 0;
1525
1526     if (!m_player || !m_playBin)
1527         return;
1528
1529     gboolean muted;
1530     g_object_get(m_playBin, "mute", &muted, NULL);
1531     m_player->muteChanged(static_cast<bool>(muted));
1532 }
1533
1534 void MediaPlayerPrivateGStreamer::muteChanged()
1535 {
1536     if (m_muteTimerHandler)
1537         g_source_remove(m_muteTimerHandler);
1538     m_muteTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateMuteChangeTimeoutCallback), this);
1539 }
1540
1541 void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
1542 {
1543     m_errorOccured = true;
1544     if (m_networkState != error) {
1545         m_networkState = error;
1546         m_player->networkStateChanged();
1547     }
1548     if (m_readyState != MediaPlayer::HaveNothing) {
1549         m_readyState = MediaPlayer::HaveNothing;
1550         m_player->readyStateChanged();
1551     }
1552 }
1553
1554 void MediaPlayerPrivateGStreamer::setSize(const IntSize& size)
1555 {
1556     m_size = size;
1557 }
1558
1559 void MediaPlayerPrivateGStreamer::setVisible(bool)
1560 {
1561 }
1562
1563
1564 void MediaPlayerPrivateGStreamer::triggerRepaint(GstBuffer* buffer)
1565 {
1566     g_return_if_fail(GST_IS_BUFFER(buffer));
1567     gst_buffer_replace(&m_buffer, buffer);
1568     m_player->repaint();
1569 }
1570
1571 void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& rect)
1572 {
1573     if (context->paintingDisabled())
1574         return;
1575
1576     if (!m_player->visible())
1577         return;
1578
1579     if (!m_buffer)
1580         return;
1581
1582     GRefPtr<GstCaps> caps = webkitGstGetPadCaps(m_videoSinkPad.get());
1583     if (!caps)
1584         return;
1585
1586     RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps.get());
1587     if (!gstImage)
1588         return;
1589
1590     context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB,
1591                        rect, gstImage->rect(), CompositeCopy, DoNotRespectImageOrientation, false);
1592 }
1593
1594 static HashSet<String> mimeTypeCache()
1595 {
1596     initializeGStreamerAndRegisterWebKitElements();
1597
1598     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
1599     static bool typeListInitialized = false;
1600
1601     if (typeListInitialized)
1602         return cache;
1603     const char* mimeTypes[] = {"application/ogg",
1604                                "application/vnd.apple.mpegurl",
1605                                "application/vnd.rn-realmedia",
1606                                "application/x-3gp",
1607                                "application/x-pn-realaudio",
1608                                "audio/3gpp",
1609                                "audio/aac",
1610                                "audio/flac",
1611                                "audio/iLBC-sh",
1612                                "audio/midi",
1613                                "audio/mobile-xmf",
1614                                "audio/mp1",
1615                                "audio/mp2",
1616                                "audio/mp3",
1617                                "audio/mp4",
1618                                "audio/mpeg",
1619                                "audio/ogg",
1620                                "audio/qcelp",
1621                                "audio/riff-midi",
1622                                "audio/wav",
1623                                "audio/webm",
1624                                "audio/x-ac3",
1625                                "audio/x-aiff",
1626                                "audio/x-amr-nb-sh",
1627                                "audio/x-amr-wb-sh",
1628                                "audio/x-au",
1629                                "audio/x-ay",
1630                                "audio/x-celt",
1631                                "audio/x-dts",
1632                                "audio/x-flac",
1633                                "audio/x-gbs",
1634                                "audio/x-gsm",
1635                                "audio/x-gym",
1636                                "audio/x-imelody",
1637                                "audio/x-ircam",
1638                                "audio/x-kss",
1639                                "audio/x-m4a",
1640                                "audio/x-mod",
1641                                "audio/x-mp3",
1642                                "audio/x-mpeg",
1643                                "audio/x-musepack",
1644                                "audio/x-nist",
1645                                "audio/x-nsf",
1646                                "audio/x-paris",
1647                                "audio/x-sap",
1648                                "audio/x-sbc",
1649                                "audio/x-sds",
1650                                "audio/x-shorten",
1651                                "audio/x-sid",
1652                                "audio/x-spc",
1653                                "audio/x-speex",
1654                                "audio/x-svx",
1655                                "audio/x-ttafile",
1656                                "audio/x-vgm",
1657                                "audio/x-voc",
1658                                "audio/x-vorbis+ogg",
1659                                "audio/x-w64",
1660                                "audio/x-wav",
1661                                "audio/x-wavpack",
1662                                "audio/x-wavpack-correction",
1663                                "video/3gpp",
1664                                "video/mj2",
1665                                "video/mp4",
1666                                "video/mpeg",
1667                                "video/mpegts",
1668                                "video/ogg",
1669                                "video/quicktime",
1670                                "video/vivo",
1671                                "video/webm",
1672                                "video/x-cdxa",
1673                                "video/x-dirac",
1674                                "video/x-dv",
1675                                "video/x-fli",
1676                                "video/x-flv",
1677                                "video/x-h263",
1678                                "video/x-ivf",
1679                                "video/x-m4v",
1680                                "video/x-matroska",
1681                                "video/x-mng",
1682                                "video/x-ms-asf",
1683                                "video/x-msvideo",
1684                                "video/x-mve",
1685                                "video/x-nuv",
1686                                "video/x-vcd"};
1687
1688     for (unsigned i = 0; i < (sizeof(mimeTypes) / sizeof(*mimeTypes)); ++i)
1689         cache.add(String(mimeTypes[i]));
1690
1691     typeListInitialized = true;
1692     return cache;
1693 }
1694
1695 void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
1696 {
1697     types = mimeTypeCache();
1698 }
1699
1700 MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs, const KURL&)
1701 {
1702     if (type.isNull() || type.isEmpty())
1703         return MediaPlayer::IsNotSupported;
1704
1705     // spec says we should not return "probably" if the codecs string is empty
1706     if (mimeTypeCache().contains(type))
1707         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
1708     return MediaPlayer::IsNotSupported;
1709 }
1710
1711 bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const
1712 {
1713     return true;
1714 }
1715
1716 bool MediaPlayerPrivateGStreamer::supportsFullscreen() const
1717 {
1718 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
1719     // See <rdar://problem/7389945>
1720     return false;
1721 #else
1722     return true;
1723 #endif
1724 }
1725
1726 PlatformMedia MediaPlayerPrivateGStreamer::platformMedia() const
1727 {
1728     PlatformMedia p;
1729 #ifndef GST_API_VERSION_1
1730     p.type = PlatformMedia::GStreamerGWorldType;
1731     p.media.gstreamerGWorld = m_gstGWorld.get();
1732 #endif
1733     return p;
1734 }
1735
1736 MediaPlayer::MovieLoadType MediaPlayerPrivateGStreamer::movieLoadType() const
1737 {
1738     if (m_readyState == MediaPlayer::HaveNothing)
1739         return MediaPlayer::Unknown;
1740
1741     if (isLiveStream())
1742         return MediaPlayer::LiveStream;
1743
1744     return MediaPlayer::Download;
1745 }
1746
1747 void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
1748 {
1749     m_originalPreloadWasAutoAndWasOverridden = m_preload != preload && m_preload == MediaPlayer::Auto;
1750
1751     m_preload = preload;
1752
1753     ASSERT(m_playBin);
1754
1755     GstPlayFlags flags;
1756     g_object_get(m_playBin, "flags", &flags, NULL);
1757     if (m_preload == MediaPlayer::Auto) {
1758         LOG_MEDIA_MESSAGE("Enabling on-disk buffering");
1759         g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
1760     } else {
1761         LOG_MEDIA_MESSAGE("Disabling on-disk buffering");
1762         g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
1763     }
1764
1765     if (m_delayingLoad && m_preload != MediaPlayer::None) {
1766         m_delayingLoad = false;
1767         commitLoad();
1768     }
1769 }
1770
1771 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
1772 {
1773     ASSERT(!m_playBin);
1774     m_playBin = gst_element_factory_make(gPlaybinName, "play");
1775
1776 #ifndef GST_API_VERSION_1
1777     m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin);
1778 #endif
1779
1780     GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
1781     gst_bus_add_signal_watch(bus);
1782     g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
1783     gst_object_unref(bus);
1784
1785     g_object_set(m_playBin, "mute", m_player->muted(), NULL);
1786
1787     g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
1788     g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
1789     g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
1790     g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
1791     g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
1792
1793 #ifndef GST_API_VERSION_1
1794     m_webkitVideoSink = webkitVideoSinkNew(m_gstGWorld.get());
1795 #else
1796     m_webkitVideoSink = webkitVideoSinkNew();
1797 #endif
1798     m_videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
1799
1800     g_signal_connect(m_webkitVideoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
1801
1802
1803 #ifndef GST_API_VERSION_1
1804     m_videoSinkBin = gst_bin_new("sink");
1805
1806     GstElement* videoTee = gst_element_factory_make("tee", "videoTee");
1807     GstElement* queue = gst_element_factory_make("queue", 0);
1808
1809     // Take ownership.
1810     gst_object_ref_sink(m_videoSinkBin);
1811
1812     // Build a new video sink consisting of a bin containing a tee
1813     // (meant to distribute data to multiple video sinks) and our
1814     // internal video sink. For fullscreen we create an autovideosink
1815     // and initially block the data flow towards it and configure it
1816
1817     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, queue, NULL);
1818
1819     // Link a new src pad from tee to queue1.
1820     GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(videoTee, "src%d"));
1821     GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink"));
1822     gst_pad_link(srcPad.get(), sinkPad.get());
1823 #endif
1824
1825     GstElement* actualVideoSink = 0;
1826     m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
1827     if (m_fpsSink) {
1828         // The verbose property has been added in -bad 0.10.22. Making
1829         // this whole code depend on it because we don't want
1830         // fpsdiplaysink to spit data on stdout.
1831         GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory);
1832         if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) {
1833             g_object_set(m_fpsSink, "silent", TRUE , NULL);
1834
1835             // Turn off text overlay unless logging is enabled.
1836 #if LOG_DISABLED
1837             g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
1838 #else
1839             WTFLogChannel* channel = getChannelFromName("Media");
1840             if (channel->state != WTFLogChannelOn)
1841                 g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
1842 #endif // LOG_DISABLED
1843
1844             if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
1845                 g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL);
1846 #ifndef GST_API_VERSION_1
1847                 gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink);
1848 #endif
1849                 actualVideoSink = m_fpsSink;
1850             } else
1851                 m_fpsSink = 0;
1852         } else
1853             m_fpsSink = 0;
1854     }
1855
1856     if (!m_fpsSink) {
1857 #ifndef GST_API_VERSION_1
1858         gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
1859 #endif
1860         actualVideoSink = m_webkitVideoSink;
1861     }
1862
1863     ASSERT(actualVideoSink);
1864
1865 #ifndef GST_API_VERSION_1
1866     // Faster elements linking.
1867     gst_element_link_pads_full(queue, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
1868
1869     // Add a ghostpad to the bin so it can proxy to tee.
1870     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(videoTee, "sink"));
1871     gst_element_add_pad(m_videoSinkBin, gst_ghost_pad_new("sink", pad.get()));
1872
1873     // Set the bin as video sink of playbin.
1874     g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL);
1875 #else
1876     g_object_set(m_playBin, "video-sink", actualVideoSink, NULL);
1877 #endif
1878
1879     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
1880     if (videoSinkPad)
1881         g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
1882
1883 }
1884
1885 }
1886
1887 #endif // USE(GSTREAMER)