X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstevent.c;h=f4bb816863e76472dc42ee663df5ced874b1e40d;hb=dac5966da6a0f53d0443dfa1ac239289028c415d;hp=2b88751d53179e19b2f9233b9e54fa41025c8a03;hpb=5cf8e689440493c51cfc94e178af94f25b04e526;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstevent.c b/gst/gstevent.c index 2b88751..f4bb816 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -17,12 +17,13 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** * SECTION:gstevent + * @title: GstEvent * @short_description: Structure describing events that are passed up and down * a pipeline * @see_also: #GstPad, #GstElement @@ -36,31 +37,29 @@ * elements will use gst_pad_send_event() or gst_pad_push_event(). * The event should be unreffed with gst_event_unref() if it has not been sent. * - * Events that have been received can be parsed with their respective + * Events that have been received can be parsed with their respective * gst_event_parse_*() functions. It is valid to pass %NULL for unwanted details. * * Events are passed between elements in parallel to the data stream. Some events * are serialized with buffers, others are not. Some events only travel downstream, - * others only upstream. Some events can travel both upstream and downstream. - * + * others only upstream. Some events can travel both upstream and downstream. + * * The events are used to signal special conditions in the datastream such as * EOS (end of stream) or the start of a new stream-segment. * Events are also used to flush the pipeline of any pending data. * - * Most of the event API is used inside plugins. Applications usually only - * construct and use seek events. + * Most of the event API is used inside plugins. Applications usually only + * construct and use seek events. * To do that gst_event_new_seek() is used to create a seek event. It takes - * the needed parameters to specity seeking time and mode. - * - * performing a seek on a pipeline - * + * the needed parameters to specify seeking time and mode. + * |[ * GstEvent *event; * gboolean result; * ... * // construct a seek event to play the media from second 2 to 5, flush * // the pipeline to decrease latency. - * event = gst_event_new_seek (1.0, - * GST_FORMAT_TIME, + * event = gst_event_new_seek (1.0, + * GST_FORMAT_TIME, * GST_SEEK_FLAG_FLUSH, * GST_SEEK_TYPE_SET, 2 * GST_SECOND, * GST_SEEK_TYPE_SET, 5 * GST_SECOND); @@ -69,10 +68,7 @@ * if (!result) * g_warning ("seek failed"); * ... - * - * - * - * Last reviewed on 2006-09-6 (0.10.10) + * ]| */ @@ -84,6 +80,7 @@ #include "gstenumtypes.h" #include "gstutils.h" #include "gstquark.h" +#include "gstvalue.h" GType _gst_event_type = 0; @@ -92,6 +89,7 @@ typedef struct GstEvent event; GstStructure *structure; + gint64 running_time_offset; } GstEventImpl; #define GST_EVENT_STRUCTURE(e) (((GstEventImpl *)(e))->structure) @@ -107,33 +105,45 @@ static GstEventQuarks event_quarks[] = { {GST_EVENT_UNKNOWN, "unknown", 0}, {GST_EVENT_FLUSH_START, "flush-start", 0}, {GST_EVENT_FLUSH_STOP, "flush-stop", 0}, - {GST_EVENT_EOS, "eos", 0}, + {GST_EVENT_SELECT_STREAMS, "select-streams", 0}, + {GST_EVENT_STREAM_START, "stream-start", 0}, + {GST_EVENT_STREAM_COLLECTION, "stream-collection", 0}, {GST_EVENT_CAPS, "caps", 0}, {GST_EVENT_SEGMENT, "segment", 0}, {GST_EVENT_TAG, "tag", 0}, + {GST_EVENT_TOC, "toc", 0}, + {GST_EVENT_PROTECTION, "protection", 0}, {GST_EVENT_BUFFERSIZE, "buffersize", 0}, {GST_EVENT_SINK_MESSAGE, "sink-message", 0}, + {GST_EVENT_EOS, "eos", 0}, + {GST_EVENT_SEGMENT_DONE, "segment-done", 0}, + {GST_EVENT_GAP, "gap", 0}, {GST_EVENT_QOS, "qos", 0}, {GST_EVENT_SEEK, "seek", 0}, {GST_EVENT_NAVIGATION, "navigation", 0}, {GST_EVENT_LATENCY, "latency", 0}, {GST_EVENT_STEP, "step", 0}, {GST_EVENT_RECONFIGURE, "reconfigure", 0}, + {GST_EVENT_TOC_SELECT, "toc-select", 0}, {GST_EVENT_CUSTOM_UPSTREAM, "custom-upstream", 0}, {GST_EVENT_CUSTOM_DOWNSTREAM, "custom-downstream", 0}, {GST_EVENT_CUSTOM_DOWNSTREAM_OOB, "custom-downstream-oob", 0}, + {GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, "custom-downstream-sticky", 0}, {GST_EVENT_CUSTOM_BOTH, "custom-both", 0}, {GST_EVENT_CUSTOM_BOTH_OOB, "custom-both-oob", 0}, + {GST_EVENT_STREAM_GROUP_DONE, "stream-group-done", 0}, {0, NULL, 0} }; +GST_DEFINE_MINI_OBJECT_TYPE (GstEvent, gst_event); + void -_gst_event_initialize (void) +_priv_gst_event_initialize (void) { gint i; - _gst_event_type = gst_mini_object_register ("GstEvent"); + _gst_event_type = gst_event_get_type (); g_type_class_ref (gst_seek_flags_get_type ()); g_type_class_ref (gst_seek_type_get_type ()); @@ -196,7 +206,7 @@ gst_event_type_get_flags (GstEventType type) { GstEventTypeFlags ret; - ret = type & ((1 << GST_EVENT_STICKY_SHIFT) - 1); + ret = type & ((1 << GST_EVENT_NUM_SHIFT) - 1); return ret; } @@ -218,12 +228,14 @@ _gst_event_free (GstEvent * event) gst_structure_set_parent_refcount (s, NULL); gst_structure_free (s); } +#ifdef USE_POISONING + memset (event, 0xff, sizeof (GstEventImpl)); +#endif - g_slice_free1 (GST_MINI_OBJECT_SIZE (event), event); + g_slice_free1 (sizeof (GstEventImpl), event); } -static void gst_event_init (GstEventImpl * event, gsize size, - GstEventType type); +static void gst_event_init (GstEventImpl * event, GstEventType type); static GstEvent * _gst_event_copy (GstEvent * event) @@ -233,7 +245,7 @@ _gst_event_copy (GstEvent * event) copy = g_slice_new0 (GstEventImpl); - gst_event_init (copy, sizeof (GstEventImpl), GST_EVENT_TYPE (event)); + gst_event_init (copy, GST_EVENT_TYPE (event)); GST_EVENT_TIMESTAMP (copy) = GST_EVENT_TIMESTAMP (event); GST_EVENT_SEQNUM (copy) = GST_EVENT_SEQNUM (event); @@ -243,37 +255,29 @@ _gst_event_copy (GstEvent * event) GST_EVENT_STRUCTURE (copy) = gst_structure_copy (s); gst_structure_set_parent_refcount (GST_EVENT_STRUCTURE (copy), ©->event.mini_object.refcount); + } else { + GST_EVENT_STRUCTURE (copy) = NULL; } + + ((GstEventImpl *) copy)->running_time_offset = + ((GstEventImpl *) event)->running_time_offset; + return GST_EVENT_CAST (copy); } static void -gst_event_init (GstEventImpl * event, gsize size, GstEventType type) +gst_event_init (GstEventImpl * event, GstEventType type) { - gst_mini_object_init (GST_MINI_OBJECT_CAST (event), _gst_event_type, size); - - event->event.mini_object.copy = (GstMiniObjectCopyFunction) _gst_event_copy; - event->event.mini_object.free = (GstMiniObjectFreeFunction) _gst_event_free; + gst_mini_object_init (GST_MINI_OBJECT_CAST (event), 0, _gst_event_type, + (GstMiniObjectCopyFunction) _gst_event_copy, NULL, + (GstMiniObjectFreeFunction) _gst_event_free); GST_EVENT_TYPE (event) = type; GST_EVENT_TIMESTAMP (event) = GST_CLOCK_TIME_NONE; GST_EVENT_SEQNUM (event) = gst_util_seqnum_next (); + event->running_time_offset = 0; } -static GstEvent * -gst_event_new (GstEventType type) -{ - GstEventImpl *event; - - event = g_slice_new0 (GstEventImpl); - - GST_CAT_DEBUG (GST_CAT_EVENT, "creating new event %p %s %d", event, - gst_event_type_get_name (type), type); - - gst_event_init (event, sizeof (GstEventImpl), type); - - return GST_EVENT_CAST (event); -} /** * gst_event_new_custom: @@ -292,28 +296,35 @@ gst_event_new (GstEventType type) * New custom events can also be created by subclassing the event type if * needed. * - * Returns: (transfer full): the new custom event. + * Returns: (transfer full) (nullable): the new custom event. */ GstEvent * gst_event_new_custom (GstEventType type, GstStructure * structure) { - GstEvent *event; + GstEventImpl *event; + + event = g_slice_new0 (GstEventImpl); + + GST_CAT_DEBUG (GST_CAT_EVENT, "creating new event %p %s %d", event, + gst_event_type_get_name (type), type); - /* structure must not have a parent */ - event = gst_event_new (type); if (structure) { + /* structure must not have a parent */ if (!gst_structure_set_parent_refcount (structure, - &event->mini_object.refcount)) + &event->event.mini_object.refcount)) goto had_parent; - GST_EVENT_STRUCTURE (event) = structure; } - return event; + gst_event_init (event, type); + + GST_EVENT_STRUCTURE (event) = structure; + + return GST_EVENT_CAST (event); /* ERRORS */ had_parent: { - gst_event_unref (event); + g_slice_free1 (sizeof (GstEventImpl), event); g_warning ("structure is already owned by another object"); return NULL; } @@ -325,9 +336,9 @@ had_parent: * * Access the structure of the event. * - * Returns: The structure of the event. The structure is still - * owned by the event, which means that you should not free it and - * that the pointer becomes invalid when you free the event. + * Returns: (transfer none) (nullable): The structure of the event. The + * structure is still owned by the event, which means that you should not free + * it and that the pointer becomes invalid when you free the event. * * MT safe. */ @@ -345,10 +356,11 @@ gst_event_get_structure (GstEvent * event) * * Get a writable version of the structure. * - * Returns: The structure of the event. The structure is still - * owned by the event, which means that you should not free it and - * that the pointer becomes invalid when you free the event. - * This function checks if @event is writable and will never return NULL. + * Returns: (transfer none): The structure of the event. The structure + * is still owned by the event, which means that you should not free + * it and that the pointer becomes invalid when you free the event. + * This function checks if @event is writable and will never return + * %NULL. * * MT safe. */ @@ -364,7 +376,7 @@ gst_event_writable_structure (GstEvent * event) if (structure == NULL) { structure = - gst_structure_id_empty_new (gst_event_type_to_quark (GST_EVENT_TYPE + gst_structure_new_id_empty (gst_event_type_to_quark (GST_EVENT_TYPE (event))); gst_structure_set_parent_refcount (structure, &event->mini_object.refcount); GST_EVENT_STRUCTURE (event) = structure; @@ -381,8 +393,6 @@ gst_event_writable_structure (GstEvent * event) * check the name of a custom event. * * Returns: %TRUE if @name matches the name of the event structure. - * - * Since: 0.10.20 */ gboolean gst_event_has_name (GstEvent * event, const gchar * name) @@ -415,8 +425,6 @@ gst_event_has_name (GstEvent * event, const gchar * name) * Returns: The event's sequence number. * * MT safe. - * - * Since: 0.10.22 */ guint32 gst_event_get_seqnum (GstEvent * event) @@ -438,20 +446,65 @@ gst_event_get_seqnum (GstEvent * event) * more information. * * MT safe. - * - * Since: 0.10.22 */ void gst_event_set_seqnum (GstEvent * event, guint32 seqnum) { g_return_if_fail (GST_IS_EVENT (event)); + g_return_if_fail (seqnum != GST_SEQNUM_INVALID); + g_return_if_fail (gst_event_is_writable (event)); GST_EVENT_SEQNUM (event) = seqnum; } -/* FIXME 0.11: It would be nice to have flush events - * that don't reset the running time in the sinks +/** + * gst_event_get_running_time_offset: + * @event: A #GstEvent. + * + * Retrieve the accumulated running time offset of the event. + * + * Events passing through #GstPads that have a running time + * offset set via gst_pad_set_offset() will get their offset + * adjusted according to the pad's offset. + * + * If the event contains any information that related to the + * running time, this information will need to be updated + * before usage with this offset. + * + * Returns: The event's running time offset + * + * MT safe. + * + * Since: 1.4 + */ +gint64 +gst_event_get_running_time_offset (GstEvent * event) +{ + g_return_val_if_fail (GST_IS_EVENT (event), 0); + + return ((GstEventImpl *) event)->running_time_offset; +} + +/** + * gst_event_set_running_time_offset: + * @event: A #GstEvent. + * @offset: A the new running time offset + * + * Set the running time offset of a event. See + * gst_event_get_running_time_offset() for more information. + * + * MT safe. + * + * Since: 1.4 */ +void +gst_event_set_running_time_offset (GstEvent * event, gint64 offset) +{ + g_return_if_fail (GST_IS_EVENT (event)); + g_return_if_fail (gst_event_is_writable (event)); + + ((GstEventImpl *) event)->running_time_offset = offset; +} /** * gst_event_new_flush_start: @@ -460,9 +513,9 @@ gst_event_set_seqnum (GstEvent * event, guint32 seqnum) * upstream and downstream and travels out-of-bounds with the dataflow. * * It marks pads as being flushing and will make them return - * #GST_FLOW_WRONG_STATE when used for data flow with gst_pad_push(), - * gst_pad_chain(), gst_pad_alloc_buffer(), gst_pad_get_range() and - * gst_pad_pull_range(). Any event (except a #GST_EVENT_FLUSH_STOP) received + * #GST_FLOW_FLUSHING when used for data flow with gst_pad_push(), + * gst_pad_chain(), gst_pad_get_range() and gst_pad_pull_range(). + * Any event (except a #GST_EVENT_FLUSH_STOP) received * on a flushing pad will return %FALSE immediately. * * Elements should unlock any blocking functions and exit their streaming @@ -476,7 +529,7 @@ gst_event_set_seqnum (GstEvent * event, guint32 seqnum) GstEvent * gst_event_new_flush_start (void) { - return gst_event_new (GST_EVENT_FLUSH_START); + return gst_event_new_custom (GST_EVENT_FLUSH_START, NULL); } /** @@ -489,7 +542,7 @@ gst_event_new_flush_start (void) * pads accept data again. * * Elements can process this event synchronized with the dataflow since - * the preceeding FLUSH_START event stopped the dataflow. + * the preceding FLUSH_START event stopped the dataflow. * * This event is typically generated to complete a seek and to resume * dataflow. @@ -504,7 +557,7 @@ gst_event_new_flush_stop (gboolean reset_time) GST_CAT_INFO (GST_CAT_EVENT, "creating flush stop %d", reset_time); event = gst_event_new_custom (GST_EVENT_FLUSH_STOP, - gst_structure_id_new (GST_QUARK (EVENT_FLUSH_STOP), + gst_structure_new_id (GST_QUARK (EVENT_FLUSH_STOP), GST_QUARK (RESET_TIME), G_TYPE_BOOLEAN, reset_time, NULL)); return event; @@ -533,11 +586,142 @@ gst_event_parse_flush_stop (GstEvent * event, gboolean * reset_time) } /** + * gst_event_new_select_streams: + * @streams: (element-type utf8) (transfer none): the list of streams to + * activate + * + * Allocate a new select-streams event. + * + * The select-streams event requests the specified @streams to be activated. + * + * The list of @streams corresponds to the "Stream ID" of each stream to be + * activated. Those ID can be obtained via the #GstStream objects present + * in #GST_EVENT_STREAM_START, #GST_EVENT_STREAM_COLLECTION or + * #GST_MESSAGE_STREAM_COLLECTION. + * + * Note: The list of @streams can not be empty. + * + * Returns: (transfer full): a new select-streams event or %NULL in case of + * an error (like an empty streams list). + * + * Since: 1.10 + */ +GstEvent * +gst_event_new_select_streams (GList * streams) +{ + GstEvent *event; + GValue val = G_VALUE_INIT; + GstStructure *struc; + GList *tmpl; + + g_return_val_if_fail (streams != NULL, NULL); + + GST_CAT_INFO (GST_CAT_EVENT, "Creating new select-streams event"); + struc = gst_structure_new_id_empty (GST_QUARK (EVENT_SELECT_STREAMS)); + g_value_init (&val, GST_TYPE_LIST); + /* Fill struc with streams */ + for (tmpl = streams; tmpl; tmpl = tmpl->next) { + GValue strval = G_VALUE_INIT; + const gchar *str = (const gchar *) tmpl->data; + g_value_init (&strval, G_TYPE_STRING); + g_value_set_string (&strval, str); + gst_value_list_append_and_take_value (&val, &strval); + } + gst_structure_id_take_value (struc, GST_QUARK (STREAMS), &val); + event = gst_event_new_custom (GST_EVENT_SELECT_STREAMS, struc); + + return event; +} + +/** + * gst_event_parse_select_streams: + * @event: The event to parse + * @streams: (out) (element-type utf8) (transfer full): the streams + * + * Parse the SELECT_STREAMS event and retrieve the contained streams. + * + * Since: 1.10 + */ +void +gst_event_parse_select_streams (GstEvent * event, GList ** streams) +{ + GstStructure *structure; + GList *res = NULL; + + g_return_if_fail (GST_IS_EVENT (event)); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS); + + structure = GST_EVENT_STRUCTURE (event); + if (G_LIKELY (streams)) { + const GValue *vlist = + gst_structure_id_get_value (structure, GST_QUARK (STREAMS)); + guint i, sz = gst_value_list_get_size (vlist); + for (i = 0; i < sz; i++) { + const GValue *strv = gst_value_list_get_value (vlist, i); + res = g_list_append (res, g_value_dup_string (strv)); + } + *streams = res; + } +} + + +/** + * gst_event_new_stream_group_done: + * @group_id: the group id of the stream group which is ending + * + * Create a new Stream Group Done event. The stream-group-done event can + * only travel downstream synchronized with the buffer flow. Elements + * that receive the event on a pad should handle it mostly like EOS, + * and emit any data or pending buffers that would depend on more data + * arriving and unblock, since there won't be any more data. + * + * This event is followed by EOS at some point in the future, and is + * generally used when switching pads - to unblock downstream so that + * new pads can be exposed before sending EOS on the existing pads. + * + * Returns: (transfer full): the new stream-group-done event. + * + * Since: 1.10 + */ +GstEvent * +gst_event_new_stream_group_done (guint group_id) +{ + GstStructure *s; + + s = gst_structure_new_id (GST_QUARK (EVENT_STREAM_GROUP_DONE), + GST_QUARK (GROUP_ID), G_TYPE_UINT, group_id, NULL); + + return gst_event_new_custom (GST_EVENT_STREAM_GROUP_DONE, s); +} + +/** + * gst_event_parse_stream_group_done: + * @event: a stream-group-done event. + * @group_id: (out): address of variable to store the group id into + * + * Parse a stream-group-done @event and store the result in the given + * @group_id location. + * + * Since: 1.10 + */ +void +gst_event_parse_stream_group_done (GstEvent * event, guint * group_id) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_GROUP_DONE); + + if (group_id) { + gst_structure_id_get (GST_EVENT_STRUCTURE (event), + GST_QUARK (GROUP_ID), G_TYPE_UINT, group_id, NULL); + } +} + +/** * gst_event_new_eos: * * Create a new EOS event. The eos event can only travel downstream * synchronized with the buffer flow. Elements that receive the EOS - * event on a pad can return #GST_FLOW_UNEXPECTED as a #GstFlowReturn + * event on a pad can return #GST_FLOW_EOS as a #GstFlowReturn * when data after the EOS event arrives. * * The EOS event will travel down to the sink elements in the pipeline @@ -554,18 +738,76 @@ gst_event_parse_flush_stop (GstEvent * event, gboolean * reset_time) GstEvent * gst_event_new_eos (void) { - return gst_event_new (GST_EVENT_EOS); + return gst_event_new_custom (GST_EVENT_EOS, NULL); +} + +/** + * gst_event_new_gap: + * @timestamp: the start time (pts) of the gap + * @duration: the duration of the gap + * + * Create a new GAP event. A gap event can be thought of as conceptually + * equivalent to a buffer to signal that there is no data for a certain + * amount of time. This is useful to signal a gap to downstream elements + * which may wait for data, such as muxers or mixers or overlays, especially + * for sparse streams such as subtitle streams. + * + * Returns: (transfer full): the new GAP event. + */ +GstEvent * +gst_event_new_gap (GstClockTime timestamp, GstClockTime duration) +{ + GstEvent *event; + + g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); + + GST_CAT_TRACE (GST_CAT_EVENT, "creating gap %" GST_TIME_FORMAT " - " + "%" GST_TIME_FORMAT " (duration: %" GST_TIME_FORMAT ")", + GST_TIME_ARGS (timestamp), GST_TIME_ARGS (timestamp + duration), + GST_TIME_ARGS (duration)); + + event = gst_event_new_custom (GST_EVENT_GAP, + gst_structure_new_id (GST_QUARK (EVENT_GAP), + GST_QUARK (TIMESTAMP), GST_TYPE_CLOCK_TIME, timestamp, + GST_QUARK (DURATION), GST_TYPE_CLOCK_TIME, duration, NULL)); + + return event; +} + +/** + * gst_event_parse_gap: + * @event: a #GstEvent of type #GST_EVENT_GAP + * @timestamp: (out) (allow-none): location where to store the + * start time (pts) of the gap, or %NULL + * @duration: (out) (allow-none): location where to store the duration of + * the gap, or %NULL + * + * Extract timestamp and duration from a new GAP event. + */ +void +gst_event_parse_gap (GstEvent * event, GstClockTime * timestamp, + GstClockTime * duration) +{ + GstStructure *structure; + + g_return_if_fail (GST_IS_EVENT (event)); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_GAP); + + structure = GST_EVENT_STRUCTURE (event); + gst_structure_id_get (structure, + GST_QUARK (TIMESTAMP), GST_TYPE_CLOCK_TIME, timestamp, + GST_QUARK (DURATION), GST_TYPE_CLOCK_TIME, duration, NULL); } /** * gst_event_new_caps: - * @caps: a #GstCaps + * @caps: (transfer none): a #GstCaps * * Create a new CAPS event for @caps. The caps event can only travel downstream * synchronized with the buffer flow and contains the format of the buffers * that will follow after the event. * - * Returns: (transfer full): the new CAPS event. + * Returns: (transfer full) (nullable): the new CAPS event. */ GstEvent * gst_event_new_caps (GstCaps * caps) @@ -578,7 +820,7 @@ gst_event_new_caps (GstCaps * caps) GST_CAT_INFO (GST_CAT_EVENT, "creating caps event %" GST_PTR_FORMAT, caps); event = gst_event_new_custom (GST_EVENT_CAPS, - gst_structure_id_new (GST_QUARK (EVENT_CAPS), + gst_structure_new_id (GST_QUARK (EVENT_CAPS), GST_QUARK (CAPS), GST_TYPE_CAPS, caps, NULL)); return event; @@ -587,7 +829,7 @@ gst_event_new_caps (GstCaps * caps) /** * gst_event_parse_caps: * @event: The event to parse - * @caps: (out): A pointer to the caps + * @caps: (out) (transfer none): A pointer to the caps * * Get the caps from @event. The caps remains valid as long as @event remains * valid. @@ -609,13 +851,13 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps) /** * gst_event_new_segment: - * @segment: a #GstSegment + * @segment: (transfer none): a #GstSegment * * Create a new SEGMENT event for @segment. The segment event can only travel * downstream synchronized with the buffer flow and contains timing information * and playback properties for the buffers that will follow. * - * The newsegment event marks the range of buffers to be processed. All + * The segment event marks the range of buffers to be processed. All * data not within the segment range is not to be processed. This can be * used intelligently by plugins to apply more efficient methods of skipping * unneeded data. The valid range is expressed with the @start and @stop @@ -636,27 +878,30 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps) * stream. (@rate * @applied_rate) should always equal the rate that has been * requested for playback. For example, if an element has an input segment * with intended playback @rate of 2.0 and applied_rate of 1.0, it can adjust - * incoming timestamps and buffer content by half and output a newsegment event + * incoming timestamps and buffer content by half and output a segment event * with @rate of 1.0 and @applied_rate of 2.0 * - * After a newsegment event, the buffer stream time is calculated with: + * After a segment event, the buffer stream time is calculated with: * * time + (TIMESTAMP(buf) - start) * ABS (rate * applied_rate) * - * Returns: (transfer full): the new SEGMENT event. + * Returns: (transfer full) (nullable): the new SEGMENT event. */ GstEvent * -gst_event_new_segment (GstSegment * segment) +gst_event_new_segment (const GstSegment * segment) { GstEvent *event; g_return_val_if_fail (segment != NULL, NULL); + g_return_val_if_fail (segment->rate != 0.0, NULL); + g_return_val_if_fail (segment->applied_rate != 0.0, NULL); + g_return_val_if_fail (segment->format != GST_FORMAT_UNDEFINED, NULL); GST_CAT_INFO (GST_CAT_EVENT, "creating segment event %" GST_SEGMENT_FORMAT, segment); event = gst_event_new_custom (GST_EVENT_SEGMENT, - gst_structure_id_new (GST_QUARK (EVENT_SEGMENT), + gst_structure_new_id (GST_QUARK (EVENT_SEGMENT), GST_QUARK (SEGMENT), GST_TYPE_SEGMENT, segment, NULL)); return event; @@ -715,14 +960,28 @@ gst_event_copy_segment (GstEvent * event, GstSegment * segment) * * Generates a metadata tag event from the given @taglist. * + * The scope of the taglist specifies if the taglist applies to the + * complete medium or only to this specific stream. As the tag event + * is a sticky event, elements should merge tags received from + * upstream with a given scope with their own tags with the same + * scope and create a new tag event from it. + * * Returns: (transfer full): a new #GstEvent */ GstEvent * gst_event_new_tag (GstTagList * taglist) { + GstStructure *s; + GValue val = G_VALUE_INIT; + const gchar *names[] = { "GstTagList-stream", "GstTagList-global" }; + g_return_val_if_fail (taglist != NULL, NULL); - return gst_event_new_custom (GST_EVENT_TAG, (GstStructure *) taglist); + s = gst_structure_new_empty (names[gst_tag_list_get_scope (taglist)]); + g_value_init (&val, GST_TYPE_TAG_LIST); + g_value_take_boxed (&val, taglist); + gst_structure_id_take_value (s, GST_QUARK (TAGLIST), &val); + return gst_event_new_custom (GST_EVENT_TAG, s); } /** @@ -738,11 +997,16 @@ gst_event_new_tag (GstTagList * taglist) void gst_event_parse_tag (GstEvent * event, GstTagList ** taglist) { + const GValue *val; + g_return_if_fail (GST_IS_EVENT (event)); g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG); + val = gst_structure_id_get_value (GST_EVENT_STRUCTURE (event), + GST_QUARK (TAGLIST)); + if (taglist) - *taglist = (GstTagList *) GST_EVENT_STRUCTURE (event); + *taglist = (GstTagList *) g_value_get_boxed (val); } /* buffersize event */ @@ -756,7 +1020,7 @@ gst_event_parse_tag (GstEvent * event, GstTagList ** taglist) * Create a new buffersize event. The event is sent downstream and notifies * elements that they should provide a buffer of the specified dimensions. * - * When the @async flag is set, a thread boundary is prefered. + * When the @async flag is set, a thread boundary is preferred. * * Returns: (transfer full): a new #GstEvent */ @@ -772,7 +1036,7 @@ gst_event_new_buffer_size (GstFormat format, gint64 minsize, ", maxsize %" G_GINT64_FORMAT ", async %d", gst_format_get_name (format), minsize, maxsize, async); - structure = gst_structure_id_new (GST_QUARK (EVENT_BUFFER_SIZE), + structure = gst_structure_new_id (GST_QUARK (EVENT_BUFFER_SIZE), GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (MINSIZE), G_TYPE_INT64, minsize, GST_QUARK (MAXSIZE), G_TYPE_INT64, maxsize, @@ -837,7 +1101,7 @@ gst_event_parse_buffer_size (GstEvent * event, GstFormat * format, * @type indicates the reason for the QoS event. #GST_QOS_TYPE_OVERFLOW is * used when a buffer arrived in time or when the sink cannot keep up with * the upstream datarate. #GST_QOS_TYPE_UNDERFLOW is when the sink is not - * receiving buffers fast enough and thus has to drop late buffers. + * receiving buffers fast enough and thus has to drop late buffers. * #GST_QOS_TYPE_THROTTLE is used when the datarate is artificially limited * by the application, for example to reduce power consumption. * @@ -862,7 +1126,7 @@ gst_event_parse_buffer_size (GstEvent * event, GstFormat * format, * increasing value. * * The upstream element can use the @diff and @timestamp values to decide - * whether to process more buffers. For possitive @diff, all buffers with + * whether to process more buffers. For positive @diff, all buffers with * timestamp <= @timestamp + @diff will certainly arrive late in the sink * as well. A (negative) @diff value so that @timestamp + @diff would yield a * result smaller than 0 is not allowed. @@ -870,7 +1134,7 @@ gst_event_parse_buffer_size (GstEvent * event, GstFormat * format, * The application can use general event probes to intercept the QoS * event and implement custom application specific QoS handling. * - * Returns: (transfer full): a new QOS event. + * Returns: (transfer full) (nullable): a new QOS event. */ GstEvent * gst_event_new_qos (GstQOSType type, gdouble proportion, @@ -882,12 +1146,12 @@ gst_event_new_qos (GstQOSType type, gdouble proportion, /* diff must be positive or timestamp + diff must be positive */ g_return_val_if_fail (diff >= 0 || -diff <= timestamp, NULL); - GST_CAT_INFO (GST_CAT_EVENT, + GST_CAT_LOG (GST_CAT_EVENT, "creating qos type %d, proportion %lf, diff %" G_GINT64_FORMAT ", timestamp %" GST_TIME_FORMAT, type, proportion, diff, GST_TIME_ARGS (timestamp)); - structure = gst_structure_id_new (GST_QUARK (EVENT_QOS), + structure = gst_structure_new_id (GST_QUARK (EVENT_QOS), GST_QUARK (TYPE), GST_TYPE_QOS_TYPE, type, GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion, GST_QUARK (DIFF), G_TYPE_INT64, diff, @@ -907,6 +1171,8 @@ gst_event_new_qos (GstQOSType type, gdouble proportion, * * Get the type, proportion, diff and timestamp in the qos event. See * gst_event_new_qos() for more information about the different QoS values. + * + * @timestamp will be adjusted for any pad offsets of pads it was passing through. */ void gst_event_parse_qos (GstEvent * event, GstQOSType * type, @@ -930,10 +1196,26 @@ gst_event_parse_qos (GstEvent * event, GstQOSType * type, *diff = g_value_get_int64 (gst_structure_id_get_value (structure, GST_QUARK (DIFF))); - if (timestamp) + if (timestamp) { + gint64 offset = gst_event_get_running_time_offset (event); + GstClockTimeDiff diff_ = + g_value_get_int64 (gst_structure_id_get_value (structure, + GST_QUARK (DIFF))); + *timestamp = g_value_get_uint64 (gst_structure_id_get_value (structure, GST_QUARK (TIMESTAMP))); + /* Catch underflows */ + if (*timestamp > -offset) + *timestamp += offset; + else + *timestamp = 0; + + /* Make sure that timestamp + diff is always >= 0. Because + * of the running time offset this might not be true */ + if (diff_ < 0 && *timestamp < -diff_) + *timestamp = (GstClockTime) - diff_; + } } /** @@ -959,26 +1241,26 @@ gst_event_parse_qos (GstEvent * event, GstQOSType * type, * * A pipeline has a default playback segment configured with a start * position of 0, a stop position of -1 and a rate of 1.0. The currently - * configured playback segment can be queried with #GST_QUERY_SEGMENT. + * configured playback segment can be queried with #GST_QUERY_SEGMENT. * - * @start_type and @stop_type specify how to adjust the currently configured + * @start_type and @stop_type specify how to adjust the currently configured * start and stop fields in playback segment. Adjustments can be made relative * or absolute to the last configured values. A type of #GST_SEEK_TYPE_NONE * means that the position should not be updated. * * When the rate is positive and @start has been updated, playback will start - * from the newly configured start position. + * from the newly configured start position. * * For negative rates, playback will start from the newly configured stop - * position (if any). If the stop position if updated, it must be different from - * -1 for negative rates. + * position (if any). If the stop position is updated, it must be different from + * -1 (#GST_CLOCK_TIME_NONE) for negative rates. * * It is not possible to seek relative to the current playback position, to do * this, PAUSE the pipeline, query the current playback position with * #GST_QUERY_POSITION and update the playback segment current position with a - * #GST_SEEK_TYPE_SET to the desired position. + * #GST_SEEK_TYPE_SET to the desired position. * - * Returns: (transfer full): a new seek event. + * Returns: (transfer full) (nullable): a new seek event. */ GstEvent * gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags, @@ -989,6 +1271,18 @@ gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags, g_return_val_if_fail (rate != 0.0, NULL); + /* SNAP flags only make sense in combination with the KEYUNIT flag. Warn + * and unset the SNAP flags if they're set without the KEYUNIT flag */ + if (!(flags & GST_SEEK_FLAG_KEY_UNIT) && + (flags & (GST_SEEK_FLAG_SNAP_BEFORE | GST_SEEK_FLAG_SNAP_AFTER | + GST_SEEK_FLAG_SNAP_NEAREST))) { + g_warning ("SNAP seeks only work in combination with the KEY_UNIT " + "flag, ignoring SNAP flags"); + flags &= + ~(GST_SEEK_FLAG_SNAP_BEFORE | GST_SEEK_FLAG_SNAP_AFTER | + GST_SEEK_FLAG_SNAP_NEAREST); + } + if (format == GST_FORMAT_TIME) { GST_CAT_INFO (GST_CAT_EVENT, "creating seek rate %lf, format TIME, flags %d, " @@ -1005,14 +1299,16 @@ gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags, stop); } - structure = gst_structure_id_new (GST_QUARK (EVENT_SEEK), + structure = gst_structure_new_id (GST_QUARK (EVENT_SEEK), GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (FLAGS), GST_TYPE_SEEK_FLAGS, flags, GST_QUARK (CUR_TYPE), GST_TYPE_SEEK_TYPE, start_type, GST_QUARK (CUR), G_TYPE_INT64, start, GST_QUARK (STOP_TYPE), GST_TYPE_SEEK_TYPE, stop_type, - GST_QUARK (STOP), G_TYPE_INT64, stop, NULL); + GST_QUARK (STOP), G_TYPE_INT64, stop, + GST_QUARK (TRICKMODE_INTERVAL), GST_TYPE_CLOCK_TIME, (GstClockTime) 0, + NULL); event = gst_event_new_custom (GST_EVENT_SEEK, structure); return event; @@ -1025,9 +1321,9 @@ gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags, * @format: (out): result location for the stream format * @flags: (out): result location for the #GstSeekFlags * @start_type: (out): result location for the #GstSeekType of the start position - * @start: (out): result location for the start postion expressed in @format + * @start: (out): result location for the start position expressed in @format * @stop_type: (out): result location for the #GstSeekType of the stop position - * @stop: (out): result location for the stop postion expressed in @format + * @stop: (out): result location for the stop position expressed in @format * * Parses a seek @event and stores the results in the given result locations. */ @@ -1073,6 +1369,48 @@ gst_event_parse_seek (GstEvent * event, gdouble * rate, } /** + * gst_event_set_seek_trickmode_interval: + * + * Sets a trickmode interval on a (writable) seek event. Elements + * that support TRICKMODE_KEY_UNITS seeks SHOULD use this as the minimal + * interval between each frame they may output. + * + * Since: 1.16 + */ +void +gst_event_set_seek_trickmode_interval (GstEvent * event, GstClockTime interval) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEEK); + g_return_if_fail (gst_event_is_writable (event)); + g_return_if_fail (GST_CLOCK_TIME_IS_VALID (interval)); + + gst_structure_id_set (GST_EVENT_STRUCTURE (event), + GST_QUARK (TRICKMODE_INTERVAL), GST_TYPE_CLOCK_TIME, interval, NULL); +} + +/** + * gst_event_parse_seek_trickmode_interval: + * @interval: (out) + * + * Retrieve the trickmode interval that may have been set on a + * seek event with gst_event_set_seek_trickmode_interval(). + * + * Since: 1.16 + */ +void +gst_event_parse_seek_trickmode_interval (GstEvent * event, + GstClockTime * interval) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (interval != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEEK); + + gst_structure_id_get (GST_EVENT_STRUCTURE (event), + GST_QUARK (TRICKMODE_INTERVAL), GST_TYPE_CLOCK_TIME, interval, NULL); +} + +/** * gst_event_new_navigation: * @structure: (transfer full): description of the event. The event will take * ownership of the structure. @@ -1101,8 +1439,6 @@ gst_event_new_navigation (GstStructure * structure) * the time format. * * Returns: (transfer full): a new #GstEvent - * - * Since: 0.10.12 */ GstEvent * gst_event_new_latency (GstClockTime latency) @@ -1113,7 +1449,7 @@ gst_event_new_latency (GstClockTime latency) GST_CAT_INFO (GST_CAT_EVENT, "creating latency event %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); - structure = gst_structure_id_new (GST_QUARK (EVENT_LATENCY), + structure = gst_structure_new_id (GST_QUARK (EVENT_LATENCY), GST_QUARK (LATENCY), G_TYPE_UINT64, latency, NULL); event = gst_event_new_custom (GST_EVENT_LATENCY, structure); @@ -1126,8 +1462,6 @@ gst_event_new_latency (GstClockTime latency) * @latency: (out): A pointer to store the latency in. * * Get the latency in the latency event. - * - * Since: 0.10.12 */ void gst_event_parse_latency (GstEvent * event, GstClockTime * latency) @@ -1153,8 +1487,9 @@ gst_event_parse_latency (GstEvent * event, GstClockTime * latency) * to skip @amount (expressed in @format) of media. It can be used to implement * stepping through the video frame by frame or for doing fast trick modes. * - * A rate of <= 0.0 is not allowed, pause the pipeline or reverse the playback - * direction of the pipeline to get the same effect. + * A rate of <= 0.0 is not allowed. Pause the pipeline, for the effect of rate + * = 0.0 or first reverse the direction of playback using a seek event to get + * the same effect as rate < 0.0. * * The @flush flag will clear any pending data in the pipeline before starting * the step operation. @@ -1162,9 +1497,7 @@ gst_event_parse_latency (GstEvent * event, GstClockTime * latency) * The @intermediate flag instructs the pipeline that this step operation is * part of a larger step operation. * - * Returns: (transfer full): a new #GstEvent - * - * Since: 0.10.24 + * Returns: (transfer full) (nullable): a new #GstEvent */ GstEvent * gst_event_new_step (GstFormat format, guint64 amount, gdouble rate, @@ -1177,7 +1510,7 @@ gst_event_new_step (GstFormat format, guint64 amount, gdouble rate, GST_CAT_INFO (GST_CAT_EVENT, "creating step event"); - structure = gst_structure_id_new (GST_QUARK (EVENT_STEP), + structure = gst_structure_new_id (GST_QUARK (EVENT_STEP), GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, @@ -1199,8 +1532,6 @@ gst_event_new_step (GstFormat format, guint64 amount, gdouble rate, * boolean in * * Parse the step event. - * - * Since: 0.10.24 */ void gst_event_parse_step (GstEvent * event, GstFormat * format, guint64 * amount, @@ -1233,14 +1564,12 @@ gst_event_parse_step (GstEvent * event, GstFormat * format, guint64 * amount, /** * gst_event_new_reconfigure: - * Create a new reconfigure event. The purpose of the reconfingure event is + * Create a new reconfigure event. The purpose of the reconfigure event is * to travel upstream and make elements renegotiate their caps or reconfigure * their buffer pools. This is useful when changing properties on elements * or changing the topology of the pipeline. * * Returns: (transfer full): a new #GstEvent - * - * Since: 0.11.0 */ GstEvent * gst_event_new_reconfigure (void) @@ -1256,19 +1585,20 @@ gst_event_new_reconfigure (void) /** * gst_event_new_sink_message: + * @name: a name for the event * @msg: (transfer none): the #GstMessage to be posted * * Create a new sink-message event. The purpose of the sink-message event is * to instruct a sink to post the message contained in the event synchronized * with the stream. * - * Returns: (transfer full): a new #GstEvent + * @name is used to store multiple sticky events on one pad. * - * Since: 0.10.26 + * Returns: (transfer full): a new #GstEvent */ -/* FIXME 0.11: take ownership of msg for consistency? */ +/* FIXME 2.0: take ownership of msg for consistency? */ GstEvent * -gst_event_new_sink_message (GstMessage * msg) +gst_event_new_sink_message (const gchar * name, GstMessage * msg) { GstEvent *event; GstStructure *structure; @@ -1277,7 +1607,7 @@ gst_event_new_sink_message (GstMessage * msg) GST_CAT_INFO (GST_CAT_EVENT, "creating sink-message event"); - structure = gst_structure_id_new (GST_QUARK (EVENT_SINK_MESSAGE), + structure = gst_structure_new_id (g_quark_from_string (name), GST_QUARK (MESSAGE), GST_TYPE_MESSAGE, msg, NULL); event = gst_event_new_custom (GST_EVENT_SINK_MESSAGE, structure); @@ -1290,8 +1620,6 @@ gst_event_new_sink_message (GstMessage * msg) * @msg: (out) (transfer full): a pointer to store the #GstMessage in. * * Parse the sink-message event. Unref @msg after usage. - * - * Since: 0.10.26 */ void gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg) @@ -1307,3 +1635,535 @@ gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg) GST_MESSAGE (g_value_dup_boxed (gst_structure_id_get_value (structure, GST_QUARK (MESSAGE)))); } + +/** + * 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 + * to be the first event that is sent for a new stream. + * + * Source elements, demuxers and other elements that create new streams + * are supposed to send this event as the first event of a new stream. It + * should not be sent after a flushing seek or in similar situations + * and is used to mark the beginning of a new logical stream. Elements + * 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_pad_create_stream_id() or gst_pad_create_stream_id_printf() can be + * used to create a stream-id. There are no particular semantics for the + * stream-id, though it should be deterministic (to support stream matching) + * and it might be used to order streams (besides any information conveyed by + * stream flags). + * + * Returns: (transfer full): the new STREAM_START event. + */ +GstEvent * +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, + GST_QUARK (FLAGS), GST_TYPE_STREAM_FLAGS, GST_STREAM_FLAG_NONE, NULL); + + return gst_event_new_custom (GST_EVENT_STREAM_START, s); +} + +/** + * gst_event_parse_stream_start: + * @event: a stream-start event. + * @stream_id: (out) (transfer none): pointer to store the stream-id + * + * Parse a stream-id @event and store the result in the given @stream_id + * location. The string stored in @stream_id must not be modified and will + * remain valid only until @event gets freed. Make a copy if you want to + * modify it or store it for later use. + */ +void +gst_event_parse_stream_start (GstEvent * event, const gchar ** stream_id) +{ + const GstStructure *structure; + const GValue *val; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + + structure = gst_event_get_structure (event); + val = gst_structure_id_get_value (structure, GST_QUARK (STREAM_ID)); + + if (stream_id) + *stream_id = g_value_get_string (val); +} + +/** + * gst_event_set_stream: + * @event: a stream-start event + * @stream: (transfer none): the stream object to set + * + * Set the @stream on the stream-start @event + * + * Since: 1.10 + */ +void +gst_event_set_stream (GstEvent * event, GstStream * stream) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + g_return_if_fail (gst_event_is_writable (event)); + + gst_structure_id_set (GST_EVENT_STRUCTURE (event), + GST_QUARK (STREAM), GST_TYPE_STREAM, stream, NULL); +} + +/** + * gst_event_parse_stream: + * @event: a stream-start event + * @stream: (out) (transfer full): address of variable to store the stream + * + * Parse a stream-start @event and extract the #GstStream from it. + * + * Since: 1.10 + */ +void +gst_event_parse_stream (GstEvent * event, GstStream ** stream) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + + if (stream) { + gst_structure_id_get (GST_EVENT_STRUCTURE (event), + GST_QUARK (STREAM), GST_TYPE_STREAM, stream, NULL); + } + +} + +/** + * gst_event_set_stream_flags: + * @event: a stream-start event + * @flags: the stream flags to set + * + * Since: 1.2 + */ +void +gst_event_set_stream_flags (GstEvent * event, GstStreamFlags flags) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + g_return_if_fail (gst_event_is_writable (event)); + + gst_structure_id_set (GST_EVENT_STRUCTURE (event), + GST_QUARK (FLAGS), GST_TYPE_STREAM_FLAGS, flags, NULL); +} + +/** + * gst_event_parse_stream_flags: + * @event: a stream-start event + * @flags: (out): address of variable where to store the stream flags + * + * Since: 1.2 + */ +void +gst_event_parse_stream_flags (GstEvent * event, GstStreamFlags * flags) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + + if (flags) { + gst_structure_id_get (GST_EVENT_STRUCTURE (event), + GST_QUARK (FLAGS), GST_TYPE_STREAM_FLAGS, flags, NULL); + } +} + +/** + * gst_event_set_group_id: + * @event: a stream-start event + * @group_id: the group id to set + * + * All streams that have the same group id are supposed to be played + * together, i.e. all streams inside a container file should have the + * same group id but different stream ids. The group id should change + * each time the stream is started, resulting in different group ids + * each time a file is played for example. + * + * Use gst_util_group_id_next() to get a new group id. + * + * Since: 1.2 + */ +void +gst_event_set_group_id (GstEvent * event, guint group_id) +{ + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START); + g_return_if_fail (gst_event_is_writable (event)); + + gst_structure_id_set (GST_EVENT_STRUCTURE (event), + GST_QUARK (GROUP_ID), G_TYPE_UINT, group_id, NULL); +} + +/** + * gst_event_parse_group_id: + * @event: a stream-start event + * @group_id: (out): address of variable where to store the group id + * + * Returns: %TRUE if a group id was set on the event and could be parsed, + * %FALSE otherwise. + * + * Since: 1.2 + */ +gboolean +gst_event_parse_group_id (GstEvent * event, guint * group_id) +{ + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START, + FALSE); + + if (group_id) { + return gst_structure_id_get (GST_EVENT_STRUCTURE (event), + GST_QUARK (GROUP_ID), G_TYPE_UINT, group_id, NULL); + } + + return TRUE; +} + +/** + * gst_event_new_stream_collection: + * @collection: Active collection for this data flow + * + * Create a new STREAM_COLLECTION event. The stream collection event can only + * travel downstream synchronized with the buffer flow. + * + * Source elements, demuxers and other elements that manage collections + * of streams and post #GstStreamCollection messages on the bus also send + * this event downstream on each pad involved in the collection, so that + * activation of a new collection can be tracked through the downstream + * data flow. + * + * Returns: (transfer full): the new STREAM_COLLECTION event. + * + * Since: 1.10 + */ +GstEvent * +gst_event_new_stream_collection (GstStreamCollection * collection) +{ + GstStructure *s; + + g_return_val_if_fail (collection != NULL, NULL); + g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), NULL); + + s = gst_structure_new_id (GST_QUARK (EVENT_STREAM_COLLECTION), + GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); + + return gst_event_new_custom (GST_EVENT_STREAM_COLLECTION, s); +} + +/** + * gst_event_parse_stream_collection: + * @event: a stream-collection event + * @collection: (out): pointer to store the collection + * + * Retrieve new #GstStreamCollection from STREAM_COLLECTION event @event. + * + * Since: 1.10 + */ +void +gst_event_parse_stream_collection (GstEvent * event, + GstStreamCollection ** collection) +{ + const GstStructure *structure; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_COLLECTION); + + structure = gst_event_get_structure (event); + + if (collection) { + gst_structure_id_get (structure, + GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); + } +} + +/** + * gst_event_new_toc: + * @toc: (transfer none): #GstToc structure. + * @updated: whether @toc was updated or not. + * + * Generate a TOC event from the given @toc. The purpose of the TOC event is to + * inform elements that some kind of the TOC was found. + * + * Returns: (transfer full): a new #GstEvent. + */ +GstEvent * +gst_event_new_toc (GstToc * toc, gboolean updated) +{ + GstStructure *toc_struct; + GQuark id; + + g_return_val_if_fail (toc != NULL, NULL); + + GST_CAT_INFO (GST_CAT_EVENT, "creating toc event"); + + /* need different structure names so sticky_multi event stuff on pads + * works, i.e. both TOC events are kept around */ + if (gst_toc_get_scope (toc) == GST_TOC_SCOPE_GLOBAL) + id = GST_QUARK (EVENT_TOC_GLOBAL); + else + id = GST_QUARK (EVENT_TOC_CURRENT); + + toc_struct = gst_structure_new_id (id, + GST_QUARK (TOC), GST_TYPE_TOC, toc, + GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL); + + return gst_event_new_custom (GST_EVENT_TOC, toc_struct); +} + +/** + * gst_event_parse_toc: + * @event: a TOC event. + * @toc: (out) (transfer full): pointer to #GstToc structure. + * @updated: (out): pointer to store TOC updated flag. + * + * Parse a TOC @event and store the results in the given @toc and @updated locations. + */ +void +gst_event_parse_toc (GstEvent * event, GstToc ** toc, gboolean * updated) +{ + const GstStructure *structure; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TOC); + g_return_if_fail (toc != NULL); + + structure = gst_event_get_structure (event); + + gst_structure_id_get (structure, + GST_QUARK (TOC), GST_TYPE_TOC, toc, + GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL); +} + +/** + * gst_event_new_toc_select: + * @uid: UID in the TOC to start playback from. + * + * Generate a TOC select event with the given @uid. The purpose of the + * TOC select event is to start playback based on the TOC's entry with the + * given @uid. + * + * Returns: a new #GstEvent. + */ +GstEvent * +gst_event_new_toc_select (const gchar * uid) +{ + GstStructure *structure; + + g_return_val_if_fail (uid != NULL, NULL); + + GST_CAT_INFO (GST_CAT_EVENT, "creating toc select event for UID: %s", uid); + + structure = gst_structure_new_id (GST_QUARK (EVENT_TOC_SELECT), + GST_QUARK (UID), G_TYPE_STRING, uid, NULL); + + return gst_event_new_custom (GST_EVENT_TOC_SELECT, structure); +} + +/** + * gst_event_parse_toc_select: + * @event: a TOC select event. + * @uid: (out) (transfer full) (allow-none): storage for the selection UID. + * + * Parse a TOC select @event and store the results in the given @uid location. + */ +void +gst_event_parse_toc_select (GstEvent * event, gchar ** uid) +{ + const GstStructure *structure; + const GValue *val; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TOC_SELECT); + + structure = gst_event_get_structure (event); + val = gst_structure_id_get_value (structure, GST_QUARK (UID)); + + if (uid != NULL) + *uid = g_strdup (g_value_get_string (val)); + +} + +/** + * gst_event_new_protection: + * @system_id: (transfer none): a string holding a UUID that uniquely + * identifies a protection system. + * @data: (transfer none): a #GstBuffer holding protection system specific + * information. The reference count of the buffer will be incremented by one. + * @origin: a string indicating where the protection + * information carried in the event was extracted from. The allowed values + * of this string will depend upon the protection scheme. + * + * Creates a new event containing information specific to a particular + * protection system (uniquely identified by @system_id), by which that + * protection system can acquire key(s) to decrypt a protected stream. + * + * In order for a decryption element to decrypt media + * protected using a specific system, it first needs all the + * protection system specific information necessary to acquire the decryption + * key(s) for that stream. The functions defined here enable this information + * to be passed in events from elements that extract it + * (e.g., ISOBMFF demuxers, MPEG DASH demuxers) to protection decrypter + * elements that use it. + * + * Events containing protection system specific information are created using + * #gst_event_new_protection, and they can be parsed by downstream elements + * using #gst_event_parse_protection. + * + * In Common Encryption, protection system specific information may be located + * within ISOBMFF files, both in movie (moov) boxes and movie fragment (moof) + * boxes; it may also be contained in ContentProtection elements within MPEG + * DASH MPDs. The events created by #gst_event_new_protection contain data + * identifying from which of these locations the encapsulated protection system + * specific information originated. This origin information is required as + * some protection systems use different encodings depending upon where the + * information originates. + * + * The events returned by gst_event_new_protection() are implemented + * in such a way as to ensure that the most recently-pushed protection info + * event of a particular @origin and @system_id will + * be stuck to the output pad of the sending element. + * + * Returns: a #GST_EVENT_PROTECTION event, if successful; %NULL + * if unsuccessful. + * + * Since: 1.6 + */ +GstEvent * +gst_event_new_protection (const gchar * system_id, + GstBuffer * data, const gchar * origin) +{ + gchar *event_name; + GstEvent *event; + GstStructure *s; + + g_return_val_if_fail (system_id != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + + event_name = + g_strconcat ("GstProtectionEvent", origin ? "-" : "", + origin ? origin : "", "-", system_id, NULL); + + GST_CAT_INFO (GST_CAT_EVENT, "creating protection event %s", event_name); + + s = gst_structure_new (event_name, "data", GST_TYPE_BUFFER, data, + "system_id", G_TYPE_STRING, system_id, NULL); + if (origin) + gst_structure_set (s, "origin", G_TYPE_STRING, origin, NULL); + event = gst_event_new_custom (GST_EVENT_PROTECTION, s); + + g_free (event_name); + return event; +} + +/** + * gst_event_parse_protection: + * @event: a #GST_EVENT_PROTECTION event. + * @system_id: (out) (allow-none) (transfer none): pointer to store the UUID + * string uniquely identifying a content protection system. + * @data: (out) (allow-none) (transfer none): pointer to store a #GstBuffer + * holding protection system specific information. + * @origin: (out) (allow-none) (transfer none): pointer to store a value that + * indicates where the protection information carried by @event was extracted + * from. + * + * Parses an event containing protection system specific information and stores + * the results in @system_id, @data and @origin. The data stored in @system_id, + * @origin and @data are valid until @event is released. + * + * Since: 1.6 + */ +void +gst_event_parse_protection (GstEvent * event, const gchar ** system_id, + GstBuffer ** data, const gchar ** origin) +{ + const GstStructure *s; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_IS_EVENT (event)); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_PROTECTION); + + s = gst_event_get_structure (event); + + if (origin) + *origin = gst_structure_get_string (s, "origin"); + + if (system_id) + *system_id = gst_structure_get_string (s, "system_id"); + + if (data) { + const GValue *value = gst_structure_get_value (s, "data"); + *data = gst_value_get_buffer (value); + } +} + +/** + * gst_event_new_segment_done: + * @format: The format of the position being done + * @position: The position of the segment being done + * + * Create a new segment-done event. This event is sent by elements that + * finish playback of a segment as a result of a segment seek. + * + * Returns: (transfer full): a new #GstEvent + */ +GstEvent * +gst_event_new_segment_done (GstFormat format, gint64 position) +{ + GstEvent *event; + GstStructure *structure; + + GST_CAT_INFO (GST_CAT_EVENT, "creating segment-done event"); + + structure = gst_structure_new_id (GST_QUARK (EVENT_SEGMENT_DONE), + GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, + GST_QUARK (POSITION), G_TYPE_INT64, position, NULL); + + event = gst_event_new_custom (GST_EVENT_SEGMENT_DONE, structure); + + return event; +} + +/** + * gst_event_parse_segment_done: + * @event: A valid #GstEvent of type GST_EVENT_SEGMENT_DONE. + * @format: (out) (allow-none): Result location for the format, or %NULL + * @position: (out) (allow-none): Result location for the position, or %NULL + * + * Extracts the position and format from the segment done message. + * + */ +void +gst_event_parse_segment_done (GstEvent * event, GstFormat * format, + gint64 * position) +{ + const GstStructure *structure; + const GValue *val; + + g_return_if_fail (event != NULL); + g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT_DONE); + + structure = gst_event_get_structure (event); + + val = gst_structure_id_get_value (structure, GST_QUARK (FORMAT)); + if (format != NULL) + *format = g_value_get_enum (val); + + val = gst_structure_id_get_value (structure, GST_QUARK (POSITION)); + if (position != NULL) + *position = g_value_get_int64 (val); +}