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