Reviewed by Oliver.
[WebKit-https.git] / WebCore / platform / graphics / gtk / MediaPlayerPrivateGStreamer.cpp
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Collabora Ltd.  All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * aint with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(VIDEO)
24
25 #include "MediaPlayerPrivateGStreamer.h"
26
27 #include "CString.h"
28 #include "CString.h"
29 #include "GraphicsContext.h"
30 #include "IntRect.h"
31 #include "KURL.h"
32 #include "MIMETypeRegistry.h"
33 #include "MediaPlayer.h"
34 #include "NotImplemented.h"
35 #include "ScrollView.h"
36 #include "Widget.h"
37
38 #include <gdk/gdkx.h>
39 #include <gst/base/gstbasesrc.h>
40 #include <gst/gst.h>
41 #include <gst/interfaces/mixer.h>
42 #include <gst/interfaces/xoverlay.h>
43 #include <gst/video/video.h>
44 #include <libgnomevfs/gnome-vfs.h>
45 #include <limits>
46 #include <math.h>
47
48 using namespace std;
49
50 namespace WebCore {
51
52 gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data)
53 {
54     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR)
55     {
56         GError* err;
57         gchar* debug;
58
59         gst_message_parse_error(message, &err, &debug);
60         if (err->code == 3) {
61             LOG_VERBOSE(Media, "File not found");
62             MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
63             if (mp)
64                 mp->loadingFailed();
65         } else {
66             LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
67             g_error_free(err);
68             g_free(debug);
69         }
70     }
71     return true;
72 }
73
74 gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data)
75 {
76     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS)
77     {
78         LOG_VERBOSE(Media, "End of Stream");
79         MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
80         mp->didEnd();
81     }
82     return true;
83 }
84
85 gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data)
86 {
87     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED)
88     {
89         MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
90         mp->updateStates();
91     }
92     return true;
93 }
94
95 gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data)
96 {
97     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING)
98     {
99         gint percent = 0;
100         gst_message_parse_buffering(message, &percent);
101         LOG_VERBOSE(Media, "Buffering %d", percent);
102     }
103     return true;
104 }
105
106 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
107     : m_player(player)
108     , m_playBin(0)
109     , m_videoSink(0)
110     , m_source(0)
111     , m_rate(1.0f)
112     , m_endTime(numeric_limits<float>::infinity())
113     , m_isEndReached(false)
114     , m_volume(0.5f)
115     , m_previousTimeCueTimerFired(0)
116     , m_networkState(MediaPlayer::Empty)
117     , m_readyState(MediaPlayer::DataUnavailable)
118     , m_startedPlaying(false)
119     , m_isStreaming(false)
120 {
121     // FIXME: We should pass the arguments from the command line
122     gst_init(0, NULL);
123 }
124
125 MediaPlayerPrivate::~MediaPlayerPrivate()
126 {
127     gst_element_set_state(m_playBin, GST_STATE_NULL);
128     gst_object_unref(GST_OBJECT(m_playBin));
129 }
130
131 void MediaPlayerPrivate::load(String url)
132 {
133     LOG_VERBOSE(Media, "Load %s", url.utf8().data());
134     if (m_networkState != MediaPlayer::Loading) {
135         m_networkState = MediaPlayer::Loading;
136         m_player->networkStateChanged();
137     }
138     if (m_readyState != MediaPlayer::DataUnavailable) {
139         m_readyState = MediaPlayer::DataUnavailable;
140         m_player->readyStateChanged();
141     }
142
143     createGSTPlayBin(url);
144     pause();
145 }
146
147 void MediaPlayerPrivate::play()
148 {
149     LOG_VERBOSE(Media, "Play");
150     // When end reached, rewind for Test video-seek-past-end-playing
151     if (m_isEndReached)
152         seek(0);
153     m_isEndReached = false;
154
155     gst_element_set_state(m_playBin, GST_STATE_PLAYING);
156     m_startedPlaying = true;
157 }
158
159 void MediaPlayerPrivate::pause()
160 {
161     LOG_VERBOSE(Media, "Pause");
162     gst_element_set_state(m_playBin, GST_STATE_PAUSED);
163     m_startedPlaying = false;
164 }
165
166 float MediaPlayerPrivate::duration()
167 {
168     if (!m_playBin)
169         return 0.0;
170
171     GstFormat fmt = GST_FORMAT_TIME;
172     gint64 len = 0;
173
174     if (gst_element_query_duration(m_playBin, &fmt, &len))
175         LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len));
176     else
177         LOG_VERBOSE(Media, "Duration query failed ");
178
179     if ((GstClockTime)len == GST_CLOCK_TIME_NONE) {
180         m_isStreaming = true;
181         return numeric_limits<float>::infinity();
182     }
183     return (float) (len / 1000000000.0);
184     // FIXME: handle 3.14.9.5 properly
185 }
186
187 float MediaPlayerPrivate::currentTime() const
188 {
189     if (!m_playBin)
190         return 0;
191     // Necessary as sometimes, gstreamer return 0:00 at the EOS
192     if (m_isEndReached)
193         return m_endTime;
194
195     float ret;
196     GstQuery* query;
197     gboolean res;
198
199     query = gst_query_new_position(GST_FORMAT_TIME);
200     res = gst_element_query(m_playBin, query);
201     if (res) {
202         gint64 position;
203         gst_query_parse_position(query, NULL, &position);
204         ret = (float) (position / 1000000000.0);
205         LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
206     } else {
207         LOG_VERBOSE(Media, "Position query failed...");
208         ret = 0.0;
209     }
210     gst_query_unref(query);
211     return ret;
212 }
213
214 void MediaPlayerPrivate::seek(float time)
215 {
216     GstClockTime sec = (GstClockTime)(time * GST_SECOND);
217
218     if (!m_playBin)
219         return;
220
221     if (m_isStreaming)
222         return;
223
224     LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
225     // FIXME: What happens when the seeked position is not available?
226     if (!gst_element_seek( m_playBin, m_rate,
227             GST_FORMAT_TIME,
228             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
229             GST_SEEK_TYPE_SET, sec,
230             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
231         LOG_VERBOSE(Media, "Seek to %f failed", time);
232 }
233
234 void MediaPlayerPrivate::setEndTime(float time)
235 {
236     if (!m_playBin)
237         return;
238     if (m_isStreaming)
239         return;
240     if (m_endTime != time) {
241         m_endTime = time;
242         GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND);
243         GstClockTime end   = (GstClockTime)(time * GST_SECOND);
244         LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end));
245         // FIXME: What happens when the seeked position is not available?
246         if (!gst_element_seek( m_playBin, m_rate,
247                 GST_FORMAT_TIME,
248                 (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
249                 GST_SEEK_TYPE_SET, start,
250                 GST_SEEK_TYPE_SET, end ))
251             LOG_VERBOSE(Media, "Seek to %f failed", time);
252     }
253 }
254
255 void MediaPlayerPrivate::addCuePoint(float time)
256 {
257     notImplemented();
258 }
259
260 void MediaPlayerPrivate::removeCuePoint(float time)
261 {
262     notImplemented();
263 }
264
265 void MediaPlayerPrivate::clearCuePoints()
266 {
267     notImplemented();
268 }
269
270 void MediaPlayerPrivate::startCuePointTimerIfNeeded()
271 {
272     notImplemented();
273 }
274
275 void MediaPlayerPrivate::cancelSeek()
276 {
277     notImplemented();
278 }
279
280 void MediaPlayerPrivate::cuePointTimerFired(Timer<MediaPlayerPrivate>*)
281 {
282     notImplemented();
283 }
284
285 bool MediaPlayerPrivate::paused() const
286 {
287     return !m_startedPlaying;
288 }
289
290 bool MediaPlayerPrivate::seeking() const
291 {
292     return false;;
293 }
294
295 // Returns the size of the video
296 IntSize MediaPlayerPrivate::naturalSize()
297 {
298     int x = 0, y = 0;
299     if (hasVideo()) {
300         GstPad* pad = NULL;
301         pad = gst_element_get_pad(m_videoSink, "sink");
302         if (pad)
303             gst_video_get_size(GST_PAD(pad), &x, &y);
304     }
305     return IntSize(x, y);
306 }
307
308 bool MediaPlayerPrivate::hasVideo()
309 {
310     gint currentVideo = -1;
311     if (m_playBin)
312         g_object_get(G_OBJECT(m_playBin), "current-video", &currentVideo, NULL);
313     return currentVideo > -1;
314 }
315
316 void MediaPlayerPrivate::setVolume(float volume)
317 {
318     m_volume = volume;
319     LOG_VERBOSE(Media, "Volume to %f", volume);
320     setMuted(false);
321 }
322
323 void MediaPlayerPrivate::setMuted(bool b)
324 {
325     if (!m_playBin) 
326         return;
327
328     if (b) {
329         g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL);
330         g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL);
331     } else {
332         g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL);
333     }
334 }
335
336 void MediaPlayerPrivate::setRate(float rate)
337 {
338     if (rate == 0.0) {
339         gst_element_set_state(m_playBin, GST_STATE_PAUSED);
340         return;
341     }
342     if (m_isStreaming)
343         return;
344
345     m_rate = rate;
346     LOG_VERBOSE(Media, "Set Rate to %f", rate);
347     if (!gst_element_seek(m_playBin, rate,
348             GST_FORMAT_TIME,
349             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
350             GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND),
351             GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND)))
352         LOG_VERBOSE(Media, "Set Rate to %f failed", rate);
353 }
354
355 int MediaPlayerPrivate::dataRate() const
356 {
357     notImplemented();
358     return 1;
359 }
360
361 MediaPlayer::NetworkState MediaPlayerPrivate::networkState()
362 {
363     return m_networkState;
364 }
365
366 MediaPlayer::ReadyState MediaPlayerPrivate::readyState()
367 {
368     return m_readyState;
369 }
370
371 float MediaPlayerPrivate::maxTimeBuffered()
372 {
373     notImplemented();
374     LOG_VERBOSE(Media, "maxTimeBuffered");
375     // rtsp streams are not buffered
376     return m_isStreaming ? 0 : maxTimeLoaded();
377 }
378
379 float MediaPlayerPrivate::maxTimeSeekable()
380 {
381     // TODO
382     LOG_VERBOSE(Media, "maxTimeSeekable");
383     if (m_isStreaming)
384         return numeric_limits<float>::infinity();
385     // infinite duration means live stream
386     return maxTimeLoaded();
387 }
388
389 float MediaPlayerPrivate::maxTimeLoaded()
390 {
391     // TODO
392     LOG_VERBOSE(Media, "maxTimeLoaded");
393     notImplemented();
394     return duration();
395 }
396
397 unsigned MediaPlayerPrivate::bytesLoaded()
398 {
399     notImplemented();
400     LOG_VERBOSE(Media, "bytesLoaded");
401     /*if (!m_playBin)
402         return 0;
403     float dur = duration();
404     float maxTime = maxTimeLoaded();
405     if (!dur)
406         return 0;*/
407     return 1;//totalBytes() * maxTime / dur;
408 }
409
410 bool MediaPlayerPrivate::totalBytesKnown()
411 {
412     notImplemented();
413     LOG_VERBOSE(Media, "totalBytesKnown");
414     return totalBytes() > 0;
415 }
416
417 unsigned MediaPlayerPrivate::totalBytes()
418 {
419     notImplemented();
420     LOG_VERBOSE(Media, "totalBytes");
421     if (!m_playBin)
422         return 0;
423
424     if (!m_source)
425         return 0;
426
427     // Do something with m_source to get the total bytes of the media
428
429     return 100;
430 }
431
432 void MediaPlayerPrivate::cancelLoad()
433 {
434     notImplemented();
435 }
436
437 void MediaPlayerPrivate::updateStates()
438 {
439     // There is no (known) way to get such level of information about
440     // the state of GStreamer, therefore, when in PAUSED state,
441     // we are sure we can display the first frame and go to play
442
443     MediaPlayer::NetworkState oldNetworkState = m_networkState;
444     MediaPlayer::ReadyState oldReadyState = m_readyState;
445     GstState state;
446     GstState pending;
447
448     if (!m_playBin)
449         return;
450
451     GstStateChangeReturn ret = gst_element_get_state (m_playBin,
452         &state, &pending, 250 * GST_NSECOND);
453
454     switch(ret) {
455     case GST_STATE_CHANGE_SUCCESS:
456         LOG_VERBOSE(Media, "State: %s, pending: %s",
457             gst_element_state_get_name(state),
458             gst_element_state_get_name(pending));
459
460         if (state == GST_STATE_READY) {
461             m_readyState = MediaPlayer::CanPlayThrough;
462         } else if (state == GST_STATE_PAUSED) {
463             m_readyState = MediaPlayer::CanPlayThrough;
464         }
465         if (m_networkState < MediaPlayer::Loaded)
466             m_networkState = MediaPlayer::Loaded;
467
468         g_object_get(m_playBin, "source", &m_source, NULL);
469         if (!m_source)
470             LOG_VERBOSE(Media, "m_source is NULL");
471         break;
472     case GST_STATE_CHANGE_ASYNC:
473         LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
474             gst_element_state_get_name(state),
475             gst_element_state_get_name(pending));
476         // Change in progress
477         return;
478         break;
479     case GST_STATE_CHANGE_NO_PREROLL:
480         LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
481             gst_element_state_get_name(state),
482             gst_element_state_get_name(pending));
483         if (state == GST_STATE_READY) {
484             m_readyState = MediaPlayer::CanPlay;
485         } else if (state == GST_STATE_PAUSED) {
486             m_readyState = MediaPlayer::CanPlay;
487         }
488         if (m_networkState < MediaPlayer::LoadedMetaData)
489             m_networkState = MediaPlayer::LoadedMetaData;
490         break;
491     default:
492         LOG_VERBOSE(Media, "Else : %d", ret);
493         break;
494     }
495
496     if (seeking())
497         m_readyState = MediaPlayer::DataUnavailable;
498
499     if (m_networkState != oldNetworkState) {
500         LOG_VERBOSE(Media, "Network State Changed from %u to %u",
501             oldNetworkState, m_networkState);
502         m_player->networkStateChanged();
503     }
504     if (m_readyState != oldReadyState) {
505         LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
506             oldReadyState, m_readyState);
507         m_player->readyStateChanged();
508     }
509 }
510
511 void MediaPlayerPrivate::loadStateChanged()
512 {
513     updateStates();
514 }
515
516 void MediaPlayerPrivate::rateChanged()
517 {
518     updateStates();
519 }
520
521 void MediaPlayerPrivate::sizeChanged()
522 {
523     notImplemented();
524 }
525
526 void MediaPlayerPrivate::timeChanged()
527 {
528     updateStates();
529     m_player->timeChanged();
530 }
531
532 void MediaPlayerPrivate::volumeChanged()
533 {
534     m_player->volumeChanged();
535 }
536
537 void MediaPlayerPrivate::didEnd()
538 {
539     m_isEndReached = true;
540     pause();
541     timeChanged();
542 }
543
544 void MediaPlayerPrivate::loadingFailed()
545 {
546     if (m_networkState != MediaPlayer::LoadFailed) {
547         m_networkState = MediaPlayer::LoadFailed;
548         m_player->networkStateChanged();
549     }
550     if (m_readyState != MediaPlayer::DataUnavailable) {
551         m_readyState = MediaPlayer::DataUnavailable;
552         m_player->readyStateChanged();
553     }
554 }
555
556 void MediaPlayerPrivate::setRect(const IntRect& r)
557 {
558     notImplemented();
559 }
560
561 void MediaPlayerPrivate::setVisible(bool b)
562 {
563     notImplemented();
564 }
565
566 void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
567 {
568     // FIXME: do the real thing
569     if (p->paintingDisabled())
570         return;
571     // For now draw a placeholder rectangle
572     p->drawRect(r);
573 }
574
575 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
576 {
577     // FIXME: do the real thing
578     notImplemented();
579     types.add(String("video/x-theora+ogg"));
580 }
581
582 void MediaPlayerPrivate::createGSTPlayBin(String url)
583 {
584     GstElement* audioSink;
585     GstBus* bus;
586
587     m_playBin = gst_element_factory_make("playbin", "play");
588
589     bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
590
591     gst_bus_add_signal_watch(bus);
592
593     g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this);
594     g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this);
595     g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this);
596     g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this);
597
598     gst_object_unref(bus);
599
600     g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL);
601     audioSink = gst_element_factory_make("gconfaudiosink", NULL);
602     m_videoSink = gst_element_factory_make("gconfvideosink", NULL);
603
604     g_object_set(m_playBin, "audio-sink", audioSink, NULL);
605     g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
606
607     setVolume(m_volume);
608 }
609
610 }
611
612 #endif
613