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