root/trunk/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp

Revision 29663, 16.3 kB (checked in by darin@apple.com, 7 months ago)

set eol-style to native on tons of files to head off future mixed-line-ending problems

  • Property svn:eol-style set to native
Line 
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Collabora Ltd.  All rights reserved.
4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * aint with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(VIDEO)
25
26 #include "MediaPlayerPrivateGStreamer.h"
27 #include "VideoSinkGStreamer.h"
28
29 #include "CString.h"
30 #include "GraphicsContext.h"
31 #include "IntRect.h"
32 #include "KURL.h"
33 #include "MIMETypeRegistry.h"
34 #include "MediaPlayer.h"
35 #include "NotImplemented.h"
36 #include "ScrollView.h"
37 #include "Widget.h"
38
39 #include <gdk/gdkx.h>
40 #include <gst/base/gstbasesrc.h>
41 #include <gst/gst.h>
42 #include <gst/interfaces/mixer.h>
43 #include <gst/interfaces/xoverlay.h>
44 #include <gst/video/video.h>
45 #include <libgnomevfs/gnome-vfs.h>
46 #include <limits>
47 #include <math.h>
48
49 using namespace std;
50
51 namespace WebCore {
52
53 gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data)
54 {
55     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR)
56     {
57         GError* err;
58         gchar* debug;
59
60         gst_message_parse_error(message, &err, &debug);
61         if (err->code == 3) {
62             LOG_VERBOSE(Media, "File not found");
63             MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
64             if (mp)
65                 mp->loadingFailed();
66         } else {
67             LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
68             g_error_free(err);
69             g_free(debug);
70         }
71     }
72     return true;
73 }
74
75 gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data)
76 {
77     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS)
78     {
79         LOG_VERBOSE(Media, "End of Stream");
80         MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
81         mp->didEnd();
82     }
83     return true;
84 }
85
86 gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data)
87 {
88     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED)
89     {
90         MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
91         mp->updateStates();
92     }
93     return true;
94 }
95
96 gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data)
97 {
98     if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING)
99     {
100         gint percent = 0;
101         gst_message_parse_buffering(message, &percent);
102         LOG_VERBOSE(Media, "Buffering %d", percent);
103     }
104     return true;
105 }
106
107 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
108     : m_player(player)
109     , m_playBin(0)
110     , m_videoSink(0)
111     , m_source(0)
112     , m_rate(1.0f)
113     , m_endTime(numeric_limits<float>::infinity())
114     , m_isEndReached(false)
115     , m_volume(0.5f)
116     , m_networkState(MediaPlayer::Empty)
117     , m_readyState(MediaPlayer::DataUnavailable)
118     , m_startedPlaying(false)
119     , m_isStreaming(false)
120     , m_rect(IntRect())
121     , m_visible(true)
122 {
123
124     static bool gstInitialized = false;
125     // FIXME: We should pass the arguments from the command line
126     if (!gstInitialized) {
127         gst_init(0, NULL);
128         gstInitialized = true;
129     }
130
131     // FIXME: The size shouldn't be fixed here, this is just a quick hack.
132     m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);
133 }
134
135 MediaPlayerPrivate::~MediaPlayerPrivate()
136 {
137     if (m_surface)
138         cairo_surface_destroy(m_surface);
139
140     if (m_playBin) {
141         gst_element_set_state(m_playBin, GST_STATE_NULL);
142         gst_object_unref(GST_OBJECT(m_playBin));
143     }
144 }
145
146 void MediaPlayerPrivate::load(String url)
147 {
148     LOG_VERBOSE(Media, "Load %s", url.utf8().data());
149     if (m_networkState != MediaPlayer::Loading) {
150         m_networkState = MediaPlayer::Loading;
151         m_player->networkStateChanged();
152     }
153     if (m_readyState != MediaPlayer::DataUnavailable) {
154         m_readyState = MediaPlayer::DataUnavailable;
155         m_player->readyStateChanged();
156     }
157
158     createGSTPlayBin(url);
159     pause();
160 }
161
162 void MediaPlayerPrivate::play()
163 {
164     LOG_VERBOSE(Media, "Play");
165     // When end reached, rewind for Test video-seek-past-end-playing
166     if (m_isEndReached)
167         seek(0);
168     m_isEndReached = false;
169
170     gst_element_set_state(m_playBin, GST_STATE_PLAYING);
171     m_startedPlaying = true;
172 }
173
174 void MediaPlayerPrivate::pause()
175 {
176     LOG_VERBOSE(Media, "Pause");
177     gst_element_set_state(m_playBin, GST_STATE_PAUSED);
178     m_startedPlaying = false;
179 }
180
181 float MediaPlayerPrivate::duration()
182 {
183     if (!m_playBin)
184         return 0.0;
185
186     GstFormat fmt = GST_FORMAT_TIME;
187     gint64 len = 0;
188
189     if (gst_element_query_duration(m_playBin, &fmt, &len))
190         LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len));
191     else
192         LOG_VERBOSE(Media, "Duration query failed ");
193
194     if ((GstClockTime)len == GST_CLOCK_TIME_NONE) {
195         m_isStreaming = true;
196         return numeric_limits<float>::infinity();
197     }
198     return (float) (len / 1000000000.0);
199     // FIXME: handle 3.14.9.5 properly
200 }
201
202 float MediaPlayerPrivate::currentTime() const
203 {
204     if (!m_playBin)
205         return 0;
206     // Necessary as sometimes, gstreamer return 0:00 at the EOS
207     if (m_isEndReached)
208         return m_endTime;
209
210     float ret;
211
212     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
213     if (gst_element_query(m_playBin, query)) {
214         gint64 position;
215         gst_query_parse_position(query, NULL, &position);
216         ret = (float) (position / 1000000000.0);
217         LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
218     } else {
219         LOG_VERBOSE(Media, "Position query failed...");
220         ret = 0.0;
221     }
222     gst_query_unref(query);
223
224     return ret;
225 }
226
227 void MediaPlayerPrivate::seek(float time)
228 {
229     GstClockTime sec = (GstClockTime)(time * GST_SECOND);
230
231     if (!m_playBin)
232         return;
233
234     if (m_isStreaming)
235         return;
236
237     LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
238     // FIXME: What happens when the seeked position is not available?
239     if (!gst_element_seek( m_playBin, m_rate,
240             GST_FORMAT_TIME,
241             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
242             GST_SEEK_TYPE_SET, sec,
243             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
244         LOG_VERBOSE(Media, "Seek to %f failed", time);
245 }
246
247 void MediaPlayerPrivate::setEndTime(float time)
248 {
249     if (!m_playBin)
250         return;
251     if (m_isStreaming)
252         return;
253     if (m_endTime != time) {
254         m_endTime = time;
255         GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND);
256         GstClockTime end   = (GstClockTime)(time * GST_SECOND);
257         LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end));
258         // FIXME: What happens when the seeked position is not available?
259         if (!gst_element_seek(m_playBin, m_rate,
260                 GST_FORMAT_TIME,
261                 (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
262                 GST_SEEK_TYPE_SET, start,
263                 GST_SEEK_TYPE_SET, end ))
264             LOG_VERBOSE(Media, "Seek to %f failed", time);
265     }
266 }
267
268 void MediaPlayerPrivate::startEndPointTimerIfNeeded()
269 {
270     notImplemented();
271 }
272
273 void MediaPlayerPrivate::cancelSeek()
274 {
275     notImplemented();
276 }
277
278 void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
279 {
280     notImplemented();
281 }
282
283 bool MediaPlayerPrivate::paused() const
284 {
285     return !m_startedPlaying;
286 }
287
288 bool MediaPlayerPrivate::seeking() const
289 {
290     return false;
291 }
292
293 // Returns the size of the video
294 IntSize MediaPlayerPrivate::naturalSize()
295 {
296     if (!hasVideo())
297         return IntSize();
298
299     int x = 0, y = 0;
300     if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
301         gst_video_get_size(GST_PAD(pad), &x, &y);
302         gst_object_unref(GST_OBJECT(pad));
303     }
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& rect)
557 {
558     m_rect = rect;
559 }
560
561 void MediaPlayerPrivate::setVisible(bool visible)
562 {
563     m_visible = visible;
564 }
565
566 void MediaPlayerPrivate::repaint()
567 {
568     m_player->repaint();
569 }
570
571 void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
572 {
573     if (context->paintingDisabled())
574         return;
575
576     if (!m_visible)
577         return;
578
579     //TODO: m_rect vs rect?
580     cairo_t* cr = context->platformContext();
581
582     cairo_save(cr);
583     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
584     cairo_translate(cr, rect.x(), rect.y());
585     cairo_rectangle(cr, 0, 0, rect.width(), rect.height());
586     cairo_set_source_surface(cr, m_surface, 0, 0);
587     cairo_fill(cr);
588     cairo_restore(cr);
589 }
590
591 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
592 {
593     // FIXME: do the real thing
594     notImplemented();
595     types.add(String("video/x-theora+ogg"));
596 }
597
598 void MediaPlayerPrivate::createGSTPlayBin(String url)
599 {
600     ASSERT(!m_playBin);
601     m_playBin = gst_element_factory_make("playbin", "play");
602
603     GstBus* bus = gst_pipeline_get_bus<