Commit 41954ff8 authored by Sebastian Dröge's avatar Sebastian Dröge

event: Add new stream-id field to the stream-start event

This is supposed to allow uniquely identifying a single stream.
parent ea761a24
......@@ -974,6 +974,7 @@ gst_event_new_gap
gst_event_parse_gap
gst_event_new_stream_start
gst_event_parse_stream_start
gst_event_new_segment
gst_event_parse_segment
......@@ -1786,6 +1787,8 @@ gst_pad_iterate_internal_links_default
gst_pad_set_element_private
gst_pad_get_element_private
gst_pad_create_stream_id
GstPadForwardFunction
gst_pad_forward
<SUBSECTION Core>
......
......@@ -1593,6 +1593,7 @@ gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg)
/**
* gst_event_new_stream_start:
* @stream_id: Identifier for this stream
*
* Create a new STREAM_START event. The stream start event can only
* travel downstream synchronized with the buffer flow. It is expected
......@@ -1605,12 +1606,48 @@ gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg)
* combining multiple streams must ensure that this event is only forwarded
* downstream once and not for every single input stream.
*
* The @stream_id should be a unique string that consists of the upstream
* stream-id, / as separator and a unique stream-id for this specific
* stream. A new stream-id should only be created for a stream if the upstream
* stream is split into (potentially) multiple new streams, e.g. in a demuxer,
* but not for every single element in the pipeline.
* gst_util_create_stream_id() can be used to create a stream-id.
*
* Returns: (transfer full): the new STREAM_START event.
*/
GstEvent *
gst_event_new_stream_start (void)
gst_event_new_stream_start (const gchar * stream_id)
{
GstStructure *s;
g_return_val_if_fail (stream_id != NULL, NULL);
s = gst_structure_new_id (GST_QUARK (EVENT_STREAM_START),
GST_QUARK (STREAM_ID), G_TYPE_STRING, stream_id, NULL);
return gst_event_new_custom (GST_EVENT_STREAM_START, s);
}
/**
* gst_event_parse_stream_start:
* @event: a stream-start event.
* @stream_id: (out): pointer to store the stream-id
*
* Parse a stream-id @event and store the result in the given @stream_id location.
*/
void
gst_event_parse_stream_start (GstEvent * event, const gchar ** stream_id)
{
return gst_event_new_custom (GST_EVENT_STREAM_START, NULL);
const GstStructure *structure;
g_return_if_fail (event != NULL);
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START);
structure = gst_event_get_structure (event);
if (stream_id)
gst_structure_id_get (structure,
GST_QUARK (STREAM_ID), G_TYPE_STRING, stream_id, NULL);
}
/**
......
......@@ -472,7 +472,8 @@ guint32 gst_event_get_seqnum (GstEvent *event);
void gst_event_set_seqnum (GstEvent *event, guint32 seqnum);
/* Stream start event */
GstEvent * gst_event_new_stream_start (void) G_GNUC_MALLOC;
GstEvent * gst_event_new_stream_start (const gchar *stream_id) G_GNUC_MALLOC;
void gst_event_parse_stream_start (GstEvent *event, const gchar **stream_id);
/* flush events */
GstEvent * gst_event_new_flush_start (void) G_GNUC_MALLOC;
......
......@@ -64,7 +64,8 @@ static const gchar *_quark_strings[] = {
"uid", "tags", "sub-entries", "info", "GstMessageTag", "GstEventTag",
"GstMessageResetTime",
"GstMessageToc", "GstEventTocGlobal", "GstEventTocCurrent",
"GstEventSegmentDone"
"GstEventSegmentDone",
"GstEventStreamStart", "stream-id"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -186,7 +186,9 @@ typedef enum _GstQuarkId
GST_QUARK_EVENT_TOC_GLOBAL = 157,
GST_QUARK_EVENT_TOC_CURRENT = 158,
GST_QUARK_EVENT_SEGMENT_DONE = 159,
GST_QUARK_MAX = 160
GST_QUARK_EVENT_STREAM_START = 160,
GST_QUARK_STREAM_ID = 161,
GST_QUARK_MAX = 162
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -3535,3 +3535,172 @@ gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d)
/* Should not happen because a_d and b_d are not 0 */
g_return_val_if_reached (0);
}
/** gst_pad_create_stream_id:
* @pad: A source #GstPad
* @parent: Parent #GstElement of @pad
* @stream_id: (allow-none): The stream-id
* @var_args: parameters for the @stream_id format string
*
* Creates a stream-id for the source #GstPad @pad by combining the
* upstream information with the optional @stream_id of the stream
* of @pad. @pad must have a parent #GstElement and which must have zero
* or one sinkpad. @stream_id can only be %NULL if the parent element
* of @pad has only a single source pad.
*
* This function generates an unique stream-id by getting the upstream
* stream-start event stream ID and appending @stream_id to it. If the
* element has no sinkpad it will generate an upstream stream-id by
* doing an URI query on the element and in the worst case just uses
* a random number. Source elements that don't implement the URI
* handler interface should ideally generate a unique, deterministic
* stream-id manually instead.
*
* Returns: A stream-id for @pad. g_free() after usage.
*/
gchar *
gst_pad_create_stream_id_printf_valist (GstPad * pad, GstElement * parent,
const gchar * stream_id, va_list var_args)
{
GstEvent *upstream_event;
gchar *upstream_stream_id = NULL, *new_stream_id;
GstPad *sinkpad;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
g_return_val_if_fail (parent->numsinkpads <= 1, NULL);
/* If the element has multiple source pads it must
* provide a stream-id for every source pad, otherwise
* all source pads will have the same and are not
* distinguishable */
g_return_val_if_fail (parent->numsrcpads == 1 || stream_id, NULL);
/* First try to get the upstream stream-start stream-id from the sinkpad.
* This will only work for non-source elements */
sinkpad = gst_element_get_static_pad (parent, "sink");
if (sinkpad) {
upstream_event =
gst_pad_get_sticky_event (sinkpad, GST_EVENT_STREAM_START, 0);
if (upstream_event) {
const gchar *tmp;
gst_event_parse_stream_start (upstream_event, &tmp);
if (tmp)
upstream_stream_id = g_strdup (tmp);
gst_event_unref (upstream_event);
}
gst_object_unref (sinkpad);
}
/* The only case where we don't have an upstream start-start event
* here is for source elements */
if (!upstream_stream_id) {
GstQuery *query;
/* Try to generate one from the URI query and
* if it fails take a random number instead */
query = gst_query_new_uri ();
if (gst_element_query (parent, query)) {
GChecksum *cs;
gchar *uri;
gst_query_parse_uri (query, &uri);
/* And then generate an SHA256 sum of the URI */
cs = g_checksum_new (G_CHECKSUM_SHA256);
g_checksum_update (cs, (const guchar *) uri, strlen (uri));
g_free (uri);
upstream_stream_id = g_strdup (g_checksum_get_string (cs));
g_checksum_free (cs);
} else {
/* Just get some random number if the URI query fails */
GST_WARNING_OBJECT (pad, "Creating random stream-id, consider "
"implementing a deterministic way of creating a stream-id");
upstream_stream_id =
g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
g_random_int (), g_random_int ());
}
gst_query_unref (query);
}
if (stream_id) {
gchar *expanded = g_strdup_vprintf (stream_id, var_args);
new_stream_id = g_strconcat (upstream_stream_id, "/", expanded, NULL);
g_free (expanded);
} else {
new_stream_id = g_strdup (upstream_stream_id);
}
g_free (upstream_stream_id);
return new_stream_id;
}
/** gst_pad_create_stream_id:
* @pad: A source #GstPad
* @parent: Parent #GstElement of @pad
* @stream_id: (allow-none): The stream-id
* @...: parameters for the @stream_id format string
*
* Creates a stream-id for the source #GstPad @pad by combining the
* upstream information with the optional @stream_id of the stream
* of @pad. @pad must have a parent #GstElement and which must have zero
* or one sinkpad. @stream_id can only be %NULL if the parent element
* of @pad has only a single source pad.
*
* This function generates an unique stream-id by getting the upstream
* stream-start event stream ID and appending @stream_id to it. If the
* element has no sinkpad it will generate an upstream stream-id by
* doing an URI query on the element and in the worst case just uses
* a random number. Source elements that don't implement the URI
* handler interface should ideally generate a unique, deterministic
* stream-id manually instead.
*
* Returns: A stream-id for @pad. g_free() after usage.
*/
gchar *
gst_pad_create_stream_id_printf (GstPad * pad, GstElement * parent,
const gchar * stream_id, ...)
{
va_list var_args;
gchar *new_stream_id;
va_start (var_args, stream_id);
new_stream_id =
gst_pad_create_stream_id_printf_valist (pad, parent, stream_id, var_args);
va_end (var_args);
return new_stream_id;
}
/** gst_pad_create_stream_id:
* @pad: A source #GstPad
* @parent: Parent #GstElement of @pad
* @stream_id: (allow-none): The stream-id
*
* Creates a stream-id for the source #GstPad @pad by combining the
* upstream information with the optional @stream_id of the stream
* of @pad. @pad must have a parent #GstElement and which must have zero
* or one sinkpad. @stream_id can only be %NULL if the parent element
* of @pad has only a single source pad.
*
* This function generates an unique stream-id by getting the upstream
* stream-start event stream ID and appending @stream_id to it. If the
* element has no sinkpad it will generate an upstream stream-id by
* doing an URI query on the element and in the worst case just uses
* a random number. Source elements that don't implement the URI
* handler interface should ideally generate a unique, deterministic
* stream-id manually instead.
*
* Returns: A stream-id for @pad. g_free() after usage.
*/
gchar *
gst_pad_create_stream_id (GstPad * pad, GstElement * parent,
const gchar * stream_id)
{
return gst_pad_create_stream_id_printf (pad, parent, stream_id, NULL);
}
......@@ -888,6 +888,10 @@ gboolean gst_pad_peer_query_convert (GstPad *pad, GstFormat
GstCaps * gst_pad_peer_query_caps (GstPad * pad, GstCaps *filter);
gboolean gst_pad_peer_query_accept_caps (GstPad * pad, GstCaps *caps);
gchar * gst_pad_create_stream_id (GstPad * pad, GstElement * parent, const gchar *stream_id);
gchar * gst_pad_create_stream_id_printf (GstPad * pad, GstElement * parent, const gchar *stream_id, ...);
gchar * gst_pad_create_stream_id_printf_valist (GstPad * pad, GstElement * parent, const gchar *stream_id, va_list var_args);
/* bin functions */
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...) G_GNUC_NULL_TERMINATED;
void gst_bin_remove_many (GstBin *bin, GstElement *element_1, ...) G_GNUC_NULL_TERMINATED;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment