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