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