changing media role to browser and moving resource allocation before building the...
[profile/ivi/webkit-efl.git] / Source / WebCore / platform / graphics / gstreamer / 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  * Copyright (C) 2009, 2010 Igalia S.L
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * aint with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25 #include "MediaPlayerPrivateGStreamer.h"
26
27 #if ENABLE(VIDEO) && USE(GSTREAMER)
28
29 #include "ColorSpace.h"
30 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
31 #include "CookieJar.h"
32 #endif
33 #include "Document.h"
34 #include "Frame.h"
35 #include "FrameView.h"
36 #include "GStreamerGWorld.h"
37 #include "GStreamerUtilities.h"
38 #include "GStreamerVersioning.h"
39 #include "GraphicsContext.h"
40 #include "GraphicsTypes.h"
41 #if ENABLE(TIZEN_MEDIA_STREAM)
42 #include "HTMLMediaElement.h"
43 #endif
44 #include "ImageGStreamer.h"
45 #include "ImageOrientation.h"
46 #include "IntRect.h"
47 #include "KURL.h"
48 #include "MIMETypeRegistry.h"
49 #include "MediaPlayer.h"
50 #include "NotImplemented.h"
51 #include "SecurityOrigin.h"
52 #include "TimeRanges.h"
53 #include "VideoSinkGStreamer.h"
54 #include "WebKitWebSourceGStreamer.h"
55 #include <gst/gst.h>
56 #include <gst/video/video.h>
57 #include <limits>
58 #include <math.h>
59 #include <wtf/gobject/GOwnPtr.h>
60 #include <wtf/text/CString.h>
61
62 #ifdef GST_API_VERSION_1
63 #include <gst/audio/streamvolume.h>
64 #else
65 #include <gst/interfaces/streamvolume.h>
66 #endif
67
68 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
69 #include "Page.h"
70 #include "Settings.h"
71 #include "VideoLayerTizen.h"
72 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
73
74 #if ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
75 #include "URIUtils.h"
76 #endif // ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
77
78 #if ENABLE(TIZEN_MEDIA_STREAM)
79 #include "WebKitCameraSourceGStreamer.h"
80 #endif // ENABLE(TIZEN_MEDIA_STREAM)
81
82 // GstPlayFlags flags from playbin2. It is the policy of GStreamer to
83 // not publicly expose element-specific enums. That's why this
84 // GstPlayFlags enum has been copied here.
85 typedef enum {
86     GST_PLAY_FLAG_VIDEO         = 0x00000001,
87     GST_PLAY_FLAG_AUDIO         = 0x00000002,
88     GST_PLAY_FLAG_TEXT          = 0x00000004,
89     GST_PLAY_FLAG_VIS           = 0x00000008,
90     GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
91     GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
92     GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
93     GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
94     GST_PLAY_FLAG_BUFFERING     = 0x000000100
95 } GstPlayFlags;
96
97 #ifdef GST_API_VERSION_1
98 static const char* gPlaybinName = "playbin";
99 #else
100 static const char* gPlaybinName = "playbin2";
101 #endif
102
103 using namespace std;
104
105 namespace WebCore {
106
107 static int greatestCommonDivisor(int a, int b)
108 {
109     while (b) {
110         int temp = a;
111         a = b;
112         b = temp % b;
113     }
114
115     return ABS(a);
116 }
117
118 static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
119 {
120     return player->handleMessage(message);
121 }
122
123 static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
124 {
125     player->sourceChanged();
126 }
127
128 static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
129 {
130     // This is called when playbin receives the notify::volume signal.
131     player->volumeChanged();
132 }
133
134 static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
135 {
136     // This is the callback of the timeout source created in ::volumeChanged.
137     player->notifyPlayerOfVolumeChange();
138     return FALSE;
139 }
140
141 static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
142 {
143     // This is called when playbin receives the notify::mute signal.
144     player->muteChanged();
145 }
146
147 static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
148 {
149     // This is the callback of the timeout source created in ::muteChanged.
150     player->notifyPlayerOfMute();
151     return FALSE;
152 }
153
154 static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
155 {
156     player->videoChanged();
157 }
158
159 static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
160 {
161     player->videoChanged();
162 }
163
164 static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
165 {
166     player->audioChanged();
167 }
168
169 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
170 static void mediaPlayerPrivateSourceSetupCallback(GObject*, GstElement* source, MediaPlayerPrivateGStreamer* player)
171 {
172     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(player->player()->mediaPlayerClient());
173
174     // Grab the current document
175     Document* document = element->document();
176     if (!document)
177         document = element->ownerDocument();
178
179     // Grab the frame and network manager
180     Frame* frame = document ? document->frame() : 0;
181     FrameLoader* frameLoader = frame ? frame->loader() : 0;
182
183     String cookie = cookies(document, player->url());
184     GstStructure* headers = gst_structure_new("extra-headers", "Cookie", G_TYPE_STRING, cookie.utf8().data(), NULL);
185     g_object_set(source, "extra-headers", headers, NULL);
186     gst_structure_free(headers);
187
188 #if ENABLE(TIZEN_WEBKIT2_PROXY)
189     player->setProxy(source);
190 #endif
191
192     if (frameLoader)
193         g_object_set(source, "user-agent", frameLoader->userAgent(player->url()).utf8().data(), NULL);
194 }
195 #endif
196
197 static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
198 {
199     // This is the callback of the timeout source created in ::audioChanged.
200     player->notifyPlayerOfAudio();
201     return FALSE;
202 }
203
204 static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
205 {
206     // This is the callback of the timeout source created in ::videoChanged.
207     player->notifyPlayerOfVideo();
208     return FALSE;
209 }
210
211 static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate)
212 {
213     playerPrivate->triggerRepaint(buffer);
214 }
215
216 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
217 static GstBusSyncReply mediaPlayerPrivateSyncHandler(GstBus* bus, GstMessage* message, MediaPlayerPrivateGStreamer* playerPrivate)
218 {
219     // ignore anything but 'prepare-xid' message
220     if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT)
221         return GST_BUS_PASS;
222     if (!gst_structure_has_name (message->structure, "prepare-xid"))
223         return GST_BUS_PASS;
224
225     playerPrivate->xWindowIdPrepared(message);
226     return GST_BUS_DROP;
227 }
228 #endif
229
230 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
231 static ASM_cb_result_t MediaPlayerAudioSessionEventSourcePause(ASM_event_sources_t eventSource, void* callbackData)
232 {
233     MediaPlayer* player = static_cast<MediaPlayer*>(callbackData);
234     if (!player)
235         return ASM_CB_RES_IGNORE;
236
237     switch (eventSource) {
238     case ASM_EVENT_SOURCE_CALL_START:
239     case ASM_EVENT_SOURCE_ALARM_START:
240     case ASM_EVENT_SOURCE_EARJACK_UNPLUG:
241     case ASM_EVENT_SOURCE_MEDIA:
242     case ASM_EVENT_SOURCE_EMERGENCY_START:
243     case ASM_EVENT_SOURCE_OTHER_PLAYER_APP:
244     case ASM_EVENT_SOURCE_RESOURCE_CONFLICT:
245         player->pause();
246
247         return ASM_CB_RES_PAUSE;
248     default:
249         return ASM_CB_RES_NONE;
250     }
251 }
252
253 static ASM_cb_result_t MediaPlayerAudioSessionEventSourcePlay(ASM_event_sources_t eventSource, void* callbackData)
254 {
255     MediaPlayer* player = static_cast<MediaPlayer*>(callbackData);
256     if (!player)
257         return ASM_CB_RES_IGNORE;
258
259     switch (eventSource) {
260     case ASM_EVENT_SOURCE_ALARM_END:
261         if (!player->hasVideo()) {
262             player->play();
263             return ASM_CB_RES_PLAYING;
264         } else
265         return ASM_CB_RES_NONE;
266     default:
267         return ASM_CB_RES_NONE;
268     }
269 }
270
271 static ASM_cb_result_t mediaPlayerPrivateAudioSessionNotifyCallback(int, ASM_event_sources_t eventSource, ASM_sound_commands_t command, unsigned int, void* callbackData)
272 {
273     if (command == ASM_COMMAND_STOP || command == ASM_COMMAND_PAUSE)
274         return MediaPlayerAudioSessionEventSourcePause(eventSource, callbackData);
275     if (command == ASM_COMMAND_PLAY || command == ASM_COMMAND_RESUME)
276         return MediaPlayerAudioSessionEventSourcePlay(eventSource, callbackData);
277
278     return ASM_CB_RES_NONE;
279 }
280 #endif
281
282 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateGStreamer::create(MediaPlayer* player)
283 {
284     return adoptPtr(new MediaPlayerPrivateGStreamer(player));
285 }
286
287 void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar)
288 {
289     if (isAvailable())
290         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
291 }
292
293 bool initializeGStreamerAndRegisterWebKitElements()
294 {
295     if (!initializeGStreamer())
296         return false;
297
298     GRefPtr<GstElementFactory> srcFactory = gst_element_factory_find("webkitwebsrc");
299     if (!srcFactory)
300 #if ENABLE(TIZEN_MEDIA_STREAM)
301         return gst_element_register(0, "webkitcamerasrc", GST_RANK_PRIMARY + 200, WEBKIT_TYPE_CAMERA_SRC);
302 #else
303         return gst_element_register(0, "webkitwebsrc", GST_RANK_PRIMARY + 100, WEBKIT_TYPE_WEB_SRC);
304 #endif // ENABLE(TIZEN_MEDIA_STREAM)
305
306     return true;
307 }
308
309 bool MediaPlayerPrivateGStreamer::isAvailable()
310 {
311     if (!initializeGStreamerAndRegisterWebKitElements())
312         return false;
313
314     GRefPtr<GstElementFactory> factory = gst_element_factory_find(gPlaybinName);
315     return factory;
316 }
317
318 MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
319     : m_player(player)
320     , m_playBin(0)
321     , m_webkitVideoSink(0)
322     , m_fpsSink(0)
323     , m_source(0)
324     , m_seekTime(0)
325     , m_changingRate(false)
326     , m_endTime(numeric_limits<float>::infinity())
327     , m_isEndReached(false)
328     , m_networkState(MediaPlayer::Empty)
329     , m_readyState(MediaPlayer::HaveNothing)
330     , m_isStreaming(false)
331     , m_size(IntSize())
332     , m_buffer(0)
333     , m_mediaLocations(0)
334     , m_mediaLocationCurrentIndex(0)
335     , m_resetPipeline(false)
336     , m_paused(true)
337     , m_seeking(false)
338     , m_buffering(false)
339     , m_playbackRate(1)
340     , m_errorOccured(false)
341     , m_mediaDuration(0)
342     , m_startedBuffering(false)
343     , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired)
344     , m_maxTimeLoaded(0)
345     , m_bufferingPercentage(0)
346     , m_preload(MediaPlayer::Auto)
347     , m_delayingLoad(false)
348     , m_mediaDurationKnown(true)
349     , m_maxTimeLoadedAtLastDidLoadingProgress(0)
350     , m_volumeTimerHandler(0)
351     , m_muteTimerHandler(0)
352     , m_hasVideo(false)
353     , m_hasAudio(false)
354     , m_audioTimerHandler(0)
355     , m_videoTimerHandler(0)
356     , m_webkitAudioSink(0)
357 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
358     , m_videoLayer(VideoLayerTizen::create(static_cast<HTMLMediaElement*>(player->mediaPlayerClient())))
359 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
360 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
361     , m_audioSessionManager(AudioSessionManagerGStreamerTizen::createAudioSessionManager())
362 #endif
363 {
364     if (initializeGStreamerAndRegisterWebKitElements())
365         createGSTPlayBin();
366 }
367
368 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
369 {
370     if (m_fillTimer.isActive())
371         m_fillTimer.stop();
372
373     if (m_buffer)
374         gst_buffer_unref(m_buffer);
375     m_buffer = 0;
376
377     if (m_mediaLocations) {
378         gst_structure_free(m_mediaLocations);
379         m_mediaLocations = 0;
380     }
381
382 #ifndef GST_API_VERSION_1
383     if (m_videoSinkBin) {
384         gst_object_unref(m_videoSinkBin);
385         m_videoSinkBin = 0;
386     }
387 #endif
388
389     if (m_playBin) {
390         gst_element_set_state(m_playBin, GST_STATE_NULL);
391         gst_object_unref(GST_OBJECT(m_playBin));
392         m_playBin = 0;
393     }
394
395 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
396     if (m_audioSessionManager)
397         m_audioSessionManager->setSoundState(ASM_STATE_STOP);
398 #endif
399
400     m_player = 0;
401
402     if (m_muteTimerHandler)
403         g_source_remove(m_muteTimerHandler);
404
405     if (m_volumeTimerHandler)
406         g_source_remove(m_volumeTimerHandler);
407
408     if (m_videoTimerHandler)
409         g_source_remove(m_videoTimerHandler);
410
411     if (m_audioTimerHandler)
412         g_source_remove(m_audioTimerHandler);
413 }
414
415 void MediaPlayerPrivateGStreamer::load(const String& url)
416 {
417 #if ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
418     crackURI(url);
419 #endif // ENABLE(TIZEN_MEDIA_STREAM) || ENABLE(TIZEN_FILE_SYSTEM)
420     KURL kurl(KURL(), url);
421     String cleanUrl(url);
422
423     // Clean out everything after file:// url path.
424     if (kurl.isLocalFile())
425         cleanUrl = cleanUrl.substring(0, kurl.pathEnd());
426
427     m_url = KURL(KURL(), cleanUrl);
428     g_object_set(m_playBin, "uri", cleanUrl.utf8().data(), NULL);
429
430     LOG_VERBOSE(Media, "Load %s", cleanUrl.utf8().data());
431
432     if (m_preload == MediaPlayer::None) {
433         LOG_VERBOSE(Media, "Delaying load.");
434         m_delayingLoad = true;
435     }
436
437     // GStreamer needs to have the pipeline set to a paused state to
438     // start providing anything useful.
439     gst_element_set_state(m_playBin, GST_STATE_PAUSED);
440
441 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
442     if (m_audioSessionManager)
443         m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
444 #endif
445
446     if (!m_delayingLoad)
447         commitLoad();
448 }
449
450 void MediaPlayerPrivateGStreamer::commitLoad()
451 {
452     ASSERT(!m_delayingLoad);
453     LOG_VERBOSE(Media, "Committing load.");
454     updateStates();
455 }
456
457 float MediaPlayerPrivateGStreamer::playbackPosition() const
458 {
459     if (m_isEndReached) {
460         // Position queries on a null pipeline return 0. If we're at
461         // the end of the stream the pipeline is null but we want to
462         // report either the seek time or the duration because this is
463         // what the Media element spec expects us to do.
464         if (m_seeking)
465             return m_seekTime;
466         if (m_mediaDuration)
467             return m_mediaDuration;
468     }
469
470     float ret = 0.0f;
471
472     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
473     if (!gst_element_query(m_playBin, query)) {
474         LOG_VERBOSE(Media, "Position query failed...");
475         gst_query_unref(query);
476         return ret;
477     }
478
479     gint64 position;
480     gst_query_parse_position(query, 0, &position);
481
482     // Position is available only if the pipeline is not in GST_STATE_NULL or
483     // GST_STATE_READY state.
484     if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
485         ret = static_cast<double>(position) / GST_SECOND;
486
487     LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
488
489     gst_query_unref(query);
490
491     return ret;
492 }
493
494 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
495 {
496     ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
497
498     GstState currentState;
499     GstState pending;
500
501     gst_element_get_state(m_playBin, &currentState, &pending, 0);
502     LOG_VERBOSE(Media, "Current state: %s, pending: %s", gst_element_state_get_name(currentState), gst_element_state_get_name(pending));
503     if (currentState == newState || pending == newState)
504         return true;
505
506     GstStateChangeReturn setStateResult = gst_element_set_state(m_playBin, newState);
507     GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
508     if (currentState != pausedOrPlaying && setStateResult == GST_STATE_CHANGE_FAILURE) {
509         loadingFailed(MediaPlayer::Empty);
510         return false;
511     }
512     return true;
513 }
514
515 void MediaPlayerPrivateGStreamer::prepareToPlay()
516 {
517     m_isEndReached = false;
518     m_seeking = false;
519
520     if (m_delayingLoad) {
521         m_delayingLoad = false;
522         commitLoad();
523     }
524 }
525
526 void MediaPlayerPrivateGStreamer::play()
527 {
528 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
529     if (m_audioSessionManager && !m_audioSessionManager->setSoundState(ASM_STATE_PLAYING))
530         return;
531
532     if (m_playBin == NULL) {
533         m_player_deferred_state = 1; // play
534         return;
535     }
536 #endif
537     if (changePipelineState(GST_STATE_PLAYING)) {
538         m_isEndReached = false;
539         LOG_VERBOSE(Media, "Play");
540     }
541 }
542
543 void MediaPlayerPrivateGStreamer::pause()
544 {
545 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
546     if (m_audioSessionManager && !m_audioSessionManager->setSoundState(ASM_STATE_PAUSE))
547         return;
548
549     if (m_playBin == NULL) {
550         m_player_deferred_state = 0; // pause
551         return;
552     }
553 #endif
554     if (m_isEndReached)
555         return;
556
557     if (changePipelineState(GST_STATE_PAUSED))
558         LOG_VERBOSE(Media, "Pause");
559 }
560
561 float MediaPlayerPrivateGStreamer::duration() const
562 {
563     if (!m_playBin)
564         return 0.0f;
565
566     if (m_errorOccured)
567         return 0.0f;
568
569     // Media duration query failed already, don't attempt new useless queries.
570     if (!m_mediaDurationKnown)
571         return numeric_limits<float>::infinity();
572
573     if (m_mediaDuration)
574         return m_mediaDuration;
575
576     GstFormat timeFormat = GST_FORMAT_TIME;
577     gint64 timeLength = 0;
578
579 #ifdef GST_API_VERSION_1
580     bool failure = !gst_element_query_duration(m_playBin, timeFormat, &timeLength) || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
581 #else
582     bool failure = !gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE;
583 #endif
584     if (failure) {
585         LOG_VERBOSE(Media, "Time duration query failed.");
586         return numeric_limits<float>::infinity();
587     }
588
589     LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
590
591     return static_cast<double>(timeLength) / GST_SECOND;
592     // FIXME: handle 3.14.9.5 properly
593 }
594
595 float MediaPlayerPrivateGStreamer::currentTime() const
596 {
597     if (!m_playBin)
598         return 0.0f;
599
600     if (m_errorOccured)
601         return 0.0f;
602
603     if (m_seeking)
604         return m_seekTime;
605
606     // Workaround for
607     // https://bugzilla.gnome.org/show_bug.cgi?id=639941 In GStreamer
608     // 0.10.35 basesink reports wrong duration in case of EOS and
609     // negative playback rate. There's no upstream accepted patch for
610     // this bug yet, hence this temporary workaround.
611     if (m_isEndReached && m_playbackRate < 0)
612         return 0.0f;
613
614     return playbackPosition();
615
616 }
617
618 void MediaPlayerPrivateGStreamer::seek(float time)
619 {
620     if (!m_playBin)
621         return;
622
623     if (m_errorOccured)
624         return;
625
626     LOG_VERBOSE(Media, "Seek attempt to %f secs", time);
627
628     // Avoid useless seeking.
629     if (time == currentTime())
630         return;
631
632     // Extract the integer part of the time (seconds) and the
633     // fractional part (microseconds). Attempt to round the
634     // microseconds so no floating point precision is lost and we can
635     // perform an accurate seek.
636     float seconds;
637     float microSeconds = modf(time, &seconds) * 1000000;
638     GTimeVal timeValue;
639     timeValue.tv_sec = static_cast<glong>(seconds);
640     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
641
642     GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
643     LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
644
645     if (!gst_element_seek(m_playBin, m_player->rate(),
646             GST_FORMAT_TIME,
647             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
648             GST_SEEK_TYPE_SET, clockTime,
649             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
650         LOG_VERBOSE(Media, "Seek to %f failed", time);
651     else {
652         m_seeking = true;
653         m_seekTime = time;
654     }
655 }
656
657 bool MediaPlayerPrivateGStreamer::paused() const
658 {
659     if (m_isEndReached) {
660         LOG_VERBOSE(Media, "Ignoring pause at EOS");
661         return true;
662     }
663
664     GstState state;
665     gst_element_get_state(m_playBin, &state, 0, 0);
666     return state == GST_STATE_PAUSED;
667 }
668
669 bool MediaPlayerPrivateGStreamer::seeking() const
670 {
671     return m_seeking;
672 }
673
674 // Returns the size of the video
675 IntSize MediaPlayerPrivateGStreamer::naturalSize() const
676 {
677     if (!hasVideo())
678         return IntSize();
679
680     if (!m_videoSize.isEmpty())
681         return m_videoSize;
682
683     GstCaps* caps = webkitGstGetPadCaps(m_videoSinkPad.get());
684     if (!caps)
685         return IntSize();
686
687
688     // TODO: handle possible clean aperture data. See
689     // https://bugzilla.gnome.org/show_bug.cgi?id=596571
690     // TODO: handle possible transformation matrix. See
691     // https://bugzilla.gnome.org/show_bug.cgi?id=596326
692
693     // Get the video PAR and original size, if this fails the
694     // video-sink has likely not yet negotiated its caps.
695     int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride;
696     IntSize originalSize;
697     GstVideoFormat format;
698     if (!getVideoSizeAndFormatFromCaps(caps, originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
699         return IntSize();
700
701     LOG_VERBOSE(Media, "Original video size: %dx%d", originalSize.width(), originalSize.height());
702     LOG_VERBOSE(Media, "Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
703
704     // Calculate DAR based on PAR and video size.
705     int displayWidth = originalSize.width() * pixelAspectRatioNumerator;
706     int displayHeight = originalSize.height() * pixelAspectRatioDenominator;
707
708     // Divide display width and height by their GCD to avoid possible overflows.
709     int displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
710     displayWidth /= displayAspectRatioGCD;
711     displayHeight /= displayAspectRatioGCD;
712
713     // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
714     guint64 width = 0, height = 0;
715     if (!(originalSize.height() % displayHeight)) {
716         LOG_VERBOSE(Media, "Keeping video original height");
717         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
718         height = static_cast<guint64>(originalSize.height());
719     } else if (!(originalSize.width() % displayWidth)) {
720         LOG_VERBOSE(Media, "Keeping video original width");
721         height = gst_util_uint64_scale_int(originalSize.width(), displayHeight, displayWidth);
722         width = static_cast<guint64>(originalSize.width());
723     } else {
724         LOG_VERBOSE(Media, "Approximating while keeping original video height");
725         width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight);
726         height = static_cast<guint64>(originalSize.height());
727     }
728
729     LOG_VERBOSE(Media, "Natural size: %" G_GUINT64_FORMAT "x%" G_GUINT64_FORMAT, width, height);
730     m_videoSize = IntSize(static_cast<int>(width), static_cast<int>(height));
731     return m_videoSize;
732 }
733
734 void MediaPlayerPrivateGStreamer::videoChanged()
735 {
736     if (m_videoTimerHandler)
737         g_source_remove(m_videoTimerHandler);
738     m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this);
739 }
740
741 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
742 {
743     m_videoTimerHandler = 0;
744
745     gint videoTracks = 0;
746     if (m_playBin)
747         g_object_get(m_playBin, "n-video", &videoTracks, NULL);
748
749     m_hasVideo = videoTracks > 0;
750
751 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
752     int width;
753     int height;
754     if (gst_video_get_size(m_videoSinkPad.get(), &width, &height)) {
755         IntSize size(width, height);
756         if (m_videoSize != size) {
757             m_videoSize = IntSize();
758             m_videoLayer->setOverlay(naturalSize());
759         }
760     }
761 #endif
762     m_videoSize = IntSize();
763
764     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
765 }
766
767 void MediaPlayerPrivateGStreamer::audioChanged()
768 {
769     if (m_audioTimerHandler)
770         g_source_remove(m_audioTimerHandler);
771     m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this);
772 }
773
774 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
775 {
776     m_audioTimerHandler = 0;
777
778     gint audioTracks = 0;
779     if (m_playBin)
780         g_object_get(m_playBin, "n-audio", &audioTracks, NULL);
781     m_hasAudio = audioTracks > 0;
782     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
783 }
784
785 void MediaPlayerPrivateGStreamer::setVolume(float volume)
786 {
787     if (!m_playBin)
788         return;
789
790     gst_stream_volume_set_volume(GST_STREAM_VOLUME(m_playBin), GST_STREAM_VOLUME_FORMAT_CUBIC,
791                                  static_cast<double>(volume));
792 }
793
794 void MediaPlayerPrivateGStreamer::notifyPlayerOfVolumeChange()
795 {
796     m_volumeTimerHandler = 0;
797
798     if (!m_player || !m_playBin)
799         return;
800     double volume;
801     volume = gst_stream_volume_get_volume(GST_STREAM_VOLUME(m_playBin), GST_STREAM_VOLUME_FORMAT_CUBIC);
802     // get_volume() can return values superior to 1.0 if the user
803     // applies software user gain via third party application (GNOME
804     // volume control for instance).
805     volume = CLAMP(volume, 0.0, 1.0);
806     m_player->volumeChanged(static_cast<float>(volume));
807 }
808
809 void MediaPlayerPrivateGStreamer::volumeChanged()
810 {
811     if (m_volumeTimerHandler)
812         g_source_remove(m_volumeTimerHandler);
813     m_volumeTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVolumeChangeTimeoutCallback), this);
814 }
815
816 void MediaPlayerPrivateGStreamer::setRate(float rate)
817 {
818     // Avoid useless playback rate update.
819     if (m_playbackRate == rate)
820         return;
821
822     GstState state;
823     GstState pending;
824
825     gst_element_get_state(m_playBin, &state, &pending, 0);
826     if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED)
827         || (pending == GST_STATE_PAUSED))
828         return;
829
830     if (m_isStreaming)
831         return;
832
833     m_playbackRate = rate;
834     m_changingRate = true;
835
836     if (!rate) {
837         gst_element_set_state(m_playBin, GST_STATE_PAUSED);
838
839 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
840         if (m_audioSessionManager)
841             m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
842 #endif
843         return;
844     }
845
846     float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND);
847     GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
848     gint64 start, end;
849     bool mute = false;
850
851     LOG_VERBOSE(Media, "Set Rate to %f", rate);
852     if (rate > 0) {
853         // Mute the sound if the playback rate is too extreme.
854         // TODO: in other cases we should perform pitch adjustments.
855         mute = (bool) (rate < 0.8 || rate > 2);
856         start = currentPosition;
857         end = GST_CLOCK_TIME_NONE;
858     } else {
859         start = 0;
860         mute = true;
861
862         // If we are at beginning of media, start from the end to
863         // avoid immediate EOS.
864         if (currentPosition <= 0)
865             end = static_cast<gint64>(duration() * GST_SECOND);
866         else
867             end = currentPosition;
868     }
869
870     LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute);
871
872     if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags,
873                           GST_SEEK_TYPE_SET, start,
874                           GST_SEEK_TYPE_SET, end))
875         LOG_VERBOSE(Media, "Set rate to %f failed", rate);
876     else
877         g_object_set(m_playBin, "mute", mute, NULL);
878 }
879
880 MediaPlayer::NetworkState MediaPlayerPrivateGStreamer::networkState() const
881 {
882     return m_networkState;
883 }
884
885 MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const
886 {
887     return m_readyState;
888 }
889
890 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
891 {
892     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
893     if (m_errorOccured || m_isStreaming)
894         return timeRanges.release();
895
896 #if GST_CHECK_VERSION(0, 10, 31)
897     float mediaDuration(duration());
898     if (!mediaDuration || isinf(mediaDuration))
899         return timeRanges.release();
900
901     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
902
903     if (!gst_element_query(m_playBin, query)) {
904         gst_query_unref(query);
905         return timeRanges.release();
906     }
907
908     gint64 rangeStart = 0, rangeStop = 0;
909     for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
910         if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
911             timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100),
912                             static_cast<float>((rangeStop * mediaDuration) / 100));
913     }
914
915     // Fallback to the more general maxTimeLoaded() if no range has
916     // been found.
917     if (!timeRanges->length())
918         if (float loaded = maxTimeLoaded())
919             timeRanges->add(0, loaded);
920
921     gst_query_unref(query);
922 #else
923     float loaded = maxTimeLoaded();
924     if (!m_errorOccured && !m_isStreaming && loaded > 0)
925         timeRanges->add(0, loaded);
926 #endif
927     return timeRanges.release();
928 }
929
930 gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
931 {
932     GOwnPtr<GError> err;
933     GOwnPtr<gchar> debug;
934     MediaPlayer::NetworkState error;
935     bool issueError = true;
936     bool attemptNextLocation = false;
937     const GstStructure* structure = gst_message_get_structure(message);
938
939     if (structure) {
940         const gchar* messageTypeName = gst_structure_get_name(structure);
941
942         // Redirect messages are sent from elements, like qtdemux, to
943         // notify of the new location(s) of the media.
944         if (!g_strcmp0(messageTypeName, "redirect")) {
945             mediaLocationChanged(message);
946             return TRUE;
947         }
948     }
949
950     switch (GST_MESSAGE_TYPE(message)) {
951     case GST_MESSAGE_ERROR:
952         if (m_resetPipeline)
953             break;
954         gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
955         LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
956
957         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin), GST_DEBUG_GRAPH_SHOW_ALL, "webkit-video.error");
958
959         error = MediaPlayer::Empty;
960         if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND
961             || err->code == GST_STREAM_ERROR_WRONG_TYPE
962             || err->code == GST_STREAM_ERROR_FAILED
963             || err->code == GST_CORE_ERROR_MISSING_PLUGIN
964             || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
965             error = MediaPlayer::FormatError;
966         else if (err->domain == GST_STREAM_ERROR) {
967             // Let the mediaPlayerClient handle the stream error, in
968             // this case the HTMLMediaElement will emit a stalled
969             // event.
970             if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) {
971                 LOG_VERBOSE(Media, "Decode error, let the Media element emit a stalled event.");
972                 break;
973             }
974             error = MediaPlayer::DecodeError;
975             attemptNextLocation = true;
976         } else if (err->domain == GST_RESOURCE_ERROR)
977             error = MediaPlayer::NetworkError;
978
979         if (attemptNextLocation)
980             issueError = !loadNextLocation();
981         if (issueError)
982             loadingFailed(error);
983         break;
984     case GST_MESSAGE_EOS:
985         LOG_VERBOSE(Media, "End of Stream");
986         didEnd();
987         break;
988     case GST_MESSAGE_STATE_CHANGED:
989         // Ignore state changes if load is delayed (preload=none). The
990         // player state will be updated once commitLoad() is called.
991         if (m_delayingLoad) {
992             LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now");
993             break;
994         }
995
996         // Ignore state changes from internal elements. They are
997         // forwarded to playbin2 anyway.
998         if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin)) {
999             updateStates();
1000
1001             // Construct a filename for the graphviz dot file output.
1002             GstState oldState, newState;
1003             gst_message_parse_state_changed(message, &oldState, &newState, 0);
1004
1005             CString dotFileName = String::format("webkit-video.%s_%s",
1006                                                  gst_element_state_get_name(oldState),
1007                                                  gst_element_state_get_name(newState)).utf8();
1008
1009             GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
1010         }
1011         break;
1012     case GST_MESSAGE_BUFFERING:
1013         processBufferingStats(message);
1014         break;
1015     case GST_MESSAGE_DURATION:
1016         LOG_VERBOSE(Media, "Duration changed");
1017         durationChanged();
1018         break;
1019     default:
1020         LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
1021                     GST_MESSAGE_TYPE_NAME(message));
1022         break;
1023     }
1024     return TRUE;
1025 }
1026
1027 void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message)
1028 {
1029     // This is the immediate buffering that needs to happen so we have
1030     // enough to play right now.
1031     m_buffering = true;
1032     const GstStructure *structure = gst_message_get_structure(message);
1033     gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage);
1034
1035     LOG_VERBOSE(Media, "[Buffering] Buffering: %d%%.", m_bufferingPercentage);
1036
1037     GstBufferingMode mode;
1038     gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
1039     if (mode != GST_BUFFERING_DOWNLOAD) {
1040         updateStates();
1041         return;
1042     }
1043
1044     // This is on-disk buffering, that allows us to download much more
1045     // than needed for right now.
1046     if (!m_startedBuffering) {
1047         LOG_VERBOSE(Media, "[Buffering] Starting on-disk buffering.");
1048
1049         m_startedBuffering = true;
1050
1051         if (m_fillTimer.isActive())
1052             m_fillTimer.stop();
1053
1054         m_fillTimer.startRepeating(0.2);
1055     }
1056 }
1057
1058 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
1059 {
1060     GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1061
1062     if (!gst_element_query(m_playBin, query)) {
1063         gst_query_unref(query);
1064         return;
1065     }
1066
1067     gint64 start, stop;
1068     gdouble fillStatus = 100.0;
1069
1070     gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
1071     gst_query_unref(query);
1072
1073     if (stop != -1)
1074         fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
1075
1076     LOG_VERBOSE(Media, "[Buffering] Download buffer filled up to %f%%", fillStatus);
1077
1078     if (!m_mediaDuration)
1079         durationChanged();
1080
1081     // Update maxTimeLoaded only if the media duration is
1082     // available. Otherwise we can't compute it.
1083     if (m_mediaDuration) {
1084         if (fillStatus == 100.0)
1085             m_maxTimeLoaded = m_mediaDuration;
1086         else
1087             m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0);
1088         LOG_VERBOSE(Media, "[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded);
1089     }
1090
1091     if (fillStatus != 100.0) {
1092         updateStates();
1093         return;
1094     }
1095
1096     // Media is now fully loaded. It will play even if network
1097     // connection is cut. Buffering is done, remove the fill source
1098     // from the main loop.
1099     m_fillTimer.stop();
1100     m_startedBuffering = false;
1101     updateStates();
1102 }
1103
1104 float MediaPlayerPrivateGStreamer::maxTimeSeekable() const
1105 {
1106     if (m_errorOccured)
1107         return 0.0f;
1108
1109     LOG_VERBOSE(Media, "maxTimeSeekable");
1110     // infinite duration means live stream
1111     if (isinf(duration()))
1112         return 0.0f;
1113
1114     return duration();
1115 }
1116
1117 float MediaPlayerPrivateGStreamer::maxTimeLoaded() const
1118 {
1119     if (m_errorOccured)
1120         return 0.0f;
1121
1122     float loaded = m_maxTimeLoaded;
1123     if (!loaded && !m_fillTimer.isActive())
1124         loaded = duration();
1125     LOG_VERBOSE(Media, "maxTimeLoaded: %f", loaded);
1126     return loaded;
1127 }
1128
1129 bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
1130 {
1131     if (!m_playBin || !m_mediaDuration || !totalBytes())
1132         return false;
1133     float currentMaxTimeLoaded = maxTimeLoaded();
1134     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
1135     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
1136     LOG_VERBOSE(Media, "didLoadingProgress: %d", didLoadingProgress);
1137     return didLoadingProgress;
1138 }
1139
1140 unsigned MediaPlayerPrivateGStreamer::totalBytes() const
1141 {
1142     if (!m_source)
1143         return 0;
1144
1145     if (m_errorOccured)
1146         return 0;
1147
1148     GstFormat fmt = GST_FORMAT_BYTES;
1149     gint64 length = 0;
1150 #ifdef GST_API_VERSION_1
1151     if (gst_element_query_duration(m_source.get(), fmt, &length)) {
1152 #else
1153     if (gst_element_query_duration(m_source.get(), &fmt, &length)) {
1154 #endif
1155         LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
1156         return static_cast<unsigned>(length);
1157     }
1158
1159     // Fall back to querying the source pads manually.
1160     // See also https://bugzilla.gnome.org/show_bug.cgi?id=638749
1161     GstIterator* iter = gst_element_iterate_src_pads(m_source.get());
1162     bool done = false;
1163     while (!done) {
1164 #ifdef GST_API_VERSION_1
1165         GValue item = G_VALUE_INIT;
1166         switch (gst_iterator_next(iter, &item)) {
1167         case GST_ITERATOR_OK: {
1168             GstPad* pad = static_cast<GstPad*>(g_value_get_object(&item));
1169             gint64 padLength = 0;
1170             if (gst_pad_query_duration(pad, fmt, &padLength) && padLength > length)
1171                 length = padLength;
1172             break;
1173         }
1174 #else
1175         gpointer data;
1176
1177         switch (gst_iterator_next(iter, &data)) {
1178         case GST_ITERATOR_OK: {
1179             GRefPtr<GstPad> pad = adoptGRef(GST_PAD_CAST(data));
1180             gint64 padLength = 0;
1181             if (gst_pad_query_duration(pad.get(), &fmt, &padLength) && padLength > length)
1182                 length = padLength;
1183             break;
1184         }
1185 #endif
1186         case GST_ITERATOR_RESYNC:
1187             gst_iterator_resync(iter);
1188             break;
1189         case GST_ITERATOR_ERROR:
1190             // Fall through.
1191         case GST_ITERATOR_DONE:
1192             done = true;
1193             break;
1194         }
1195
1196 #ifdef GST_API_VERSION_1
1197         g_value_unset(&item);
1198 #endif
1199     }
1200
1201     gst_iterator_free(iter);
1202
1203     LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
1204
1205     return static_cast<unsigned>(length);
1206 }
1207
1208 unsigned MediaPlayerPrivateGStreamer::decodedFrameCount() const
1209 {
1210     guint64 decodedFrames = 0;
1211     if (m_fpsSink)
1212         g_object_get(m_fpsSink, "frames-rendered", &decodedFrames, NULL);
1213     return static_cast<unsigned>(decodedFrames);
1214 }
1215
1216 unsigned MediaPlayerPrivateGStreamer::droppedFrameCount() const
1217 {
1218     guint64 framesDropped = 0;
1219     if (m_fpsSink)
1220         g_object_get(m_fpsSink, "frames-dropped", &framesDropped, NULL);
1221     return static_cast<unsigned>(framesDropped);
1222 }
1223
1224 unsigned MediaPlayerPrivateGStreamer::audioDecodedByteCount() const
1225 {
1226     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1227     gint64 position = 0;
1228
1229     if (m_webkitAudioSink && gst_element_query(m_webkitAudioSink.get(), query))
1230         gst_query_parse_position(query, 0, &position);
1231
1232     gst_query_unref(query);
1233     return static_cast<unsigned>(position);
1234 }
1235
1236 unsigned MediaPlayerPrivateGStreamer::videoDecodedByteCount() const
1237 {
1238     GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES);
1239     gint64 position = 0;
1240
1241     if (gst_element_query(m_webkitVideoSink, query))
1242         gst_query_parse_position(query, 0, &position);
1243
1244     gst_query_unref(query);
1245     return static_cast<unsigned>(position);
1246 }
1247
1248 void MediaPlayerPrivateGStreamer::updateAudioSink()
1249 {
1250     if (!m_playBin)
1251         return;
1252
1253     GstElement* sinkPtr = 0;
1254
1255     g_object_get(m_playBin, "audio-sink", &sinkPtr, NULL);
1256     m_webkitAudioSink = adoptGRef(sinkPtr);
1257
1258 }
1259
1260
1261 void MediaPlayerPrivateGStreamer::sourceChanged()
1262 {
1263     GstElement* srcPtr = 0;
1264
1265     g_object_get(m_playBin, "source", &srcPtr, NULL);
1266     m_source = adoptGRef(srcPtr);
1267
1268     if (WEBKIT_IS_WEB_SRC(m_source.get()))
1269         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
1270 }
1271
1272 void MediaPlayerPrivateGStreamer::cancelLoad()
1273 {
1274     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
1275         return;
1276
1277     if (m_playBin)
1278         gst_element_set_state(m_playBin, GST_STATE_NULL);
1279
1280 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1281     if (m_audioSessionManager)
1282         m_audioSessionManager->setSoundState(ASM_STATE_STOP);
1283 #endif
1284 }
1285
1286 void MediaPlayerPrivateGStreamer::updateStates()
1287 {
1288     if (!m_playBin)
1289         return;
1290
1291     if (m_errorOccured)
1292         return;
1293
1294     MediaPlayer::NetworkState oldNetworkState = m_networkState;
1295     MediaPlayer::ReadyState oldReadyState = m_readyState;
1296     GstState state;
1297     GstState pending;
1298
1299     GstStateChangeReturn ret = gst_element_get_state(m_playBin,
1300         &state, &pending, 250 * GST_NSECOND);
1301
1302     bool shouldUpdateAfterSeek = false;
1303     switch (ret) {
1304     case GST_STATE_CHANGE_SUCCESS:
1305         LOG_VERBOSE(Media, "State: %s, pending: %s",
1306             gst_element_state_get_name(state),
1307             gst_element_state_get_name(pending));
1308
1309         m_resetPipeline = state <= GST_STATE_READY;
1310
1311         // Try to figure out ready and network states.
1312         if (state == GST_STATE_READY) {
1313             m_readyState = MediaPlayer::HaveMetadata;
1314             m_networkState = MediaPlayer::Empty;
1315             // Cache the duration without emiting the durationchange
1316             // event because it's taken care of by the media element
1317             // in this precise case.
1318             if (!m_isEndReached)
1319                 cacheDuration();
1320         } else if ((state == GST_STATE_NULL) || (maxTimeLoaded() == duration())) {
1321             m_networkState = MediaPlayer::Loaded;
1322             m_readyState = MediaPlayer::HaveEnoughData;
1323         } else {
1324             m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
1325             m_networkState = MediaPlayer::Loading;
1326         }
1327
1328         if (m_buffering && state != GST_STATE_READY) {
1329             m_readyState = MediaPlayer::HaveCurrentData;
1330             m_networkState = MediaPlayer::Loading;
1331         }
1332
1333         // Now let's try to get the states in more detail using
1334         // information from GStreamer, while we sync states where
1335         // needed.
1336         if (state == GST_STATE_PAUSED) {
1337             if (!m_webkitAudioSink)
1338                 updateAudioSink();
1339             if (m_buffering && m_bufferingPercentage == 100) {
1340                 m_buffering = false;
1341                 m_bufferingPercentage = 0;
1342                 m_readyState = MediaPlayer::HaveEnoughData;
1343
1344                 LOG_VERBOSE(Media, "[Buffering] Complete.");
1345
1346                 if (!m_paused) {
1347                     LOG_VERBOSE(Media, "[Buffering] Restarting playback.");
1348                     gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1349
1350 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1351                     if (m_audioSessionManager)
1352                         m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1353 #endif
1354                 }
1355             } else if (!m_buffering && (currentTime() < duration())) {
1356                 m_paused = true;
1357             }
1358         } else if (state == GST_STATE_PLAYING) {
1359             m_readyState = MediaPlayer::HaveEnoughData;
1360             m_paused = false;
1361
1362             if (m_buffering) {
1363                 m_readyState = MediaPlayer::HaveCurrentData;
1364                 m_networkState = MediaPlayer::Loading;
1365
1366                 LOG_VERBOSE(Media, "[Buffering] Pausing stream for buffering.");
1367
1368                 gst_element_set_state(m_playBin, GST_STATE_PAUSED);
1369
1370 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1371                 if (m_audioSessionManager)
1372                     m_audioSessionManager->setSoundState(ASM_STATE_PAUSE);
1373 #endif
1374             }
1375         } else
1376             m_paused = true;
1377
1378         // Is on-disk buffering in progress?
1379         if (m_fillTimer.isActive())
1380             m_networkState = MediaPlayer::Loading;
1381
1382         if (m_changingRate) {
1383             m_player->rateChanged();
1384             m_changingRate = false;
1385         }
1386
1387         if (m_seeking) {
1388             shouldUpdateAfterSeek = true;
1389             m_seeking = false;
1390         }
1391
1392         break;
1393     case GST_STATE_CHANGE_ASYNC:
1394         LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
1395             gst_element_state_get_name(state),
1396             gst_element_state_get_name(pending));
1397         // Change in progress
1398
1399         if (!m_isStreaming && !m_buffering)
1400             return;
1401
1402         if (m_seeking) {
1403             shouldUpdateAfterSeek = true;
1404             m_seeking = false;
1405         }
1406         break;
1407     case GST_STATE_CHANGE_FAILURE:
1408         LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
1409             gst_element_state_get_name(state),
1410             gst_element_state_get_name(pending));
1411         // Change failed
1412         return;
1413     case GST_STATE_CHANGE_NO_PREROLL:
1414         LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
1415             gst_element_state_get_name(state),
1416             gst_element_state_get_name(pending));
1417
1418         if (state == GST_STATE_READY)
1419             m_readyState = MediaPlayer::HaveNothing;
1420         else if (state == GST_STATE_PAUSED) {
1421             m_readyState = MediaPlayer::HaveEnoughData;
1422             m_paused = true;
1423             // Live pipelines go in PAUSED without prerolling.
1424             m_isStreaming = true;
1425         } else if (state == GST_STATE_PLAYING)
1426             m_paused = false;
1427
1428         if (m_seeking) {
1429             shouldUpdateAfterSeek = true;
1430             m_seeking = false;
1431             if (!m_paused) {
1432                 gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1433
1434 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1435                 if (m_audioSessionManager)
1436                     m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1437 #endif
1438             }
1439         } else if (!m_paused) {
1440             gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1441
1442 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1443             if (m_audioSessionManager)
1444                 m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1445 #endif
1446         }
1447
1448         m_networkState = MediaPlayer::Loading;
1449         break;
1450     default:
1451         LOG_VERBOSE(Media, "Else : %d", ret);
1452         break;
1453     }
1454
1455     if (seeking())
1456         m_readyState = MediaPlayer::HaveNothing;
1457
1458     if (shouldUpdateAfterSeek)
1459         timeChanged();
1460
1461     if (m_networkState != oldNetworkState) {
1462         LOG_VERBOSE(Media, "Network State Changed from %u to %u",
1463             oldNetworkState, m_networkState);
1464         m_player->networkStateChanged();
1465     }
1466     if (m_readyState != oldReadyState) {
1467         LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
1468             oldReadyState, m_readyState);
1469         m_player->readyStateChanged();
1470 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
1471         if (state == GST_STATE_PLAYING)
1472             m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
1473 #endif
1474     }
1475 }
1476
1477 void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
1478 {
1479     if (m_mediaLocations)
1480         gst_structure_free(m_mediaLocations);
1481
1482     const GstStructure* structure = gst_message_get_structure(message);
1483     if (structure) {
1484         // This structure can contain:
1485         // - both a new-location string and embedded locations structure
1486         // - or only a new-location string.
1487         m_mediaLocations = gst_structure_copy(structure);
1488         const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1489
1490         if (locations)
1491             m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1;
1492
1493         loadNextLocation();
1494     }
1495 }
1496
1497 bool MediaPlayerPrivateGStreamer::loadNextLocation()
1498 {
1499     if (!m_mediaLocations)
1500         return false;
1501
1502     const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
1503     const gchar* newLocation = 0;
1504
1505     if (!locations) {
1506         // Fallback on new-location string.
1507         newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
1508         if (!newLocation)
1509             return false;
1510     }
1511
1512     if (!newLocation) {
1513         if (m_mediaLocationCurrentIndex < 0) {
1514             m_mediaLocations = 0;
1515             return false;
1516         }
1517
1518         const GValue* location = gst_value_list_get_value(locations,
1519                                                           m_mediaLocationCurrentIndex);
1520         const GstStructure* structure = gst_value_get_structure(location);
1521
1522         if (!structure) {
1523             m_mediaLocationCurrentIndex--;
1524             return false;
1525         }
1526
1527         newLocation = gst_structure_get_string(structure, "new-location");
1528     }
1529
1530     if (newLocation) {
1531         // Found a candidate. new-location is not always an absolute url
1532         // though. We need to take the base of the current url and
1533         // append the value of new-location to it.
1534
1535         gchar* currentLocation = 0;
1536         g_object_get(m_playBin, "uri", &currentLocation, NULL);
1537
1538         KURL currentUrl(KURL(), currentLocation);
1539         g_free(currentLocation);
1540
1541         KURL newUrl;
1542
1543         if (gst_uri_is_valid(newLocation))
1544             newUrl = KURL(KURL(), newLocation);
1545         else
1546             newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
1547
1548         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
1549         if (securityOrigin->canRequest(newUrl)) {
1550             LOG_VERBOSE(Media, "New media url: %s", newUrl.string().utf8().data());
1551
1552             // Reset player states.
1553             m_networkState = MediaPlayer::Loading;
1554             m_player->networkStateChanged();
1555             m_readyState = MediaPlayer::HaveNothing;
1556             m_player->readyStateChanged();
1557
1558             // Reset pipeline state.
1559             m_resetPipeline = true;
1560             gst_element_set_state(m_playBin, GST_STATE_READY);
1561
1562 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1563             if (m_audioSessionManager)
1564                 m_audioSessionManager->setSoundState(ASM_STATE_NONE);
1565 #endif
1566             GstState state;
1567             gst_element_get_state(m_playBin, &state, 0, 0);
1568             if (state <= GST_STATE_READY) {
1569                 // Set the new uri and start playing.
1570                 g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
1571                 gst_element_set_state(m_playBin, GST_STATE_PLAYING);
1572
1573 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1574                 if (m_audioSessionManager)
1575                     m_audioSessionManager->setSoundState(ASM_STATE_PLAYING);
1576 #endif
1577                 return true;
1578             }
1579         }
1580     }
1581     m_mediaLocationCurrentIndex--;
1582     return false;
1583
1584 }
1585
1586 void MediaPlayerPrivateGStreamer::loadStateChanged()
1587 {
1588     updateStates();
1589 }
1590
1591 void MediaPlayerPrivateGStreamer::sizeChanged()
1592 {
1593     notImplemented();
1594 }
1595
1596 void MediaPlayerPrivateGStreamer::timeChanged()
1597 {
1598     updateStates();
1599     m_player->timeChanged();
1600 }
1601
1602 void MediaPlayerPrivateGStreamer::didEnd()
1603 {
1604     // Synchronize position and duration values to not confuse the
1605     // HTMLMediaElement. In some cases like reverse playback the
1606     // position is not always reported as 0 for instance.
1607     float now = currentTime();
1608     if (now > 0 && now <= duration() && m_mediaDuration != now) {
1609         m_mediaDurationKnown = true;
1610         m_mediaDuration = now;
1611         m_player->durationChanged();
1612     }
1613
1614     m_isEndReached = true;
1615     timeChanged();
1616
1617     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
1618         m_paused = true;
1619         gst_element_set_state(m_playBin, GST_STATE_NULL);
1620
1621 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1622         if (m_audioSessionManager)
1623             m_audioSessionManager->setSoundState(ASM_STATE_STOP);
1624 #endif
1625     }
1626 }
1627
1628 void MediaPlayerPrivateGStreamer::cacheDuration()
1629 {
1630     // Reset cached media duration
1631     m_mediaDuration = 0;
1632
1633     // And re-cache it if possible.
1634     GstState state;
1635     gst_element_get_state(m_playBin, &state, 0, 0);
1636     float newDuration = duration();
1637
1638     if (state <= GST_STATE_READY) {
1639         // Don't set m_mediaDurationKnown yet if the pipeline is not
1640         // paused. This allows duration() query to fail at least once
1641         // before playback starts and duration becomes known.
1642         if (!isinf(newDuration))
1643             m_mediaDuration = newDuration;
1644     } else {
1645         m_mediaDurationKnown = !isinf(newDuration);
1646         if (m_mediaDurationKnown)
1647             m_mediaDuration = newDuration;
1648     }
1649
1650     if (!isinf(newDuration))
1651         m_mediaDuration = newDuration;
1652 }
1653
1654 void MediaPlayerPrivateGStreamer::durationChanged()
1655 {
1656     float previousDuration = m_mediaDuration;
1657
1658     cacheDuration();
1659     // Avoid emiting durationchanged in the case where the previous
1660     // duration was 0 because that case is already handled by the
1661     // HTMLMediaElement.
1662     if (previousDuration && m_mediaDuration != previousDuration)
1663         m_player->durationChanged();
1664 }
1665
1666 bool MediaPlayerPrivateGStreamer::supportsMuting() const
1667 {
1668     return true;
1669 }
1670
1671 void MediaPlayerPrivateGStreamer::setMuted(bool muted)
1672 {
1673     if (!m_playBin)
1674         return;
1675
1676     g_object_set(m_playBin, "mute", muted, NULL);
1677 }
1678
1679 void MediaPlayerPrivateGStreamer::notifyPlayerOfMute()
1680 {
1681     m_muteTimerHandler = 0;
1682
1683     if (!m_player || !m_playBin)
1684         return;
1685
1686     gboolean muted;
1687     g_object_get(m_playBin, "mute", &muted, NULL);
1688     m_player->muteChanged(static_cast<bool>(muted));
1689 }
1690
1691 void MediaPlayerPrivateGStreamer::muteChanged()
1692 {
1693     if (m_muteTimerHandler)
1694         g_source_remove(m_muteTimerHandler);
1695     m_muteTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateMuteChangeTimeoutCallback), this);
1696 }
1697
1698 void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error)
1699 {
1700     m_errorOccured = true;
1701     if (m_networkState != error) {
1702         m_networkState = error;
1703         m_player->networkStateChanged();
1704     }
1705     if (m_readyState != MediaPlayer::HaveNothing) {
1706         m_readyState = MediaPlayer::HaveNothing;
1707         m_player->readyStateChanged();
1708     }
1709 }
1710
1711 void MediaPlayerPrivateGStreamer::setSize(const IntSize& size)
1712 {
1713     m_size = size;
1714 }
1715
1716 void MediaPlayerPrivateGStreamer::setVisible(bool visible)
1717 {
1718 }
1719
1720 void MediaPlayerPrivateGStreamer::triggerRepaint(GstBuffer* buffer)
1721 {
1722     g_return_if_fail(GST_IS_BUFFER(buffer));
1723     gst_buffer_replace(&m_buffer, buffer);
1724 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && !ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1725     if (m_videoSize.isEmpty())
1726         m_videoSize =  naturalSize();
1727     m_videoLayer->paintVideoLayer(m_videoSize);
1728 #else
1729     m_player->repaint();
1730 #endif
1731 }
1732
1733 void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& rect)
1734 {
1735     if (context->paintingDisabled())
1736         return;
1737
1738     if (!m_player->visible())
1739         return;
1740
1741     if (!m_buffer)
1742         return;
1743
1744     GstCaps* caps = webkitGstGetPadCaps(m_videoSinkPad.get());
1745     if (!caps)
1746         return;
1747
1748     RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps);
1749     if (!gstImage)
1750         return;
1751
1752     context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB,
1753                        rect, gstImage->rect(), CompositeCopy, DoNotRespectImageOrientation, false);
1754 }
1755
1756 static HashSet<String> mimeTypeCache()
1757 {
1758     initializeGStreamerAndRegisterWebKitElements();
1759
1760     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
1761     static bool typeListInitialized = false;
1762
1763     if (typeListInitialized)
1764         return cache;
1765     const char* mimeTypes[] = {"application/ogg",
1766                                "application/vnd.apple.mpegurl",
1767                                "application/vnd.rn-realmedia",
1768                                "application/x-3gp",
1769                                "application/x-pn-realaudio",
1770                                "audio/3gpp",
1771                                "audio/aac",
1772                                "audio/flac",
1773                                "audio/iLBC-sh",
1774                                "audio/midi",
1775                                "audio/mobile-xmf",
1776                                "audio/mp1",
1777                                "audio/mp2",
1778                                "audio/mp3",
1779                                "audio/mp4",
1780                                "audio/mpeg",
1781                                "audio/ogg",
1782                                "audio/qcelp",
1783                                "audio/riff-midi",
1784                                "audio/wav",
1785                                "audio/webm",
1786                                "audio/x-ac3",
1787                                "audio/x-aiff",
1788                                "audio/x-amr-nb-sh",
1789                                "audio/x-amr-wb-sh",
1790                                "audio/x-au",
1791                                "audio/x-ay",
1792                                "audio/x-celt",
1793                                "audio/x-dts",
1794                                "audio/x-flac",
1795                                "audio/x-gbs",
1796                                "audio/x-gsm",
1797                                "audio/x-gym",
1798                                "audio/x-imelody",
1799                                "audio/x-ircam",
1800                                "audio/x-kss",
1801                                "audio/x-m4a",
1802                                "audio/x-mod",
1803                                "audio/x-mp3",
1804                                "audio/x-mpeg",
1805                                "audio/x-musepack",
1806                                "audio/x-nist",
1807                                "audio/x-nsf",
1808                                "audio/x-paris",
1809                                "audio/x-sap",
1810                                "audio/x-sbc",
1811                                "audio/x-sds",
1812                                "audio/x-shorten",
1813                                "audio/x-sid",
1814                                "audio/x-spc",
1815                                "audio/x-speex",
1816                                "audio/x-svx",
1817                                "audio/x-ttafile",
1818                                "audio/x-vgm",
1819                                "audio/x-voc",
1820                                "audio/x-vorbis+ogg",
1821                                "audio/x-w64",
1822                                "audio/x-wav",
1823                                "audio/x-wavpack",
1824                                "audio/x-wavpack-correction",
1825                                "video/3gpp",
1826                                "video/mj2",
1827                                "video/mp4",
1828                                "video/mpeg",
1829                                "video/mpegts",
1830                                "video/ogg",
1831                                "video/quicktime",
1832                                "video/vivo",
1833                                "video/webm",
1834                                "video/x-cdxa",
1835                                "video/x-dirac",
1836                                "video/x-dv",
1837                                "video/x-fli",
1838                                "video/x-flv",
1839                                "video/x-h263",
1840                                "video/x-ivf",
1841                                "video/x-m4v",
1842                                "video/x-matroska",
1843                                "video/x-mng",
1844                                "video/x-ms-asf",
1845                                "video/x-msvideo",
1846                                "video/x-mve",
1847                                "video/x-nuv",
1848                                "video/x-vcd"};
1849
1850     for (unsigned i = 0; i < (sizeof(mimeTypes) / sizeof(*mimeTypes)); ++i)
1851         cache.add(String(mimeTypes[i]));
1852
1853     typeListInitialized = true;
1854     return cache;
1855 }
1856
1857 void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types)
1858 {
1859     types = mimeTypeCache();
1860 }
1861
1862 MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs, const KURL&)
1863 {
1864     if (type.isNull() || type.isEmpty())
1865         return MediaPlayer::IsNotSupported;
1866
1867     // spec says we should not return "probably" if the codecs string is empty
1868     if (mimeTypeCache().contains(type))
1869         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
1870     return MediaPlayer::IsNotSupported;
1871 }
1872
1873 bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const
1874 {
1875     return true;
1876 }
1877
1878 bool MediaPlayerPrivateGStreamer::supportsFullscreen() const
1879 {
1880 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
1881     // See <rdar://problem/7389945>
1882     return false;
1883 #else
1884     return true;
1885 #endif
1886 }
1887
1888 PlatformMedia MediaPlayerPrivateGStreamer::platformMedia() const
1889 {
1890     PlatformMedia p;
1891 #ifndef GST_API_VERSION_1
1892     p.type = PlatformMedia::GStreamerGWorldType;
1893     p.media.gstreamerGWorld = m_gstGWorld.get();
1894 #endif
1895     return p;
1896 }
1897
1898 void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload)
1899 {
1900     ASSERT(m_playBin);
1901
1902     m_preload = preload;
1903
1904     GstPlayFlags flags;
1905     g_object_get(m_playBin, "flags", &flags, NULL);
1906 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1907     flags = (GstPlayFlags)(flags | GST_PLAY_FLAG_NATIVE_VIDEO);
1908 #endif
1909     if (preload == MediaPlayer::None)
1910         g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
1911     else
1912         g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
1913
1914     if (m_delayingLoad && m_preload != MediaPlayer::None) {
1915         m_delayingLoad = false;
1916         commitLoad();
1917     }
1918 }
1919
1920 const char * MediaPlayerPrivateGStreamer::mediaClass() const
1921 {
1922     static const gchar *default_media_class = "browser";
1923
1924     return default_media_class;
1925 }
1926
1927 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
1928 {
1929     ASSERT(!m_playBin);
1930     const gchar *media_class = mediaClass();
1931     int asm_handle = 0;
1932
1933 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
1934     if (m_audioSessionManager) {
1935         m_playBin = NULL;
1936         m_player_deferred_state = -1; // ignore
1937         m_audioSessionManager->registerAudioSessionManager(MM_SESSION_TYPE_SHARE, mediaPlayerPrivateAudioSessionNotifyCallback, player());
1938         asm_handle = m_audioSessionManager->getAsmHandle();
1939     }
1940 #endif
1941
1942     m_playBin = gst_element_factory_make(gPlaybinName, "play");
1943
1944     GstElement *sink = gst_element_factory_make("pulsesink", "audio-sink");
1945     if (sink != NULL) {
1946         GstStructure *props;
1947         FILE *f;
1948         guint32 ids[256];
1949         guint32 rsetid = 0;
1950         gchar *fnam_str = g_strdup_printf("/tmp/murphy/mapping-file-%d", getpid());
1951
1952         if ((f = fopen(fnam_str, "r"))) {
1953           if (fread((void *)ids, sizeof(guint32), 256, f) == 256)
1954               rsetid = ids[(asm_handle & 0xff)];
1955
1956           fclose(f);
1957         }
1958
1959         g_free(fnam_str);
1960
1961         gchar *prop_str = g_strdup_printf("props,resource.set.id=(string)%u,media.role=%s", rsetid, media_class);
1962
1963         props = gst_structure_from_string(prop_str, NULL);
1964         g_object_set(sink, "stream-properties", props, NULL);
1965         gst_structure_free(props);
1966
1967         g_object_set(m_playBin, "audio-sink", sink, NULL);
1968
1969         g_free(prop_str);
1970     }
1971
1972 #ifndef GST_API_VERSION_1
1973     m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin);
1974 #endif
1975
1976     GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
1977     gst_bus_add_signal_watch(bus);
1978     g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
1979 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1980     gst_bus_set_sync_handler(bus, GstBusSyncHandler(mediaPlayerPrivateSyncHandler), this);
1981 #endif
1982     gst_object_unref(bus);
1983
1984     g_object_set(m_playBin, "mute", m_player->muted(), NULL);
1985
1986     g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
1987     g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
1988     g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
1989     g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
1990     g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
1991 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
1992     g_signal_connect(m_playBin, "source-setup", G_CALLBACK(mediaPlayerPrivateSourceSetupCallback), this);
1993 #endif
1994
1995 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1996     m_webkitVideoSink = m_videoLayer->createVideoSink();
1997     m_videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
1998 #else // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
1999 #ifndef GST_API_VERSION_1
2000     m_webkitVideoSink = webkitVideoSinkNew(m_gstGWorld.get());
2001 #else
2002     m_webkitVideoSink = webkitVideoSinkNew();
2003 #endif
2004     m_videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
2005
2006     g_signal_connect(m_webkitVideoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
2007 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER) && ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2008
2009 #ifndef GST_API_VERSION_1
2010     m_videoSinkBin = gst_bin_new("sink");
2011
2012     GstElement* videoTee = gst_element_factory_make("tee", "videoTee");
2013 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2014     GstElement* queue = gst_element_factory_make("queue", 0);
2015 #endif
2016     // Take ownership.
2017     gst_object_ref_sink(m_videoSinkBin);
2018
2019     // Build a new video sink consisting of a bin containing a tee
2020     // (meant to distribute data to multiple video sinks) and our
2021     // internal video sink. For fullscreen we create an autovideosink
2022     // and initially block the data flow towards it and configure it
2023 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2024     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, queue, NULL);
2025 #else
2026     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, NULL);
2027 #endif
2028
2029 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2030     // Link a new src pad from tee to queue1.
2031     GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(videoTee, "src%d"));
2032     GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink"));
2033     gst_pad_link(srcPad.get(), sinkPad.get());
2034 #endif
2035 #endif
2036
2037     GstElement* actualVideoSink = 0;
2038     m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
2039     if (m_fpsSink) {
2040         // The verbose property has been added in -bad 0.10.22. Making
2041         // this whole code depend on it because we don't want
2042         // fpsdiplaysink to spit data on stdout.
2043         GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory);
2044         if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) {
2045             g_object_set(m_fpsSink, "silent", TRUE , NULL);
2046
2047             // Turn off text overlay unless logging is enabled.
2048 #if LOG_DISABLED
2049             g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
2050 #else
2051             WTFLogChannel* channel = getChannelFromName("Media");
2052             if (channel->state != WTFLogChannelOn)
2053                 g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
2054 #endif // LOG_DISABLED
2055
2056             if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
2057                 g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL);
2058 #ifndef GST_API_VERSION_1
2059                 gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink);
2060 #endif
2061                 actualVideoSink = m_fpsSink;
2062             } else
2063                 m_fpsSink = 0;
2064         } else
2065             m_fpsSink = 0;
2066     }
2067
2068     if (!m_fpsSink) {
2069 #ifndef GST_API_VERSION_1
2070         gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
2071 #endif
2072         actualVideoSink = m_webkitVideoSink;
2073     }
2074
2075     ASSERT(actualVideoSink);
2076
2077 #ifndef GST_API_VERSION_1
2078 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2079     // Link a new src pad from tee to queue1.
2080     GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(videoTee, "src%d"));
2081     GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(actualVideoSink, "sink"));
2082     gst_pad_link(srcPad.get(), sinkPad.get());
2083 #else
2084     // Faster elements linking.
2085     gst_element_link_pads_full(queue, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
2086 #endif
2087     // Add a ghostpad to the bin so it can proxy to tee.
2088     GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(videoTee, "sink"));
2089     gst_element_add_pad(m_videoSinkBin, gst_ghost_pad_new("sink", pad.get()));
2090
2091     // Set the bin as video sink of playbin.
2092     g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL);
2093 #else
2094     g_object_set(m_playBin, "video-sink", actualVideoSink, NULL);
2095 #endif
2096
2097     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_webkitVideoSink, "sink"));
2098     if (videoSinkPad)
2099         g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
2100
2101 #if ENABLE(TIZEN_GSTREAMER_AUDIO)
2102     if (m_player_deferred_state == 1)
2103         play();
2104     else if (m_player_deferred_state == 0)
2105         pause();
2106 #endif
2107 }
2108
2109 #if ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
2110 bool MediaPlayerPrivateGStreamer::supportsAcceleratedRendering() const
2111 {
2112     bool isEmbedVideo = false;
2113     if (m_player->mediaPlayerClient()) {
2114         Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
2115         if (document && document->settings()) {
2116             isEmbedVideo = document->settings()->acceleratedCompositingForVideoEnabled()
2117                                 && document->settings()->acceleratedCompositingEnabled();
2118             LOG_VERBOSE(Media, "isEmbedVideo: %d", isEmbedVideo);
2119         }
2120     }
2121
2122     return isEmbedVideo;
2123 }
2124
2125 PlatformLayer* MediaPlayerPrivateGStreamer::platformLayer() const
2126 {
2127     return m_videoLayer->platformLayer();
2128 }
2129
2130 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2131 void MediaPlayerPrivateGStreamer::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
2132 {
2133     m_videoLayer->paintCurrentFrameInContext(context, rect);
2134 }
2135
2136 void MediaPlayerPrivateGStreamer::xWindowIdPrepared(GstMessage* message)
2137 {
2138     int width;
2139     int height;
2140     gst_structure_get_int(message->structure, "video-width", &width);
2141     gst_structure_get_int(message->structure, "video-height", &height);
2142
2143     IntSize size(width, height);
2144     m_videoSize = size;
2145     m_videoLayer->setOverlay(size);
2146 }
2147 #endif // ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
2148 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING) && USE(TIZEN_TEXTURE_MAPPER)
2149
2150 #if ENABLE(TIZEN_WEBKIT2_PROXY)
2151 void MediaPlayerPrivateGStreamer::setProxy(GstElement* source)
2152 {
2153     SoupSession* session = WebCore::ResourceHandle::defaultSession();
2154     if (!session)
2155         return;
2156
2157     SoupURI* proxyUri = 0;
2158     g_object_get(session, SOUP_SESSION_PROXY_URI, &proxyUri, NULL);
2159     if (!proxyUri)
2160         return;
2161
2162     char* proxy = soup_uri_to_string(proxyUri, false);
2163     g_object_set(source, "proxy", proxy, NULL);
2164
2165     soup_uri_free(proxyUri);
2166     g_free(proxy);
2167 }
2168 #endif
2169
2170 }
2171
2172 #endif // USE(GSTREAMER)