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