root/trunk/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp

Revision 50424, 24.4 KB (checked in by eric@webkit.org, 5 days ago)

2009-11-02 Philippe Normand < pnormand@igalia.com>

Reviewed by Jan Alonzo.

[GTK] Failing media/video-played-reset.html
 https://bugs.webkit.org/show_bug.cgi?id=30589

new m_seekTime attribute to keep track of the seek position

  • platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp: (WebCore::MediaPlayerPrivate::currentTime): (WebCore::MediaPlayerPrivate::seek):
  • platform/graphics/gtk/MediaPlayerPrivateGStreamer.h:
  • Property svn:eol-style set to native
Line 
1/*
2 * Copyright (C) 2007, 2009 Apple Inc.  All rights reserved.
3 * Copyright (C) 2007 Collabora Ltd.  All rights reserved.
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
6 *
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 "GraphicsContext.h"
33#include "IntRect.h"
34#include "KURL.h"
35#include "MIMETypeRegistry.h"
36#include "MediaPlayer.h"
37#include "NotImplemented.h"
38#include "ScrollView.h"
39#include "TimeRanges.h"
40#include "VideoSinkGStreamer.h"
41#include "Widget.h"
42
43#include <gst/gst.h>
44#include <gst/interfaces/mixer.h>
45#include <gst/interfaces/xoverlay.h>
46#include <gst/video/video.h>
47#include <limits>
48#include <math.h>
49#include <wtf/GOwnPtr.h>
50
51using namespace std;
52
53namespace WebCore {
54
55gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
56{
57    GOwnPtr<GError> err;
58    GOwnPtr<gchar> debug;
59    MediaPlayer::NetworkState error;
60    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
61    gint percent = 0;
62
63    switch (GST_MESSAGE_TYPE(message)) {
64    case GST_MESSAGE_ERROR:
65        gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
66        LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
67
68        error = MediaPlayer::Empty;
69        if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND ||
70            err->code == GST_STREAM_ERROR_WRONG_TYPE ||
71            err->code == GST_STREAM_ERROR_FAILED ||
72            err->code == GST_CORE_ERROR_MISSING_PLUGIN ||
73            err->code == GST_RESOURCE_ERROR_NOT_FOUND)
74            error = MediaPlayer::FormatError;
75        else if (err->domain == GST_STREAM_ERROR)
76            error = MediaPlayer::DecodeError;
77        else if (err->domain == GST_RESOURCE_ERROR)
78            error = MediaPlayer::NetworkError;
79
80        if (mp)
81            mp->loadingFailed(error);
82        break;
83    case GST_MESSAGE_EOS:
84        LOG_VERBOSE(Media, "End of Stream");
85        mp->didEnd();
86        break;
87    case GST_MESSAGE_STATE_CHANGED:
88        mp->updateStates();
89        break;
90    case GST_MESSAGE_BUFFERING:
91        gst_message_parse_buffering(message, &percent);
92        LOG_VERBOSE(Media, "Buffering %d", percent);
93        break;
94    default:
95        LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
96                    GST_MESSAGE_TYPE_NAME(message));
97        break;
98    }
99    return true;
100}
101
102void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate)
103{
104    g_return_if_fail(GST_IS_BUFFER(buffer));
105    gst_buffer_replace(&playerPrivate->m_buffer, buffer);
106    playerPrivate->repaint();
107}
108
109MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
110{
111    return new MediaPlayerPrivate(player);
112}
113
114void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
115{
116    if (isAvailable())
117        registrar(create, getSupportedTypes, supportsType);
118}
119
120static bool gstInitialized = false;
121
122static void do_gst_init()
123{
124    // FIXME: We should pass the arguments from the command line
125    if (!gstInitialized) {
126        gst_init(0, 0);
127        gstInitialized = true;
128        gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY,
129                             WEBKIT_TYPE_DATA_SRC);
130
131    }
132}
133
134MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
135    : m_player(player)
136    , m_playBin(0)
137    , m_videoSink(0)
138    , m_source(0)
139    , m_seekTime(0)
140    , m_endTime(numeric_limits<float>::infinity())
141    , m_networkState(MediaPlayer::Empty)
142    , m_readyState(MediaPlayer::HaveNothing)
143    , m_startedPlaying(false)
144    , m_isStreaming(false)
145    , m_size(IntSize())
146    , m_buffer(0)
147    , m_paused(true)
148    , m_seeking(false)
149    , m_errorOccured(false)
150{
151    do_gst_init();
152}
153
154MediaPlayerPrivate::~MediaPlayerPrivate()
155{
156    if (m_buffer)
157        gst_buffer_unref(m_buffer);
158    m_buffer = 0;
159
160    if (m_playBin) {
161        gst_element_set_state(m_playBin, GST_STATE_NULL);
162        gst_object_unref(GST_OBJECT(m_playBin));
163    }
164
165    if (m_videoSink) {
166        g_object_unref(m_videoSink);
167        m_videoSink = 0;
168    }
169}
170
171void MediaPlayerPrivate::load(const String& url)
172{
173    LOG_VERBOSE(Media, "Load %s", url.utf8().data());
174    if (m_networkState != MediaPlayer::Loading) {
175        m_networkState = MediaPlayer::Loading;
176        m_player->networkStateChanged();
177    }
178    if (m_readyState != MediaPlayer::HaveNothing) {
179        m_readyState = MediaPlayer::HaveNothing;
180        m_player->readyStateChanged();
181    }
182
183    createGSTPlayBin(url);
184    pause();
185}
186
187void MediaPlayerPrivate::play()
188{
189    LOG_VERBOSE(Media, "Play");
190    gst_element_set_state(m_playBin, GST_STATE_PLAYING);
191}
192
193void MediaPlayerPrivate::pause()
194{
195    LOG_VERBOSE(Media, "Pause");
196    gst_element_set_state(m_playBin, GST_STATE_PAUSED);
197}
198
199float MediaPlayerPrivate::duration() const
200{
201    if (!m_playBin)
202        return 0.0;
203
204    if (m_errorOccured)
205        return 0.0;
206
207    GstFormat timeFormat = GST_FORMAT_TIME;
208    gint64 timeLength = 0;
209
210    if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) {
211        LOG_VERBOSE(Media, "Time duration query failed.");
212        return numeric_limits<float>::infinity();
213    }
214
215    LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
216
217    return (float) ((guint64) timeLength / 1000000000.0);
218    // FIXME: handle 3.14.9.5 properly
219}
220
221float MediaPlayerPrivate::currentTime() const
222{
223    if (!m_playBin)
224        return 0;
225
226    if (m_errorOccured)
227        return 0;
228
229    if (m_seeking)
230        return m_seekTime;
231
232    float ret = 0.0;
233
234    GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
235    if (!gst_element_query(m_playBin, query)) {
236        LOG_VERBOSE(Media, "Position query failed...");
237        gst_query_unref(query);
238        return ret;
239    }
240
241    gint64 position;
242    gst_query_parse_position(query, 0, &position);
243    ret = (float) (position / 1000000000.0);
244    LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
245
246    gst_query_unref(query);
247
248    return ret;
249}
250
251void MediaPlayerPrivate::seek(float time)
252{
253    GstClockTime sec = (GstClockTime)(time * GST_SECOND);
254
255    if (!m_playBin)
256        return;
257
258    if (m_isStreaming)
259        return;
260
261    if (m_errorOccured)
262        return;
263
264    LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
265    if (!gst_element_seek(m_playBin, m_player->rate(),
266            GST_FORMAT_TIME,
267            (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
268            GST_SEEK_TYPE_SET, sec,
269            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
270        LOG_VERBOSE(Media, "Seek to %f failed", time);
271    else {
272        m_seeking = true;
273        m_seekTime = sec;
274    }
275}
276
277void MediaPlayerPrivate::setEndTime(float time)
278{
279    notImplemented();
280}
281
282void MediaPlayerPrivate::startEndPointTimerIfNeeded()
283{
284    notImplemented();
285}
286
287void MediaPlayerPrivate::cancelSeek()
288{
289    notImplemented();
290}
291
292void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
293{
294    notImplemented();
295}
296
297bool MediaPlayerPrivate::paused() const
298{
299    return m_paused;
300}
301
302bool MediaPlayerPrivate::seeking() const
303{
304    return m_seeking;
305}
306
307// Returns the size of the video
308IntSize MediaPlayerPrivate::naturalSize() const
309{
310    if (!hasVideo())
311        return IntSize();
312
313    // TODO: handle possible clean aperture data. See
314    // https://bugzilla.gnome.org/show_bug.cgi?id=596571
315    // TODO: handle possible transformation matrix. See
316    // https://bugzilla.gnome.org/show_bug.cgi?id=596326
317    int width = 0, height = 0;
318    if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
319        GstCaps* caps = GST_PAD_CAPS(pad);
320        gfloat pixelAspectRatio;
321        gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
322
323        if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) ||
324            !gst_video_format_parse_caps(caps, NULL, &width, &height) ||
325            !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
326                                                           &pixelAspectRatioDenominator)) {
327            gst_object_unref(GST_OBJECT(pad));
328            return IntSize();
329        }
330
331        pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator;
332        width *= pixelAspectRatio;
333        height /= pixelAspectRatio;
334        gst_object_unref(GST_OBJECT(pad));
335    }
336
337    return IntSize(width, height);
338}
339
340bool MediaPlayerPrivate::hasVideo() const
341{
342    gint currentVideo = -1;
343    if (m_playBin)
344        g_object_get(G_OBJECT(m_playBin), "current-video", &currentVideo, NULL);
345    return currentVideo > -1;
346}
347
348bool MediaPlayerPrivate::hasAudio() const
349{
350    gint currentAudio = -1;
351    if (m_playBin)
352        g_object_get(G_OBJECT(m_playBin), "current-audio", &currentAudio, NULL);
353    return currentAudio > -1;
354}
355
356void MediaPlayerPrivate::setVolume(float volume)
357{
358    if (!m_playBin)
359        return;
360
361    g_object_set(G_OBJECT(m_playBin), "volume", static_cast<double>(volume), NULL);
362}
363
364void MediaPlayerPrivate::setRate(float rate)
365{
366    if (rate == 0.0) {
367        gst_element_set_state(m_playBin, GST_STATE_PAUSED);
368        return;
369    }
370
371    if (m_isStreaming)
372        return;
373
374    LOG_VERBOSE(Media, "Set Rate to %f", rate);
375    seek(currentTime());
376}
377
378int MediaPlayerPrivate::dataRate() const
379{
380    notImplemented();
381    return 1;
382}
383
384MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
385{
386    return m_networkState;
387}
388
389MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
390{
391    return m_readyState;
392}
393
394PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
395{
396    RefPtr<TimeRanges> timeRanges = TimeRanges::create();
397    float loaded = maxTimeLoaded();
398    if (!m_errorOccured && !m_isStreaming && loaded > 0)
399        timeRanges->add(0, loaded);
400    return timeRanges.release();
401}
402
403float MediaPlayerPrivate::maxTimeSeekable() const
404{
405    if (m_errorOccured)
406        return 0.0;
407
408    // TODO
409    LOG_VERBOSE(Media, "maxTimeSeekable");
410    if (m_isStreaming)
411        return numeric_limits<float>::infinity();
412    // infinite duration means live stream
413    return maxTimeLoaded();
414}
415
416float MediaPlayerPrivate::maxTimeLoaded() const
417{
418    if (m_errorOccured)
419        return 0.0;
420
421    // TODO
422    LOG_VERBOSE(Media, "maxTimeLoaded");
423    notImplemented();
424    return duration();
425}
426
427unsigned MediaPlayerPrivate::bytesLoaded() const
428{
429    notImplemented();
430    LOG_VERBOSE(Media, "bytesLoaded");
431    /*if (!m_playBin)
432        return 0;
433    float dur = duration();
434    float maxTime = maxTimeLoaded();
435    if (!dur)
436        return 0;*/
437
438    return 1;//totalBytes() * maxTime / dur;
439}
440
441bool MediaPlayerPrivate::totalBytesKnown() const
442{
443    LOG_VERBOSE(Media, "totalBytesKnown");
444    return totalBytes() > 0;
445}
446
447unsigned MediaPlayerPrivate::totalBytes() const
448{
449    LOG_VERBOSE(Media, "totalBytes");
450    if (!m_source)
451        return 0;
452
453    if (m_errorOccured)
454        return 0;
455
456    GstFormat fmt = GST_FORMAT_BYTES;
457    gint64 length = 0;
458    gst_element_query_duration(m_source, &fmt, &length);
459
460    return length;
461}
462
463void MediaPlayerPrivate::cancelLoad()
464{
465    if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
466        return;
467
468    if (m_playBin)
469        gst_element_set_state(m_playBin, GST_STATE_NULL);
470}
471
472void MediaPlayerPrivate::updateStates()
473{
474    // There is no (known) way to get such level of information about
475    // the state of GStreamer, therefore, when in PAUSED state,
476    // we are sure we can display the first frame and go to play
477
478    if (!m_playBin)
479        return;
480
481    if (m_errorOccured)
482        return;
483
484    MediaPlayer::NetworkState oldNetworkState = m_networkState;
485    MediaPlayer::ReadyState oldReadyState = m_readyState;
486    GstState state;
487    GstState pending;
488
489    GstStateChangeReturn ret = gst_element_get_state(m_playBin,
490        &state, &pending, 250 * GST_NSECOND);
491
492    bool shouldUpdateAfterSeek = false;
493    switch (ret) {
494    case GST_STATE_CHANGE_SUCCESS:
495        LOG_VERBOSE(Media, "State: %s, pending: %s",
496            gst_element_state_get_name(state),
497            gst_element_state_get_name(pending));
498
499        if (state == GST_STATE_READY)
500            m_readyState = MediaPlayer::HaveNothing;
501        else if (state == GST_STATE_PAUSED)
502            m_readyState = MediaPlayer::HaveEnoughData;
503
504        if (state == GST_STATE_PLAYING) {
505            m_readyState = MediaPlayer::HaveEnoughData;
506            m_paused = false;
507        } else
508            m_paused = true;
509
510        if (m_seeking) {
511            shouldUpdateAfterSeek = true;
512            m_seeking = false;
513        }
514
515        m_networkState = MediaPlayer::Loaded;
516
517        g_object_get(m_playBin, "source", &m_source, NULL);
518        if (!m_source)
519            LOG_VERBOSE(Media, "m_source is 0");
520        break;
521    case GST_STATE_CHANGE_ASYNC:
522        LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
523            gst_element_state_get_name(state),
524            gst_element_state_get_name(pending));
525        // Change in progress
526        return;
527    case GST_STATE_CHANGE_FAILURE:
528        LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
529            gst_element_state_get_name(state),
530            gst_element_state_get_name(pending));
531        // Change failed
532        return;
533    case GST_STATE_CHANGE_NO_PREROLL:
534        LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
535            gst_element_state_get_name(state),
536            gst_element_state_get_name(pending));
537
538        if (state == GST_STATE_READY)
539            m_readyState = MediaPlayer::HaveNothing;
540        else if (state == GST_STATE_PAUSED)
541            m_readyState = MediaPlayer::HaveCurrentData;
542
543        m_networkState = MediaPlayer::Loading;
544        break;
545    default:
546        LOG_VERBOSE(Media, "Else : %d", ret);
547        break;
548    }
549
550    if (seeking())
551        m_readyState = MediaPlayer::HaveNothing;
552
553    if (shouldUpdateAfterSeek)
554        timeChanged();
555
556    if (m_networkState != oldNetworkState) {
557        LOG_VERBOSE(Media, "Network State Changed from %u to %u",
558            oldNetworkState, m_networkState);
559        m_player->networkStateChanged();
560    }
561    if (m_readyState != oldReadyState) {
562        LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
563            oldReadyState, m_readyState);
564        m_player->readyStateChanged();
565    }
566}
567
568void MediaPlayerPrivate::loadStateChanged()
569{
570    updateStates();
571}
572
573void MediaPlayerPrivate::rateChanged()
574{
575    updateStates();
576}
577
578void MediaPlayerPrivate::sizeChanged()
579{
580    notImplemented();
581}
582
583void MediaPlayerPrivate::timeChanged()
584{
585    updateStates();
586    m_player->timeChanged();
587}
588
589void MediaPlayerPrivate::volumeChanged()
590{
591    m_player->volumeChanged();
592}
593
594void MediaPlayerPrivate::didEnd()
595{
596    timeChanged();
597}
598
599void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error)
600{
601    m_errorOccured = true;
602    if (m_networkState != error) {
603        m_networkState = error;
604        m_player->networkStateChanged();
605    }
606    if (m_readyState != MediaPlayer::HaveNothing) {
607        m_readyState = MediaPlayer::HaveNothing;
608        m_player->readyStateChanged();
609    }
610}
611
612void MediaPlayerPrivate::setSize(const IntSize& size)
613{
614    m_size = size;
615}
616
617void MediaPlayerPrivate::setVisible(bool visible)
618{
619}
620
621void MediaPlayerPrivate::repaint()
622{
623    m_player->repaint();
624}
625
626void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
627{
628    if (context->paintingDisabled())
629        return;
630
631    if (!m_player->visible())
632        return;
633    if (!m_buffer)
634        return;
635
636    int width = 0, height = 0;
637    int pixelAspectRatioNumerator = 0;
638    int pixelAspectRatioDenominator = 0;
639    double doublePixelAspectRatioNumerator = 0;
640    double doublePixelAspectRatioDenominator = 0;
641    double displayWidth;
642    double displayHeight;
643    double scale, gapHeight, gapWidth;
644    GstVideoFormat format;
645
646    GstCaps *caps = gst_buffer_get_caps(m_buffer);
647
648    if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height) ||
649        !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator))) {
650      gst_caps_unref(caps);
651      return;
652    }
653
654    displayWidth = width;
655    displayHeight = height;
656    doublePixelAspectRatioNumerator = pixelAspectRatioNumerator;
657    doublePixelAspectRatioDenominator = pixelAspectRatioDenominator;
658
659    cairo_format_t cairoFormat;
660    if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA)
661        cairoFormat = CAIRO_FORMAT_ARGB32;
662    else
663        cairoFormat = CAIRO_FORMAT_RGB24;
664
665    cairo_t* cr = context->platformContext();
666    cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer),
667                                                               cairoFormat,
668                                                               width, height,
669                                                               4 * width);
670
671    cairo_save(cr);
672    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
673
674    // Calculate the display width/height from the storage width/height and the pixel aspect ratio
675    displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator;
676    displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator;
677
678    // Calculate the largest scale factor that would fill the target surface
679    scale = MIN(rect.width() / displayWidth, rect.height() / displayHeight);
680    // And calculate the new display width/height
681    displayWidth *= scale;
682    displayHeight *= scale;
683
684    // Calculate gap between border an picture on every side
685    gapWidth = (rect.width() - displayWidth) / 2.0;
686    gapHeight = (rect.height() - displayHeight) / 2.0;
687
688    // Paint the rectangle on the context and draw the buffer inside the rectangle
689
690    // Go to the new origin and center the video frame.
691    cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight);
692    cairo_rectangle(cr, 0, 0, rect.width(), rect.height());
693    // Scale the video frame according to the pixel aspect ratio.
694    cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator,
695                doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator);
696    // Scale the video frame to fill the target surface as good as possible.
697    cairo_scale(cr, scale, scale);
698    // And paint it.
699    cairo_set_source_surface(cr, src, 0, 0);
700    cairo_fill(cr);
701    cairo_restore(cr);
702
703    cairo_surface_destroy(src);
704    gst_caps_unref(caps);
705}
706
707static HashSet<String> mimeTypeCache()
708{
709
710    do_gst_init();
711
712    static HashSet<String> cache;
713    static bool typeListInitialized = false;
714
715    if (!typeListInitialized) {
716        // These subtypes are already beeing supported by WebKit itself
717        HashSet<String> ignoredApplicationSubtypes;
718        ignoredApplicationSubtypes.add(String("javascript"));
719        ignoredApplicationSubtypes.add(String("ecmascript"));
720        ignoredApplicationSubtypes.add(String("x-javascript"));
721        ignoredApplicationSubtypes.add(String("xml"));
722        ignoredApplicationSubtypes.add(String("xhtml+xml"));
723        ignoredApplicationSubtypes.add(String("rss+xml"));
724        ignoredApplicationSubtypes.add(String("atom+xml"));
725        ignoredApplicationSubtypes.add(String("x-ftp-directory"));
726        ignoredApplicationSubtypes.add(String("x-java-applet"));
727        ignoredApplicationSubtypes.add(String("x-java-bean"));
728        ignoredApplicationSubtypes.add(String("x-java-vm"));
729        ignoredApplicationSubtypes.add(String("x-shockwave-flash"));
730
731        GList* factories = gst_type_find_factory_get_list();
732        for (GList* iterator = factories; iterator; iterator = iterator->next) {
733            GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data);
734            GstCaps* caps = gst_type_find_factory_get_caps(factory);
735
736            // Splitting the capability by comma and taking the first part
737            // as capability can be something like "audio/x-wavpack, framed=(boolean)false"
738            GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps));
739            gchar** capability = g_strsplit(capabilityString.get(), ",", 2);
740            gchar** mimetype = g_strsplit(capability[0], "/", 2);
741
742            // GStreamer plugins can be capable of supporting types which WebKit supports
743            // by default. In that case, we should not consider these types supportable by GStreamer.
744            // Examples of what GStreamer can support but should not be added:
745            // text/plain, text/html, image/jpeg, application/xml
746            if (g_str_equal(mimetype[0], "audio") ||
747                    g_str_equal(mimetype[0], "video") ||
748                    (g_str_equal(mimetype[0], "application") &&
749                        !ignoredApplicationSubtypes.contains(String(mimetype[1])))) {
750                cache.add(String(capability[0]));
751
752                // These formats are supported by GStreamer, but not correctly advertised
753                if (g_str_equal(capability[0], "video/x-h264") ||
754                    g_str_equal(capability[0], "audio/x-m4a")) {
755                    cache.add(String("video/mp4"));
756                    cache.add(String("audio/aac"));
757                }
758
759                if (g_str_equal(capability[0], "video/x-theora"))
760                    cache.add(String("video/ogg"));
761
762                if (g_str_equal(capability[0], "audio/x-wav"))
763                    cache.add(String("audio/wav"));
764
765                if (g_str_equal(capability[0], "audio/mpeg")) {
766                    // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ]
767                    gchar** versionAndLayer = g_strsplit(capability[1], ",", 2);
768
769                    if (g_str_has_suffix (versionAndLayer[0], "(int)1")) {
770                        for (int i = 0; versionAndLayer[1][i] != '\0'; i++) {
771                            if (versionAndLayer[1][i] == '1')
772                                cache.add(String("audio/mp1"));
773                            else if (versionAndLayer[1][i] == '2')
774                                cache.add(String("audio/mp2"));
775                            else if (versionAndLayer[1][i] == '3')
776                                cache.add(String("audio/mp3"));
777                        }
778                    }
779
780                    g_strfreev(versionAndLayer);
781                }
782            }
783
784            g_strfreev(capability);
785            g_strfreev(mimetype);
786        }
787
788        gst_plugin_feature_list_free(factories);
789        typeListInitialized = true;
790    }
791
792    return cache;
793}
794
795void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
796{
797    types = mimeTypeCache();
798}
799
800MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
801{
802    if (type.isNull() || type.isEmpty())
803        return MediaPlayer::IsNotSupported;
804
805    // spec says we should not return "probably" if the codecs string is empty
806    if (mimeTypeCache().contains(type))
807        return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
808    return MediaPlayer::IsNotSupported;
809}
810
811bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
812{
813    return true;
814}
815
816bool MediaPlayerPrivate::supportsFullscreen() const
817{
818    return true;
819}
820
821void MediaPlayerPrivate::createGSTPlayBin(String url)
822{
823    ASSERT(!m_playBin);
824    m_playBin = gst_element_factory_make("playbin2", "play");
825
826    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
827    gst_bus_add_signal_watch(bus);
828    g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
829    gst_object_unref(bus);
830
831    g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(),
832        "volume", static_cast<double>(m_player->volume()), NULL);
833
834    m_videoSink = webkit_video_sink_new();
835
836    g_object_ref_sink(m_videoSink);
837    g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
838
839    g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
840}
841
842}
843
844#endif
Note: See TracBrowser for help on using the browser.