Home | History | Annotate | Download | only in gtk
      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  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * aint with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  */
     22 
     23 #include "config.h"
     24 
     25 #if ENABLE(VIDEO)
     26 
     27 #include "MediaPlayerPrivateGStreamer.h"
     28 
     29 
     30 #include "CString.h"
     31 #include "DataSourceGStreamer.h"
     32 #include "Document.h"
     33 #include "Frame.h"
     34 #include "FrameView.h"
     35 #include "GOwnPtrGtk.h"
     36 #include "GraphicsContext.h"
     37 #include "IntRect.h"
     38 #include "KURL.h"
     39 #include "MIMETypeRegistry.h"
     40 #include "MediaPlayer.h"
     41 #include "NotImplemented.h"
     42 #include "ScrollView.h"
     43 #include "SecurityOrigin.h"
     44 #include "TimeRanges.h"
     45 #include "VideoSinkGStreamer.h"
     46 #include "WebKitWebSourceGStreamer.h"
     47 #include "Widget.h"
     48 
     49 #include <gst/gst.h>
     50 #include <gst/interfaces/mixer.h>
     51 #include <gst/interfaces/xoverlay.h>
     52 #include <gst/video/video.h>
     53 #include <limits>
     54 #include <math.h>
     55 #include <webkit/webkitwebview.h>
     56 #include <wtf/gtk/GOwnPtr.h>
     57 
     58 using namespace std;
     59 
     60 namespace WebCore {
     61 
     62 gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
     63 {
     64     GOwnPtr<GError> err;
     65     GOwnPtr<gchar> debug;
     66     MediaPlayer::NetworkState error;
     67     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
     68     gint percent = 0;
     69     bool issueError = true;
     70     bool attemptNextLocation = false;
     71 
     72     if (message->structure) {
     73         const gchar* messageTypeName = gst_structure_get_name(message->structure);
     74 
     75         // Redirect messages are sent from elements, like qtdemux, to
     76         // notify of the new location(s) of the media.
     77         if (!g_strcmp0(messageTypeName, "redirect")) {
     78             mp->mediaLocationChanged(message);
     79             return true;
     80         }
     81     }
     82 
     83     switch (GST_MESSAGE_TYPE(message)) {
     84     case GST_MESSAGE_ERROR:
     85         if (mp && mp->pipelineReset())
     86             break;
     87         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
     88         LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
     89 
     90         error = MediaPlayer::Empty;
     91         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
     92             || err->code == GST_STREAM_ERROR_WRONG_TYPE
     93             || err->code == GST_STREAM_ERROR_FAILED
     94             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
     95             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
     96             error = MediaPlayer::FormatError;
     97         else if (err->domain == GST_STREAM_ERROR) {
     98             error = MediaPlayer::DecodeError;
     99             attemptNextLocation = true;
    100         } else if (err->domain == GST_RESOURCE_ERROR)
    101             error = MediaPlayer::NetworkError;
    102 
    103         if (mp) {
    104             if (attemptNextLocation)
    105                 issueError = !mp->loadNextLocation();
    106             if (issueError)
    107                 mp->loadingFailed(error);
    108         }
    109         break;
    110     case GST_MESSAGE_EOS:
    111         LOG_VERBOSE(Media, "End of Stream");
    112         mp->didEnd();
    113         break;
    114     case GST_MESSAGE_STATE_CHANGED:
    115         mp->updateStates();
    116         break;
    117     case GST_MESSAGE_BUFFERING:
    118         gst_message_parse_buffering(message, &percent);
    119         LOG_VERBOSE(Media, "Buffering %d", percent);
    120         break;
    121     case GST_MESSAGE_DURATION:
    122         LOG_VERBOSE(Media, "Duration changed");
    123         mp->durationChanged();
    124         break;
    125     default:
    126         LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
    127                     GST_MESSAGE_TYPE_NAME(message));
    128         break;
    129     }
    130     return true;
    131 }
    132 
    133 void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data)
    134 {
    135     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
    136     GOwnPtr<GstElement> element;
    137 
    138     g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL);
    139     gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element.get());
    140 
    141     if (WEBKIT_IS_WEB_SRC(element.get())) {
    142         Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0;
    143 
    144         if (frame)
    145             webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame);
    146     }
    147 }
    148 
    149 void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
    150 {
    151     // This is called when playbin receives the notify::volume signal.
    152     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
    153     mp->volumeChanged();
    154 }
    155 
    156 gboolean notifyVolumeIdleCallback(gpointer data)
    157 {
    158     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
    159     mp->volumeChangedCallback();
    160     return FALSE;
    161 }
    162 
    163 void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
    164 {
    165     // This is called when playbin receives the notify::mute signal.
    166     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
    167     mp->muteChanged();
    168 }
    169 
    170 gboolean notifyMuteIdleCallback(gpointer data)
    171 {
    172     MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
    173     mp->muteChangedCallback();
    174     return FALSE;
    175 }
    176 
    177 static float playbackPosition(GstElement* playbin)
    178 {
    179 
    180     float ret = 0.0;
    181 
    182     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
    183     if (!gst_element_query(playbin, query)) {
    184         LOG_VERBOSE(Media, "Position query failed...");
    185         gst_query_unref(query);
    186         return ret;
    187     }
    188 
    189     gint64 position;
    190     gst_query_parse_position(query, 0, &position);
    191 
    192     // Position is available only if the pipeline is not in GST_STATE_NULL or
    193     // GST_STATE_READY state.
    194     if (position !=  static_cast<gint64>(GST_CLOCK_TIME_NONE))
    195         ret = static_cast<float>(position) / static_cast<float>(GST_SECOND);
    196 
    197     LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
    198 
    199     gst_query_unref(query);
    200 
    201     return ret;
    202 }
    203 
    204 
    205 void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate)
    206 {
    207     g_return_if_fail(GST_IS_BUFFER(buffer));
    208     gst_buffer_replace(&playerPrivate->m_buffer, buffer);
    209     playerPrivate->repaint();
    210 }
    211 
    212 MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
    213 {
    214     return new MediaPlayerPrivate(player);
    215 }
    216 
    217 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
    218 {
    219     if (isAvailable())
    220         registrar(create, getSupportedTypes, supportsType);
    221 }
    222 
    223 static bool gstInitialized = false;
    224 
    225 static bool doGstInit()
    226 {
    227     // FIXME: We should pass the arguments from the command line
    228     if (!gstInitialized) {
    229         GOwnPtr<GError> error;
    230         gstInitialized = gst_init_check(0, 0, &error.outPtr());
    231         if (!gstInitialized) {
    232             LOG_VERBOSE(Media, "Could not initialize GStreamer: %s",
    233                         error ? error->message : "unknown error occurred");
    234         } else {
    235             gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY,
    236                                  WEBKIT_TYPE_DATA_SRC);
    237             gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100,
    238                                  WEBKIT_TYPE_WEB_SRC);
    239         }
    240 
    241     }
    242     return gstInitialized;
    243 }
    244 
    245 bool MediaPlayerPrivate::isAvailable()
    246 {
    247     if (!doGstInit())
    248         return false;
    249 
    250     GstElementFactory* factory = gst_element_factory_find("playbin2");
    251     if (factory) {
    252         gst_object_unref(GST_OBJECT(factory));
    253         return true;
    254     }
    255     return false;
    256 }
    257 
    258 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
    259     : m_player(player)
    260     , m_playBin(0)
    261     , m_videoSink(0)
    262     , m_fpsSink(0)
    263     , m_source(0)
    264     , m_seekTime(0)
    265     , m_changingRate(false)
    266     , m_endTime(numeric_limits<float>::infinity())
    267     , m_networkState(MediaPlayer::Empty)
    268     , m_readyState(MediaPlayer::HaveNothing)
    269     , m_startedPlaying(false)
    270     , m_isStreaming(false)
    271     , m_size(IntSize())
    272     , m_buffer(0)
    273     , m_mediaLocations(0)
    274     , m_mediaLocationCurrentIndex(0)
    275     , m_resetPipeline(false)
    276     , m_paused(true)
    277     , m_seeking(false)
    278     , m_playbackRate(1)
    279     , m_errorOccured(false)
    280     , m_volumeIdleId(0)
    281     , m_mediaDuration(0.0)
    282     , m_muteIdleId(0)
    283 {
    284     doGstInit();
    285 }
    286 
    287 MediaPlayerPrivate::~MediaPlayerPrivate()
    288 {
    289     if (m_volumeIdleId) {
    290         g_source_remove(m_volumeIdleId);
    291         m_volumeIdleId = 0;
    292     }
    293 
    294     if (m_muteIdleId) {
    295         g_source_remove(m_muteIdleId);
    296         m_muteIdleId = 0;
    297     }
    298 
    299     if (m_buffer)
    300         gst_buffer_unref(m_buffer);
    301     m_buffer = 0;
    302 
    303     if (m_mediaLocations) {
    304         gst_structure_free(m_mediaLocations);
    305         m_mediaLocations = 0;
    306     }
    307 
    308     if (m_source) {
    309         gst_object_unref(m_source);
    310         m_source = 0;
    311     }
    312 
    313     if (m_playBin) {
    314         gst_element_set_state(m_playBin, GST_STATE_NULL);
    315         gst_object_unref(GST_OBJECT(m_playBin));
    316     }
    317 
    318     if (m_videoSink) {
    319         g_object_unref(m_videoSink);
    320         m_videoSink = 0;
    321     }
    322 
    323     if (m_fpsSink) {
    324         g_object_unref(m_fpsSink);
    325         m_fpsSink = 0;
    326     }
    327 }
    328 
    329 void MediaPlayerPrivate::load(const String& url)
    330 {
    331     LOG_VERBOSE(Media, "Load %s", url.utf8().data());
    332     if (m_networkState != MediaPlayer::Loading) {
    333         m_networkState = MediaPlayer::Loading;
    334         m_player->networkStateChanged();
    335     }
    336     if (m_readyState != MediaPlayer::HaveNothing) {
    337         m_readyState = MediaPlayer::HaveNothing;
    338         m_player->readyStateChanged();
    339     }
    340 
    341     createGSTPlayBin(url);
    342     pause();
    343 }
    344 
    345 bool MediaPlayerPrivate::changePipelineState(GstState newState)
    346 {
    347     ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
    348 
    349     GstState currentState;
    350     GstState pending;
    351 
    352     gst_element_get_state(m_playBin, &currentState, &pending, 0);
    353     if (currentState != newState && pending != newState) {
    354         GstStateChangeReturn ret = gst_element_set_state(m_playBin, newState);
    355         GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
    356         if (currentState != pausedOrPlaying && ret == GST_STATE_CHANGE_FAILURE) {
    357             loadingFailed(MediaPlayer::Empty);
    358             return false;
    359         }
    360     }
    361     return true;
    362 }
    363 
    364 void MediaPlayerPrivate::play()
    365 {
    366     if (changePipelineState(GST_STATE_PLAYING))
    367         LOG_VERBOSE(Media, "Play");
    368 }
    369 
    370 void MediaPlayerPrivate::pause()
    371 {
    372     if (changePipelineState(GST_STATE_PAUSED))
    373         LOG_VERBOSE(Media, "Pause");
    374 }
    375 
    376 float MediaPlayerPrivate::duration() const
    377 {
    378     if (!m_playBin)
    379         return 0.0;
    380 
    381     if (m_errorOccured)
    382         return 0.0;
    383 
    384     if (m_mediaDuration)
    385         return m_mediaDuration;
    386 
    387     GstFormat timeFormat = GST_FORMAT_TIME;
    388     gint64 timeLength = 0;
    389 
    390     if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) {
    391         LOG_VERBOSE(Media, "Time duration query failed.");
    392         return numeric_limits<float>::infinity();
    393     }
    394 
    395     LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
    396 
    397     return (float) ((guint64) timeLength / 1000000000.0);
    398     // FIXME: handle 3.14.9.5 properly
    399 }
    400 
    401 float MediaPlayerPrivate::currentTime() const
    402 {
    403     if (!m_playBin)
    404         return 0;
    405 
    406     if (m_errorOccured)
    407         return 0;
    408 
    409     if (m_seeking)
    410         return m_seekTime;
    411 
    412     return playbackPosition(m_playBin);
    413 
    414 }
    415 
    416 void MediaPlayerPrivate::seek(float time)
    417 {
    418     // Avoid useless seeking.
    419     if (time == playbackPosition(m_playBin))
    420         return;
    421 
    422     if (!m_playBin)
    423         return;
    424 
    425     if (m_isStreaming)
    426         return;
    427 
    428     if (m_errorOccured)
    429         return;
    430 
    431     GstClockTime sec = (GstClockTime)(time * GST_SECOND);
    432     LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
    433     if (!gst_element_seek(m_playBin, m_player->rate(),
    434             GST_FORMAT_TIME,
    435             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
    436             GST_SEEK_TYPE_SET, sec,
    437             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
    438         LOG_VERBOSE(Media, "Seek to %f failed", time);
    439     else {
    440         m_seeking = true;
    441         m_seekTime = sec;
    442     }
    443 }
    444 
    445 void MediaPlayerPrivate::startEndPointTimerIfNeeded()
    446 {
    447     notImplemented();
    448 }
    449 
    450 void MediaPlayerPrivate::cancelSeek()
    451 {
    452     notImplemented();
    453 }
    454 
    455 void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
    456 {
    457     notImplemented();
    458 }
    459 
    460 bool MediaPlayerPrivate::paused() const
    461 {
    462     return m_paused;
    463 }
    464 
    465 bool MediaPlayerPrivate::seeking() const
    466 {
    467     return m_seeking;
    468 }
    469 
    470 // Returns the size of the video
    471 IntSize MediaPlayerPrivate::naturalSize() const
    472 {
    473     if (!hasVideo())
    474         return IntSize();
    475 
    476     // TODO: handle possible clean aperture data. See
    477     // https://bugzilla.gnome.org/show_bug.cgi?id=596571
    478     // TODO: handle possible transformation matrix. See
    479     // https://bugzilla.gnome.org/show_bug.cgi?id=596326
    480     int width = 0, height = 0;
    481     if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
    482         GstCaps* caps = GST_PAD_CAPS(pad);
    483         gfloat pixelAspectRatio;
    484         gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
    485 
    486         if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
    487             || !gst_video_format_parse_caps(caps, 0, &width, &height)
    488             || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
    489                                                         &pixelAspectRatioDenominator)) {
    490             gst_object_unref(GST_OBJECT(pad));
    491             return IntSize();
    492         }
    493 
    494         pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator;
    495         width *= pixelAspectRatio;
    496         height /= pixelAspectRatio;
    497         gst_object_unref(GST_OBJECT(pad));
    498     }
    499 
    500     return IntSize(width, height);
    501 }
    502 
    503 bool MediaPlayerPrivate::hasVideo() const
    504 {
    505     gint currentVideo = -1;
    506     if (m_playBin)
    507         g_object_get(m_playBin, "current-video", &currentVideo, NULL);
    508     return currentVideo > -1;
    509 }
    510 
    511 bool MediaPlayerPrivate::hasAudio() const
    512 {
    513     gint currentAudio = -1;
    514     if (m_playBin)
    515         g_object_get(m_playBin, "current-audio", &currentAudio, NULL);
    516     return currentAudio > -1;
    517 }
    518 
    519 void MediaPlayerPrivate::setVolume(float volume)
    520 {
    521     if (!m_playBin)
    522         return;
    523 
    524     g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL);
    525 }
    526 
    527 void MediaPlayerPrivate::volumeChangedCallback()
    528 {
    529     double volume;
    530     g_object_get(m_playBin, "volume", &volume, NULL);
    531     m_player->volumeChanged(static_cast<float>(volume));
    532 }
    533 
    534 void MediaPlayerPrivate::volumeChanged()
    535 {
    536     if (m_volumeIdleId)
    537         g_source_remove(m_volumeIdleId);
    538     m_volumeIdleId = g_idle_add((GSourceFunc) notifyVolumeIdleCallback, this);
    539 }
    540 
    541 void MediaPlayerPrivate::setRate(float rate)
    542 {
    543     // Avoid useless playback rate update.
    544     if (m_playbackRate == rate)
    545         return;
    546 
    547     GstState state;
    548     GstState pending;
    549 
    550     gst_element_get_state(m_playBin, &state, &pending, 0);
    551     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
    552         || (pending == GST_STATE_PAUSED))
    553         return;
    554 
    555     if (m_isStreaming)
    556         return;
    557 
    558     m_playbackRate = rate;
    559     m_changingRate = true;
    560     float currentPosition = playbackPosition(m_playBin) * GST_SECOND;
    561     GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
    562     gint64 start, end;
    563     bool mute = false;
    564 
    565     LOG_VERBOSE(Media, "Set Rate to %f", rate);
    566     if (rate >= 0) {
    567         // Mute the sound if the playback rate is too extreme.
    568         // TODO: in other cases we should perform pitch adjustments.
    569         mute = (bool) (rate < 0.8 || rate > 2);
    570         start = currentPosition;
    571         end = GST_CLOCK_TIME_NONE;
    572     } else {
    573         start = 0;
    574         mute = true;
    575 
    576         // If we are at beginning of media, start from the end to
    577         // avoid immediate EOS.
    578         if (currentPosition <= 0)
    579             end = duration() * GST_SECOND;
    580         else
    581             end = currentPosition;
    582     }
    583 
    584     LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute);
    585 
    586     if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags,
    587                           GST_SEEK_TYPE_SET, start,
    588                           GST_SEEK_TYPE_SET, end))
    589         LOG_VERBOSE(Media, "Set rate to %f failed", rate);
    590     else
    591         g_object_set(m_playBin, "mute", mute, NULL);
    592 }
    593 
    594 MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
    595 {
    596     return m_networkState;
    597 }
    598 
    599 MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
    600 {
    601     return m_readyState;
    602 }
    603 
    604 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
    605 {
    606     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
    607     float loaded = maxTimeLoaded();
    608     if (!m_errorOccured && !m_isStreaming && loaded > 0)
    609         timeRanges->add(0, loaded);
    610     return timeRanges.release();
    611 }
    612 
    613 float MediaPlayerPrivate::maxTimeSeekable() const
    614 {
    615     if (m_errorOccured)
    616         return 0.0;
    617 
    618     // TODO
    619     LOG_VERBOSE(Media, "maxTimeSeekable");
    620     if (m_isStreaming)
    621         return numeric_limits<float>::infinity();
    622     // infinite duration means live stream
    623     return maxTimeLoaded();
    624 }
    625 
    626 float MediaPlayerPrivate::maxTimeLoaded() const
    627 {
    628     if (m_errorOccured)
    629         return 0.0;
    630 
    631     // TODO
    632     LOG_VERBOSE(Media, "maxTimeLoaded");
    633     notImplemented();
    634     return duration();
    635 }
    636 
    637 unsigned MediaPlayerPrivate::bytesLoaded() const
    638 {
    639     notImplemented();
    640     LOG_VERBOSE(Media, "bytesLoaded");
    641     /*if (!m_playBin)
    642         return 0;
    643     float dur = duration();
    644     float maxTime = maxTimeLoaded();
    645     if (!dur)
    646         return 0;*/
    647 
    648     return 1; // totalBytes() * maxTime / dur;
    649 }
    650 
    651 unsigned MediaPlayerPrivate::totalBytes() const
    652 {
    653     LOG_VERBOSE(Media, "totalBytes");
    654     if (!m_source)
    655         return 0;
    656 
    657     if (m_errorOccured)
    658         return 0;
    659 
    660     GstFormat fmt = GST_FORMAT_BYTES;
    661     gint64 length = 0;
    662     gst_element_query_duration(m_source, &fmt, &length);
    663 
    664     return length;
    665 }
    666 
    667 void MediaPlayerPrivate::cancelLoad()
    668 {
    669     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
    670         return;
    671 
    672     if (m_playBin)
    673         gst_element_set_state(m_playBin, GST_STATE_NULL);
    674 }
    675 
    676 void MediaPlayerPrivate::updateStates()
    677 {
    678     // There is no (known) way to get such level of information about
    679     // the state of GStreamer, therefore, when in PAUSED state,
    680     // we are sure we can display the first frame and go to play
    681 
    682     if (!m_playBin)
    683         return;
    684 
    685     if (m_errorOccured)
    686         return;
    687 
    688     MediaPlayer::NetworkState oldNetworkState = m_networkState;
    689     MediaPlayer::ReadyState oldReadyState = m_readyState;
    690     GstState state;
    691     GstState pending;
    692 
    693     GstStateChangeReturn ret = gst_element_get_state(m_playBin,
    694         &state, &pending, 250 * GST_NSECOND);
    695 
    696     bool shouldUpdateAfterSeek = false;
    697     switch (ret) {
    698     case GST_STATE_CHANGE_SUCCESS:
    699         LOG_VERBOSE(Media, "State: %s, pending: %s",
    700             gst_element_state_get_name(state),
    701             gst_element_state_get_name(pending));
    702 
    703         m_resetPipeline = state <= GST_STATE_READY;
    704 
    705         if (state == GST_STATE_READY)
    706             m_readyState = MediaPlayer::HaveNothing;
    707         else if (state == GST_STATE_PAUSED)
    708             m_readyState = MediaPlayer::HaveEnoughData;
    709 
    710         if (state == GST_STATE_PLAYING) {
    711             m_readyState = MediaPlayer::HaveEnoughData;
    712             m_paused = false;
    713             if (!m_mediaDuration) {
    714                 float newDuration = duration();
    715                 if (!isinf(newDuration))
    716                     m_mediaDuration = newDuration;
    717             }
    718         } else
    719             m_paused = true;
    720 
    721         if (m_changingRate) {
    722             m_player->rateChanged();
    723             m_changingRate = false;
    724         }
    725 
    726         if (m_seeking) {
    727             shouldUpdateAfterSeek = true;
    728             m_seeking = false;
    729         }
    730 
    731         m_networkState = MediaPlayer::Loaded;
    732         break;
    733     case GST_STATE_CHANGE_ASYNC:
    734         LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
    735             gst_element_state_get_name(state),
    736             gst_element_state_get_name(pending));
    737         // Change in progress
    738         return;
    739     case GST_STATE_CHANGE_FAILURE:
    740         LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
    741             gst_element_state_get_name(state),
    742             gst_element_state_get_name(pending));
    743         // Change failed
    744         return;
    745     case GST_STATE_CHANGE_NO_PREROLL:
    746         LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
    747             gst_element_state_get_name(state),
    748             gst_element_state_get_name(pending));
    749 
    750         if (state == GST_STATE_READY)
    751             m_readyState = MediaPlayer::HaveNothing;
    752         else if (state == GST_STATE_PAUSED)
    753             m_readyState = MediaPlayer::HaveCurrentData;
    754 
    755         m_networkState = MediaPlayer::Loading;
    756         break;
    757     default:
    758         LOG_VERBOSE(Media, "Else : %d", ret);
    759         break;
    760     }
    761 
    762     if (seeking())
    763         m_readyState = MediaPlayer::HaveNothing;
    764 
    765     if (shouldUpdateAfterSeek)
    766         timeChanged();
    767 
    768     if (m_networkState != oldNetworkState) {
    769         LOG_VERBOSE(Media, "Network State Changed from %u to %u",
    770             oldNetworkState, m_networkState);
    771         m_player->networkStateChanged();
    772     }
    773     if (m_readyState != oldReadyState) {
    774         LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
    775             oldReadyState, m_readyState);
    776         m_player->readyStateChanged();
    777     }
    778 }
    779 
    780 void MediaPlayerPrivate::mediaLocationChanged(GstMessage* message)
    781 {
    782     if (m_mediaLocations)
    783         gst_structure_free(m_mediaLocations);
    784 
    785     if (message->structure) {
    786         // This structure can contain:
    787         // - both a new-location string and embedded locations structure
    788         // - or only a new-location string.
    789         m_mediaLocations = gst_structure_copy(message->structure);
    790         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
    791 
    792         if (locations)
    793             m_mediaLocationCurrentIndex = gst_value_list_get_size(locations) -1;
    794 
    795         loadNextLocation();
    796     }
    797 }
    798 
    799 bool MediaPlayerPrivate::loadNextLocation()
    800 {
    801     if (!m_mediaLocations)
    802         return false;
    803 
    804     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
    805     const gchar* newLocation = 0;
    806 
    807     if (!locations) {
    808         // Fallback on new-location string.
    809         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
    810         if (!newLocation)
    811             return false;
    812     }
    813 
    814     if (!newLocation) {
    815         if (m_mediaLocationCurrentIndex < 0) {
    816             m_mediaLocations = 0;
    817             return false;
    818         }
    819 
    820         const GValue* location = gst_value_list_get_value(locations,
    821                                                           m_mediaLocationCurrentIndex);
    822         const GstStructure* structure = gst_value_get_structure(location);
    823 
    824         if (!structure) {
    825             m_mediaLocationCurrentIndex--;
    826             return false;
    827         }
    828 
    829         newLocation = gst_structure_get_string(structure, "new-location");
    830     }
    831 
    832     if (newLocation) {
    833         // Found a candidate. new-location is not always an absolute url
    834         // though. We need to take the base of the current url and
    835         // append the value of new-location to it.
    836 
    837         gchar* currentLocation = 0;
    838         g_object_get(m_playBin, "uri", &currentLocation, NULL);
    839 
    840         KURL currentUrl(KURL(), currentLocation);
    841         g_free(currentLocation);
    842 
    843         KURL newUrl;
    844 
    845         if (gst_uri_is_valid(newLocation))
    846             newUrl = KURL(KURL(), newLocation);
    847         else
    848             newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
    849 
    850         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
    851         if (securityOrigin->canRequest(newUrl)) {
    852             LOG_VERBOSE(Media, "New media url: %s", newUrl.string().utf8().data());
    853 
    854             // Reset player states.
    855             m_networkState = MediaPlayer::Loading;
    856             m_player->networkStateChanged();
    857             m_readyState = MediaPlayer::HaveNothing;
    858             m_player->readyStateChanged();
    859 
    860             // Reset pipeline state.
    861             m_resetPipeline = true;
    862             gst_element_set_state(m_playBin, GST_STATE_READY);
    863 
    864             GstState state;
    865             gst_element_get_state(m_playBin, &state, 0, 0);
    866             if (state <= GST_STATE_READY) {
    867                 // Set the new uri and start playing.
    868                 g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
    869                 gst_element_set_state(m_playBin, GST_STATE_PLAYING);
    870                 return true;
    871             }
    872         }
    873     }
    874     m_mediaLocationCurrentIndex--;
    875     return false;
    876 
    877 }
    878 
    879 void MediaPlayerPrivate::loadStateChanged()
    880 {
    881     updateStates();
    882 }
    883 
    884 void MediaPlayerPrivate::sizeChanged()
    885 {
    886     notImplemented();
    887 }
    888 
    889 void MediaPlayerPrivate::timeChanged()
    890 {
    891     updateStates();
    892     m_player->timeChanged();
    893 }
    894 
    895 void MediaPlayerPrivate::didEnd()
    896 {
    897     // EOS was reached but in case of reverse playback the position is
    898     // not always 0. So to not confuse the HTMLMediaElement we
    899     // synchronize position and duration values.
    900     float now = currentTime();
    901     if (now > 0)
    902         m_mediaDuration = now;
    903     gst_element_set_state(m_playBin, GST_STATE_PAUSED);
    904 
    905     timeChanged();
    906 }
    907 
    908 void MediaPlayerPrivate::durationChanged()
    909 {
    910     // Reset cached media duration
    911     m_mediaDuration = 0;
    912 
    913     // And re-cache it if possible.
    914     float newDuration = duration();
    915     if (!isinf(newDuration))
    916         m_mediaDuration = newDuration;
    917 
    918     m_player->durationChanged();
    919 }
    920 
    921 bool MediaPlayerPrivate::supportsMuting() const
    922 {
    923     return true;
    924 }
    925 
    926 void MediaPlayerPrivate::setMuted(bool muted)
    927 {
    928     if (!m_playBin)
    929         return;
    930 
    931     g_object_set(m_playBin, "mute", muted, NULL);
    932 }
    933 
    934 void MediaPlayerPrivate::muteChangedCallback()
    935 {
    936     gboolean muted;
    937     g_object_get(m_playBin, "mute", &muted, NULL);
    938     m_player->muteChanged(static_cast<bool>(muted));
    939 }
    940 
    941 void MediaPlayerPrivate::muteChanged()
    942 {
    943     if (m_muteIdleId)
    944         g_source_remove(m_muteIdleId);
    945 
    946     m_muteIdleId = g_idle_add((GSourceFunc) notifyMuteIdleCallback, this);
    947 }
    948 
    949 void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error)
    950 {
    951     m_errorOccured = true;
    952     if (m_networkState != error) {
    953         m_networkState = error;
    954         m_player->networkStateChanged();
    955     }
    956     if (m_readyState != MediaPlayer::HaveNothing) {
    957         m_readyState = MediaPlayer::HaveNothing;
    958         m_player->readyStateChanged();
    959     }
    960 }
    961 
    962 void MediaPlayerPrivate::setSize(const IntSize& size)
    963 {
    964     m_size = size;
    965 }
    966 
    967 void MediaPlayerPrivate::setVisible(bool visible)
    968 {
    969 }
    970 
    971 void MediaPlayerPrivate::repaint()
    972 {
    973     m_player->repaint();
    974 }
    975 
    976 void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
    977 {
    978     if (context->paintingDisabled())
    979         return;
    980 
    981     if (!m_player->visible())
    982         return;
    983     if (!m_buffer)
    984         return;
    985 
    986     int width = 0, height = 0;
    987     GstCaps* caps = gst_buffer_get_caps(m_buffer);
    988     GstVideoFormat format;
    989 
    990     if (!gst_video_format_parse_caps(caps, &format, &width, &height)) {
    991       gst_caps_unref(caps);
    992       return;
    993     }
    994 
    995     cairo_format_t cairoFormat;
    996     if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA)
    997         cairoFormat = CAIRO_FORMAT_ARGB32;
    998     else
    999         cairoFormat = CAIRO_FORMAT_RGB24;
   1000 
   1001     cairo_t* cr = context->platformContext();
   1002     cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer),
   1003                                                                cairoFormat,
   1004                                                                width, height,
   1005                                                                4 * width);
   1006 
   1007     cairo_save(cr);
   1008 
   1009     // translate and scale the context to correct size
   1010     cairo_translate(cr, rect.x(), rect.y());
   1011     cairo_scale(cr, static_cast<double>(rect.width()) / width, static_cast<double>(rect.height()) / height);
   1012 
   1013     // And paint it.
   1014     cairo_set_source_surface(cr, src, 0, 0);
   1015     cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD);
   1016     cairo_rectangle(cr, 0, 0, width, height);
   1017     cairo_fill(cr);
   1018     cairo_restore(cr);
   1019 
   1020     cairo_surface_destroy(src);
   1021     gst_caps_unref(caps);
   1022 }
   1023 
   1024 static HashSet<String> mimeTypeCache()
   1025 {
   1026 
   1027     doGstInit();
   1028 
   1029     static HashSet<String> cache;
   1030     static bool typeListInitialized = false;
   1031 
   1032     if (!typeListInitialized) {
   1033         // Build a whitelist of mime-types known to be supported by
   1034         // GStreamer.
   1035         HashSet<String> handledApplicationSubtypes;
   1036         handledApplicationSubtypes.add(String("ogg"));
   1037         handledApplicationSubtypes.add(String("x-3gp"));
   1038         handledApplicationSubtypes.add(String("vnd.rn-realmedia"));
   1039         handledApplicationSubtypes.add(String("x-pn-realaudio"));
   1040 
   1041         GList* factories = gst_type_find_factory_get_list();
   1042         for (GList* iterator = factories; iterator; iterator = iterator->next) {
   1043             GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data);
   1044             GstCaps* caps = gst_type_find_factory_get_caps(factory);
   1045 
   1046             if (!caps)
   1047                 continue;
   1048 
   1049             for (guint structureIndex = 0; structureIndex < gst_caps_get_size(caps); structureIndex++) {
   1050                 GstStructure* structure = gst_caps_get_structure(caps, structureIndex);
   1051                 const gchar* name = gst_structure_get_name(structure);
   1052                 bool cached = false;
   1053 
   1054                 // These formats are supported by GStreamer, but not
   1055                 // correctly advertised.
   1056                 if (g_str_equal(name, "video/x-h264")
   1057                     || g_str_equal(name, "audio/x-m4a")) {
   1058                     cache.add(String("video/mp4"));
   1059                     cache.add(String("audio/aac"));
   1060                     cached = true;
   1061                 }
   1062 
   1063                 if (g_str_equal(name, "video/x-theora")) {
   1064                     cache.add(String("video/ogg"));
   1065                     cached = true;
   1066                 }
   1067 
   1068                 if (g_str_equal(name, "audio/x-vorbis")) {
   1069                     cache.add(String("audio/ogg"));
   1070                     cached = true;
   1071                 }
   1072 
   1073                 if (g_str_equal(name, "audio/x-wav")) {
   1074                     cache.add(String("audio/wav"));
   1075                     cached = true;
   1076                 }
   1077 
   1078                 if (g_str_equal(name, "audio/mpeg")) {
   1079                     cache.add(String(name));
   1080                     cached = true;
   1081 
   1082                     // This is what we are handling:
   1083                     // mpegversion=(int)1, layer=(int)[ 1, 3 ]
   1084                     gint mpegVersion = 0;
   1085                     if (gst_structure_get_int(structure, "mpegversion", &mpegVersion) && (mpegVersion == 1)) {
   1086                         const GValue* layer = gst_structure_get_value(structure, "layer");
   1087                         if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) {
   1088                             gint minLayer = gst_value_get_int_range_min(layer);
   1089                             gint maxLayer = gst_value_get_int_range_max(layer);
   1090                             if (minLayer <= 1 && 1 <= maxLayer)
   1091                                 cache.add(String("audio/mp1"));
   1092                             if (minLayer <= 2 && 2 <= maxLayer)
   1093                                 cache.add(String("audio/mp2"));
   1094                             if (minLayer <= 3 && 3 <= maxLayer)
   1095                                 cache.add(String("audio/mp3"));
   1096                         }
   1097                     }
   1098                 }
   1099 
   1100                 if (!cached) {
   1101                     // GStreamer plugins can be capable of supporting
   1102                     // types which WebKit supports by default. In that
   1103                     // case, we should not consider these types
   1104                     // supportable by GStreamer.  Examples of what
   1105                     // GStreamer can support but should not be added:
   1106                     // text/plain, text/html, image/jpeg,
   1107                     // application/xml
   1108                     gchar** mimetype = g_strsplit(name, "/", 2);
   1109                     if (g_str_equal(mimetype[0], "audio")
   1110                         || g_str_equal(mimetype[0], "video")
   1111                         || (g_str_equal(mimetype[0], "application")
   1112                             && handledApplicationSubtypes.contains(String(mimetype[1]))))
   1113                         cache.add(String(name));
   1114 
   1115                     g_strfreev(mimetype);
   1116                 }
   1117             }
   1118         }
   1119 
   1120         gst_plugin_feature_list_free(factories);
   1121         typeListInitialized = true;
   1122     }
   1123 
   1124     return cache;
   1125 }
   1126 
   1127 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
   1128 {
   1129     types = mimeTypeCache();
   1130 }
   1131 
   1132 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
   1133 {
   1134     if (type.isNull() || type.isEmpty())
   1135         return MediaPlayer::IsNotSupported;
   1136 
   1137     // spec says we should not return "probably" if the codecs string is empty
   1138     if (mimeTypeCache().contains(type))
   1139         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
   1140     return MediaPlayer::IsNotSupported;
   1141 }
   1142 
   1143 bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
   1144 {
   1145     return true;
   1146 }
   1147 
   1148 bool MediaPlayerPrivate::supportsFullscreen() const
   1149 {
   1150     return true;
   1151 }
   1152 
   1153 void MediaPlayerPrivate::createGSTPlayBin(String url)
   1154 {
   1155     ASSERT(!m_playBin);
   1156     m_playBin = gst_element_factory_make("playbin2", "play");
   1157 
   1158     GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
   1159     gst_bus_add_signal_watch(bus);
   1160     g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
   1161     gst_object_unref(bus);
   1162 
   1163     g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
   1164 
   1165     g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
   1166     g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
   1167     g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
   1168 
   1169     m_videoSink = webkit_video_sink_new();
   1170 
   1171     g_object_ref_sink(m_videoSink);
   1172 
   1173     WTFLogChannel* channel = getChannelFromName("Media");
   1174     if (channel->state == WTFLogChannelOn) {
   1175         m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
   1176         if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
   1177             g_object_set(m_fpsSink, "video-sink", m_videoSink, NULL);
   1178             g_object_ref_sink(m_fpsSink);
   1179             g_object_set(m_playBin, "video-sink", m_fpsSink, NULL);
   1180         } else {
   1181             m_fpsSink = 0;
   1182             g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
   1183             LOG(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
   1184         }
   1185     } else
   1186         g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
   1187 
   1188     g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
   1189 }
   1190 
   1191 }
   1192 
   1193 #endif
   1194