#define GST_URI_DECODE_BIN_LOCK(dec) (g_mutex_lock(GST_URI_DECODE_BIN_GET_LOCK(dec)))
#define GST_URI_DECODE_BIN_UNLOCK(dec) (g_mutex_unlock(GST_URI_DECODE_BIN_GET_LOCK(dec)))
+typedef struct _GstURIDecodeBinStream
+{
+ gulong probe_id;
+ guint bitrate;
+} GstURIDecodeBinStream;
+
/**
* GstURIDecodeBin
*
guint have_type_id; /* have-type signal id from typefind */
GSList *decodebins;
GSList *pending_decodebins;
+ GHashTable *streams;
gint numpads;
/* for dynamic sources */
no_more_pads_full (element, FALSE, bin);
}
-/* Called by the signal handlers when a decodebin has
+static void
+configure_stream_buffering (GstURIDecodeBin * decoder)
+{
+ GstElement *queue = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+ gint bitrate = 0;
+
+ /* automatic configuration enabled ? */
+ if (decoder->buffer_size != -1)
+ return;
+
+ GST_URI_DECODE_BIN_LOCK (decoder);
+ if (decoder->queue)
+ queue = gst_object_ref (decoder->queue);
+
+ g_hash_table_iter_init (&iter, decoder->streams);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GstURIDecodeBinStream *stream = value;
+
+ if (stream->bitrate && bitrate >= 0)
+ bitrate += stream->bitrate;
+ else
+ bitrate = -1;
+ }
+ GST_URI_DECODE_BIN_UNLOCK (decoder);
+
+ GST_DEBUG_OBJECT (decoder, "overall bitrate %d", bitrate);
+ if (!queue)
+ return;
+
+ if (bitrate > 0) {
+ guint64 time;
+ guint bytes;
+
+ /* all streams have a bitrate;
+ * configure queue size based on queue duration using combined bitrate */
+ g_object_get (queue, "max-size-time", &time, NULL);
+ GST_DEBUG_OBJECT (decoder, "queue buffering time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (time));
+ if (time > 0) {
+ bytes = gst_util_uint64_scale (time, bitrate, 8 * GST_SECOND);
+ GST_DEBUG_OBJECT (decoder, "corresponds to buffer size %d", bytes);
+ g_object_set (queue, "max-size-bytes", bytes, NULL);
+ }
+ }
+
+ gst_object_unref (queue);
+}
+
+static gboolean
+decoded_pad_event_probe (GstPad * pad, GstEvent * event,
+ GstURIDecodeBin * decoder)
+{
+ GST_LOG_OBJECT (pad, "%s, decoder %p", GST_EVENT_TYPE_NAME (event), decoder);
+
+ /* look for a bitrate tag */
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ {
+ GstTagList *list;
+ guint bitrate = 0;
+ GstURIDecodeBinStream *stream;
+
+ gst_event_parse_tag (event, &list);
+ if (!gst_tag_list_get_uint_index (list, GST_TAG_NOMINAL_BITRATE, 0,
+ &bitrate)) {
+ gst_tag_list_get_uint_index (list, GST_TAG_BITRATE, 0, &bitrate);
+ }
+ GST_DEBUG_OBJECT (pad, "found bitrate %u", bitrate);
+ if (bitrate) {
+ GST_URI_DECODE_BIN_LOCK (decoder);
+ stream = g_hash_table_lookup (decoder->streams, pad);
+ GST_URI_DECODE_BIN_UNLOCK (decoder);
+ if (stream) {
+ stream->bitrate = bitrate;
+ /* no longer need this probe now */
+ gst_pad_remove_event_probe (pad, stream->probe_id);
+ /* configure buffer if possible */
+ configure_stream_buffering (decoder);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* never drop */
+ return TRUE;
+}
+
+/* Called by the signal handlers when a decodebin has
* found a new raw pad.
*/
static void
GstPad *newpad;
GstPadTemplate *pad_tmpl;
gchar *padname;
+ GstURIDecodeBinStream *stream;
GST_DEBUG_OBJECT (element, "new decoded pad, name: <%s>. Last: %d",
GST_PAD_NAME (pad), last);
/* store ref to the ghostpad so we can remove it */
g_object_set_data (G_OBJECT (pad), "uridecodebin.ghostpad", newpad);
+ /* add event probe to monitor tags */
+ stream = g_slice_alloc0 (sizeof (GstURIDecodeBinStream));
+ stream->probe_id =
+ gst_pad_add_event_probe (pad, G_CALLBACK (decoded_pad_event_probe),
+ decoder);
+ GST_URI_DECODE_BIN_LOCK (decoder);
+ g_hash_table_insert (decoder->streams, pad, stream);
+ GST_URI_DECODE_BIN_UNLOCK (decoder);
+
gst_pad_set_active (newpad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (decoder), newpad);
}
-
static gboolean
source_pad_event_probe (GstPad * pad, GstEvent * event,
GstURIDecodeBin * decoder)
}
}
+static void
+free_stream (gpointer value)
+{
+ g_slice_free (GstURIDecodeBinStream, value);
+}
+
/* remove source and all related elements */
static void
remove_source (GstURIDecodeBin * bin)
gst_bin_remove (GST_BIN_CAST (bin), bin->typefind);
bin->typefind = NULL;
}
+ if (bin->streams) {
+ g_hash_table_destroy (bin->streams);
+ bin->streams = NULL;
+ }
/* Don't loose the SOURCE flag */
GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE);
}
/* remove the old decoders now, if any */
remove_decoders (decoder, FALSE);
+ /* stream admin setup */
+ decoder->streams = g_hash_table_new_full (NULL, NULL, NULL, free_stream);
+
/* see if the source element emits raw audio/video all by itself,
* if so, we can create streams for the pads and be done with it.
* Also check that is has source pads, if not, we assume it will