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