event: add construct and parse API for the new STREAM CONFIG event

codec data and stream headers don't belong into caps, since they
are not negotiated. We signal them using the STREAM CONFIG event
instead.
This commit is contained in:
Tim-Philipp Müller 2012-01-27 17:39:12 +00:00
parent 1969b94267
commit 75e17f0002
5 changed files with 308 additions and 3 deletions

View file

@ -84,6 +84,7 @@
#include "gstenumtypes.h"
#include "gstutils.h"
#include "gstquark.h"
#include "gstvalue.h"
GType _gst_event_type = 0;
@ -614,6 +615,213 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps)
GST_QUARK (CAPS)));
}
/**
* gst_event_new_stream_config:
* @flags: the stream config flags
*
* Create a new STREAM CONFIG event. The stream config event travels
* downstream synchronized with the buffer flow and contains stream
* configuration information for the stream, such as stream-headers
* or codec-data. It is optional and should be sent after the CAPS
* event.
*
* Returns: (transfer full): the new STREAM CONFIG event.
*/
GstEvent *
gst_event_new_stream_config (GstStreamConfigFlags flags)
{
GstEvent *event;
GST_CAT_INFO (GST_CAT_EVENT, "creating stream info event, flags=0x%x", flags);
event = gst_event_new_custom (GST_EVENT_STREAM_CONFIG,
gst_structure_new_id (GST_QUARK (EVENT_STREAM_CONFIG),
GST_QUARK (FLAGS), GST_TYPE_STREAM_CONFIG_FLAGS, flags, NULL));
return event;
}
/**
* gst_event_parse_stream_config:
* @event: The event to parse
* @flags: (out): a pointer to a variable to store the stream config flags
*
* Get the stream config flags from @event.
*/
void
gst_event_parse_stream_config (GstEvent * event, GstStreamConfigFlags * flags)
{
GstStructure *structure;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
structure = GST_EVENT_STRUCTURE (event);
if (G_LIKELY (flags != NULL)) {
*flags =
g_value_get_enum (gst_structure_id_get_value (structure,
GST_QUARK (FLAGS)));
}
}
/**
* gst_event_set_stream_config_codec_data:
* @event: a stream config event
* @buf: a #GstBuffer with codec data
*
* Set codec data on the stream info event to signal out of bound setup data
* to downstream elements. Unlike stream headers, codec data contains data
* that is required to interpret the data stream, but is not valid as-is
* inside the data stream and thus can't just be prepended to or inserted
* into the data stream.
*/
void
gst_event_set_stream_config_codec_data (GstEvent * event, GstBuffer * buf)
{
GstStructure *s;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
g_return_if_fail (GST_IS_BUFFER (buf) && gst_buffer_get_size (buf) > 0);
s = GST_EVENT_STRUCTURE (event);
gst_structure_id_set (s, GST_QUARK (CODEC_DATA), GST_TYPE_BUFFER, buf, NULL);
}
/**
* gst_event_set_stream_config_codec_data:
* @event: a stream config event
* @buf: (transfer none): location where to store the #GstBuffer with codec data
*
* Extracts the codec data buffer from the stream info event. Will store
* %NULL in @buf if the event contains no codec data. The buffer returned
* will remain valid as long as @event remains valid. The caller should
* acquire a referenceto to @buf if needed.
*/
void
gst_event_parse_stream_config_codec_data (GstEvent * event, GstBuffer ** buf)
{
const GValue *val;
GstStructure *s;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
g_return_if_fail (buf != NULL);
s = GST_EVENT_STRUCTURE (event);
val = gst_structure_id_get_value (s, GST_QUARK (CODEC_DATA));
if (val != NULL)
*buf = g_value_get_boxed (val);
else
*buf = NULL;
}
/**
* gst_event_add_stream_config_header:
* @event: a stream config event
* @buf: a #GstBuffer with stream header data
*
* Adds a stream header to the stream info event to signal stream headers to
* to downstream elements such as multifilesink, tcpserversink etc. Stream
* headers can be and should usually be prepended to the data stream at any
* point in the stream (which requires a streamable format), e.g. to a new
* client connecting, or when starting a new file segment. stream header
* buffers will all be used together in the order they were added to the
* stream config event. Stream headers are sent as buffers at the beginning
* of the data flow in addition to the stream config event. Elements that
* care about stream headers need to make sure that they don't insert or
* interpret these header buffers twice if they interpret them.
*/
void
gst_event_add_stream_config_header (GstEvent * event, GstBuffer * buf)
{
GstStructure *s;
GValue buf_val = { 0, };
GValue *val;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
g_return_if_fail (GST_IS_BUFFER (buf) && gst_buffer_get_size (buf) > 0);
g_value_init (&buf_val, GST_TYPE_BUFFER);
g_value_set_boxed (&buf_val, buf);
s = GST_EVENT_STRUCTURE (event);
val = (GValue *) gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
if (val == NULL) {
GValue new_array = { 0, };
g_value_init (&new_array, GST_TYPE_ARRAY);
gst_value_array_append_value (&new_array, &buf_val);
gst_structure_id_take_value (s, GST_QUARK (STREAM_HEADERS), &new_array);
} else {
gst_value_array_append_value (val, &buf_val);
}
g_value_unset (&buf_val);
}
/**
* gst_event_get_n_stream_config_headers:
* @event: a stream config event
*
* Extract the number of stream header buffers.
*
* Returns: the number of stream header buffers attached to the stream info
* @event.
*/
guint
gst_event_get_n_stream_config_headers (GstEvent * event)
{
const GValue *val;
GstStructure *s;
guint num = 0;
g_return_val_if_fail (GST_IS_EVENT (event), 0);
g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG, 0);
s = GST_EVENT_STRUCTURE (event);
val = gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
if (val != NULL)
num = gst_value_array_get_size (val);
return num;
}
/**
* gst_event_parse_nth_stream_config_header:
* @event: a stream config event
* @index: number of the stream header to retrieve
* @buf: location where to store the n-th stream header #GstBuffer
*
* Retrieves the n-th stream header buffer attached to the stream config
* event and stores it in @buf. Will store %NULL in @buf if there is no such
* stream header.
*/
void
gst_event_parse_nth_stream_config_header (GstEvent * event, guint index,
GstBuffer ** buf)
{
const GValue *val, *buf_val;
GstStructure *s;
GstBuffer *ret = NULL;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
g_return_if_fail (buf != NULL);
s = GST_EVENT_STRUCTURE (event);
val = gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
if (val != NULL) {
buf_val = gst_value_array_get_value (val, index);
if (buf_val != NULL)
ret = g_value_get_boxed (buf_val);
}
*buf = ret;
}
/**
* gst_event_new_segment:
* @segment: (transfer none): a #GstSegment

View file

@ -374,6 +374,17 @@ typedef enum {
GST_QOS_TYPE_THROTTLE = 2
} GstQOSType;
/**
* GstStreamConfigFlags:
* @GST_STREAM_CONFIG_FLAG_NONE: no flags set
*
* GstStreamConfigFlags are flags passed with the stream config event, see
* gst_event_new_stream_config().
*/
typedef enum {
GST_STREAM_CONFIG_FLAG_NONE = 0
} GstStreamConfigFlags;
/**
* GstEvent:
* @mini_object: the parent structure
@ -483,6 +494,23 @@ GstEvent * gst_event_new_eos (void) G_GNUC_MALLOC;
GstEvent * gst_event_new_caps (GstCaps *caps) G_GNUC_MALLOC;
void gst_event_parse_caps (GstEvent *event, GstCaps **caps);
/* Stream config */
GstEvent * gst_event_new_stream_config (GstStreamConfigFlags flags) G_GNUC_MALLOC;
void gst_event_parse_stream_config (GstEvent * event, GstStreamConfigFlags * flags);
void gst_event_set_stream_config_codec_data (GstEvent * event, GstBuffer * buf);
void gst_event_parse_stream_config_codec_data (GstEvent * event, GstBuffer ** buf);
void gst_event_add_stream_config_header (GstEvent * event, GstBuffer * buf);
guint gst_event_get_n_stream_config_headers (GstEvent * event);
void gst_event_parse_nth_stream_config_header (GstEvent * event, guint index, GstBuffer ** buf);
/* segment event */
GstEvent* gst_event_new_segment (const GstSegment *segment) G_GNUC_MALLOC;
void gst_event_parse_segment (GstEvent *event, const GstSegment **segment);

View file

@ -55,7 +55,8 @@ static const gchar *_quark_strings[] = {
"GstQueryAllocation", "need-pool", "meta", "pool", "GstEventCaps",
"GstEventReconfigure", "segment", "GstQueryScheduling", "pull-mode",
"allocator", "GstEventFlushStop", "options", "GstQueryAcceptCaps",
"result", "GstQueryCaps", "filter", "modes"
"result", "GstQueryCaps", "filter", "modes", "GstEventStreamConfig",
"codec-data", "stream-headers"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -158,8 +158,10 @@ typedef enum _GstQuarkId
GST_QUARK_QUERY_CAPS = 129,
GST_QUARK_FILTER = 130,
GST_QUARK_MODES = 131,
GST_QUARK_MAX = 132
GST_QUARK_EVENT_STREAM_CONFIG = 132,
GST_QUARK_CODEC_DATA = 133,
GST_QUARK_STREAM_HEADERS = 134,
GST_QUARK_MAX = 135
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];

View file

@ -91,6 +91,72 @@ GST_START_TEST (create_events)
gst_event_unref (event);
}
/* STREAM CONFIG */
{
GstStreamConfigFlags flags = 0x987654;
GstBuffer *buf, *cd, *sh1, *sh2;
gpointer dummy;
event = gst_event_new_stream_config (GST_STREAM_CONFIG_FLAG_NONE);
gst_event_parse_stream_config (event, &flags);
fail_unless_equals_int (flags, GST_STREAM_CONFIG_FLAG_NONE);
fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 0);
/* set buf to something random but guaranteed to be non-NULL */
buf = (GstBuffer *) & dummy;
gst_event_parse_stream_config_codec_data (event, &buf);
fail_unless (buf == NULL);
buf = (GstBuffer *) & dummy;
gst_event_parse_nth_stream_config_header (event, 0, &buf);
fail_unless (buf == NULL);
buf = (GstBuffer *) & dummy;
gst_event_parse_nth_stream_config_header (event, 98416, &buf);
fail_unless (buf == NULL);
ASSERT_CRITICAL (gst_event_set_stream_config_codec_data (event, NULL));
ASSERT_CRITICAL (gst_event_add_stream_config_header (event, NULL));
cd = gst_buffer_new_wrapped_full ((gpointer) "SetMeUpScottie", NULL, 0, 14);
gst_event_set_stream_config_codec_data (event, cd);
gst_buffer_unref (cd);
buf = (GstBuffer *) & dummy;
gst_event_parse_nth_stream_config_header (event, 0, &buf);
fail_unless (buf == NULL);
gst_event_parse_stream_config_codec_data (event, &buf);
fail_unless (buf == cd);
fail_unless (GST_IS_BUFFER (buf));
gst_event_unref (event);
event = gst_event_new_stream_config (GST_STREAM_CONFIG_FLAG_NONE);
fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 0);
sh1 = gst_buffer_new_wrapped_full ((gpointer) "Strea", NULL, 0, 5);
gst_event_add_stream_config_header (event, sh1);
gst_buffer_unref (sh1);
fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 1);
sh2 = gst_buffer_new_wrapped_full ((gpointer) "mHeader", NULL, 0, 7);
gst_event_add_stream_config_header (event, sh2);
gst_buffer_unref (sh2);
fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 2);
buf = (GstBuffer *) & dummy;
gst_event_parse_nth_stream_config_header (event, 1, &buf);
fail_unless (buf == sh2);
fail_unless (GST_IS_BUFFER (buf));
buf = (GstBuffer *) & dummy;
gst_event_parse_nth_stream_config_header (event, 0, &buf);
fail_unless (buf == sh1);
fail_unless (GST_IS_BUFFER (buf));
gst_event_unref (event);
}
/* TAGS */
{
GstTagList *taglist = gst_tag_list_new_empty ();