Index: totem/src/Makefile.am --- totem~totem-playbin/src/Makefile.am 2004-07-08 09:56:43.000000000 +0200 +++ totem/src/Makefile.am 2004-09-15 14:00:41.000000000 +0200 @@ -25,8 +25,9 @@ plugin_LTLIBRARIES = $(TOTEM_MOZILLA_PLUGIN) if TOTEM_GST -MM = bacon-video-widget-gst.c \ - gstvideowidget.c \ +MM = bacon-video-widget-gst.c \ + gststreaminfo.h \ + gstvideowidget.c \ gstvideowidget.h else MM = bacon-video-widget-xine.c @@ -160,6 +161,7 @@ CLEANFILES = *.bak *.gladep core* *.orig *~ $(MARSHALFILES) $(desktop_DATA) EXTRA_DIST = bacon-video-widget-xine.c \ bacon-video-widget-gst.c \ + gststreaminfo.h \ gstvideowidget.c \ gstvideowidget.h \ $(BACON_V4L_SELECTION) \ Index: totem/src/bacon-video-widget-gst.c --- totem~totem-playbin/src/bacon-video-widget-gst.c 2004-07-22 19:59:01.000000000 +0200 +++ totem/src/bacon-video-widget-gst.c 2004-09-23 10:47:10.000000000 +0200 @@ -1,6 +1,7 @@ /* - * Copyright (C) 2003 the Gstreamer project + * Copyright (C) 2003-2004 the Gstreamer project * Julien Moutte + * Ronald Bultje * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,7 +12,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + *_ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -22,9 +23,6 @@ #include -/* libgstplay */ -#include - /* gstgconf */ #include @@ -41,20 +39,14 @@ /* gtk+/gnome */ #include #include +#include #include "bacon-video-widget.h" #include "baconvideowidget-marshal.h" #include "scrsaver.h" #include "video-utils.h" #include "gstvideowidget.h" - -#include -#define _(String) gettext (String) -#ifdef gettext_noop -# define N_(String) gettext_noop (String) -#else -# define N_(String) (String) -#endif +#include "gststreaminfo.h" #define DEFAULT_HEIGHT 420 #define DEFAULT_WIDTH 315 @@ -64,14 +56,14 @@ /* Signals */ enum { - ERROR, - EOS, - TITLE_CHANGE, - CHANNELS_CHANGE, - TICK, - GOT_METADATA, - BUFFERING, - SPEED_WARNING, + SIGNAL_ERROR, + SIGNAL_EOS, + SIGNAL_TITLE_CHANGE, + SIGNAL_CHANNELS_CHANGE, + SIGNAL_TICK, + SIGNAL_GOT_METADATA, + SIGNAL_BUFFERING, + SIGNAL_SPEED_WARNING, LAST_SIGNAL }; @@ -100,7 +92,8 @@ { double display_ratio; - GstPlay *play; + GstElement *play; + guint update_id; GstVideoWidget *vw; GstMixer *mixer; GstMixerTrack *mixer_track; @@ -109,14 +102,14 @@ GdkPixbuf *logo_pixbuf; - gboolean media_has_video; + gboolean media_has_video, media_has_audio; gint64 stream_length; gint64 current_time_nanos; gint64 current_time; float current_position; - GHashTable *metadata_hash; + GstTagList *tagcache; char *last_error_message; @@ -139,8 +132,9 @@ GAsyncQueue *queue; - guint video_width; - guint video_height; + gint video_width; + gint video_height; + gdouble video_fps; guint init_width; guint init_height; @@ -201,12 +195,12 @@ bacon_video_widget_vw_realized (GtkWidget * widget, BaconVideoWidget * bvw) { GdkWindow *video_window = NULL; - + video_window = gst_video_widget_get_video_window (GST_VIDEO_WIDGET (widget)); if (video_window) bvw->priv->video_window = video_window; - + if (GST_IS_X_OVERLAY (bvw->priv->xoverlay) && GDK_IS_WINDOW (video_window)) gst_x_overlay_set_xwindow_id (bvw->priv->xoverlay, GDK_WINDOW_XID (video_window)); @@ -237,8 +231,9 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - + if (GST_IS_X_OVERLAY (bvw->priv->xoverlay)) { + bacon_video_widget_vw_realized (widget, bvw); gst_x_overlay_expose (bvw->priv->xoverlay); } @@ -432,7 +427,7 @@ G_PARAM_WRITABLE)); /* Signals */ - bvw_table_signals[ERROR] = + bvw_table_signals[SIGNAL_ERROR] = g_signal_new ("error", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -442,21 +437,21 @@ G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); - bvw_table_signals[EOS] = + bvw_table_signals[SIGNAL_EOS] = g_signal_new ("eos", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (BaconVideoWidgetClass, eos), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - bvw_table_signals[GOT_METADATA] = + bvw_table_signals[SIGNAL_GOT_METADATA] = g_signal_new ("got-metadata", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (BaconVideoWidgetClass, got_metadata), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - bvw_table_signals[TITLE_CHANGE] = + bvw_table_signals[SIGNAL_TITLE_CHANGE] = g_signal_new ("title-change", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -465,14 +460,14 @@ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); - bvw_table_signals[CHANNELS_CHANGE] = + bvw_table_signals[SIGNAL_CHANNELS_CHANGE] = g_signal_new ("channels-change", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (BaconVideoWidgetClass, channels_change), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - bvw_table_signals[TICK] = + bvw_table_signals[SIGNAL_TICK] = g_signal_new ("tick", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -482,7 +477,7 @@ G_TYPE_NONE, 4, G_TYPE_INT64, G_TYPE_INT64, G_TYPE_FLOAT, G_TYPE_BOOLEAN); - bvw_table_signals[BUFFERING] = + bvw_table_signals[SIGNAL_BUFFERING] = g_signal_new ("buffering", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -490,7 +485,7 @@ NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - bvw_table_signals[SPEED_WARNING] = + bvw_table_signals[SIGNAL_SPEED_WARNING] = g_signal_new ("speed-warning", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, @@ -513,6 +508,8 @@ bvw->priv = g_new0 (BaconVideoWidgetPrivate, 1); bvw->priv->queue = g_async_queue_new (); + bvw->priv->update_id = 0; + bvw->priv->tagcache = NULL; } static void @@ -528,29 +525,6 @@ requisition.height); } -static void -store_tag (const GstTagList *list, const gchar *tag, gpointer data) -{ - BaconVideoWidget *bvw = NULL; - char *str = NULL; - - if (data && BACON_IS_VIDEO_WIDGET (data)) - bvw = BACON_VIDEO_WIDGET (data); - - if (gst_tag_list_get_tag_size (list, tag)) { - if (gst_tag_get_type (tag) == G_TYPE_STRING) { - g_assert (gst_tag_list_get_string_index (list, tag, 0, &str)); - } - else { - str = g_strdup_value_contents ( - gst_tag_list_get_value_index (list, tag, 0)); - } - - g_hash_table_replace (bvw->priv->metadata_hash, - g_strdup (gst_tag_get_nick (tag)), str); - } -} - static gboolean bacon_video_widget_signal_idler (BaconVideoWidget *bvw) { @@ -568,21 +542,42 @@ { case ASYNC_VIDEO_SIZE: { - gint width, height; - width = signal->signal_data.video_size.width; - height = signal->signal_data.video_size.height; - - if ( (width <= 1) || (height <= 1) ) - return FALSE; - - bvw->priv->media_has_video = TRUE; - bvw->priv->video_width = width; - bvw->priv->video_height = height; + GList *streaminfo = NULL; + + /* Note that we don't use the size provided by the xoverlay + * element - we also need framerate and it's all provided + * in the caps that we can get through playbin. */ + + g_object_get (G_OBJECT (bvw->priv->play), "stream-info", + &streaminfo, NULL); + for ( ; streaminfo != NULL; streaminfo = streaminfo->next) { + GstStreamInfo *info = streaminfo->data; + + switch (info->type) { + case GST_STREAM_TYPE_VIDEO: { + GstStructure *s; + + s = gst_caps_get_structure (GST_PAD_CAPS (info->pad), 0); + if (s) { + gst_structure_get_int (s, "width", &bvw->priv->video_width); + gst_structure_get_int (s, "height", &bvw->priv->video_height); + gst_structure_get_double (s, "framerate", &bvw->priv->video_fps); + } + break; + } + default: + break; + } + } if (bvw->priv->vw) { gst_video_widget_set_logo_focus (bvw->priv->vw, FALSE); - gst_video_widget_set_source_size (bvw->priv->vw, width, height); + gst_video_widget_set_source_size (bvw->priv->vw, + bvw->priv->video_width, + bvw->priv->video_height); } + + g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL); break; } case ASYNC_ERROR: @@ -602,7 +597,7 @@ if (emit) { g_signal_emit (G_OBJECT (bvw), - bvw_table_signals[ERROR], 0, + bvw_table_signals[SIGNAL_ERROR], 0, error_message, TRUE, FALSE); /* Keep a copy of the last emitted message */ @@ -622,10 +617,20 @@ case ASYNC_FOUND_TAG: { GstTagList *tag_list = signal->signal_data.found_tag.tag_list; - if (GST_IS_TAG_LIST (tag_list)) { - gst_tag_list_foreach (tag_list, store_tag, bvw); - gst_tag_list_free (tag_list); - g_signal_emit (G_OBJECT (bvw), bvw_table_signals[GOT_METADATA], + + if (tag_list) { + if (bvw->priv->tagcache) { + GstTagList *taglist; + + taglist = gst_tag_list_merge (bvw->priv->tagcache, tag_list, + GST_TAG_MERGE_APPEND); + gst_tag_list_free (tag_list); + gst_tag_list_free (bvw->priv->tagcache); + bvw->priv->tagcache = taglist; + } else { + bvw->priv->tagcache = tag_list; + } + g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL); } break; @@ -634,7 +639,7 @@ { gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY); - g_signal_emit (G_OBJECT (bvw), bvw_table_signals[EOS], 0, NULL); + g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_EOS], 0, NULL); break; } default: @@ -648,7 +653,7 @@ } static void -got_found_tag (GstPlay *play, GstElement *source, +got_found_tag (GstElement *play, GstElement *source, GstTagList *tag_list, BaconVideoWidget * bvw) { BVWSignal *signal; @@ -667,14 +672,14 @@ } static void -got_video_size (GstPlay * play, gint width, gint height, - BaconVideoWidget * bvw) +got_video_size (GstElement * play, guint width, guint height, + BaconVideoWidget * bvw) { BVWSignal *signal; - + g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - + signal = g_new0 (BVWSignal, 1); signal->signal_id = ASYNC_VIDEO_SIZE; signal->signal_data.video_size.width = width; @@ -686,7 +691,7 @@ } static void -got_eos (GstPlay * play, BaconVideoWidget * bvw) +got_eos (GstElement * play, BaconVideoWidget * bvw) { BVWSignal *signal; @@ -702,7 +707,7 @@ } static void -got_stream_length (GstPlay * play, gint64 length_nanos, +got_stream_length (GstElement * play, gint64 length_nanos, BaconVideoWidget * bvw) { g_return_if_fail (bvw != NULL); @@ -710,11 +715,11 @@ bvw->priv->stream_length = (gint64) length_nanos / GST_MSECOND; - g_signal_emit (G_OBJECT (bvw), bvw_table_signals[GOT_METADATA], 0, NULL); + g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL); } static void -got_time_tick (GstPlay * play, gint64 time_nanos, BaconVideoWidget * bvw) +got_time_tick (GstElement * play, gint64 time_nanos, BaconVideoWidget * bvw) { gboolean seekable; @@ -739,20 +744,107 @@ seekable = bacon_video_widget_is_seekable (bvw); g_signal_emit (G_OBJECT (bvw), - bvw_table_signals[TICK], 0, + bvw_table_signals[SIGNAL_TICK], 0, bvw->priv->current_time, bvw->priv->stream_length, bvw->priv->current_position, seekable); } +static gboolean +cb_iterate (BaconVideoWidget *bvw) +{ + GstFormat fmt = GST_FORMAT_TIME; + gint64 value; + gboolean res; + + if (!GST_FLAG_IS_SET (bvw->priv->play, GST_BIN_SELF_SCHEDULABLE)) { + res = gst_bin_iterate (GST_BIN (bvw->priv->play)); + } else { + g_usleep (100); + res = (gst_element_get_state (bvw->priv->play) == GST_STATE_PLAYING); + } + + /* check length/pos of stream */ + if (!bvw->priv->stream_length) { + if (gst_element_query (GST_ELEMENT (bvw->priv->play), + GST_QUERY_TOTAL, &fmt, &value)) { + got_stream_length (GST_ELEMENT (bvw->priv->play), + value, bvw); + } + } + if (gst_element_query (GST_ELEMENT (bvw->priv->play), + GST_QUERY_POSITION, &fmt, &value)) { + got_time_tick (GST_ELEMENT (bvw->priv->play), + value, bvw); + } + + if (!res) + bvw->priv->update_id = 0; + + return res; +} + static void -got_error (GstPlay *play, GstElement *orig, GError *error, +state_change (GstElement *play, GstElementState old_state, + GstElementState new_state, BaconVideoWidget *bvw) +{ + if (old_state == GST_STATE_PLAYING) { + if (bvw->priv->update_id != 0) { + g_source_remove (bvw->priv->update_id); + bvw->priv->update_id = 0; + } + } else if (new_state == GST_STATE_PLAYING) { + if (bvw->priv->update_id != 0) + g_source_remove (bvw->priv->update_id); + bvw->priv->update_id = g_idle_add ((GSourceFunc) cb_iterate, bvw); + } + + if (old_state <= GST_STATE_READY && + new_state >= GST_STATE_PAUSED) { + GList *streaminfo = NULL; + + g_object_get (G_OBJECT (bvw->priv->play), "stream-info", + &streaminfo, NULL); + for ( ; streaminfo != NULL; streaminfo = streaminfo->next) { + GstStreamInfo *info = streaminfo->data; + + switch (info->type) { + case GST_STREAM_TYPE_AUDIO: + bvw->priv->media_has_audio = TRUE; + break; + case GST_STREAM_TYPE_VIDEO: + bvw->priv->media_has_video = TRUE; + break; + default: + break; + } + } + } else if (new_state <= GST_STATE_READY && + old_state >= GST_STATE_PAUSED) { + bvw->priv->media_has_video = FALSE; + bvw->priv->media_has_audio = FALSE; + + /* clean metadata cache */ + if (bvw->priv->tagcache) + { + gst_tag_list_free (bvw->priv->tagcache); + bvw->priv->tagcache = NULL; + } + } +} + +static void +got_error (GstElement *play, GstElement *orig, GError *error, gchar *debug, BaconVideoWidget * bvw) { BVWSignal *signal; g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); + + /* the handler will catch it */ + if (GST_STATE (play) != GST_STATE_PLAYING) + return; signal = g_new0 (BVWSignal, 1); signal->signal_id = ASYNC_ERROR; @@ -788,12 +880,6 @@ g_async_queue_unref (bvw->priv->queue); bvw->priv->queue = NULL; } - - if (bvw->priv->metadata_hash) - { - g_hash_table_destroy (bvw->priv->metadata_hash); - bvw->priv->metadata_hash = NULL; - } if (bvw->priv->vis_plugins_list) { @@ -802,13 +888,24 @@ bvw->priv->vis_plugins_list = NULL; } - if (bvw->priv->play != NULL && GST_IS_PLAY (bvw->priv->play)) + if (bvw->priv->play != NULL && GST_IS_ELEMENT (bvw->priv->play)) { gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY); - /* FIXME: we are leaking the GstPlay. */ - /* g_object_unref (bvw->priv->play); */ + gst_object_unref (GST_OBJECT (bvw->priv->play)); bvw->priv->play = NULL; } + + if (bvw->priv->update_id) + { + g_source_remove (bvw->priv->update_id); + bvw->priv->update_id = 0; + } + + if (bvw->priv->tagcache) + { + gst_tag_list_free (bvw->priv->tagcache); + bvw->priv->tagcache = NULL; + } } static void @@ -823,12 +920,6 @@ { } -static gboolean -dummy_true_function (gpointer key, gpointer value, gpointer data) -{ - return TRUE; -} - /* ============================================================= */ /* */ /* Public Methods */ @@ -935,15 +1026,30 @@ bacon_video_widget_open (BaconVideoWidget * bvw, const gchar * mrl, GError ** error) { - GstElement * datasrc = NULL; + gboolean ret; g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (mrl != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); g_return_val_if_fail (bvw->priv->play != NULL, FALSE); g_return_val_if_fail (bvw->priv->mrl == NULL, FALSE); - - bvw->priv->mrl = g_strdup (mrl); + + g_free (bvw->priv->mrl); + if (strchr (mrl, ':')) { + bvw->priv->mrl = g_strdup (mrl); + } else { + if (mrl[0] == '/') { + bvw->priv->mrl = g_strdup_printf ("file://%s", mrl); + } else { + gchar cwd[PATH_MAX]; + + bvw->priv->mrl = g_strdup_printf ("file://%s/%s", + getcwd (cwd, PATH_MAX), + mrl); + } + } + + gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY); /* Resetting last_error_message to NULL */ if (bvw->priv->last_error_message) @@ -952,60 +1058,34 @@ bvw->priv->last_error_message = NULL; } - /* Cleaning metadata hash */ - g_hash_table_foreach_remove (bvw->priv->metadata_hash, - dummy_true_function, bvw); gst_video_widget_set_source_size (GST_VIDEO_WIDGET (bvw->priv->vw), 1, 1); bvw->priv->media_has_video = FALSE; bvw->priv->stream_length = 0; - - if (g_file_test (mrl, G_FILE_TEST_EXISTS)) - { - datasrc = gst_element_factory_make ("filesrc", "source"); - if (GST_IS_ELEMENT (datasrc)) - gst_play_set_data_src (bvw->priv->play, datasrc); - gst_play_set_location (bvw->priv->play, mrl); - } - else if (g_str_has_prefix (mrl, "dvd://")) - { - datasrc = gst_element_factory_make ("dvdnavsrc", "source"); - if (GST_IS_ELEMENT (datasrc)) - gst_play_set_data_src (bvw->priv->play, datasrc); - gst_play_set_location (bvw->priv->play, bvw->priv->media_device); - } - else if (g_str_has_prefix (mrl, "v4l://")) - { - datasrc = gst_element_factory_make ("v4lsrc", "source"); - if (GST_IS_ELEMENT (datasrc)) - gst_play_set_data_src (bvw->priv->play, datasrc); - gst_play_set_location (bvw->priv->play, "/dev/video"); - } - else if (g_str_has_prefix (mrl, "cdda://")) - { - datasrc = gst_element_factory_make ("cdparanoia", "source"); - if (GST_IS_ELEMENT (datasrc)) - gst_play_set_data_src (bvw->priv->play, datasrc); - gst_play_set_location (bvw->priv->play, bvw->priv->media_device); - } - else + + g_object_set (G_OBJECT (bvw->priv->play), "uri", + bvw->priv->mrl, NULL); + + ret = (gst_element_set_state (bvw->priv->play, GST_STATE_PAUSED) == + GST_STATE_SUCCESS); + if (!ret) { - datasrc = gst_element_factory_make ("gnomevfssrc", "source"); - if (GST_IS_ELEMENT (datasrc)) - gst_play_set_data_src (bvw->priv->play, datasrc); - gst_play_set_location (bvw->priv->play, mrl); + g_set_error (error, 0, 0, bvw->priv->last_error_message ? + bvw->priv->last_error_message : "Failed to open; reason unknown"); } - - return TRUE; + + return ret; } gboolean bacon_video_widget_play (BaconVideoWidget * bvw, GError ** error) { + gboolean ret; + g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); /* Resetting last_error_message to NULL */ if (bvw->priv->last_error_message) @@ -1014,9 +1094,15 @@ bvw->priv->last_error_message = NULL; } - gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_PLAYING); + ret = (gst_element_set_state (GST_ELEMENT (bvw->priv->play), + GST_STATE_PLAYING) == GST_STATE_SUCCESS); + if (!ret) + { + g_set_error (error, 0, 0, bvw->priv->last_error_message ? + bvw->priv->last_error_message : "Failed to play; reason unknown"); + } - return TRUE; + return ret; } gboolean @@ -1026,7 +1112,7 @@ g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); /* Resetting last_error_message to NULL */ if (bvw->priv->last_error_message) @@ -1037,7 +1123,10 @@ length_nanos = (gint64) (bvw->priv->stream_length * GST_MSECOND); seek_time = (gint64) (length_nanos * position); - gst_play_seek_to_time (bvw->priv->play, seek_time); + + gst_element_seek (bvw->priv->play, GST_SEEK_METHOD_SET | + GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME, + seek_time); return TRUE; } @@ -1047,7 +1136,7 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); /* Resetting last_error_message to NULL */ if (bvw->priv->last_error_message) @@ -1056,7 +1145,9 @@ bvw->priv->last_error_message = NULL; } - gst_play_seek_to_time (bvw->priv->play, time * GST_MSECOND); + gst_element_seek (bvw->priv->play, GST_SEEK_METHOD_SET | + GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME, + time * GST_MSECOND); return TRUE; } @@ -1066,7 +1157,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY); } @@ -1076,12 +1167,11 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY); if (bvw->priv->mrl) { - gst_play_set_location (bvw->priv->play, "/dev/null"); g_free (bvw->priv->mrl); bvw->priv->mrl = NULL; } @@ -1093,7 +1183,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); } void @@ -1140,7 +1230,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_PAUSED); } @@ -1156,62 +1246,34 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); - if (GST_IS_MIXER_TRACK (bvw->priv->mixer_track)) - return TRUE; - else - return FALSE; + return TRUE; } void bacon_video_widget_set_volume (BaconVideoWidget * bvw, int volume) { - gint *volumes; - g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); - - if (GST_IS_MIXER_TRACK (bvw->priv->mixer_track)) { - gint i = 0; - GstMixerTrack *mixer_track = bvw->priv->mixer_track; - - volumes = g_malloc (sizeof (gint) * mixer_track->num_channels); - - /* We set the volume for each one of the channel respecting the min/max - volume of the mixer track */ - for (i=0; inum_channels; i++) - volumes[i] = ((mixer_track->max_volume - mixer_track->min_volume) * volume / 100 ) + mixer_track->min_volume; - - gst_mixer_set_volume (bvw->priv->mixer, bvw->priv->mixer_track, - volumes); - g_free (volumes); - } + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); + + g_object_set (G_OBJECT (bvw->priv->play), "volume", + (gdouble) (1. * volume / 100), NULL); } int bacon_video_widget_get_volume (BaconVideoWidget * bvw) { - gint *volumes, volume = 0; - + gdouble vol; + g_return_val_if_fail (bvw != NULL, -1); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), -1); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), -1); - - if (GST_IS_MIXER_TRACK (bvw->priv->mixer_track)) { - GstMixerTrack *mixer_track = bvw->priv->mixer_track; - - volumes = g_malloc (sizeof (gint) * mixer_track->num_channels); - - gst_mixer_get_volume (bvw->priv->mixer, bvw->priv->mixer_track, - volumes); - volume = (volumes [0] - mixer_track->min_volume) * 100 / (mixer_track->max_volume - mixer_track->min_volume); - - g_free (volumes); - } - - return volume; + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), -1); + + g_object_get (G_OBJECT (bvw->priv->play), "volume", &vol, NULL); + + return (gint) (vol * 100 + 0.5); } gboolean @@ -1271,7 +1333,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); if (bvw->priv->media_device) g_free (bvw->priv->media_device); @@ -1285,8 +1347,10 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); + return FALSE; +#if 0 if (!bvw->priv->media_has_video) { if (!show_visuals) @@ -1298,6 +1362,7 @@ } return TRUE; +#endif } GList * @@ -1308,7 +1373,7 @@ g_return_val_if_fail (bvw != NULL, NULL); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), NULL); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), NULL); /* Cache */ if (bvw->priv->vis_plugins_list) @@ -1368,12 +1433,14 @@ gboolean bacon_video_widget_set_visuals (BaconVideoWidget * bvw, const char *name) { - gboolean paused = FALSE; + //gboolean paused = FALSE; g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); + return FALSE; +#if 0 if (GST_STATE (GST_ELEMENT (bvw->priv->play)) == GST_STATE_PLAYING) { gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_PAUSED); @@ -1399,6 +1466,7 @@ { return FALSE; } +#endif } void @@ -1408,7 +1476,7 @@ int fps, w, h; g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); if (bvw->priv->vis_element == NULL) return; @@ -1448,7 +1516,7 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); g_return_val_if_fail (GST_IS_VIDEO_WIDGET (bvw->priv->vw), FALSE); return gst_video_widget_get_auto_resize (bvw->priv->vw); @@ -1460,7 +1528,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); g_return_if_fail (GST_IS_VIDEO_WIDGET (bvw->priv->vw)); gst_video_widget_set_auto_resize (bvw->priv->vw, auto_resize); @@ -1472,7 +1540,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); } BaconVideoWidgetAspectRatio @@ -1480,7 +1548,7 @@ { g_return_val_if_fail (bvw != NULL, 0); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), 0); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), 0); return BVW_RATIO_AUTO; } @@ -1490,7 +1558,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); g_return_if_fail (GST_IS_VIDEO_WIDGET (bvw->priv->vw)); gst_video_widget_set_scale (bvw->priv->vw, ratio); @@ -1643,7 +1711,7 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); if (GST_STATE (GST_ELEMENT (bvw->priv->play)) == GST_STATE_PLAYING) return TRUE; @@ -1656,7 +1724,7 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); if (bvw->priv->stream_length) return TRUE; @@ -1669,8 +1737,11 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); - + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); + + return FALSE; + +#if 0 switch (type) { case MEDIA_DVD: @@ -1682,17 +1753,18 @@ default: return FALSE; } +#endif } G_CONST_RETURN gchar ** bacon_video_widget_get_mrls (BaconVideoWidget * bvw, MediaType type) { - const gchar **mrls; - g_return_val_if_fail (bvw != NULL, NULL); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), NULL); - + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), NULL); + + return NULL; +#if 0 switch (type) { case MEDIA_DVD: @@ -1712,6 +1784,7 @@ default: return NULL; } +#endif } static void @@ -1719,41 +1792,50 @@ BaconVideoWidgetMetadataType type, GValue * value) { - const char *string = NULL; + char *string = NULL; + gboolean res = FALSE; g_value_init (value, G_TYPE_STRING); if (bvw->priv->play == NULL) { - g_value_set_string (value, ""); + g_value_set_string (value, NULL); return; } switch (type) { case BVW_INFO_TITLE: - string = g_hash_table_lookup (bvw->priv->metadata_hash, "title"); + res = gst_tag_list_get_string (bvw->priv->tagcache, + GST_TAG_TITLE, &string); break; case BVW_INFO_ARTIST: - string = g_hash_table_lookup (bvw->priv->metadata_hash, "artist"); + res = gst_tag_list_get_string (bvw->priv->tagcache, + GST_TAG_ARTIST, &string); break; case BVW_INFO_YEAR: - string = g_hash_table_lookup (bvw->priv->metadata_hash, "year"); + res = gst_tag_list_get_string (bvw->priv->tagcache, + GST_TAG_DATE, &string); break; case BVW_INFO_VIDEO_CODEC: - string = g_hash_table_lookup (bvw->priv->metadata_hash, "video-codec"); + res = gst_tag_list_get_string (bvw->priv->tagcache, + GST_TAG_VIDEO_CODEC, &string); break; case BVW_INFO_AUDIO_CODEC: - string = g_hash_table_lookup (bvw->priv->metadata_hash, "audio-codec"); + res = gst_tag_list_get_string (bvw->priv->tagcache, + GST_TAG_AUDIO_CODEC, &string); break; case BVW_INFO_CDINDEX: - string = NULL; + res = FALSE; break; default: g_assert_not_reached (); } - g_value_set_string (value, string); + if (res) + g_value_set_string (value, string); + else + g_value_set_string (value, NULL); return; } @@ -1785,7 +1867,10 @@ integer = bvw->priv->video_height; break; case BVW_INFO_FPS: - integer = 0; + if (bvw->priv->video_fps - (int)bvw->priv->video_fps >= 0.5) + integer = bvw->priv->video_fps + 1; + else + integer = bvw->priv->video_fps; break; case BVW_INFO_BITRATE: integer = 0; @@ -1820,7 +1905,7 @@ boolean = bvw->priv->media_has_video; break; case BVW_INFO_HAS_AUDIO: - boolean = TRUE; + boolean = bvw->priv->media_has_audio; break; default: g_assert_not_reached (); @@ -1838,7 +1923,7 @@ { g_return_if_fail (bvw != NULL); g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); - g_return_if_fail (GST_IS_PLAY (bvw->priv->play)); + g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play)); switch (type) { @@ -1873,7 +1958,7 @@ { g_return_val_if_fail (bvw != NULL, FALSE); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE); return FALSE; } @@ -1882,7 +1967,7 @@ { g_return_val_if_fail (bvw != NULL, NULL); g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL); - g_return_val_if_fail (GST_IS_PLAY (bvw->priv->play), NULL); + g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), NULL); return NULL; } @@ -1922,19 +2007,16 @@ bvw = BACON_VIDEO_WIDGET (g_object_new (bacon_video_widget_get_type (), NULL)); - bvw->priv->play = gst_play_new (err); - - if (*err != NULL) { + bvw->priv->play = gst_element_factory_make ("playbin", "play"); + if (!bvw->priv->play) { + g_set_error (err, bacon_video_widget_error_quark (), + 0, _("Failed to create a GStreamer play object")); + g_object_unref (G_OBJECT (bvw)); return NULL; } bvw->priv->media_device = g_strdup ("/dev/dvd"); - bvw->priv->metadata_hash = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - - bvw->priv->init_width = bvw->priv->init_height = 0; //FIXME @@ -1957,23 +2039,19 @@ return NULL; } - gst_play_set_video_sink (bvw->priv->play, video_sink); - gst_play_set_audio_sink (bvw->priv->play, audio_sink); + g_object_set (G_OBJECT (bvw->priv->play), "video-sink", + video_sink, NULL); + g_object_set (G_OBJECT (bvw->priv->play), "audio-sink", + audio_sink, NULL); bvw->priv->vis_plugins_list = NULL; - g_signal_connect (G_OBJECT (bvw->priv->play), - "have_video_size", (GtkSignalFunc) got_video_size, - (gpointer) bvw); - g_signal_connect (G_OBJECT (bvw->priv->play), "eos", (GtkSignalFunc) got_eos, (gpointer) bvw); - g_signal_connect (G_OBJECT (bvw->priv->play), "stream_length", - (GtkSignalFunc) got_stream_length, (gpointer) bvw); + g_signal_connect (G_OBJECT (bvw->priv->play), "state-change", + G_CALLBACK (state_change), (gpointer) bvw); g_signal_connect (G_OBJECT (bvw->priv->play), "found_tag", (GtkSignalFunc) got_found_tag, (gpointer) bvw); - g_signal_connect (G_OBJECT (bvw->priv->play), "time_tick", - (GtkSignalFunc) got_time_tick, (gpointer) bvw); g_signal_connect (G_OBJECT (bvw->priv->play), "error", (GtkSignalFunc) got_error, (gpointer) bvw); @@ -2015,11 +2093,15 @@ GstElement *element = NULL; GList *elements = NULL, *l_elements = NULL; - element = gst_bin_get_by_interface (GST_BIN (bvw->priv->play), + element = gst_bin_get_by_interface (GST_BIN (video_sink), GST_TYPE_X_OVERLAY); if (GST_IS_X_OVERLAY (element)) bvw->priv->xoverlay = GST_X_OVERLAY (element); - + + g_signal_connect (G_OBJECT (bvw->priv->xoverlay), + "desired-size-changed", G_CALLBACK (got_video_size), + (gpointer) bvw); + /* Get them all and prefer hardware one */ elements = gst_bin_get_all_by_interface (GST_BIN (bvw->priv->play), GST_TYPE_COLOR_BALANCE); @@ -2058,50 +2140,6 @@ { bvw->priv->balance = GST_COLOR_BALANCE (element); } - - /* Get them all and prefer software one */ - elements = gst_bin_get_all_by_interface (GST_BIN (bvw->priv->play), - GST_TYPE_MIXER); - l_elements = elements; - - /* We take the first one */ - if (elements && GST_IS_MIXER (elements->data)) - element = GST_ELEMENT (elements->data); - - while (elements) - { - GstElement *local_element = NULL; - GstMixerClass *m_class = NULL; - - if (elements->data && GST_IS_MIXER (elements->data)) - { - local_element = GST_ELEMENT (elements->data); - m_class = GST_MIXER_GET_CLASS (elements->data); - - /* If one of them is hardware type we use that one then */ - if (GST_MIXER_TYPE (m_class) == GST_MIXER_SOFTWARE) - { - element = local_element; - } - } - - elements = g_list_next (elements); - } - - if (l_elements) - g_list_free (l_elements); - - elements = l_elements = NULL; - - if (GST_IS_MIXER (element)) { - const GList *tracks; - bvw->priv->mixer = GST_MIXER (element); - tracks = gst_mixer_list_tracks (GST_MIXER (element)); - if (tracks) - bvw->priv->mixer_track = GST_MIXER_TRACK (tracks->data); - } - else - g_warning ("can't find any mixer element, no volume."); } return GTK_WIDGET (bvw); Index: totem/configure.in --- totem~totem-playbin/configure.in 2004-08-21 11:23:02.000000000 +0200 +++ totem/configure.in 2004-09-15 10:59:32.000000000 +0200 @@ -53,7 +53,7 @@ dnl start with 0.8 GST_MAJORMINOR=0.8 PKG_CHECK_MODULES(GST, \ - gstreamer-play-$GST_MAJORMINOR >= $GST_REQS \ + gstreamer-$GST_MAJORMINOR >= $GST_REQS \ gstreamer-gconf-$GST_MAJORMINOR >= $GST_REQS \ gstreamer-interfaces-$GST_MAJORMINOR >= $GST_REQS, HAVE_GSTREAMER=yes,HAVE_GSTREAMER=no) Index: totem/src/gststreaminfo.h --- totem~totem-playbin/src/gststreaminfo.h 2004-09-15 14:03:54.000000000 +0200 +++ totem/src/gststreaminfo.h 2004-09-15 14:00:22.000000000 +0200 @@ -0,0 +1,64 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_STREAMINFO_H__ +#define __GST_STREAMINFO_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_STREAM_INFO (gst_stream_info_get_type()) +#define GST_STREAM_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STREAM_INFO,GstStreamInfo)) +#define GST_STREAM_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STREAM_INFO,GstStreamInfoClass)) +#define GST_IS_STREAM_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STREAM_INFO)) +#define GST_IS_STREAM_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STREAM_INFO)) + +typedef struct _GstStreamInfo GstStreamInfo; +typedef struct _GstStreamInfoClass GstStreamInfoClass; + +typedef enum { + GST_STREAM_TYPE_UNKNOWN = 0, + GST_STREAM_TYPE_AUDIO = 1, + GST_STREAM_TYPE_VIDEO = 2, + GST_STREAM_TYPE_TEXT = 3, +} GstStreamType; + +struct _GstStreamInfo { + GObject parent; + + GstPad *pad; + GstStreamType type; + gchar *decoder; +}; + +struct _GstStreamInfoClass { + GObjectClass parent_class; +}; + +GType gst_stream_info_get_type (void); + +GstStreamInfo* gst_stream_info_new (GstPad *pad, GstStreamType type, gchar *decoder); + + +G_END_DECLS + +#endif /* __GST_STREAMINFO_H__ */ +