From aec03a453595d35c6e9523abdc37b552ed239d80 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 24 Nov 2008 20:25:24 +0000 Subject: [PATCH] gst/playback/gstplaybin2.c: Add notification of current stream. Add ability to configure buffer sizes. Original commit message from CVS: * gst/playback/gstplaybin2.c: Add notification of current stream. Add ability to configure buffer sizes. * gst/playback/gsturidecodebin.c: Add ability to configure buffer sizes for streaming mode. Bug #561734. --- ChangeLog | 9 ++ gst/playback/gstplaybin2.c | 145 ++++++++++++++++++++++++++++++++- gst/playback/gsturidecodebin.c | 48 +++++++++++ 3 files changed, 200 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54fbad2ecc..f951de45db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-11-24 Michael Smith + + * gst/playback/gstplaybin2.c: + Add notification of current stream. Add ability to configure buffer + sizes. + * gst/playback/gsturidecodebin.c: + Add ability to configure buffer sizes for streaming mode. + Bug #561734. + 2008-11-24 Stefan Kost * gst-libs/gst/audio/gstbaseaudiosink.c: diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 1b33f8224e..555745b43d 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -336,6 +336,9 @@ struct _GstPlayBin gint current_text; /* the currently selected stream */ gchar *encoding; /* subtitle encoding */ + guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */ + guint buffer_size; /* When buffering, the max buffer size (bytes) */ + /* our play sink */ GstPlaySink *playsink; @@ -393,6 +396,8 @@ struct _GstPlayBinClass #define DEFAULT_FRAME NULL #define DEFAULT_FONT_DESC NULL #define DEFAULT_CONNECTION_SPEED 0 +#define DEFAULT_BUFFER_DURATION -1 +#define DEFAULT_BUFFER_SIZE -1 enum { @@ -415,7 +420,9 @@ enum PROP_MUTE, PROP_FRAME, PROP_FONT_DESC, - PROP_CONNECTION_SPEED + PROP_CONNECTION_SPEED, + PROP_BUFFER_SIZE, + PROP_BUFFER_DURATION }; /* signals */ @@ -696,6 +703,18 @@ gst_play_bin_class_init (GstPlayBinClass * klass) "Network connection speed in kbps (0 = unknown)", 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE, + g_param_spec_int ("buffer-size", "Buffer size (bytes)", + "Buffer size when buffering network streams", + -1, G_MAXINT, DEFAULT_BUFFER_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION, + g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)", + "Buffer duration when buffering network streams", + -1, G_MAXINT64, DEFAULT_BUFFER_DURATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstPlayBin2::about-to-finish * @playbin: a #GstPlayBin2 @@ -955,6 +974,9 @@ gst_play_bin_init (GstPlayBin * playbin) playbin->current_video = DEFAULT_CURRENT_VIDEO; playbin->current_audio = DEFAULT_CURRENT_AUDIO; playbin->current_text = DEFAULT_CURRENT_TEXT; + + playbin->buffer_duration = DEFAULT_BUFFER_DURATION; + playbin->buffer_size = DEFAULT_BUFFER_SIZE; } static void @@ -1160,6 +1182,34 @@ gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps) return result; } +/* Returns current stream number, or -1 if none has been selected yet */ +static int +get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels) +{ + /* Internal API cleanup would make this easier... */ + int i; + GstPad *pad, *current; + GstObject *selector = NULL; + int ret = -1; + + for (i = 0; i < channels->len; i++) { + pad = g_ptr_array_index (channels, i); + if ((selector = gst_pad_get_parent (pad))) { + g_object_get (selector, "active-pad", ¤t, NULL); + + if (pad == current) { + ret = i; + break; + } + } + } + + if (selector) + gst_object_unref (selector); + + return ret; +} + static gboolean gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream) { @@ -1365,6 +1415,12 @@ gst_play_bin_set_property (GObject * object, guint prop_id, playbin->connection_speed = g_value_get_uint (value) * 1000; GST_PLAY_BIN_UNLOCK (playbin); break; + case PROP_BUFFER_SIZE: + playbin->buffer_size = g_value_get_int (value); + break; + case PROP_BUFFER_DURATION: + playbin->buffer_duration = g_value_get_int64 (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1496,6 +1552,16 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, g_value_set_uint (value, playbin->connection_speed / 1000); GST_PLAY_BIN_UNLOCK (playbin); break; + case PROP_BUFFER_SIZE: + GST_OBJECT_LOCK (playbin); + g_value_set_int (value, playbin->buffer_size); + GST_OBJECT_UNLOCK (playbin); + break; + case PROP_BUFFER_DURATION: + GST_OBJECT_LOCK (playbin); + g_value_set_int64 (value, playbin->buffer_duration); + GST_OBJECT_UNLOCK (playbin); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1529,6 +1595,51 @@ gst_play_bin_handle_message (GstBin * bin, GstMessage * msg) GST_BIN_CLASS (parent_class)->handle_message (bin, msg); } +static void +selector_active_pad_changed (GObject * selector, GParamSpec * pspec, + GstPlayBin * playbin) +{ + gchar *property; + GstSourceGroup *group; + GstSourceSelect *select = NULL; + int i; + + GST_PLAY_BIN_LOCK (playbin); + group = get_group (playbin); + + for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + if (selector == G_OBJECT (group->selector[i].selector)) { + select = &group->selector[i]; + } + } + + switch (select->type) { + case GST_PLAY_SINK_TYPE_VIDEO: + case GST_PLAY_SINK_TYPE_VIDEO_RAW: + property = "current-video"; + playbin->current_video = get_current_stream_number (playbin, + group->video_channels); + break; + case GST_PLAY_SINK_TYPE_AUDIO: + case GST_PLAY_SINK_TYPE_AUDIO_RAW: + property = "current-audio"; + playbin->current_audio = get_current_stream_number (playbin, + group->audio_channels); + break; + case GST_PLAY_SINK_TYPE_TEXT: + property = "current-text"; + playbin->current_text = get_current_stream_number (playbin, + group->text_channels); + break; + default: + property = NULL; + } + GST_PLAY_BIN_UNLOCK (playbin); + + if (property) + g_object_notify (G_OBJECT (playbin), property); +} + static void selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data) { @@ -1537,7 +1648,7 @@ selector_blocked (GstPad * pad, gboolean blocked, gpointer user_data) } /* this function is called when a new pad is added to decodebin. We check the - * type of the pad and add it to the selecter element of the group. + * type of the pad and add it to the selector element of the group. */ static void pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) @@ -1550,6 +1661,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) GstPadLinkReturn res; GstSourceSelect *select = NULL; gint i; + gboolean changed = FALSE; playbin = group->playbin; @@ -1581,6 +1693,9 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) if (select->selector == NULL) goto no_selector; + g_signal_connect (select->selector, "notify::active-pad", + G_CALLBACK (selector_active_pad_changed), playbin); + GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector); gst_bin_add (GST_BIN_CAST (playbin), select->selector); gst_element_set_state (select->selector, GST_STATE_PAUSED); @@ -1612,11 +1727,35 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) /* store selector pad so we can release it */ g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad); + + changed = TRUE; } GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p", GST_DEBUG_PAD_NAME (pad), select->selector); GST_SOURCE_GROUP_UNLOCK (group); + if (changed) { + int signal; + switch (select->type) { + case GST_PLAY_SINK_TYPE_VIDEO: + case GST_PLAY_SINK_TYPE_VIDEO_RAW: + signal = SIGNAL_VIDEO_CHANGED; + break; + case GST_PLAY_SINK_TYPE_AUDIO: + case GST_PLAY_SINK_TYPE_AUDIO_RAW: + signal = SIGNAL_AUDIO_CHANGED; + break; + case GST_PLAY_SINK_TYPE_TEXT: + signal = SIGNAL_TEXT_CHANGED; + break; + default: + signal = -1; + } + + if (signal >= 0) + g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL); + } + return; /* ERRORS */ @@ -1992,6 +2131,8 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group) g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL); /* configure uri */ g_object_set (uridecodebin, "uri", group->uri, NULL); + g_object_set (uridecodebin, "buffer-time", playbin->buffer_duration, NULL); + g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL); /* connect pads and other things */ g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb), diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index 2b59454318..e5ea264ba1 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -74,6 +74,9 @@ struct _GstURIDecodeBin gchar *encoding; gboolean is_stream; + guint64 buffer_duration; /* When streaming, buffer duration (ns) */ + guint buffer_size; /* When streaming, buffer size (bytes) */ + GstElement *source; GstElement *typefind; guint have_type_id; /* have-type signal id from typefind */ @@ -141,6 +144,8 @@ enum #define DEFAULT_CONNECTION_SPEED 0 #define DEFAULT_CAPS NULL #define DEFAULT_SUBTITLE_ENCODING NULL +#define DEFAULT_BUFFER_DURATION -1 +#define DEFAULT_BUFFER_SIZE -1 enum { @@ -150,6 +155,8 @@ enum PROP_CONNECTION_SPEED, PROP_CAPS, PROP_SUBTITLE_ENCODING, + PROP_BUFFER_SIZE, + PROP_BUFFER_DURATION, PROP_LAST }; @@ -289,6 +296,17 @@ gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass) "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE, + g_param_spec_int ("buffer-size", "Buffer size (bytes)", + "Buffer size when buffering network streams", + -1, G_MAXINT, DEFAULT_BUFFER_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BUFFER_DURATION, + g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)", + "Buffer duration when buffering network streams", + -1, G_MAXINT64, DEFAULT_BUFFER_DURATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstURIDecodeBin::unknown-type: * @pad: the new pad containing caps that cannot be resolved to a 'final' @@ -401,6 +419,9 @@ gst_uri_decode_bin_init (GstURIDecodeBin * dec, GstURIDecodeBinClass * klass) dec->connection_speed = DEFAULT_CONNECTION_SPEED; dec->caps = DEFAULT_CAPS; dec->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING); + + dec->buffer_duration = DEFAULT_BUFFER_DURATION; + dec->buffer_size = DEFAULT_BUFFER_SIZE; } static void @@ -465,6 +486,12 @@ gst_uri_decode_bin_set_property (GObject * object, guint prop_id, case PROP_SUBTITLE_ENCODING: gst_uri_decode_bin_set_encoding (dec, g_value_get_string (value)); break; + case PROP_BUFFER_SIZE: + dec->buffer_size = g_value_get_int (value); + break; + case PROP_BUFFER_DURATION: + dec->buffer_duration = g_value_get_int64 (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -503,6 +530,16 @@ gst_uri_decode_bin_get_property (GObject * object, guint prop_id, g_value_set_string (value, dec->encoding); GST_OBJECT_UNLOCK (dec); break; + case PROP_BUFFER_SIZE: + GST_OBJECT_LOCK (dec); + g_value_set_int (value, dec->buffer_size); + GST_OBJECT_UNLOCK (dec); + break; + case PROP_BUFFER_DURATION: + GST_OBJECT_LOCK (dec); + g_value_set_int64 (value, dec->buffer_duration); + GST_OBJECT_UNLOCK (dec); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1102,6 +1139,17 @@ type_found (GstElement * typefind, guint probability, g_object_set (G_OBJECT (queue), "use-buffering", TRUE, NULL); // g_object_set (G_OBJECT (queue), "temp-location", "temp", NULL); + /* Disable max-size-buffers */ + g_object_set (G_OBJECT (queue), "max-size-buffers", 0, NULL); + + /* If buffer size or duration are set, set them on the queue2 element */ + if (decoder->buffer_size != -1) + g_object_set (G_OBJECT (queue), "max-size-bytes", + decoder->buffer_size, NULL); + if (decoder->buffer_duration != -1) + g_object_set (G_OBJECT (queue), "max-size-time", + decoder->buffer_duration, NULL); + gst_bin_add (GST_BIN_CAST (decoder), queue); if (!gst_element_link (typefind, queue))