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