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