[Qt][WK1] REGRESSION(r154988): compositing/video/video-with-invalid-source.html
[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, 2011, 2012, 2013 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 "GStreamerUtilities.h"
30 #include "GStreamerVersioning.h"
31 #include "KURL.h"
32 #include "Logging.h"
33 #include "MIMETypeRegistry.h"
34 #include "MediaPlayer.h"
35 #include "NotImplemented.h"
36 #include "SecurityOrigin.h"
37 #include "TimeRanges.h"
38 #include "WebKitWebSourceGStreamer.h"
39 #include <gst/gst.h>
40 #include <gst/pbutils/missing-plugins.h>
41 #include <limits>
42 #include <wtf/gobject/GOwnPtr.h>
43 #include <wtf/text/CString.h>
44
45 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
46 #include "InbandTextTrackPrivateGStreamer.h"
47 #include "TextCombinerGStreamer.h"
48 #include "TextSinkGStreamer.h"
49 #endif
50
51 #ifdef GST_API_VERSION_1
52 #include <gst/audio/streamvolume.h>
53 #else
54 #include <gst/interfaces/streamvolume.h>
55 #endif
56
57 // GstPlayFlags flags from playbin2. It is the policy of GStreamer to
58 // not publicly expose element-specific enums. That's why this
59 // GstPlayFlags enum has been copied here.
60 typedef enum {
61     GST_PLAY_FLAG_VIDEO         = 0x00000001,
62     GST_PLAY_FLAG_AUDIO         = 0x00000002,
63     GST_PLAY_FLAG_TEXT          = 0x00000004,
64     GST_PLAY_FLAG_VIS           = 0x00000008,
65     GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
66     GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
67     GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
68     GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
69     GST_PLAY_FLAG_BUFFERING     = 0x000000100
70 } GstPlayFlags;
71
72 // gPercentMax is used when parsing buffering ranges with
73 // gst_query_parse_nth_buffering_range as there was a bug in GStreamer
74 // 0.10 that was using 100 instead of GST_FORMAT_PERCENT_MAX. This was
75 // corrected in 1.0. gst_query_parse_buffering_range worked as
76 // expected with GST_FORMAT_PERCENT_MAX in both cases.
77 #ifdef GST_API_VERSION_1
78 static const char* gPlaybinName = "playbin";
79 static const gint64 gPercentMax = GST_FORMAT_PERCENT_MAX;
80 #else
81 static const char* gPlaybinName = "playbin2";
82 static const gint64 gPercentMax = 100;
83 #endif
84 // Max interval in seconds to stay in the READY state on manual
85 // state change requests.
86 static const guint gReadyStateTimerInterval = 60;
87
88 GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
89 #define GST_CAT_DEFAULT webkit_media_player_debug
90
91 using namespace std;
92
93 namespace WebCore {
94
95 static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
96 {
97     return player->handleMessage(message);
98 }
99
100 static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
101 {
102     player->sourceChanged();
103 }
104
105 static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
106 {
107     player->videoChanged();
108 }
109
110 static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
111 {
112     player->videoChanged();
113 }
114
115 static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
116 {
117     player->audioChanged();
118 }
119
120 static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
121 {
122     // This is the callback of the timeout source created in ::audioChanged.
123     player->notifyPlayerOfAudio();
124     return FALSE;
125 }
126
127 #ifdef GST_API_VERSION_1
128 static void setAudioStreamPropertiesCallback(GstChildProxy*, GObject* object, gchar*,
129     MediaPlayerPrivateGStreamer* player)
130 #else
131 static void setAudioStreamPropertiesCallback(GstChildProxy*, GObject* object, MediaPlayerPrivateGStreamer* player)
132 #endif
133 {
134     player->setAudioStreamProperties(object);
135 }
136
137 static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
138 {
139     // This is the callback of the timeout source created in ::videoChanged.
140     player->notifyPlayerOfVideo();
141     return FALSE;
142 }
143
144 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
145 static void mediaPlayerPrivateTextChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
146 {
147     player->textChanged();
148 }
149
150 static gboolean mediaPlayerPrivateTextChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
151 {
152     // This is the callback of the timeout source created in ::textChanged.
153     player->notifyPlayerOfText();
154     return FALSE;
155 }
156
157 static GstFlowReturn mediaPlayerPrivateNewTextSampleCallback(GObject*, MediaPlayerPrivateGStreamer* player)
158 {
159     player->newTextSample();
160     return GST_FLOW_OK;
161 }
162 #endif
163
164 static gboolean mediaPlayerPrivateReadyStateTimeoutCallback(MediaPlayerPrivateGStreamer* player)
165 {
166     // This is the callback of the timeout source created in ::changePipelineState.
167     // Reset pipeline if we are sitting on READY state when timeout is reached
168     player->changePipelineState(GST_STATE_NULL);
169     return FALSE;
170 }
171
172 static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsReturn result, gpointer userData)
173 {
174     MediaPlayerPrivateGStreamer* player = reinterpret_cast<MediaPlayerPrivateGStreamer*>(userData);
175     player->handlePluginInstallerResult(result);
176 }
177
178 static GstClockTime toGstClockTime(float time)
179 {
180     // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to
181     // round the microseconds so no floating point precision is lost and we can perform an accurate seek.
182     float seconds;
183     float microSeconds = modf(time, &seconds) * 1000000;
184     GTimeVal timeValue;
185     timeValue.tv_sec = static_cast<glong>(seconds);
186     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
187     return GST_TIMEVAL_TO_TIME(timeValue);
188 }
189
190 void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
191 {
192     if (g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
193         return;
194
195     const char* role = m_player->mediaPlayerClient() && m_player->mediaPlayerClient()->mediaPlayerIsVideo()
196         ? "video" : "music";
197     GstStructure* structure = gst_structure_new("stream-properties", "media.role", G_TYPE_STRING, role, NULL);
198     g_object_set(object, "stream-properties", structure, NULL);
199     gst_structure_free(structure);
200     GOwnPtr<gchar> elementName(gst_element_get_name(GST_ELEMENT(object)));
201     LOG_MEDIA_MESSAGE("Set media.role as %s at %s", role, elementName.get());
202 }
203
204 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
205 {
206     return adoptPtr(new MediaPlayerPrivateGStreamer(player));
207 }
208
209 void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
210 {
211     if (isAvailable())
212         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
213 }
214
215 bool initializeGStreamerAndRegisterWebKitElements()
216 {
217     if (!initializeGStreamer())
218         return false;
219
220     GRefPtr<GstElementFactory> srcFactory = gst_element_factory_find("webkitwebsrc");
221     if (!srcFactory) {
222         GST_DEBUG_CATEGORY_INIT(webkit_media_player_debug, "webkitmediaplayer", 0, "WebKit media player");
223         return gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC);
224     }
225
226     return true;
227 }
228
229 bool MediaPlayerPrivateGStreamer::isAvailable()
230 {
231     if (!initializeGStreamerAndRegisterWebKitElements())
232         return false;
233
234     GRefPtr<GstElementFactory> factory = gst_element_factory_find(gPlaybinName);
235     return factory;
236 }
237
238 MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
239     : MediaPlayerPrivateGStreamerBase(player)
240     , m_source(0)
241     , m_seekTime(0)
242     , m_changingRate(false)
243     , m_endTime(numeric_limits<float>::infinity())
244     , m_isEndReached(false)
245     , m_isStreaming(false)
246     , m_mediaLocations(0)
247     , m_mediaLocationCurrentIndex(0)
248     , m_resetPipeline(false)
249     , m_paused(true)
250     , m_seeking(false)
251     , m_seekIsPending(false)
252     , m_timeOfOverlappingSeek(-1)
253     , m_buffering(false)
254     , m_playbackRate(1)
255     , m_errorOccured(false)
256     , m_mediaDuration(0)
257     , m_downloadFinished(false)
258     , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
259     , m_maxTimeLoaded(0)
260     , m_bufferingPercentage(0)
261     , m_preload(player->preload())
262     , m_delayingLoad(false)
263     , m_mediaDurationKnown(true)
264     , m_maxTimeLoadedAtLastDidLoadingProgress(0)
265     , m_volumeAndMuteInitialized(false)
266     , m_hasVideo(false)
267     , m_hasAudio(false)
268     , m_audioTimerHandler(0)
269     , m_textTimerHandler(0)
270     , m_videoTimerHandler(0)
271     , m_readyTimerHandler(0)
272     , m_webkitAudioSink(0)
273     , m_totalBytes(-1)
274     , m_preservesPitch(false)
275     , m_requestedState(GST_STATE_VOID_PENDING)
276     , m_missingPlugins(false)
277 {
278 }
279
280 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
281 {
282 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
283     for (size_t i = 0; i < m_textTracks.size(); ++i)
284         m_textTracks[i]->disconnect();
285 #endif
286     if (m_fillTimer.isActive())
287         m_fillTimer.stop();
288
289     if (m_mediaLocations) {
290         gst_structure_free(m_mediaLocations);
291         m_mediaLocations = 0;
292     }
293
294     if (m_autoAudioSink)
295         g_signal_handlers_disconnect_by_func(G_OBJECT(m_autoAudioSink.get()),
296             reinterpret_cast<gpointer>(setAudioStreamPropertiesCallback), this);
297
298     if (m_readyTimerHandler)
299         g_source_remove(m_readyTimerHandler);
300
301     if (m_playBin) {
302         GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_playBin.get()));
303         ASSERT(bus);
304         g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateMessageCallback), this);
305         gst_bus_remove_signal_watch(bus.get());
306
307         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateSourceChangedCallback), this);
308         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoChangedCallback), this);
309         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateAudioChangedCallback), this);
310 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
311         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateNewTextSampleCallback), this);
312         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateTextChangedCallback), this);
313 #endif
314
315         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
316         m_playBin.clear();
317     }
318
319     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink.get(), "sink"));
320     g_signal_handlers_disconnect_by_func(videoSinkPad.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
321
322     if (m_videoTimerHandler)
323         g_source_remove(m_videoTimerHandler);
324
325     if (m_audioTimerHandler)
326         g_source_remove(m_audioTimerHandler);
327
328     if (m_textTimerHandler)
329         g_source_remove(m_textTimerHandler);
330 }
331
332 void MediaPlayerPrivateGStreamer::load(const String& url)
333 {
334     if (!initializeGStreamerAndRegisterWebKitElements())
335         return;
336
337     KURL kurl(KURL(), url);
338     String cleanUrl(url);
339
340     // Clean out everything after file:// url path.
341     if (kurl.isLocalFile())
342         cleanUrl = cleanUrl.substring(0, kurl.pathEnd());
343
344     if (!m_playBin)
345         createGSTPlayBin();
346
347     ASSERT(m_playBin);
348
349     m_url = KURL(KURL(), cleanUrl);
350     g_object_set(m_playBin.get(), "uri", cleanUrl.utf8().data(), NULL);
351
352     INFO_MEDIA_MESSAGE("Load %s", cleanUrl.utf8().data());
353
354     if (m_preload == MediaPlayer::None) {
355         LOG_MEDIA_MESSAGE("Delaying load.");
356         m_delayingLoad = true;
357     }
358
359     // Reset network and ready states. Those will be set properly once
360     // the pipeline pre-rolled.
361     m_networkState = MediaPlayer::Loading;
362     m_player->networkStateChanged();
363     m_readyState = MediaPlayer::HaveNothing;
364     m_player->readyStateChanged();
365     m_volumeAndMuteInitialized = false;
366
367     if (!m_delayingLoad)
368         commitLoad();
369 }
370
371 #if ENABLE(MEDIA_SOURCE)
372 void MediaPlayerPrivateGStreamer::load(const String& url, PassRefPtr<MediaSource>)
373 {
374     notImplemented();
375 }
376 #endif
377
378 void MediaPlayerPrivateGStreamer::commitLoad()
379 {
380     ASSERT(!m_delayingLoad);
381     LOG_MEDIA_MESSAGE("Committing load.");
382
383     // GStreamer needs to have the pipeline set to a paused state to
384     // start providing anything useful.
385     changePipelineState(GST_STATE_PAUSED);
386
387     setDownloadBuffering();
388     updateStates();
389 }
390
391 float MediaPlayerPrivateGStreamer::playbackPosition() const
392 {
393     if (m_isEndReached) {
394         // Position queries on a null pipeline return 0. If we're at
395         // the end of the stream the pipeline is null but we want to
396         // report either the seek time or the duration because this is
397         // what the Media element spec expects us to do.
398         if (m_seeking)
399             return m_seekTime;
400         if (m_mediaDuration)
401             return m_mediaDuration;
402         return 0;
403     }
404
405     // Position is only available if no async state change is going on and the state is either paused or playing.
406     gint64 position = GST_CLOCK_TIME_NONE;
407     GstQuery* query= gst_query_new_position(GST_FORMAT_TIME);
408     if (gst_element_query(m_playBin.get(), query))
409         gst_query_parse_position(query, 0, &position);
410
411     float result = 0.0f;
412     if (static_cast<GstClockTime>(position) != GST_CLOCK_TIME_NONE)
413         result = static_cast<double>(position) / GST_SECOND;
414     else if (m_canFallBackToLastFinishedSeekPositon)
415         result = m_seekTime;
416
417     LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
418
419     gst_query_unref(query);
420
421     return result;
422 }
423
424 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
425 {
426     ASSERT(m_playBin);
427
428     GstState currentState;
429     GstState pending;
430
431     gst_element_get_state(m_playBin.get(), &currentState, &pending, 0);
432     if (currentState == newState || pending == newState) {
433         LOG_MEDIA_MESSAGE("Rejected state change to %s from %s with %s pending", gst_element_state_get_name(newState),
434             gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
435         return true;
436     }
437
438     LOG_MEDIA_MESSAGE("Changing state change to %s from %s with %s pending", gst_element_state_get_name(newState),
439         gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
440
441     GstStateChangeReturn setStateResult = gst_element_set_state(m_playBin.get(), newState);
442     GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
443     if (currentState != pausedOrPlaying && setStateResult == GST_STATE_CHANGE_FAILURE) {
444         return false;
445     }
446
447     // Create a timer when entering the READY state so that we can free resources
448     // if we stay for too long on READY.
449     // Also lets remove the timer if we request a state change for any state other than READY.
450     // See also https://bugs.webkit.org/show_bug.cgi?id=117354
451     if (newState == GST_STATE_READY && !m_readyTimerHandler) {
452         m_readyTimerHandler = g_timeout_add_seconds(gReadyStateTimerInterval, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateReadyStateTimeoutCallback), this);
453     } else if (newState != GST_STATE_READY && m_readyTimerHandler) {
454         g_source_remove(m_readyTimerHandler);
455         m_readyTimerHandler = 0;
456     }
457
458     return true;
459 }
460
461 void MediaPlayerPrivateGStreamer::prepareToPlay()
462 {
463     m_preload = MediaPlayer::Auto;
464     if (m_delayingLoad) {
465         m_delayingLoad = false;
466         commitLoad();
467     }
468 }
469
470 void MediaPlayerPrivateGStreamer::play()
471 {
472     if (changePipelineState(GST_STATE_PLAYING)) {
473         m_isEndReached = false;
474         m_delayingLoad = false;
475         m_preload = MediaPlayer::Auto;
476         setDownloadBuffering();
477         LOG_MEDIA_MESSAGE("Play");
478     } else {
479         loadingFailed(MediaPlayer::Empty);
480     }
481 }
482
483 void MediaPlayerPrivateGStreamer::pause()
484 {
485     GstState currentState, pendingState;
486     gst_element_get_state(m_playBin.get(), &currentState, &pendingState, 0);
487     if (currentState < GST_STATE_PAUSED && pendingState <= GST_STATE_PAUSED)
488         return;
489
490     if (changePipelineState(GST_STATE_PAUSED))
491         INFO_MEDIA_MESSAGE("Pause");
492     else
493         loadingFailed(MediaPlayer::Empty);
494 }
495
496 float MediaPlayerPrivateGStreamer::duration() const
497 {
498     if (!m_playBin)
499         return 0.0f;
500
501     if (m_errorOccured)
502         return 0.0f;
503
504     // Media duration query failed already, don't attempt new useless queries.
505     if (!m_mediaDurationKnown)
506         return numeric_limits<float>::infinity();
507
508     if (m_mediaDuration)
509         return m_mediaDuration;
510
511     GstFormat timeFormat = GST_FORMAT_TIME;
512     gint64 timeLength = 0;
513
514 #ifdef GST_API_VERSION_1
515     bool failure = !gst_element_query_duration(m_playBin.get(), timeFormat, &timeLength) || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
516 #else
517     bool failure = !gst_element_query_duration(m_playBin.get(), &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
518 #endif
519     if (failure) {
520         LOG_MEDIA_MESSAGE("Time duration query failed for %s", m_url.string().utf8().data());
521         return numeric_limits<float>::infinity();
522     }
523
524     LOG_MEDIA_MESSAGE("Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
525
526     m_mediaDuration = static_cast<double>(timeLength) / GST_SECOND;
527     return m_mediaDuration;
528     // FIXME: handle 3.14.9.5 properly
529 }
530
531 float MediaPlayerPrivateGStreamer::currentTime() const
532 {
533     if (!m_playBin)
534         return 0.0f;
535
536     if (m_errorOccured)
537         return 0.0f;
538
539     if (m_seeking)
540         return m_seekTime;
541
542     // Workaround for
543     // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer
544     // 0.10.35 basesink reports wrong duration in case of EOS and
545     // negative playback rate. There's no upstream accepted patch for
546     // this bug yet, hence this temporary workaround.
547     if (m_isEndReached && m_playbackRate < 0)
548         return 0.0f;
549
550     return playbackPosition();
551 }
552
553 void MediaPlayerPrivateGStreamer::seek(float time)
554 {
555     if (!m_playBin)
556         return;
557
558     if (m_errorOccured)
559         return;
560
561     INFO_MEDIA_MESSAGE("[Seek] seek attempt to %f secs", time);
562
563     // Avoid useless seeking.
564     if (time == currentTime())
565         return;
566
567     if (isLiveStream())
568         return;
569
570     GstClockTime clockTime = toGstClockTime(time);
571     INFO_MEDIA_MESSAGE("[Seek] seeking to %" GST_TIME_FORMAT " (%f)", GST_TIME_ARGS(clockTime), time);
572
573     if (m_seeking) {
574         m_timeOfOverlappingSeek = time;
575         if (m_seekIsPending) {
576             m_seekTime = time;
577             return;
578         }
579     }
580
581     GstState state;
582     GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
583     if (getStateResult == GST_STATE_CHANGE_FAILURE || getStateResult == GST_STATE_CHANGE_NO_PREROLL) {
584         LOG_MEDIA_MESSAGE("[Seek] cannot seek, current state change is %s", gst_element_state_change_return_get_name(getStateResult));
585         return;
586     }
587     if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED || m_isEndReached) {
588         m_seekIsPending = true;
589         if (m_isEndReached) {
590             LOG_MEDIA_MESSAGE("[Seek] reset pipeline");
591             m_resetPipeline = true;
592             if (!changePipelineState(GST_STATE_PAUSED))
593                 loadingFailed(MediaPlayer::Empty);
594         }
595     } else {
596         // We can seek now.
597         if (!gst_element_seek(m_playBin.get(), m_player->rate(), GST_FORMAT_TIME, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
598             GST_SEEK_TYPE_SET, clockTime, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
599             LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", time);
600             return;
601         }
602     }
603
604     m_seeking = true;
605     m_seekTime = time;
606     m_isEndReached = false;
607 }
608
609 bool MediaPlayerPrivateGStreamer::paused() const
610 {
611     if (m_isEndReached) {
612         LOG_MEDIA_MESSAGE("Ignoring pause at EOS");
613         return true;
614     }
615
616     GstState state;
617     gst_element_get_state(m_playBin.get(), &state, 0, 0);
618     return state == GST_STATE_PAUSED;
619 }
620
621 bool MediaPlayerPrivateGStreamer::seeking() const
622 {
623     return m_seeking;
624 }
625
626 void MediaPlayerPrivateGStreamer::videoChanged()
627 {
628     if (m_videoTimerHandler)
629         g_source_remove(m_videoTimerHandler);
630     m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this);
631 }
632
633 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
634 {
635     m_videoTimerHandler = 0;
636
637     gint videoTracks = 0;
638     if (m_playBin)
639         g_object_get(m_playBin.get(), "n-video", &videoTracks, NULL);
640
641     m_hasVideo = videoTracks > 0;
642
643     m_videoSize = IntSize();
644
645     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
646 }
647
648 void MediaPlayerPrivateGStreamer::audioChanged()
649 {
650     if (m_audioTimerHandler)
651         g_source_remove(m_audioTimerHandler);
652     m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this);
653 }
654
655 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
656 {
657     m_audioTimerHandler = 0;
658
659     gint audioTracks = 0;
660     if (m_playBin)
661         g_object_get(m_playBin.get(), "n-audio", &audioTracks, NULL);
662     m_hasAudio = audioTracks > 0;
663     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
664 }
665
666 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
667 void MediaPlayerPrivateGStreamer::textChanged()
668 {
669     if (m_textTimerHandler)
670         g_source_remove(m_textTimerHandler);
671     m_textTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateTextChangeTimeoutCallback), this);
672 }
673
674 void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
675 {
676     m_textTimerHandler = 0;
677
678     gint numTracks = 0;
679     if (m_playBin)
680         g_object_get(m_playBin.get(), "n-text", &numTracks, NULL);
681
682     for (gint i = 0; i < numTracks; ++i) {
683         GstPad* pad;
684         g_signal_emit_by_name(m_playBin.get(), "get-text-pad", i, &pad, NULL);
685         ASSERT(pad);
686
687         if (i < static_cast<gint>(m_textTracks.size())) {
688             RefPtr<InbandTextTrackPrivateGStreamer> existingTrack = m_textTracks[i];
689             existingTrack->setIndex(i);
690             if (existingTrack->pad() == pad) {
691                 gst_object_unref(pad);
692                 continue;
693             }
694         }
695
696         RefPtr<InbandTextTrackPrivateGStreamer> track = InbandTextTrackPrivateGStreamer::create(i, adoptGRef(pad));
697         m_textTracks.insert(i, track);
698         m_player->addTextTrack(track.release());
699     }
700
701     while (static_cast<gint>(m_textTracks.size()) > numTracks) {
702         RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks.last();
703         track->disconnect();
704         m_textTracks.removeLast();
705         m_player->removeTextTrack(track.release());
706     }
707 }
708
709 void MediaPlayerPrivateGStreamer::newTextSample()
710 {
711     if (!m_textAppSink)
712         return;
713
714     GRefPtr<GstEvent> streamStartEvent = adoptGRef(
715         gst_pad_get_sticky_event(m_textAppSinkPad.get(), GST_EVENT_STREAM_START, 0));
716
717     GstSample* sample;
718     g_signal_emit_by_name(m_textAppSink.get(), "pull-sample", &sample, NULL);
719     ASSERT(sample);
720
721     if (streamStartEvent) {
722         bool found = FALSE;
723         const gchar* id;
724         gst_event_parse_stream_start(streamStartEvent.get(), &id);
725         for (size_t i = 0; i < m_textTracks.size(); ++i) {
726             RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks[i];
727             if (track->streamId() == id) {
728                 track->handleSample(sample);
729                 found = true;
730                 break;
731             }
732         }
733         if (!found)
734             WARN_MEDIA_MESSAGE("Got sample with unknown stream ID.");
735     } else
736         WARN_MEDIA_MESSAGE("Unable to handle sample with no stream start event.");
737     gst_sample_unref(sample);
738 }
739 #endif
740
741 void MediaPlayerPrivateGStreamer::setRate(float rate)
742 {
743     // Avoid useless playback rate update.
744     if (m_playbackRate == rate)
745         return;
746
747     GstState state;
748     GstState pending;
749
750     gst_element_get_state(m_playBin.get(), &state, &pending, 0);
751     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
752         || (pending == GST_STATE_PAUSED))
753         return;
754
755     if (isLiveStream())
756         return;
757
758     m_playbackRate = rate;
759     m_changingRate = true;
760
761     if (!rate) {
762         changePipelineState(GST_STATE_PAUSED);
763         return;
764     }
765
766     float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND);
767     GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
768     gint64 start, end;
769     bool mute = false;
770
771     INFO_MEDIA_MESSAGE("Set Rate to %f", rate);
772     if (rate > 0) {
773         // Mute the sound if the playback rate is too extreme and
774         // audio pitch is not adjusted.
775         mute = (!m_preservesPitch && (rate < 0.8 || rate > 2));
776         start = currentPosition;
777         end = GST_CLOCK_TIME_NONE;
778     } else {
779         start = 0;
780         mute = true;
781
782         // If we are at beginning of media, start from the end to
783         // avoid immediate EOS.
784         if (currentPosition <= 0)
785             end = static_cast<gint64>(duration() * GST_SECOND);
786         else
787             end = currentPosition;
788     }
789
790     INFO_MEDIA_MESSAGE("Need to mute audio?: %d", (int) mute);
791
792     if (!gst_element_seek(m_playBin.get(), rate, GST_FORMAT_TIME, flags,
793                           GST_SEEK_TYPE_SET, start,
794                           GST_SEEK_TYPE_SET, end))
795         ERROR_MEDIA_MESSAGE("Set rate to %f failed", rate);
796     else
797         g_object_set(m_playBin.get(), "mute", mute, NULL);
798 }
799
800 void MediaPlayerPrivateGStreamer::setPreservesPitch(bool preservesPitch)
801 {
802     m_preservesPitch = preservesPitch;
803 }
804
805 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
806 {
807     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
808     if (m_errorOccured || isLiveStream())
809         return timeRanges.release();
810
811 #if GST_CHECK_VERSION(0, 10, 31)
812     float mediaDuration(duration());
813     if (!mediaDuration || std::isinf(mediaDuration))
814         return timeRanges.release();
815
816     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
817
818     if (!gst_element_query(m_playBin.get(), query)) {
819         gst_query_unref(query);
820         return timeRanges.release();
821     }
822
823     for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
824         gint64 rangeStart = 0, rangeStop = 0;
825         if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
826             timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / gPercentMax),
827                 static_cast<float>((rangeStop * mediaDuration) / gPercentMax));
828     }
829
830     // Fallback to the more general maxTimeLoaded() if no range has
831     // been found.
832     if (!timeRanges->length())
833         if (float loaded = maxTimeLoaded())
834             timeRanges->add(0, loaded);
835
836     gst_query_unref(query);
837 #else
838     float loaded = maxTimeLoaded();
839     if (!m_errorOccured && !isLiveStream() && loaded > 0)
840         timeRanges->add(0, loaded);
841 #endif
842     return timeRanges.release();
843 }
844
845 gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
846 {
847     GOwnPtr<GError> err;
848     GOwnPtr<gchar> debug;
849     MediaPlayer::NetworkState error;
850     bool issueError = true;
851     bool attemptNextLocation = false;
852     const GstStructure* structure = gst_message_get_structure(message);
853     GstState requestedState, currentState;
854
855     m_canFallBackToLastFinishedSeekPositon = false;
856
857     if (structure) {
858         const gchar* messageTypeName = gst_structure_get_name(structure);
859
860         // Redirect messages are sent from elements, like qtdemux, to
861         // notify of the new location(s) of the media.
862         if (!g_strcmp0(messageTypeName, "redirect")) {
863             mediaLocationChanged(message);
864             return TRUE;
865         }
866     }
867
868     // We ignore state changes from internal elements. They are forwarded to playbin2 anyway.
869     bool messageSourceIsPlaybin = GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get());
870
871     LOG_MEDIA_MESSAGE("Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
872     switch (GST_MESSAGE_TYPE(message)) {
873     case GST_MESSAGE_ERROR:
874         if (m_resetPipeline)
875             break;
876         if (m_missingPlugins)
877             break;
878         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
879         ERROR_MEDIA_MESSAGE("Error %d: %s (url=%s)", err->code, err->message, m_url.string().utf8().data());
880
881         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, "webkit-video.error");
882
883         error = MediaPlayer::Empty;
884         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
885             || err->code == GST_STREAM_ERROR_WRONG_TYPE
886             || err->code == GST_STREAM_ERROR_FAILED
887             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
888             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
889             error = MediaPlayer::FormatError;
890         else if (err->domain == GST_STREAM_ERROR) {
891             // Let the mediaPlayerClient handle the stream error, in
892             // this case the HTMLMediaElement will emit a stalled
893             // event.
894             if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) {
895                 ERROR_MEDIA_MESSAGE("Decode error, let the Media element emit a stalled event.");
896                 break;
897             }
898             error = MediaPlayer::DecodeError;
899             attemptNextLocation = true;
900         } else if (err->domain == GST_RESOURCE_ERROR)
901             error = MediaPlayer::NetworkError;
902
903         if (attemptNextLocation)
904             issueError = !loadNextLocation();
905         if (issueError)
906             loadingFailed(error);
907         break;
908     case GST_MESSAGE_EOS:
909         didEnd();
910         break;
911     case GST_MESSAGE_ASYNC_DONE:
912         if (!messageSourceIsPlaybin || m_delayingLoad)
913             break;
914         asyncStateChangeDone();
915         break;
916     case GST_MESSAGE_STATE_CHANGED: {
917         if (!messageSourceIsPlaybin || m_delayingLoad)
918             break;
919         updateStates();
920
921         // Construct a filename for the graphviz dot file output.
922         GstState newState;
923         gst_message_parse_state_changed(message, &currentState, &newState, 0);
924         CString dotFileName = String::format("webkit-video.%s_%s", gst_element_state_get_name(currentState), gst_element_state_get_name(newState)).utf8();
925         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
926
927         break;
928     }
929     case GST_MESSAGE_BUFFERING:
930         processBufferingStats(message);
931         break;
932 #ifdef GST_API_VERSION_1
933     case GST_MESSAGE_DURATION_CHANGED:
934 #else
935     case GST_MESSAGE_DURATION:
936 #endif
937         if (messageSourceIsPlaybin)
938             durationChanged();
939         break;
940     case GST_MESSAGE_REQUEST_STATE:
941         gst_message_parse_request_state(message, &requestedState);
942         gst_element_get_state(m_playBin.get(), &currentState, NULL, 250);
943         if (requestedState < currentState) {
944             GOwnPtr<gchar> elementName(gst_element_get_name(GST_ELEMENT(message)));
945             INFO_MEDIA_MESSAGE("Element %s requested state change to %s", elementName.get(),
946                 gst_element_state_get_name(requestedState));
947             m_requestedState = requestedState;
948             if (!changePipelineState(requestedState))
949                 loadingFailed(MediaPlayer::Empty);
950         }
951         break;
952     case GST_MESSAGE_ELEMENT:
953         if (gst_is_missing_plugin_message(message)) {
954             gchar* detail = gst_missing_plugin_message_get_installer_detail(message);
955             gchar* detailArray[2] = {detail, 0};
956             GstInstallPluginsReturn result = gst_install_plugins_async(detailArray, 0, mediaPlayerPrivatePluginInstallerResultFunction, this);
957             m_missingPlugins = result == GST_INSTALL_PLUGINS_STARTED_OK;
958             g_free(detail);
959         }
960         break;
961     default:
962         LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
963                     GST_MESSAGE_TYPE_NAME(message));
964         break;
965     }
966     return TRUE;
967 }
968
969 void MediaPlayerPrivateGStreamer::handlePluginInstallerResult(GstInstallPluginsReturn result)
970 {
971     m_missingPlugins = false;
972     if (result == GST_INSTALL_PLUGINS_SUCCESS) {
973         changePipelineState(GST_STATE_READY);
974         changePipelineState(GST_STATE_PAUSED);
975     }
976 }
977
978 void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
979 {
980     m_buffering = true;
981     const GstStructure *structure = gst_message_get_structure(message);
982     gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
983
984     LOG_MEDIA_MESSAGE("[Buffering] Buffering: %d%%.", m_bufferingPercentage);
985
986     updateStates();
987 }
988
989 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
990 {
991     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
992
993     if (!gst_element_query(m_playBin.get(), query)) {
994         gst_query_unref(query);
995         return;
996     }
997
998     gint64 start, stop;
999     gdouble fillStatus = 100.0;
1000
1001     gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
1002     gst_query_unref(query);
1003
1004     if (stop != -1)
1005         fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
1006
1007     LOG_MEDIA_MESSAGE("[Buffering] Download buffer filled up to %f%%", fillStatus);
1008
1009     if (!m_mediaDuration)
1010         durationChanged();
1011
1012     // Update maxTimeLoaded only if the media duration is
1013     // available. Otherwise we can't compute it.
1014     if (m_mediaDuration) {
1015         if (fillStatus == 100.0)
1016             m_maxTimeLoaded = m_mediaDuration;
1017         else
1018             m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
1019         LOG_MEDIA_MESSAGE("[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
1020     }
1021
1022     m_downloadFinished = fillStatus == 100.0;
1023     if (!m_downloadFinished) {
1024         updateStates();
1025         return;
1026     }
1027
1028     // Media is now fully loaded. It will play even if network
1029     // connection is cut. Buffering is done, remove the fill source
1030     // from the main loop.
1031     m_fillTimer.stop();
1032     updateStates();
1033 }
1034
1035 float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
1036 {
1037     if (m_errorOccured)
1038         return 0.0f;
1039
1040     LOG_MEDIA_MESSAGE("maxTimeSeekable");
1041     // infinite duration means live stream
1042     if (std::isinf(duration()))
1043         return 0.0f;
1044
1045     return duration();
1046 }
1047
1048 float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
1049 {
1050     if (m_errorOccured)
1051         return 0.0f;
1052
1053     float loaded = m_maxTimeLoaded;
1054     if (m_isEndReached && m_mediaDuration)
1055         loaded = m_mediaDuration;
1056     LOG_MEDIA_MESSAGE("maxTimeLoaded: %f", loaded);
1057     return loaded;
1058 }
1059
1060 bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
1061 {
1062     if (!m_playBin || !m_mediaDuration || !totalBytes())
1063         return false;
1064     float currentMaxTimeLoaded = maxTimeLoaded();
1065     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
1066     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
1067     LOG_MEDIA_MESSAGE("didLoadingProgress: %d", didLoadingProgress);
1068     return didLoadingProgress;
1069 }
1070
1071 unsigned MediaPlayerPrivateGStreamer::totalBytes() const
1072 {
1073     if (m_errorOccured)
1074         return 0;
1075
1076     if (m_totalBytes != -1)
1077         return m_totalBytes;
1078
1079     if (!m_source)
1080         return 0;
1081
1082     GstFormat fmt = GST_FORMAT_BYTES;
1083     gint64 length = 0;
1084 #ifdef GST_API_VERSION_1
1085     if (gst_element_query_duration(m_source.get(), fmt, &length)) {
1086 #else
1087     if (gst_element_query_duration(m_source.get(), &fmt, &length)) {
1088 #endif
1089         INFO_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1090         m_totalBytes = static_cast<unsigned>(length);
1091         m_isStreaming = !length;
1092         return m_totalBytes;
1093     }
1094
1095     // Fall back to querying the source pads manually.
1096     // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
1097     GstIterator* iter = gst_element_iterate_src_pads(m_source.get());
1098     bool done = false;
1099     while (!done) {
1100 #ifdef GST_API_VERSION_1
1101         GValue item = G_VALUE_INIT;
1102         switch (gst_iterator_next(iter, &item)) {
1103         case GST_ITERATOR_OK: {
1104             GstPad* pad = static_cast<GstPad*>(g_value_get_object(&item));
1105             gint64 padLength = 0;
1106             if (gst_pad_query_duration(pad, fmt, &padLength) && padLength > length)
1107                 length = padLength;
1108             break;
1109         }
1110 #else
1111         gpointer data;
1112
1113         switch (gst_iterator_next(iter, &data)) {
1114         case GST_ITERATOR_OK: {
1115             GRefPtr<GstPad> pad = adoptGRef(GST_PAD_CAST(data));
1116             gint64 padLength = 0;
1117             if (gst_pad_query_duration(pad.get(), &fmt, &padLength) && padLength > length)
1118                 length = padLength;
1119             break;
1120         }
1121 #endif
1122         case GST_ITERATOR_RESYNC:
1123             gst_iterator_resync(iter);
1124             break;
1125         case GST_ITERATOR_ERROR:
1126             // Fall through.
1127         case GST_ITERATOR_DONE:
1128             done = true;
1129             break;
1130         }
1131
1132 #ifdef GST_API_VERSION_1
1133         g_value_unset(&item);
1134 #endif
1135     }
1136
1137     gst_iterator_free(iter);
1138
1139     INFO_MEDIA_MESSAGE("totalBytes %" G_GINT64_FORMAT, length);
1140     m_totalBytes = static_cast<unsigned>(length);
1141     m_isStreaming = !length;
1142     return m_totalBytes;
1143 }
1144
1145 void MediaPlayerPrivateGStreamer::updateAudioSink()
1146 {
1147     if (!m_playBin)
1148         return;
1149
1150     GstElement* sinkPtr = 0;
1151
1152     g_object_get(m_playBin.get(), "audio-sink", &sinkPtr, NULL);
1153     m_webkitAudioSink = adoptGRef(sinkPtr);
1154
1155 }
1156
1157 GstElement* MediaPlayerPrivateGStreamer::audioSink() const
1158 {
1159     return m_webkitAudioSink.get();
1160 }
1161
1162 void MediaPlayerPrivateGStreamer::sourceChanged()
1163 {
1164     GstElement* srcPtr = 0;
1165
1166     g_object_get(m_playBin.get(), "source", &srcPtr, NULL);
1167     m_source = adoptGRef(srcPtr);
1168
1169     if (WEBKIT_IS_WEB_SRC(m_source.get()))
1170         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
1171 }
1172
1173 void MediaPlayerPrivateGStreamer::cancelLoad()
1174 {
1175     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
1176         return;
1177
1178     if (m_playBin)
1179         changePipelineState(GST_STATE_READY);
1180 }
1181
1182 void MediaPlayerPrivateGStreamer::asyncStateChangeDone()
1183 {
1184     if (!m_playBin || m_errorOccured)
1185         return;
1186
1187     if (m_seeking) {
1188         if (m_seekIsPending)
1189             updateStates();
1190         else {
1191             LOG_MEDIA_MESSAGE("[Seek] seeked to %f", m_seekTime);
1192             m_seeking = false;
1193             if (m_timeOfOverlappingSeek != m_seekTime && m_timeOfOverlappingSeek != -1) {
1194                 seek(m_timeOfOverlappingSeek);
1195                 m_timeOfOverlappingSeek = -1;
1196                 return;
1197             }
1198             m_timeOfOverlappingSeek = -1;
1199
1200             // The pipeline can still have a pending state. In this case a position query will fail.
1201             // Right now we can use m_seekTime as a fallback.
1202             m_canFallBackToLastFinishedSeekPositon = true;
1203             timeChanged();
1204         }
1205     } else
1206         updateStates();
1207 }
1208
1209 void MediaPlayerPrivateGStreamer::updateStates()
1210 {
1211     if (!m_playBin)
1212         return;
1213
1214     if (m_errorOccured)
1215         return;
1216
1217     MediaPlayer::NetworkState oldNetworkState = m_networkState;
1218     MediaPlayer::ReadyState oldReadyState = m_readyState;
1219     GstState state;
1220     GstState pending;
1221
1222     GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, &pending, 250 * GST_NSECOND);
1223
1224     bool shouldUpdatePlaybackState = false;
1225     switch (getStateResult) {
1226     case GST_STATE_CHANGE_SUCCESS: {
1227         LOG_MEDIA_MESSAGE("State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1228
1229         // Do nothing if on EOS and state changed to READY to avoid recreating the player
1230         // on HTMLMediaElement and properly generate the video 'ended' event.
1231         if (m_isEndReached && state == GST_STATE_READY)
1232             break;
1233
1234         if (state <= GST_STATE_READY) {
1235             m_resetPipeline = true;
1236             m_mediaDuration = 0;
1237         } else {
1238             m_resetPipeline = false;
1239             cacheDuration();
1240         }
1241
1242         bool didBuffering = m_buffering;
1243
1244         // Update ready and network states.
1245         switch (state) {
1246         case GST_STATE_NULL:
1247             m_readyState = MediaPlayer::HaveNothing;
1248             m_networkState = MediaPlayer::Empty;
1249             break;
1250         case GST_STATE_READY:
1251             m_readyState = MediaPlayer::HaveMetadata;
1252             m_networkState = MediaPlayer::Empty;
1253             break;
1254         case GST_STATE_PAUSED:
1255         case GST_STATE_PLAYING:
1256             if (m_buffering) {
1257                 if (m_bufferingPercentage == 100) {
1258                     LOG_MEDIA_MESSAGE("[Buffering] Complete.");
1259                     m_buffering = false;
1260                     m_readyState = MediaPlayer::HaveEnoughData;
1261                     m_networkState = m_downloadFinished ? MediaPlayer::Idle : MediaPlayer::Loading;
1262                 } else {
1263                     m_readyState = MediaPlayer::HaveCurrentData;
1264                     m_networkState = MediaPlayer::Loading;
1265                 }
1266             } else if (m_downloadFinished) {
1267                 m_readyState = MediaPlayer::HaveEnoughData;
1268                 m_networkState = MediaPlayer::Loaded;
1269             } else {
1270                 m_readyState = MediaPlayer::HaveFutureData;
1271                 m_networkState = MediaPlayer::Loading;
1272             }
1273
1274             break;
1275         default:
1276             ASSERT_NOT_REACHED();
1277             break;
1278         }
1279
1280         // Sync states where needed.
1281         if (state == GST_STATE_PAUSED) {
1282             if (!m_webkitAudioSink)
1283                 updateAudioSink();
1284
1285             if (!m_volumeAndMuteInitialized) {
1286                 notifyPlayerOfVolumeChange();
1287                 notifyPlayerOfMute();
1288                 m_volumeAndMuteInitialized = true;
1289             }
1290
1291             if (didBuffering && !m_buffering && !m_paused) {
1292                 LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
1293                 changePipelineState(GST_STATE_PLAYING);
1294             }
1295         } else if (state == GST_STATE_PLAYING) {
1296             m_paused = false;
1297
1298             if (m_buffering && !isLiveStream()) {
1299                 LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
1300                 changePipelineState(GST_STATE_PAUSED);
1301             }
1302         } else
1303             m_paused = true;
1304
1305         if (m_changingRate) {
1306             m_player->rateChanged();
1307             m_changingRate = false;
1308         }
1309
1310         if (m_requestedState == GST_STATE_PAUSED && state == GST_STATE_PAUSED) {
1311             shouldUpdatePlaybackState = true;
1312             LOG_MEDIA_MESSAGE("Requested state change to %s was completed", gst_element_state_get_name(state));
1313         }
1314
1315         break;
1316     }
1317     case GST_STATE_CHANGE_ASYNC:
1318         LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1319         // Change in progress.
1320         break;
1321     case GST_STATE_CHANGE_FAILURE:
1322         LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1323         // Change failed
1324         return;
1325     case GST_STATE_CHANGE_NO_PREROLL:
1326         LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
1327
1328         // Live pipelines go in PAUSED without prerolling.
1329         m_isStreaming = true;
1330         setDownloadBuffering();
1331
1332         if (state == GST_STATE_READY)
1333             m_readyState = MediaPlayer::HaveNothing;
1334         else if (state == GST_STATE_PAUSED) {
1335             m_readyState = MediaPlayer::HaveEnoughData;
1336             m_paused = true;
1337         } else if (state == GST_STATE_PLAYING)
1338             m_paused = false;
1339
1340         if (!m_paused)
1341             changePipelineState(GST_STATE_PLAYING);
1342
1343         m_networkState = MediaPlayer::Loading;
1344         break;
1345     default:
1346         LOG_MEDIA_MESSAGE("Else : %d", getStateResult);
1347         break;
1348     }
1349
1350     m_requestedState = GST_STATE_VOID_PENDING;
1351
1352     if (shouldUpdatePlaybackState)
1353         m_player->playbackStateChanged();
1354
1355     if (m_networkState != oldNetworkState) {
1356         LOG_MEDIA_MESSAGE("Network State Changed from %u to %u", oldNetworkState, m_networkState);
1357         m_player->networkStateChanged();
1358     }
1359     if (m_readyState != oldReadyState) {
1360         LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u", oldReadyState, m_readyState);
1361         m_player->readyStateChanged();
1362     }
1363
1364     if (m_seekIsPending && getStateResult == GST_STATE_CHANGE_SUCCESS && (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)) {
1365         LOG_MEDIA_MESSAGE("[Seek] committing pending seek to %f", m_seekTime);
1366         m_seekIsPending = false;
1367         m_seeking = gst_element_seek(m_playBin.get(), m_player->rate(), GST_FORMAT_TIME, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
1368             GST_SEEK_TYPE_SET, toGstClockTime(m_seekTime), GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1369         if (!m_seeking)
1370             LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", m_seekTime);
1371     }
1372 }
1373
1374 void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
1375 {
1376     if (m_mediaLocations)
1377         gst_structure_free(m_mediaLocations);
1378
1379     const GstStructure* structure = gst_message_get_structure(message);
1380     if (structure) {
1381         // This structure can contain:
1382         // - both a new-location string and embedded locations structure
1383         // - or only a new-location string.
1384         m_mediaLocations = gst_structure_copy(structure);
1385         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1386
1387         if (locations)
1388             m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
1389
1390         loadNextLocation();
1391     }
1392 }
1393
1394 bool MediaPlayerPrivateGStreamer::loadNextLocation()
1395 {
1396     if (!m_mediaLocations)
1397         return false;
1398
1399     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1400     const gchar* newLocation = 0;
1401
1402     if (!locations) {
1403         // Fallback on new-location string.
1404         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
1405         if (!newLocation)
1406             return false;
1407     }
1408
1409     if (!newLocation) {
1410         if (m_mediaLocationCurrentIndex < 0) {
1411             m_mediaLocations = 0;
1412             return false;
1413         }
1414
1415         const GValue* location = gst_value_list_get_value(locations,
1416                                                           m_mediaLocationCurrentIndex);
1417         const GstStructure* structure = gst_value_get_structure(location);
1418
1419         if (!structure) {
1420             m_mediaLocationCurrentIndex--;
1421             return false;
1422         }
1423
1424         newLocation = gst_structure_get_string(structure, "new-location");
1425     }
1426
1427     if (newLocation) {
1428         // Found a candidate. new-location is not always an absolute url
1429         // though. We need to take the base of the current url and
1430         // append the value of new-location to it.
1431         KURL baseUrl = gst_uri_is_valid(newLocation) ? KURL() : m_url;
1432         KURL newUrl = KURL(baseUrl, newLocation);
1433
1434         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(m_url);
1435         if (securityOrigin->canRequest(newUrl)) {
1436             INFO_MEDIA_MESSAGE("New media url: %s", newUrl.string().utf8().data());
1437
1438             // Reset player states.
1439             m_networkState = MediaPlayer::Loading;
1440             m_player->networkStateChanged();
1441             m_readyState = MediaPlayer::HaveNothing;
1442             m_player->readyStateChanged();
1443
1444             // Reset pipeline state.
1445             m_resetPipeline = true;
1446             changePipelineState(GST_STATE_READY);
1447
1448             GstState state;
1449             gst_element_get_state(m_playBin.get(), &state, 0, 0);
1450             if (state <= GST_STATE_READY) {
1451                 // Set the new uri and start playing.
1452                 g_object_set(m_playBin.get(), "uri", newUrl.string().utf8().data(), NULL);
1453                 m_url = newUrl;
1454                 changePipelineState(GST_STATE_PLAYING);
1455                 return true;
1456             }
1457         } else
1458             INFO_MEDIA_MESSAGE("Not allowed to load new media location: %s", newUrl.string().utf8().data());
1459     }
1460     m_mediaLocationCurrentIndex--;
1461     return false;
1462 }
1463
1464 void MediaPlayerPrivateGStreamer::loadStateChanged()
1465 {
1466     updateStates();
1467 }
1468
1469 void MediaPlayerPrivateGStreamer::timeChanged()
1470 {
1471     updateStates();
1472     m_player->timeChanged();
1473 }
1474
1475 void MediaPlayerPrivateGStreamer::didEnd()
1476 {
1477     // Synchronize position and duration values to not confuse the
1478     // HTMLMediaElement. In some cases like reverse playback the
1479     // position is not always reported as 0 for instance.
1480     float now = currentTime();
1481     if (now > 0 && now <= duration() && m_mediaDuration != now) {
1482         m_mediaDurationKnown = true;
1483         m_mediaDuration = now;
1484         m_player->durationChanged();
1485     }
1486
1487     m_isEndReached = true;
1488     timeChanged();
1489
1490     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
1491         m_paused = true;
1492         changePipelineState(GST_STATE_READY);
1493         m_downloadFinished = false;
1494     }
1495 }
1496
1497 void MediaPlayerPrivateGStreamer::cacheDuration()
1498 {
1499     if (m_mediaDuration || !m_mediaDurationKnown)
1500         return;
1501
1502     float newDuration = duration();
1503     if (std::isinf(newDuration)) {
1504         // Only pretend that duration is not available if the the query failed in a stable pipeline state.
1505         GstState state;
1506         if (gst_element_get_state(m_playBin.get(), &state, 0, 0) == GST_STATE_CHANGE_SUCCESS && state > GST_STATE_READY)
1507             m_mediaDurationKnown = false;
1508         return;
1509     }
1510
1511     m_mediaDuration = newDuration;
1512 }
1513
1514 void MediaPlayerPrivateGStreamer::durationChanged()
1515 {
1516     float previousDuration = m_mediaDuration;
1517
1518     cacheDuration();
1519     // Avoid emiting durationchanged in the case where the previous
1520     // duration was 0 because that case is already handled by the
1521     // HTMLMediaElement.
1522     if (previousDuration && m_mediaDuration != previousDuration)
1523         m_player->durationChanged();
1524 }
1525
1526 void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
1527 {
1528     m_errorOccured = true;
1529     if (m_networkState != error) {
1530         m_networkState = error;
1531         m_player->networkStateChanged();
1532     }
1533     if (m_readyState != MediaPlayer::HaveNothing) {
1534         m_readyState = MediaPlayer::HaveNothing;
1535         m_player->readyStateChanged();
1536     }
1537
1538     // Loading failed, remove ready timer.
1539     if (m_readyTimerHandler) {
1540         g_source_remove(m_readyTimerHandler);
1541         m_readyTimerHandler = 0;
1542     }
1543 }
1544
1545 static HashSet<String> mimeTypeCache()
1546 {
1547     initializeGStreamerAndRegisterWebKitElements();
1548
1549     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
1550     static bool typeListInitialized = false;
1551
1552     if (typeListInitialized)
1553         return cache;
1554
1555     const char* mimeTypes[] = {
1556         "application/ogg",
1557         "application/vnd.apple.mpegurl",
1558         "application/vnd.rn-realmedia",
1559         "application/x-3gp",
1560         "application/x-pn-realaudio",
1561         "audio/3gpp",
1562         "audio/aac",
1563         "audio/flac",
1564         "audio/iLBC-sh",
1565         "audio/midi",
1566         "audio/mobile-xmf",
1567         "audio/mp1",
1568         "audio/mp2",
1569         "audio/mp3",
1570         "audio/mp4",
1571         "audio/mpeg",
1572         "audio/ogg",
1573         "audio/opus",
1574         "audio/qcelp",
1575         "audio/riff-midi",
1576         "audio/speex",
1577         "audio/wav",
1578         "audio/webm",
1579         "audio/x-ac3",
1580         "audio/x-aiff",
1581         "audio/x-amr-nb-sh",
1582         "audio/x-amr-wb-sh",
1583         "audio/x-au",
1584         "audio/x-ay",
1585         "audio/x-celt",
1586         "audio/x-dts",
1587         "audio/x-flac",
1588         "audio/x-gbs",
1589         "audio/x-gsm",
1590         "audio/x-gym",
1591         "audio/x-imelody",
1592         "audio/x-ircam",
1593         "audio/x-kss",
1594         "audio/x-m4a",
1595         "audio/x-mod",
1596         "audio/x-mp3",
1597         "audio/x-mpeg",
1598         "audio/x-musepack",
1599         "audio/x-nist",
1600         "audio/x-nsf",
1601         "audio/x-paris",
1602         "audio/x-sap",
1603         "audio/x-sbc",
1604         "audio/x-sds",
1605         "audio/x-shorten",
1606         "audio/x-sid",
1607         "audio/x-spc",
1608         "audio/x-speex",
1609         "audio/x-svx",
1610         "audio/x-ttafile",
1611         "audio/x-vgm",
1612         "audio/x-voc",
1613         "audio/x-vorbis+ogg",
1614         "audio/x-w64",
1615         "audio/x-wav",
1616         "audio/x-wavpack",
1617         "audio/x-wavpack-correction",
1618         "video/3gpp",
1619         "video/mj2",
1620         "video/mp4",
1621         "video/mpeg",
1622         "video/mpegts",
1623         "video/ogg",
1624         "video/quicktime",
1625         "video/vivo",
1626         "video/webm",
1627         "video/x-cdxa",
1628         "video/x-dirac",
1629         "video/x-dv",
1630         "video/x-fli",
1631         "video/x-flv",
1632         "video/x-h263",
1633         "video/x-ivf",
1634         "video/x-m4v",
1635         "video/x-matroska",
1636         "video/x-mng",
1637         "video/x-ms-asf",
1638         "video/x-msvideo",
1639         "video/x-mve",
1640         "video/x-nuv",
1641         "video/x-vcd"
1642     };
1643
1644     for (unsigned i = 0; i < (sizeof(mimeTypes) / sizeof(*mimeTypes)); ++i)
1645         cache.add(String(mimeTypes[i]));
1646
1647     typeListInitialized = true;
1648     return cache;
1649 }
1650
1651 void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
1652 {
1653     types = mimeTypeCache();
1654 }
1655
1656 MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs, const KURL&)
1657 {
1658     if (type.isNull() || type.isEmpty())
1659         return MediaPlayer::IsNotSupported;
1660
1661     // spec says we should not return "probably" if the codecs string is empty
1662     if (mimeTypeCache().contains(type))
1663         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
1664     return MediaPlayer::IsNotSupported;
1665 }
1666
1667 void MediaPlayerPrivateGStreamer::setDownloadBuffering()
1668 {
1669     if (!m_playBin)
1670         return;
1671
1672     GstPlayFlags flags;
1673     g_object_get(m_playBin.get(), "flags", &flags, NULL);
1674
1675     // We don't want to stop downloading if we already started it.
1676     if (flags & GST_PLAY_FLAG_DOWNLOAD && m_readyState > MediaPlayer::HaveNothing && !m_resetPipeline)
1677         return;
1678
1679     bool shouldDownload = !isLiveStream() && m_preload == MediaPlayer::Auto;
1680     if (shouldDownload) {
1681         LOG_MEDIA_MESSAGE("Enabling on-disk buffering");
1682         g_object_set(m_playBin.get(), "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
1683         m_fillTimer.startRepeating(0.2);
1684     } else {
1685         LOG_MEDIA_MESSAGE("Disabling on-disk buffering");
1686         g_object_set(m_playBin.get(), "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
1687         m_fillTimer.stop();
1688     }
1689 }
1690
1691 void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
1692 {
1693     if (preload == MediaPlayer::Auto && isLiveStream())
1694         return;
1695
1696     m_preload = preload;
1697     setDownloadBuffering();
1698
1699     if (m_delayingLoad && m_preload != MediaPlayer::None) {
1700         m_delayingLoad = false;
1701         commitLoad();
1702     }
1703 }
1704
1705 void MediaPlayerPrivateGStreamer::createAudioSink()
1706 {
1707     // Construct audio sink if pitch preserving is enabled.
1708     if (!m_preservesPitch)
1709         return;
1710
1711     if (!m_playBin)
1712         return;
1713
1714     GstElement* scale = gst_element_factory_make("scaletempo", 0);
1715     if (!scale) {
1716         GST_WARNING("Failed to create scaletempo");
1717         return;
1718     }
1719
1720     GstElement* convert = gst_element_factory_make("audioconvert", 0);
1721     GstElement* resample = gst_element_factory_make("audioresample", 0);
1722     GstElement* sink = gst_element_factory_make("autoaudiosink", 0);
1723
1724     m_autoAudioSink = sink;
1725
1726     g_signal_connect(sink, "child-added", G_CALLBACK(setAudioStreamPropertiesCallback), this);
1727
1728     GstElement* audioSink = gst_bin_new("audio-sink");
1729     gst_bin_add_many(GST_BIN(audioSink), scale, convert, resample, sink, NULL);
1730
1731     if (!gst_element_link_many(scale, convert, resample, sink, NULL)) {
1732         GST_WARNING("Failed to link audio sink elements");
1733         gst_object_unref(audioSink);
1734         return;
1735     }
1736
1737     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(scale, "sink"));
1738     gst_element_add_pad(audioSink, gst_ghost_pad_new("sink", pad.get()));
1739
1740     g_object_set(m_playBin.get(), "audio-sink", audioSink, NULL);
1741 }
1742
1743 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
1744 {
1745     ASSERT(!m_playBin);
1746
1747     // gst_element_factory_make() returns a floating reference so
1748     // we should not adopt.
1749     m_playBin = gst_element_factory_make(gPlaybinName, "play");
1750     setStreamVolumeElement(GST_STREAM_VOLUME(m_playBin.get()));
1751
1752     GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_playBin.get()));
1753     gst_bus_add_signal_watch(bus.get());
1754     g_signal_connect(bus.get(), "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
1755
1756     g_object_set(m_playBin.get(), "mute", m_player->muted(), NULL);
1757
1758     g_signal_connect(m_playBin.get(), "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
1759     g_signal_connect(m_playBin.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
1760     g_signal_connect(m_playBin.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
1761 #if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
1762     if (webkitGstCheckVersion(1, 1, 2)) {
1763         g_signal_connect(m_playBin.get(), "text-changed", G_CALLBACK(mediaPlayerPrivateTextChangedCallback), this);
1764
1765         GstElement* textCombiner = webkitTextCombinerNew();
1766         ASSERT(textCombiner);
1767         g_object_set(m_playBin.get(), "text-stream-combiner", textCombiner, NULL);
1768
1769         m_textAppSink = webkitTextSinkNew();
1770         ASSERT(m_textAppSink);
1771
1772         m_textAppSinkPad = adoptGRef(gst_element_get_static_pad(m_textAppSink.get(), "sink"));
1773         ASSERT(m_textAppSinkPad);
1774
1775         g_object_set(m_textAppSink.get(), "emit-signals", true, "enable-last-sample", false, "caps", gst_caps_new_empty_simple("text/vtt"), NULL);
1776         g_signal_connect(m_textAppSink.get(), "new-sample", G_CALLBACK(mediaPlayerPrivateNewTextSampleCallback), this);
1777
1778         g_object_set(m_playBin.get(), "text-sink", m_textAppSink.get(), NULL);
1779     }
1780 #endif
1781
1782     GstElement* videoElement = createVideoSink(m_playBin.get());
1783
1784     g_object_set(m_playBin.get(), "video-sink", videoElement, NULL);
1785
1786     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink.get(), "sink"));
1787     if (videoSinkPad)
1788         g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
1789
1790     createAudioSink();
1791 }
1792
1793 void MediaPlayerPrivateGStreamer::simulateAudioInterruption()
1794 {
1795     GstMessage* message = gst_message_new_request_state(GST_OBJECT(m_playBin.get()), GST_STATE_PAUSED);
1796     gst_element_post_message(m_playBin.get(), message);
1797 }
1798
1799 }
1800
1801 #endif // USE(GSTREAMER)