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