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