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