/* GStreamer * Copyright (C) 2004 Wim Taymans * * gstmessage.c: GstMessage subsystem * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * 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., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * SECTION:gstmessage * @title: GstMessage * @short_description: Lightweight objects to signal the application of * pipeline events * @see_also: #GstBus, #GstMiniObject, #GstElement * * Messages are implemented as a subclass of #GstMiniObject with a generic * #GstStructure as the content. This allows for writing custom messages without * requiring an API change while allowing a wide range of different types * of messages. * * Messages are posted by objects in the pipeline and are passed to the * application using the #GstBus. * * The basic use pattern of posting a message on a #GstBus is as follows: * |[ * gst_bus_post (bus, gst_message_new_eos()); * ]| * * A #GstElement usually posts messages on the bus provided by the parent * container using gst_element_post_message(). */ #include "gst_private.h" #include /* memcpy */ #include "gsterror.h" #include "gstenumtypes.h" #include "gstinfo.h" #include "gstmessage.h" #include "gsttaglist.h" #include "gstutils.h" #include "gstquark.h" #include "gstvalue.h" typedef struct { GstMessage message; GstStructure *structure; } GstMessageImpl; #define GST_MESSAGE_STRUCTURE(m) (((GstMessageImpl *)(m))->structure) typedef struct { const gint type; const gchar *name; GQuark quark; } GstMessageQuarks; static GstMessageQuarks message_quarks[] = { {GST_MESSAGE_UNKNOWN, "unknown", 0}, {GST_MESSAGE_EOS, "eos", 0}, {GST_MESSAGE_ERROR, "error", 0}, {GST_MESSAGE_WARNING, "warning", 0}, {GST_MESSAGE_INFO, "info", 0}, {GST_MESSAGE_TAG, "tag", 0}, {GST_MESSAGE_BUFFERING, "buffering", 0}, {GST_MESSAGE_STATE_CHANGED, "state-changed", 0}, {GST_MESSAGE_STATE_DIRTY, "state-dirty", 0}, {GST_MESSAGE_STEP_DONE, "step-done", 0}, {GST_MESSAGE_CLOCK_PROVIDE, "clock-provide", 0}, {GST_MESSAGE_CLOCK_LOST, "clock-lost", 0}, {GST_MESSAGE_NEW_CLOCK, "new-clock", 0}, {GST_MESSAGE_STRUCTURE_CHANGE, "structure-change", 0}, {GST_MESSAGE_STREAM_STATUS, "stream-status", 0}, {GST_MESSAGE_APPLICATION, "application", 0}, {GST_MESSAGE_ELEMENT, "element", 0}, {GST_MESSAGE_SEGMENT_START, "segment-start", 0}, {GST_MESSAGE_SEGMENT_DONE, "segment-done", 0}, {GST_MESSAGE_DURATION_CHANGED, "duration-changed", 0}, {GST_MESSAGE_LATENCY, "latency", 0}, {GST_MESSAGE_ASYNC_START, "async-start", 0}, {GST_MESSAGE_ASYNC_DONE, "async-done", 0}, {GST_MESSAGE_REQUEST_STATE, "request-state", 0}, {GST_MESSAGE_STEP_START, "step-start", 0}, {GST_MESSAGE_QOS, "qos", 0}, {GST_MESSAGE_PROGRESS, "progress", 0}, {GST_MESSAGE_TOC, "toc", 0}, {GST_MESSAGE_RESET_TIME, "reset-time", 0}, {GST_MESSAGE_STREAM_START, "stream-start", 0}, {GST_MESSAGE_NEED_CONTEXT, "need-context", 0}, {GST_MESSAGE_HAVE_CONTEXT, "have-context", 0}, {GST_MESSAGE_DEVICE_ADDED, "device-added", 0}, {GST_MESSAGE_DEVICE_REMOVED, "device-removed", 0}, {GST_MESSAGE_PROPERTY_NOTIFY, "property-notify", 0}, {GST_MESSAGE_STREAM_COLLECTION, "stream-collection", 0}, {GST_MESSAGE_STREAMS_SELECTED, "streams-selected", 0}, {GST_MESSAGE_REDIRECT, "redirect", 0}, {0, NULL, 0} }; static GQuark details_quark = 0; GType _gst_message_type = 0; GST_DEFINE_MINI_OBJECT_TYPE (GstMessage, gst_message); void _priv_gst_message_initialize (void) { gint i; GST_CAT_INFO (GST_CAT_GST_INIT, "init messages"); for (i = 0; message_quarks[i].name; i++) { message_quarks[i].quark = g_quark_from_static_string (message_quarks[i].name); } details_quark = g_quark_from_static_string ("details"); _gst_message_type = gst_message_get_type (); } /** * gst_message_type_get_name: * @type: the message type * * Get a printable name for the given message type. Do not modify or free. * * Returns: a reference to the static name of the message. */ const gchar * gst_message_type_get_name (GstMessageType type) { gint i; for (i = 0; message_quarks[i].name; i++) { if (type == message_quarks[i].type) return message_quarks[i].name; } return "unknown"; } /** * gst_message_type_to_quark: * @type: the message type * * Get the unique quark for the given message type. * * Returns: the quark associated with the message type */ GQuark gst_message_type_to_quark (GstMessageType type) { gint i; for (i = 0; message_quarks[i].name; i++) { if (type == message_quarks[i].type) return message_quarks[i].quark; } return 0; } static gboolean _gst_message_dispose (GstMessage * message) { gboolean do_free = TRUE; if (GST_MINI_OBJECT_FLAG_IS_SET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY)) { /* revive message, so bus can finish with it and clean it up */ gst_message_ref (message); GST_INFO ("[msg %p] signalling async free", message); GST_MESSAGE_LOCK (message); GST_MESSAGE_SIGNAL (message); GST_MESSAGE_UNLOCK (message); /* don't free it yet, let bus finish with it first */ do_free = FALSE; } return do_free; } static void _gst_message_free (GstMessage * message) { GstStructure *structure; g_return_if_fail (message != NULL); GST_CAT_LOG (GST_CAT_MESSAGE, "finalize message %p, %s from %s", message, GST_MESSAGE_TYPE_NAME (message), GST_MESSAGE_SRC_NAME (message)); if (GST_MESSAGE_SRC (message)) { gst_object_unref (GST_MESSAGE_SRC (message)); GST_MESSAGE_SRC (message) = NULL; } structure = GST_MESSAGE_STRUCTURE (message); if (structure) { gst_structure_set_parent_refcount (structure, NULL); gst_structure_free (structure); } g_slice_free1 (sizeof (GstMessageImpl), message); } static void gst_message_init (GstMessageImpl * message, GstMessageType type, GstObject * src); static GstMessage * _gst_message_copy (GstMessage * message) { GstMessageImpl *copy; GstStructure *structure; GST_CAT_LOG (GST_CAT_MESSAGE, "copy message %p, %s from %s", message, GST_MESSAGE_TYPE_NAME (message), GST_OBJECT_NAME (GST_MESSAGE_SRC (message))); copy = g_slice_new0 (GstMessageImpl); gst_message_init (copy, GST_MESSAGE_TYPE (message), GST_MESSAGE_SRC (message)); GST_MESSAGE_TIMESTAMP (copy) = GST_MESSAGE_TIMESTAMP (message); GST_MESSAGE_SEQNUM (copy) = GST_MESSAGE_SEQNUM (message); structure = GST_MESSAGE_STRUCTURE (message); if (structure) { GST_MESSAGE_STRUCTURE (copy) = gst_structure_copy (structure); gst_structure_set_parent_refcount (GST_MESSAGE_STRUCTURE (copy), ©->message.mini_object.refcount); } else { GST_MESSAGE_STRUCTURE (copy) = NULL; } return GST_MESSAGE_CAST (copy); } static void gst_message_init (GstMessageImpl * message, GstMessageType type, GstObject * src) { gst_mini_object_init (GST_MINI_OBJECT_CAST (message), 0, _gst_message_type, (GstMiniObjectCopyFunction) _gst_message_copy, (GstMiniObjectDisposeFunction) _gst_message_dispose, (GstMiniObjectFreeFunction) _gst_message_free); GST_MESSAGE_TYPE (message) = type; if (src) gst_object_ref (src); GST_MESSAGE_SRC (message) = src; GST_MESSAGE_TIMESTAMP (message) = GST_CLOCK_TIME_NONE; GST_MESSAGE_SEQNUM (message) = gst_util_seqnum_next (); } /** * gst_message_new_custom: * @type: The #GstMessageType to distinguish messages * @src: (transfer none) (allow-none): The object originating the message. * @structure: (transfer full) (allow-none): the structure for the * message. The message will take ownership of the structure. * * Create a new custom-typed message. This can be used for anything not * handled by other message-specific functions to pass a message to the * app. The structure field can be %NULL. * * Returns: (transfer full) (nullable): The new message. * * MT safe. */ GstMessage * gst_message_new_custom (GstMessageType type, GstObject * src, GstStructure * structure) { GstMessageImpl *message; message = g_slice_new0 (GstMessageImpl); GST_CAT_LOG (GST_CAT_MESSAGE, "source %s: creating new message %p %s", (src ? GST_OBJECT_NAME (src) : "NULL"), message, gst_message_type_get_name (type)); if (structure) { /* structure must not have a parent */ if (!gst_structure_set_parent_refcount (structure, &message->message.mini_object.refcount)) goto had_parent; } gst_message_init (message, type, src); GST_MESSAGE_STRUCTURE (message) = structure; return GST_MESSAGE_CAST (message); /* ERRORS */ had_parent: { g_slice_free1 (sizeof (GstMessageImpl), message); g_warning ("structure is already owned by another object"); return NULL; } } /** * gst_message_get_seqnum: * @message: A #GstMessage. * * Retrieve the sequence number of a message. * * Messages have ever-incrementing sequence numbers, which may also be set * explicitly via gst_message_set_seqnum(). Sequence numbers are typically used * to indicate that a message corresponds to some other set of messages or * events, for example a SEGMENT_DONE message corresponding to a SEEK event. It * is considered good practice to make this correspondence when possible, though * it is not required. * * Note that events and messages share the same sequence number incrementor; * two events or messages will never have the same sequence number unless * that correspondence was made explicitly. * * Returns: The message's sequence number. * * MT safe. */ guint32 gst_message_get_seqnum (GstMessage * message) { g_return_val_if_fail (GST_IS_MESSAGE (message), -1); return GST_MESSAGE_SEQNUM (message); } /** * gst_message_set_seqnum: * @message: A #GstMessage. * @seqnum: A sequence number. * * Set the sequence number of a message. * * This function might be called by the creator of a message to indicate that * the message relates to other messages or events. See gst_message_get_seqnum() * for more information. * * MT safe. */ void gst_message_set_seqnum (GstMessage * message, guint32 seqnum) { g_return_if_fail (GST_IS_MESSAGE (message)); GST_MESSAGE_SEQNUM (message) = seqnum; } /** * gst_message_new_eos: * @src: (transfer none) (allow-none): The object originating the message. * * Create a new eos message. This message is generated and posted in * the sink elements of a GstBin. The bin will only forward the EOS * message to the application if all sinks have posted an EOS message. * * Returns: (transfer full): The new eos message. * * MT safe. */ GstMessage * gst_message_new_eos (GstObject * src) { GstMessage *message; message = gst_message_new_custom (GST_MESSAGE_EOS, src, NULL); return message; } /** * gst_message_new_error_with_details: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * @details: (transfer full): (allow-none): A GstStructure with details * * Create a new error message. The message will copy @error and * @debug. This message is posted by element when a fatal event * occurred. The pipeline will probably (partially) stop. The application * receiving this message should stop the pipeline. * * Returns: (transfer full) (nullable): the new error message. * * Since: 1.10 */ GstMessage * gst_message_new_error_with_details (GstObject * src, GError * error, const gchar * debug, GstStructure * details) { GstMessage *message; GstStructure *structure; if (debug && !g_utf8_validate (debug, -1, NULL)) { debug = NULL; g_warning ("Trying to set debug field of error message, but " "string is not valid UTF-8. Please file a bug."); } structure = gst_structure_new_id (GST_QUARK (MESSAGE_ERROR), GST_QUARK (GERROR), G_TYPE_ERROR, error, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); message = gst_message_new_custom (GST_MESSAGE_ERROR, src, structure); if (details) { GValue v = G_VALUE_INIT; g_value_init (&v, GST_TYPE_STRUCTURE); g_value_take_boxed (&v, details); gst_structure_id_take_value (GST_MESSAGE_STRUCTURE (message), details_quark, &v); } return message; } /** * gst_message_new_error: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * * Create a new error message. The message will copy @error and * @debug. This message is posted by element when a fatal event * occurred. The pipeline will probably (partially) stop. The application * receiving this message should stop the pipeline. * * Returns: (transfer full): the new error message. * * MT safe. */ GstMessage * gst_message_new_error (GstObject * src, GError * error, const gchar * debug) { return gst_message_new_error_with_details (src, error, debug, NULL); } /** * gst_message_parse_error_details: * @message: The message object * @structure: (transfer none) (out): A pointer to the returned details * * Returns the optional details structure, may be NULL if none. * The returned structure must not be freed. * * Since: 1.10 */ void gst_message_parse_error_details (GstMessage * message, const GstStructure ** structure) { const GValue *v; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR); g_return_if_fail (structure != NULL); *structure = NULL; v = gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (message), details_quark); if (v) { *structure = g_value_get_boxed (v); } } /** * gst_message_new_warning_with_details: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * @details: (transfer full): (allow-none): A GstStructure with details * * Create a new warning message. The message will make copies of @error and * @debug. * * Returns: (transfer full) (nullable): the new warning message. * * Since: 1.10 */ GstMessage * gst_message_new_warning_with_details (GstObject * src, GError * error, const gchar * debug, GstStructure * details) { GstMessage *message; GstStructure *structure; if (debug && !g_utf8_validate (debug, -1, NULL)) { debug = NULL; g_warning ("Trying to set debug field of warning message, but " "string is not valid UTF-8. Please file a bug."); } structure = gst_structure_new_id (GST_QUARK (MESSAGE_WARNING), GST_QUARK (GERROR), G_TYPE_ERROR, error, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); message = gst_message_new_custom (GST_MESSAGE_WARNING, src, structure); if (details) { GValue v = G_VALUE_INIT; g_value_init (&v, GST_TYPE_STRUCTURE); g_value_take_boxed (&v, details); gst_structure_id_take_value (GST_MESSAGE_STRUCTURE (message), details_quark, &v); } return message; } /** * gst_message_new_warning: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * * Create a new warning message. The message will make copies of @error and * @debug. * * Returns: (transfer full): the new warning message. * * MT safe. */ GstMessage * gst_message_new_warning (GstObject * src, GError * error, const gchar * debug) { return gst_message_new_warning_with_details (src, error, debug, NULL); } /** * gst_message_parse_warning_details: * @message: The message object * @structure: (transfer none) (out): A pointer to the returned details structure * * Returns the optional details structure, may be NULL if none * The returned structure must not be freed. * * Since: 1.10 */ void gst_message_parse_warning_details (GstMessage * message, const GstStructure ** structure) { const GValue *v; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING); g_return_if_fail (structure != NULL); *structure = NULL; v = gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (message), details_quark); if (v) { *structure = g_value_get_boxed (v); } } /** * gst_message_new_info_with_details: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * @details: (transfer full): (allow-none): A GstStructure with details * * Create a new info message. The message will make copies of @error and * @debug. * * Returns: (transfer full) (nullable): the new warning message. * * Since: 1.10 */ GstMessage * gst_message_new_info_with_details (GstObject * src, GError * error, const gchar * debug, GstStructure * details) { GstMessage *message; GstStructure *structure; if (debug && !g_utf8_validate (debug, -1, NULL)) { debug = NULL; g_warning ("Trying to set debug field of info message, but " "string is not valid UTF-8. Please file a bug."); } structure = gst_structure_new_id (GST_QUARK (MESSAGE_INFO), GST_QUARK (GERROR), G_TYPE_ERROR, error, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); message = gst_message_new_custom (GST_MESSAGE_INFO, src, structure); if (details) { GValue v = G_VALUE_INIT; g_value_init (&v, GST_TYPE_STRUCTURE); g_value_take_boxed (&v, details); gst_structure_id_take_value (GST_MESSAGE_STRUCTURE (message), details_quark, &v); } return message; } /** * gst_message_new_info: * @src: (transfer none) (allow-none): The object originating the message. * @error: (transfer none): The GError for this message. * @debug: A debugging string. * * Create a new info message. The message will make copies of @error and * @debug. * * Returns: (transfer full): the new info message. * * MT safe. */ GstMessage * gst_message_new_info (GstObject * src, GError * error, const gchar * debug) { return gst_message_new_info_with_details (src, error, debug, NULL); } /** * gst_message_parse_info_details: * @message: The message object * @structure: (transfer none) (out): A pointer to the returned details structure * * Returns the optional details structure, may be NULL if none * The returned structure must not be freed. * * Since: 1.10 */ void gst_message_parse_info_details (GstMessage * message, const GstStructure ** structure) { const GValue *v; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_INFO); g_return_if_fail (structure != NULL); *structure = NULL; v = gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (message), details_quark); if (v) { *structure = g_value_get_boxed (v); } } /** * gst_message_new_tag: * @src: (transfer none) (allow-none): The object originating the message. * @tag_list: (transfer full): the tag list for the message. * * Create a new tag message. The message will take ownership of the tag list. * The message is posted by elements that discovered a new taglist. * * Returns: (transfer full): the new tag message. * * MT safe. */ GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list) { GstStructure *s; GstMessage *message; GValue val = G_VALUE_INIT; g_return_val_if_fail (GST_IS_TAG_LIST (tag_list), NULL); s = gst_structure_new_id_empty (GST_QUARK (MESSAGE_TAG)); g_value_init (&val, GST_TYPE_TAG_LIST); g_value_take_boxed (&val, tag_list); gst_structure_id_take_value (s, GST_QUARK (TAGLIST), &val); message = gst_message_new_custom (GST_MESSAGE_TAG, src, s); return message; } /** * gst_message_new_buffering: * @src: (transfer none) (allow-none): The object originating the message. * @percent: The buffering percent * * Create a new buffering message. This message can be posted by an element that * needs to buffer data before it can continue processing. @percent should be a * value between 0 and 100. A value of 100 means that the buffering completed. * * When @percent is < 100 the application should PAUSE a PLAYING pipeline. When * @percent is 100, the application can set the pipeline (back) to PLAYING. * The application must be prepared to receive BUFFERING messages in the * PREROLLING state and may only set the pipeline to PLAYING after receiving a * message with @percent set to 100, which can happen after the pipeline * completed prerolling. * * MT safe. * * Returns: (transfer full) (nullable): The new buffering message. */ GstMessage * gst_message_new_buffering (GstObject * src, gint percent) { GstMessage *message; GstStructure *structure; gint64 buffering_left; g_return_val_if_fail (percent >= 0 && percent <= 100, NULL); buffering_left = (percent == 100 ? 0 : -1); structure = gst_structure_new_id (GST_QUARK (MESSAGE_BUFFERING), GST_QUARK (BUFFER_PERCENT), G_TYPE_INT, percent, GST_QUARK (BUFFERING_MODE), GST_TYPE_BUFFERING_MODE, GST_BUFFERING_STREAM, GST_QUARK (AVG_IN_RATE), G_TYPE_INT, -1, GST_QUARK (AVG_OUT_RATE), G_TYPE_INT, -1, GST_QUARK (BUFFERING_LEFT), G_TYPE_INT64, buffering_left, NULL); message = gst_message_new_custom (GST_MESSAGE_BUFFERING, src, structure); return message; } /** * gst_message_new_state_changed: * @src: (transfer none) (allow-none): The object originating the message. * @oldstate: the previous state * @newstate: the new (current) state * @pending: the pending (target) state * * Create a state change message. This message is posted whenever an element * changed its state. * * Returns: (transfer full): the new state change message. * * MT safe. */ GstMessage * gst_message_new_state_changed (GstObject * src, GstState oldstate, GstState newstate, GstState pending) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_STATE_CHANGED), GST_QUARK (OLD_STATE), GST_TYPE_STATE, (gint) oldstate, GST_QUARK (NEW_STATE), GST_TYPE_STATE, (gint) newstate, GST_QUARK (PENDING_STATE), GST_TYPE_STATE, (gint) pending, NULL); message = gst_message_new_custom (GST_MESSAGE_STATE_CHANGED, src, structure); return message; } /** * gst_message_new_state_dirty: * @src: (transfer none) (allow-none): The object originating the message * * Create a state dirty message. This message is posted whenever an element * changed its state asynchronously and is used internally to update the * states of container objects. * * Returns: (transfer full): the new state dirty message. * * MT safe. */ GstMessage * gst_message_new_state_dirty (GstObject * src) { GstMessage *message; message = gst_message_new_custom (GST_MESSAGE_STATE_DIRTY, src, NULL); return message; } /** * gst_message_new_clock_provide: * @src: (transfer none) (allow-none): The object originating the message. * @clock: (transfer none): the clock it provides * @ready: %TRUE if the sender can provide a clock * * Create a clock provide message. This message is posted whenever an * element is ready to provide a clock or lost its ability to provide * a clock (maybe because it paused or became EOS). * * This message is mainly used internally to manage the clock * selection. * * Returns: (transfer full): the new provide clock message. * * MT safe. */ GstMessage * gst_message_new_clock_provide (GstObject * src, GstClock * clock, gboolean ready) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_CLOCK_PROVIDE), GST_QUARK (CLOCK), GST_TYPE_CLOCK, clock, GST_QUARK (READY), G_TYPE_BOOLEAN, ready, NULL); message = gst_message_new_custom (GST_MESSAGE_CLOCK_PROVIDE, src, structure); return message; } /** * gst_message_new_clock_lost: * @src: (transfer none) (allow-none): The object originating the message. * @clock: (transfer none): the clock that was lost * * Create a clock lost message. This message is posted whenever the * clock is not valid anymore. * * If this message is posted by the pipeline, the pipeline will * select a new clock again when it goes to PLAYING. It might therefore * be needed to set the pipeline to PAUSED and PLAYING again. * * Returns: (transfer full): The new clock lost message. * * MT safe. */ GstMessage * gst_message_new_clock_lost (GstObject * src, GstClock * clock) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_CLOCK_LOST), GST_QUARK (CLOCK), GST_TYPE_CLOCK, clock, NULL); message = gst_message_new_custom (GST_MESSAGE_CLOCK_LOST, src, structure); return message; } /** * gst_message_new_new_clock: * @src: (transfer none) (allow-none): The object originating the message. * @clock: (transfer none): the new selected clock * * Create a new clock message. This message is posted whenever the * pipeline selects a new clock for the pipeline. * * Returns: (transfer full): The new new clock message. * * MT safe. */ GstMessage * gst_message_new_new_clock (GstObject * src, GstClock * clock) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_NEW_CLOCK), GST_QUARK (CLOCK), GST_TYPE_CLOCK, clock, NULL); message = gst_message_new_custom (GST_MESSAGE_NEW_CLOCK, src, structure); return message; } /** * gst_message_new_structure_change: * @src: (transfer none) (allow-none): The object originating the message. * @type: The change type. * @owner: (transfer none): The owner element of @src. * @busy: Whether the structure change is busy. * * Create a new structure change message. This message is posted when the * structure of a pipeline is in the process of being changed, for example * when pads are linked or unlinked. * * @src should be the sinkpad that unlinked or linked. * * Returns: (transfer full): the new structure change message. * * MT safe. */ GstMessage * gst_message_new_structure_change (GstObject * src, GstStructureChangeType type, GstElement * owner, gboolean busy) { GstMessage *message; GstStructure *structure; g_return_val_if_fail (GST_IS_PAD (src), NULL); /* g_return_val_if_fail (GST_PAD_DIRECTION (src) == GST_PAD_SINK, NULL); */ g_return_val_if_fail (GST_IS_ELEMENT (owner), NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_STRUCTURE_CHANGE), GST_QUARK (TYPE), GST_TYPE_STRUCTURE_CHANGE_TYPE, type, GST_QUARK (OWNER), GST_TYPE_ELEMENT, owner, GST_QUARK (BUSY), G_TYPE_BOOLEAN, busy, NULL); message = gst_message_new_custom (GST_MESSAGE_STRUCTURE_CHANGE, src, structure); return message; } /** * gst_message_new_segment_start: * @src: (transfer none) (allow-none): The object originating the message. * @format: The format of the position being played * @position: The position of the segment being played * * Create a new segment message. This message is posted by elements that * start playback of a segment as a result of a segment seek. This message * is not received by the application but is used for maintenance reasons in * container elements. * * Returns: (transfer full): the new segment start message. * * MT safe. */ GstMessage * gst_message_new_segment_start (GstObject * src, GstFormat format, gint64 position) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_SEGMENT_START), GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (POSITION), G_TYPE_INT64, position, NULL); message = gst_message_new_custom (GST_MESSAGE_SEGMENT_START, src, structure); return message; } /** * gst_message_new_segment_done: * @src: (transfer none) (allow-none): The object originating the message. * @format: The format of the position being done * @position: The position of the segment being done * * Create a new segment done message. This message is posted by elements that * finish playback of a segment as a result of a segment seek. This message * is received by the application after all elements that posted a segment_start * have posted the segment_done. * * Returns: (transfer full): the new segment done message. * * MT safe. */ GstMessage * gst_message_new_segment_done (GstObject * src, GstFormat format, gint64 position) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_SEGMENT_DONE), GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (POSITION), G_TYPE_INT64, position, NULL); message = gst_message_new_custom (GST_MESSAGE_SEGMENT_DONE, src, structure); return message; } /** * gst_message_new_application: * @src: (transfer none) (allow-none): The object originating the message. * @structure: (transfer full): the structure for the message. The message * will take ownership of the structure. * * Create a new application-typed message. GStreamer will never create these * messages; they are a gift from us to you. Enjoy. * * Returns: (transfer full) (nullable): The new application message. * * MT safe. */ GstMessage * gst_message_new_application (GstObject * src, GstStructure * structure) { g_return_val_if_fail (structure != NULL, NULL); return gst_message_new_custom (GST_MESSAGE_APPLICATION, src, structure); } /** * gst_message_new_element: * @src: (transfer none) (allow-none): The object originating the message. * @structure: (transfer full): The structure for the * message. The message will take ownership of the structure. * * Create a new element-specific message. This is meant as a generic way of * allowing one-way communication from an element to an application, for example * "the firewire cable was unplugged". The format of the message should be * documented in the element's documentation. The structure field can be %NULL. * * Returns: (transfer full) (nullable): The new element message. * * MT safe. */ GstMessage * gst_message_new_element (GstObject * src, GstStructure * structure) { g_return_val_if_fail (structure != NULL, NULL); return gst_message_new_custom (GST_MESSAGE_ELEMENT, src, structure); } /** * gst_message_new_duration_changed: * @src: (transfer none) (allow-none): The object originating the message. * * Create a new duration changed message. This message is posted by elements * that know the duration of a stream when the duration changes. This message * is received by bins and is used to calculate the total duration of a * pipeline. * * Returns: (transfer full): The new duration-changed message. * * MT safe. */ GstMessage * gst_message_new_duration_changed (GstObject * src) { GstMessage *message; message = gst_message_new_custom (GST_MESSAGE_DURATION_CHANGED, src, gst_structure_new_id_empty (GST_QUARK (MESSAGE_DURATION_CHANGED))); return message; } /** * gst_message_new_async_start: * @src: (transfer none) (allow-none): The object originating the message. * * This message is posted by elements when they start an ASYNC state change. * * Returns: (transfer full): The new async_start message. * * MT safe. */ GstMessage * gst_message_new_async_start (GstObject * src) { GstMessage *message; message = gst_message_new_custom (GST_MESSAGE_ASYNC_START, src, NULL); return message; } /** * gst_message_new_async_done: * @src: (transfer none) (allow-none): The object originating the message. * @running_time: the desired running_time * * The message is posted when elements completed an ASYNC state change. * @running_time contains the time of the desired running_time when this * elements goes to PLAYING. A value of #GST_CLOCK_TIME_NONE for @running_time * means that the element has no clock interaction and thus doesn't care about * the running_time of the pipeline. * * Returns: (transfer full): The new async_done message. * * MT safe. */ GstMessage * gst_message_new_async_done (GstObject * src, GstClockTime running_time) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_ASYNC_DONE), GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time, NULL); message = gst_message_new_custom (GST_MESSAGE_ASYNC_DONE, src, structure); return message; } /** * gst_message_new_latency: * @src: (transfer none) (allow-none): The object originating the message. * * This message can be posted by elements when their latency requirements have * changed. * * Returns: (transfer full): The new latency message. * * MT safe. */ GstMessage * gst_message_new_latency (GstObject * src) { GstMessage *message; message = gst_message_new_custom (GST_MESSAGE_LATENCY, src, NULL); return message; } /** * gst_message_new_request_state: * @src: (transfer none) (allow-none): The object originating the message. * @state: The new requested state * * This message can be posted by elements when they want to have their state * changed. A typical use case would be an audio server that wants to pause the * pipeline because a higher priority stream is being played. * * Returns: (transfer full): the new request state message. * * MT safe. */ GstMessage * gst_message_new_request_state (GstObject * src, GstState state) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_REQUEST_STATE), GST_QUARK (NEW_STATE), GST_TYPE_STATE, (gint) state, NULL); message = gst_message_new_custom (GST_MESSAGE_REQUEST_STATE, src, structure); return message; } /** * gst_message_get_structure: * @message: The #GstMessage. * * Access the structure of the message. * * Returns: (transfer none) (nullable): The structure of the message. The * structure is still owned by the message, which means that you should not * free it and that the pointer becomes invalid when you free the message. * * MT safe. */ const GstStructure * gst_message_get_structure (GstMessage * message) { g_return_val_if_fail (GST_IS_MESSAGE (message), NULL); return GST_MESSAGE_STRUCTURE (message); } /** * gst_message_writable_structure: * @message: The #GstMessage. * * Get a writable version of the structure. * * Returns: (transfer none): The structure of the message. The structure * is still owned by the message, which means that you should not free * it and that the pointer becomes invalid when you free the message. * This function checks if @message is writable and will never return * %NULL. * * MT safe. * * Since: 1.14 */ GstStructure * gst_message_writable_structure (GstMessage * message) { GstStructure *structure; g_return_val_if_fail (GST_IS_MESSAGE (message), NULL); g_return_val_if_fail (gst_message_is_writable (message), NULL); structure = GST_MESSAGE_STRUCTURE (message); if (structure == NULL) { structure = gst_structure_new_id_empty (gst_message_type_to_quark (GST_MESSAGE_TYPE (message))); gst_structure_set_parent_refcount (structure, &message->mini_object.refcount); GST_MESSAGE_STRUCTURE (message) = structure; } return structure; } /** * gst_message_has_name: * @message: The #GstMessage. * @name: name to check * * Checks if @message has the given @name. This function is usually used to * check the name of a custom message. * * Returns: %TRUE if @name matches the name of the message structure. */ gboolean gst_message_has_name (GstMessage * message, const gchar * name) { GstStructure *structure; g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE); structure = GST_MESSAGE_STRUCTURE (message); if (structure == NULL) return FALSE; return gst_structure_has_name (structure, name); } /** * gst_message_parse_tag: * @message: A valid #GstMessage of type GST_MESSAGE_TAG. * @tag_list: (out callee-allocates): return location for the tag-list. * * Extracts the tag list from the GstMessage. The tag list returned in the * output argument is a copy; the caller must free it when done. * * Typical usage of this function might be: * |[ * ... * switch (GST_MESSAGE_TYPE (msg)) { * case GST_MESSAGE_TAG: { * GstTagList *tags = NULL; * * gst_message_parse_tag (msg, &tags); * g_print ("Got tags from element %s\n", GST_OBJECT_NAME (msg->src)); * handle_tags (tags); * gst_tag_list_unref (tags); * break; * } * ... * } * ... * ]| * * MT safe. */ void gst_message_parse_tag (GstMessage * message, GstTagList ** tag_list) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TAG); g_return_if_fail (tag_list != NULL); gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (TAGLIST), GST_TYPE_TAG_LIST, tag_list, NULL); } /** * gst_message_parse_buffering: * @message: A valid #GstMessage of type GST_MESSAGE_BUFFERING. * @percent: (out) (allow-none): Return location for the percent. * * Extracts the buffering percent from the GstMessage. see also * gst_message_new_buffering(). * * MT safe. */ void gst_message_parse_buffering (GstMessage * message, gint * percent) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_BUFFERING); if (percent) *percent = g_value_get_int (gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (message), GST_QUARK (BUFFER_PERCENT))); } /** * gst_message_set_buffering_stats: * @message: A valid #GstMessage of type GST_MESSAGE_BUFFERING. * @mode: a buffering mode * @avg_in: the average input rate * @avg_out: the average output rate * @buffering_left: amount of buffering time left in milliseconds * * Configures the buffering stats values in @message. */ void gst_message_set_buffering_stats (GstMessage * message, GstBufferingMode mode, gint avg_in, gint avg_out, gint64 buffering_left) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_BUFFERING); gst_structure_id_set (GST_MESSAGE_STRUCTURE (message), GST_QUARK (BUFFERING_MODE), GST_TYPE_BUFFERING_MODE, mode, GST_QUARK (AVG_IN_RATE), G_TYPE_INT, avg_in, GST_QUARK (AVG_OUT_RATE), G_TYPE_INT, avg_out, GST_QUARK (BUFFERING_LEFT), G_TYPE_INT64, buffering_left, NULL); } /** * gst_message_parse_buffering_stats: * @message: A valid #GstMessage of type GST_MESSAGE_BUFFERING. * @mode: (out) (allow-none): a buffering mode, or %NULL * @avg_in: (out) (allow-none): the average input rate, or %NULL * @avg_out: (out) (allow-none): the average output rate, or %NULL * @buffering_left: (out) (allow-none): amount of buffering time left in * milliseconds, or %NULL * * Extracts the buffering stats values from @message. */ void gst_message_parse_buffering_stats (GstMessage * message, GstBufferingMode * mode, gint * avg_in, gint * avg_out, gint64 * buffering_left) { GstStructure *structure; g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_BUFFERING); structure = GST_MESSAGE_STRUCTURE (message); if (mode) *mode = (GstBufferingMode) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (BUFFERING_MODE))); if (avg_in) *avg_in = g_value_get_int (gst_structure_id_get_value (structure, GST_QUARK (AVG_IN_RATE))); if (avg_out) *avg_out = g_value_get_int (gst_structure_id_get_value (structure, GST_QUARK (AVG_OUT_RATE))); if (buffering_left) *buffering_left = g_value_get_int64 (gst_structure_id_get_value (structure, GST_QUARK (BUFFERING_LEFT))); } /** * gst_message_parse_state_changed: * @message: a valid #GstMessage of type GST_MESSAGE_STATE_CHANGED * @oldstate: (out) (allow-none): the previous state, or %NULL * @newstate: (out) (allow-none): the new (current) state, or %NULL * @pending: (out) (allow-none): the pending (target) state, or %NULL * * Extracts the old and new states from the GstMessage. * * Typical usage of this function might be: * |[ * ... * switch (GST_MESSAGE_TYPE (msg)) { * case GST_MESSAGE_STATE_CHANGED: { * GstState old_state, new_state; * * gst_message_parse_state_changed (msg, &old_state, &new_state, NULL); * g_print ("Element %s changed state from %s to %s.\n", * GST_OBJECT_NAME (msg->src), * gst_element_state_get_name (old_state), * gst_element_state_get_name (new_state)); * break; * } * ... * } * ... * ]| * * MT safe. */ void gst_message_parse_state_changed (GstMessage * message, GstState * oldstate, GstState * newstate, GstState * pending) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STATE_CHANGED); structure = GST_MESSAGE_STRUCTURE (message); if (oldstate) *oldstate = (GstState) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (OLD_STATE))); if (newstate) *newstate = (GstState) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (NEW_STATE))); if (pending) *pending = (GstState) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (PENDING_STATE))); } /** * gst_message_parse_clock_provide: * @message: A valid #GstMessage of type GST_MESSAGE_CLOCK_PROVIDE. * @clock: (out) (allow-none) (transfer none): a pointer to hold a clock * object, or %NULL * @ready: (out) (allow-none): a pointer to hold the ready flag, or %NULL * * Extracts the clock and ready flag from the GstMessage. * The clock object returned remains valid until the message is freed. * * MT safe. */ void gst_message_parse_clock_provide (GstMessage * message, GstClock ** clock, gboolean * ready) { const GValue *clock_gvalue; GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_CLOCK_PROVIDE); structure = GST_MESSAGE_STRUCTURE (message); clock_gvalue = gst_structure_id_get_value (structure, GST_QUARK (CLOCK)); g_return_if_fail (clock_gvalue != NULL); g_return_if_fail (G_VALUE_TYPE (clock_gvalue) == GST_TYPE_CLOCK); if (ready) *ready = g_value_get_boolean (gst_structure_id_get_value (structure, GST_QUARK (READY))); if (clock) *clock = (GstClock *) g_value_get_object (clock_gvalue); } /** * gst_message_parse_clock_lost: * @message: A valid #GstMessage of type GST_MESSAGE_CLOCK_LOST. * @clock: (out) (allow-none) (transfer none): a pointer to hold the lost clock * * Extracts the lost clock from the GstMessage. * The clock object returned remains valid until the message is freed. * * MT safe. */ void gst_message_parse_clock_lost (GstMessage * message, GstClock ** clock) { const GValue *clock_gvalue; GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_CLOCK_LOST); structure = GST_MESSAGE_STRUCTURE (message); clock_gvalue = gst_structure_id_get_value (structure, GST_QUARK (CLOCK)); g_return_if_fail (clock_gvalue != NULL); g_return_if_fail (G_VALUE_TYPE (clock_gvalue) == GST_TYPE_CLOCK); if (clock) *clock = (GstClock *) g_value_get_object (clock_gvalue); } /** * gst_message_parse_new_clock: * @message: A valid #GstMessage of type GST_MESSAGE_NEW_CLOCK. * @clock: (out) (allow-none) (transfer none): a pointer to hold the selected * new clock * * Extracts the new clock from the GstMessage. * The clock object returned remains valid until the message is freed. * * MT safe. */ void gst_message_parse_new_clock (GstMessage * message, GstClock ** clock) { const GValue *clock_gvalue; GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEW_CLOCK); structure = GST_MESSAGE_STRUCTURE (message); clock_gvalue = gst_structure_id_get_value (structure, GST_QUARK (CLOCK)); g_return_if_fail (clock_gvalue != NULL); g_return_if_fail (G_VALUE_TYPE (clock_gvalue) == GST_TYPE_CLOCK); if (clock) *clock = (GstClock *) g_value_get_object (clock_gvalue); } /** * gst_message_parse_structure_change: * @message: A valid #GstMessage of type GST_MESSAGE_STRUCTURE_CHANGE. * @type: (out): A pointer to hold the change type * @owner: (out) (allow-none) (transfer none): The owner element of the * message source * @busy: (out) (allow-none): a pointer to hold whether the change is in * progress or has been completed * * Extracts the change type and completion status from the GstMessage. * * MT safe. */ void gst_message_parse_structure_change (GstMessage * message, GstStructureChangeType * type, GstElement ** owner, gboolean * busy) { const GValue *owner_gvalue; GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STRUCTURE_CHANGE); structure = GST_MESSAGE_STRUCTURE (message); owner_gvalue = gst_structure_id_get_value (structure, GST_QUARK (OWNER)); g_return_if_fail (owner_gvalue != NULL); g_return_if_fail (G_VALUE_TYPE (owner_gvalue) == GST_TYPE_ELEMENT); if (type) *type = (GstStructureChangeType) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (TYPE))); if (owner) *owner = (GstElement *) g_value_get_object (owner_gvalue); if (busy) *busy = g_value_get_boolean (gst_structure_id_get_value (structure, GST_QUARK (BUSY))); } /** * gst_message_parse_error: * @message: A valid #GstMessage of type GST_MESSAGE_ERROR. * @gerror: (out) (allow-none) (transfer full): location for the GError * @debug: (out) (allow-none) (transfer full): location for the debug message, * or %NULL * * Extracts the GError and debug string from the GstMessage. The values returned * in the output arguments are copies; the caller must free them when done. * * Typical usage of this function might be: * |[ * ... * switch (GST_MESSAGE_TYPE (msg)) { * case GST_MESSAGE_ERROR: { * GError *err = NULL; * gchar *dbg_info = NULL; * * gst_message_parse_error (msg, &err, &dbg_info); * g_printerr ("ERROR from element %s: %s\n", * GST_OBJECT_NAME (msg->src), err->message); * g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); * g_error_free (err); * g_free (dbg_info); * break; * } * ... * } * ... * ]| * * MT safe. */ void gst_message_parse_error (GstMessage * message, GError ** gerror, gchar ** debug) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR); gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (GERROR), G_TYPE_ERROR, gerror, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); } /** * gst_message_parse_warning: * @message: A valid #GstMessage of type GST_MESSAGE_WARNING. * @gerror: (out) (allow-none) (transfer full): location for the GError * @debug: (out) (allow-none) (transfer full): location for the debug message, * or %NULL * * Extracts the GError and debug string from the GstMessage. The values returned * in the output arguments are copies; the caller must free them when done. * * MT safe. */ void gst_message_parse_warning (GstMessage * message, GError ** gerror, gchar ** debug) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING); gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (GERROR), G_TYPE_ERROR, gerror, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); } /** * gst_message_parse_info: * @message: A valid #GstMessage of type GST_MESSAGE_INFO. * @gerror: (out) (allow-none) (transfer full): location for the GError * @debug: (out) (allow-none) (transfer full): location for the debug message, * or %NULL * * Extracts the GError and debug string from the GstMessage. The values returned * in the output arguments are copies; the caller must free them when done. * * MT safe. */ void gst_message_parse_info (GstMessage * message, GError ** gerror, gchar ** debug) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_INFO); gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (GERROR), G_TYPE_ERROR, gerror, GST_QUARK (DEBUG), G_TYPE_STRING, debug, NULL); } /** * gst_message_parse_segment_start: * @message: A valid #GstMessage of type GST_MESSAGE_SEGMENT_START. * @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 start message. * * MT safe. */ void gst_message_parse_segment_start (GstMessage * message, GstFormat * format, gint64 * position) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_SEGMENT_START); structure = GST_MESSAGE_STRUCTURE (message); if (format) *format = (GstFormat) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (FORMAT))); if (position) *position = g_value_get_int64 (gst_structure_id_get_value (structure, GST_QUARK (POSITION))); } /** * gst_message_parse_segment_done: * @message: A valid #GstMessage of type GST_MESSAGE_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. * * MT safe. */ void gst_message_parse_segment_done (GstMessage * message, GstFormat * format, gint64 * position) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_SEGMENT_DONE); structure = GST_MESSAGE_STRUCTURE (message); if (format) *format = (GstFormat) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (FORMAT))); if (position) *position = g_value_get_int64 (gst_structure_id_get_value (structure, GST_QUARK (POSITION))); } /** * gst_message_parse_async_done: * @message: A valid #GstMessage of type GST_MESSAGE_ASYNC_DONE. * @running_time: (out) (allow-none): Result location for the running_time or %NULL * * Extract the running_time from the async_done message. * * MT safe. */ void gst_message_parse_async_done (GstMessage * message, GstClockTime * running_time) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_DONE); structure = GST_MESSAGE_STRUCTURE (message); if (running_time) *running_time = g_value_get_uint64 (gst_structure_id_get_value (structure, GST_QUARK (RUNNING_TIME))); } /** * gst_message_parse_request_state: * @message: A valid #GstMessage of type GST_MESSAGE_REQUEST_STATE. * @state: (out) (allow-none): Result location for the requested state or %NULL * * Extract the requested state from the request_state message. * * MT safe. */ void gst_message_parse_request_state (GstMessage * message, GstState * state) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REQUEST_STATE); structure = GST_MESSAGE_STRUCTURE (message); if (state) *state = (GstState) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (NEW_STATE))); } /** * gst_message_new_stream_status: * @src: The object originating the message. * @type: The stream status type. * @owner: (transfer none): the owner element of @src. * * Create a new stream status message. This message is posted when a streaming * thread is created/destroyed or when the state changed. * * Returns: (transfer full): the new stream status message. * * MT safe. */ GstMessage * gst_message_new_stream_status (GstObject * src, GstStreamStatusType type, GstElement * owner) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_STREAM_STATUS), GST_QUARK (TYPE), GST_TYPE_STREAM_STATUS_TYPE, (gint) type, GST_QUARK (OWNER), GST_TYPE_ELEMENT, owner, NULL); message = gst_message_new_custom (GST_MESSAGE_STREAM_STATUS, src, structure); return message; } /** * gst_message_parse_stream_status: * @message: A valid #GstMessage of type GST_MESSAGE_STREAM_STATUS. * @type: (out): A pointer to hold the status type * @owner: (out) (transfer none): The owner element of the message source * * Extracts the stream status type and owner the GstMessage. The returned * owner remains valid for as long as the reference to @message is valid and * should thus not be unreffed. * * MT safe. */ void gst_message_parse_stream_status (GstMessage * message, GstStreamStatusType * type, GstElement ** owner) { const GValue *owner_gvalue; GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_STATUS); structure = GST_MESSAGE_STRUCTURE (message); owner_gvalue = gst_structure_id_get_value (structure, GST_QUARK (OWNER)); g_return_if_fail (owner_gvalue != NULL); if (type) *type = (GstStreamStatusType) g_value_get_enum (gst_structure_id_get_value (structure, GST_QUARK (TYPE))); if (owner) *owner = (GstElement *) g_value_get_object (owner_gvalue); } /** * gst_message_set_stream_status_object: * @message: A valid #GstMessage of type GST_MESSAGE_STREAM_STATUS. * @object: the object controlling the streaming * * Configures the object handling the streaming thread. This is usually a * GstTask object but other objects might be added in the future. */ void gst_message_set_stream_status_object (GstMessage * message, const GValue * object) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_STATUS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_set_value (structure, GST_QUARK (OBJECT), object); } /** * gst_message_get_stream_status_object: * @message: A valid #GstMessage of type GST_MESSAGE_STREAM_STATUS. * * Extracts the object managing the streaming thread from @message. * * Returns: (nullable): a GValue containing the object that manages the * streaming thread. This object is usually of type GstTask but other types can * be added in the future. The object remains valid as long as @message is * valid. */ const GValue * gst_message_get_stream_status_object (GstMessage * message) { const GValue *result; GstStructure *structure; g_return_val_if_fail (GST_IS_MESSAGE (message), NULL); g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_STATUS, NULL); structure = GST_MESSAGE_STRUCTURE (message); result = gst_structure_id_get_value (structure, GST_QUARK (OBJECT)); return result; } /** * gst_message_new_step_done: * @src: The object originating the message. * @format: the format of @amount * @amount: the amount of stepped data * @rate: the rate of the stepped amount * @flush: is this an flushing step * @intermediate: is this an intermediate step * @duration: the duration of the data * @eos: the step caused EOS * * This message is posted by elements when they complete a part, when @intermediate set * to %TRUE, or a complete step operation. * * @duration will contain the amount of time (in GST_FORMAT_TIME) of the stepped * @amount of media in format @format. * * Returns: (transfer full): the new step_done message. * * MT safe. */ GstMessage * gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount, gdouble rate, gboolean flush, gboolean intermediate, guint64 duration, gboolean eos) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_STEP_DONE), GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush, GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, GST_QUARK (DURATION), G_TYPE_UINT64, duration, GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL); message = gst_message_new_custom (GST_MESSAGE_STEP_DONE, src, structure); return message; } /** * gst_message_parse_step_done: * @message: A valid #GstMessage of type GST_MESSAGE_STEP_DONE. * @format: (out) (allow-none): result location for the format * @amount: (out) (allow-none): result location for the amount * @rate: (out) (allow-none): result location for the rate * @flush: (out) (allow-none): result location for the flush flag * @intermediate: (out) (allow-none): result location for the intermediate flag * @duration: (out) (allow-none): result location for the duration * @eos: (out) (allow-none): result location for the EOS flag * * Extract the values the step_done message. * * MT safe. */ void gst_message_parse_step_done (GstMessage * message, GstFormat * format, guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate, guint64 * duration, gboolean * eos) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_DONE); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush, GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, GST_QUARK (DURATION), G_TYPE_UINT64, duration, GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL); } /** * gst_message_new_step_start: * @src: The object originating the message. * @active: if the step is active or queued * @format: the format of @amount * @amount: the amount of stepped data * @rate: the rate of the stepped amount * @flush: is this an flushing step * @intermediate: is this an intermediate step * * This message is posted by elements when they accept or activate a new step * event for @amount in @format. * * @active is set to %FALSE when the element accepted the new step event and has * queued it for execution in the streaming threads. * * @active is set to %TRUE when the element has activated the step operation and * is now ready to start executing the step in the streaming thread. After this * message is emitted, the application can queue a new step operation in the * element. * * Returns: (transfer full): The new step_start message. * * MT safe. */ GstMessage * gst_message_new_step_start (GstObject * src, gboolean active, GstFormat format, guint64 amount, gdouble rate, gboolean flush, gboolean intermediate) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_STEP_START), GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush, GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL); message = gst_message_new_custom (GST_MESSAGE_STEP_START, src, structure); return message; } /** * gst_message_parse_step_start: * @message: A valid #GstMessage of type GST_MESSAGE_STEP_DONE. * @active: (out) (allow-none): result location for the active flag * @format: (out) (allow-none): result location for the format * @amount: (out) (allow-none): result location for the amount * @rate: (out) (allow-none): result location for the rate * @flush: (out) (allow-none): result location for the flush flag * @intermediate: (out) (allow-none): result location for the intermediate flag * * Extract the values from step_start message. * * MT safe. */ void gst_message_parse_step_start (GstMessage * message, gboolean * active, GstFormat * format, guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_START); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (AMOUNT), G_TYPE_UINT64, amount, GST_QUARK (RATE), G_TYPE_DOUBLE, rate, GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush, GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL); } /** * gst_message_new_qos: * @src: The object originating the message. * @live: if the message was generated by a live element * @running_time: the running time of the buffer that generated the message * @stream_time: the stream time of the buffer that generated the message * @timestamp: the timestamps of the buffer that generated the message * @duration: the duration of the buffer that generated the message * * A QOS message is posted on the bus whenever an element decides to drop a * buffer because of QoS reasons or whenever it changes its processing strategy * because of QoS reasons (quality adjustments such as processing at lower * accuracy). * * This message can be posted by an element that performs synchronisation against the * clock (live) or it could be dropped by an element that performs QoS because of QOS * events received from a downstream element (!live). * * @running_time, @stream_time, @timestamp, @duration should be set to the * respective running-time, stream-time, timestamp and duration of the (dropped) * buffer that generated the QoS event. Values can be left to * GST_CLOCK_TIME_NONE when unknown. * * Returns: (transfer full): The new qos message. * * MT safe. */ GstMessage * gst_message_new_qos (GstObject * src, gboolean live, guint64 running_time, guint64 stream_time, guint64 timestamp, guint64 duration) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_QOS), GST_QUARK (LIVE), G_TYPE_BOOLEAN, live, GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time, GST_QUARK (STREAM_TIME), G_TYPE_UINT64, stream_time, GST_QUARK (TIMESTAMP), G_TYPE_UINT64, timestamp, GST_QUARK (DURATION), G_TYPE_UINT64, duration, GST_QUARK (JITTER), G_TYPE_INT64, (gint64) 0, GST_QUARK (PROPORTION), G_TYPE_DOUBLE, (gdouble) 1.0, GST_QUARK (QUALITY), G_TYPE_INT, (gint) 1000000, GST_QUARK (FORMAT), GST_TYPE_FORMAT, GST_FORMAT_UNDEFINED, GST_QUARK (PROCESSED), G_TYPE_UINT64, (guint64) - 1, GST_QUARK (DROPPED), G_TYPE_UINT64, (guint64) - 1, NULL); message = gst_message_new_custom (GST_MESSAGE_QOS, src, structure); return message; } /** * gst_message_set_qos_values: * @message: A valid #GstMessage of type GST_MESSAGE_QOS. * @jitter: The difference of the running-time against the deadline. * @proportion: Long term prediction of the ideal rate relative to normal rate * to get optimal quality. * @quality: An element dependent integer value that specifies the current * quality level of the element. The default maximum quality is 1000000. * * Set the QoS values that have been calculated/analysed from the QoS data * * MT safe. */ void gst_message_set_qos_values (GstMessage * message, gint64 jitter, gdouble proportion, gint quality) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_set (structure, GST_QUARK (JITTER), G_TYPE_INT64, jitter, GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion, GST_QUARK (QUALITY), G_TYPE_INT, quality, NULL); } /** * gst_message_set_qos_stats: * @message: A valid #GstMessage of type GST_MESSAGE_QOS. * @format: Units of the 'processed' and 'dropped' fields. Video sinks and video * filters will use GST_FORMAT_BUFFERS (frames). Audio sinks and audio filters * will likely use GST_FORMAT_DEFAULT (samples). * @processed: Total number of units correctly processed since the last state * change to READY or a flushing operation. * @dropped: Total number of units dropped since the last state change to READY * or a flushing operation. * * Set the QoS stats representing the history of the current continuous pipeline * playback period. * * When @format is @GST_FORMAT_UNDEFINED both @dropped and @processed are * invalid. Values of -1 for either @processed or @dropped mean unknown values. * * MT safe. */ void gst_message_set_qos_stats (GstMessage * message, GstFormat format, guint64 processed, guint64 dropped) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_set (structure, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (PROCESSED), G_TYPE_UINT64, processed, GST_QUARK (DROPPED), G_TYPE_UINT64, dropped, NULL); } /** * gst_message_parse_qos: * @message: A valid #GstMessage of type GST_MESSAGE_QOS. * @live: (out) (allow-none): if the message was generated by a live element * @running_time: (out) (allow-none): the running time of the buffer that * generated the message * @stream_time: (out) (allow-none): the stream time of the buffer that * generated the message * @timestamp: (out) (allow-none): the timestamps of the buffer that * generated the message * @duration: (out) (allow-none): the duration of the buffer that * generated the message * * Extract the timestamps and live status from the QoS message. * * The returned values give the running_time, stream_time, timestamp and * duration of the dropped buffer. Values of GST_CLOCK_TIME_NONE mean unknown * values. * * MT safe. */ void gst_message_parse_qos (GstMessage * message, gboolean * live, guint64 * running_time, guint64 * stream_time, guint64 * timestamp, guint64 * duration) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (LIVE), G_TYPE_BOOLEAN, live, GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time, GST_QUARK (STREAM_TIME), G_TYPE_UINT64, stream_time, GST_QUARK (TIMESTAMP), G_TYPE_UINT64, timestamp, GST_QUARK (DURATION), G_TYPE_UINT64, duration, NULL); } /** * gst_message_parse_qos_values: * @message: A valid #GstMessage of type GST_MESSAGE_QOS. * @jitter: (out) (allow-none): The difference of the running-time against * the deadline. * @proportion: (out) (allow-none): Long term prediction of the ideal rate * relative to normal rate to get optimal quality. * @quality: (out) (allow-none): An element dependent integer value that * specifies the current quality level of the element. The default * maximum quality is 1000000. * * Extract the QoS values that have been calculated/analysed from the QoS data * * MT safe. */ void gst_message_parse_qos_values (GstMessage * message, gint64 * jitter, gdouble * proportion, gint * quality) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (JITTER), G_TYPE_INT64, jitter, GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion, GST_QUARK (QUALITY), G_TYPE_INT, quality, NULL); } /** * gst_message_parse_qos_stats: * @message: A valid #GstMessage of type GST_MESSAGE_QOS. * @format: (out) (allow-none): Units of the 'processed' and 'dropped' fields. * Video sinks and video filters will use GST_FORMAT_BUFFERS (frames). * Audio sinks and audio filters will likely use GST_FORMAT_DEFAULT * (samples). * @processed: (out) (allow-none): Total number of units correctly processed * since the last state change to READY or a flushing operation. * @dropped: (out) (allow-none): Total number of units dropped since the last * state change to READY or a flushing operation. * * Extract the QoS stats representing the history of the current continuous * pipeline playback period. * * When @format is @GST_FORMAT_UNDEFINED both @dropped and @processed are * invalid. Values of -1 for either @processed or @dropped mean unknown values. * * MT safe. */ void gst_message_parse_qos_stats (GstMessage * message, GstFormat * format, guint64 * processed, guint64 * dropped) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (FORMAT), GST_TYPE_FORMAT, format, GST_QUARK (PROCESSED), G_TYPE_UINT64, processed, GST_QUARK (DROPPED), G_TYPE_UINT64, dropped, NULL); } /** * gst_message_new_progress: * @src: The object originating the message. * @type: a #GstProgressType * @code: a progress code * @text: free, user visible text describing the progress * * Progress messages are posted by elements when they use an asynchronous task * to perform actions triggered by a state change. * * @code contains a well defined string describing the action. * @text should contain a user visible string detailing the current action. * * Returns: (transfer full) (nullable): The new qos message. */ GstMessage * gst_message_new_progress (GstObject * src, GstProgressType type, const gchar * code, const gchar * text) { GstMessage *message; GstStructure *structure; gint percent = 100, timeout = -1; g_return_val_if_fail (code != NULL, NULL); g_return_val_if_fail (text != NULL, NULL); if (type == GST_PROGRESS_TYPE_START || type == GST_PROGRESS_TYPE_CONTINUE) percent = 0; structure = gst_structure_new_id (GST_QUARK (MESSAGE_PROGRESS), GST_QUARK (TYPE), GST_TYPE_PROGRESS_TYPE, type, GST_QUARK (CODE), G_TYPE_STRING, code, GST_QUARK (TEXT), G_TYPE_STRING, text, GST_QUARK (PERCENT), G_TYPE_INT, percent, GST_QUARK (TIMEOUT), G_TYPE_INT, timeout, NULL); message = gst_message_new_custom (GST_MESSAGE_PROGRESS, src, structure); return message; } /** * gst_message_parse_progress: * @message: A valid #GstMessage of type GST_MESSAGE_PROGRESS. * @type: (out) (allow-none): location for the type * @code: (out) (allow-none) (transfer full): location for the code * @text: (out) (allow-none) (transfer full): location for the text * * Parses the progress @type, @code and @text. */ void gst_message_parse_progress (GstMessage * message, GstProgressType * type, gchar ** code, gchar ** text) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_PROGRESS); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_get (structure, GST_QUARK (TYPE), GST_TYPE_PROGRESS_TYPE, type, GST_QUARK (CODE), G_TYPE_STRING, code, GST_QUARK (TEXT), G_TYPE_STRING, text, NULL); } /** * gst_message_new_toc: * @src: the object originating the message. * @toc: (transfer none): #GstToc structure for the message. * @updated: whether TOC was updated or not. * * Create a new TOC message. The message is posted by elements * that discovered or updated a TOC. * * Returns: (transfer full): a new TOC message. * * MT safe. */ GstMessage * gst_message_new_toc (GstObject * src, GstToc * toc, gboolean updated) { GstStructure *toc_struct; g_return_val_if_fail (toc != NULL, NULL); toc_struct = gst_structure_new_id (GST_QUARK (MESSAGE_TOC), GST_QUARK (TOC), GST_TYPE_TOC, toc, GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL); return gst_message_new_custom (GST_MESSAGE_TOC, src, toc_struct); } /** * gst_message_parse_toc: * @message: a valid #GstMessage of type GST_MESSAGE_TOC. * @toc: (out) (transfer full): return location for the TOC. * @updated: (out): return location for the updated flag. * * Extract the TOC from the #GstMessage. The TOC returned in the * output argument is a copy; the caller must free it with * gst_toc_unref() when done. * * MT safe. */ void gst_message_parse_toc (GstMessage * message, GstToc ** toc, gboolean * updated) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TOC); g_return_if_fail (toc != NULL); gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (TOC), GST_TYPE_TOC, toc, GST_QUARK (UPDATED), G_TYPE_BOOLEAN, updated, NULL); } /** * gst_message_new_reset_time: * @src: (transfer none) (allow-none): The object originating the message. * @running_time: the requested running-time * * This message is posted when the pipeline running-time should be reset to * @running_time, like after a flushing seek. * * Returns: (transfer full): The new reset_time message. * * MT safe. */ GstMessage * gst_message_new_reset_time (GstObject * src, GstClockTime running_time) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_RESET_TIME), GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time, NULL); message = gst_message_new_custom (GST_MESSAGE_RESET_TIME, src, structure); return message; } /** * gst_message_parse_reset_time: * @message: A valid #GstMessage of type GST_MESSAGE_RESET_TIME. * @running_time: (out) (allow-none): Result location for the running_time or * %NULL * * Extract the running-time from the RESET_TIME message. * * MT safe. */ void gst_message_parse_reset_time (GstMessage * message, GstClockTime * running_time) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_RESET_TIME); structure = GST_MESSAGE_STRUCTURE (message); if (running_time) *running_time = g_value_get_uint64 (gst_structure_id_get_value (structure, GST_QUARK (RUNNING_TIME))); } /** * gst_message_new_stream_start: * @src: (transfer none) (allow-none): The object originating the message. * * Create a new stream_start message. This message is generated and posted in * the sink elements of a GstBin. The bin will only forward the STREAM_START * message to the application if all sinks have posted an STREAM_START message. * * Returns: (transfer full): The new stream_start message. * * MT safe. */ GstMessage * gst_message_new_stream_start (GstObject * src) { GstMessage *message; GstStructure *s; s = gst_structure_new_id_empty (GST_QUARK (MESSAGE_STREAM_START)); message = gst_message_new_custom (GST_MESSAGE_STREAM_START, src, s); return message; } /** * gst_message_set_group_id: * @message: the message * @group_id: the group id * * Sets the group id on the stream-start message. * * 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. * * MT safe. * * Since: 1.2 */ void gst_message_set_group_id (GstMessage * message, guint group_id) { GstStructure *structure; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_START); g_return_if_fail (gst_message_is_writable (message)); structure = GST_MESSAGE_STRUCTURE (message); gst_structure_id_set (structure, GST_QUARK (GROUP_ID), G_TYPE_UINT, group_id, NULL); } /** * gst_message_parse_group_id: * @message: A valid #GstMessage of type GST_MESSAGE_STREAM_START. * @group_id: (out) (allow-none): Result location for the group id or * %NULL * * Extract the group from the STREAM_START message. * * Returns: %TRUE if the message had a group id set, %FALSE otherwise * * MT safe. * * Since: 1.2 */ gboolean gst_message_parse_group_id (GstMessage * message, guint * group_id) { GstStructure *structure; const GValue *v; g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE); g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_START, FALSE); if (!group_id) return TRUE; structure = GST_MESSAGE_STRUCTURE (message); v = gst_structure_id_get_value (structure, GST_QUARK (GROUP_ID)); if (!v) return FALSE; *group_id = g_value_get_uint (v); return TRUE; } /** * gst_message_new_need_context: * @src: (transfer none) (allow-none): The object originating the message. * @context_type: The context type that is needed * * This message is posted when an element needs a specific #GstContext. * * Returns: (transfer full): The new need-context message. * * MT safe. * * Since: 1.2 */ GstMessage * gst_message_new_need_context (GstObject * src, const gchar * context_type) { GstMessage *message; GstStructure *structure; g_return_val_if_fail (context_type != NULL, NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_NEED_CONTEXT), GST_QUARK (CONTEXT_TYPE), G_TYPE_STRING, context_type, NULL); message = gst_message_new_custom (GST_MESSAGE_NEED_CONTEXT, src, structure); return message; } /** * gst_message_parse_context_type: * @message: a GST_MESSAGE_NEED_CONTEXT type message * @context_type: (out) (transfer none) (allow-none): the context type, or %NULL * * Parse a context type from an existing GST_MESSAGE_NEED_CONTEXT message. * * Returns: a #gboolean indicating if the parsing succeeded. * * Since: 1.2 */ gboolean gst_message_parse_context_type (GstMessage * message, const gchar ** context_type) { GstStructure *structure; const GValue *value; g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_NEED_CONTEXT, FALSE); structure = GST_MESSAGE_STRUCTURE (message); if (context_type) { value = gst_structure_id_get_value (structure, GST_QUARK (CONTEXT_TYPE)); *context_type = g_value_get_string (value); } return TRUE; } /** * gst_message_new_have_context: * @src: (transfer none) (allow-none): The object originating the message. * @context: (transfer full): the context * * This message is posted when an element has a new local #GstContext. * * Returns: (transfer full): The new have-context message. * * MT safe. * * Since: 1.2 */ GstMessage * gst_message_new_have_context (GstObject * src, GstContext * context) { GstMessage *message; GstStructure *structure; structure = gst_structure_new_id (GST_QUARK (MESSAGE_HAVE_CONTEXT), GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL); message = gst_message_new_custom (GST_MESSAGE_HAVE_CONTEXT, src, structure); gst_context_unref (context); return message; } /** * gst_message_parse_have_context: * @message: A valid #GstMessage of type GST_MESSAGE_HAVE_CONTEXT. * @context: (out) (transfer full) (allow-none): Result location for the * context or %NULL * * Extract the context from the HAVE_CONTEXT message. * * MT safe. * * Since: 1.2 */ void gst_message_parse_have_context (GstMessage * message, GstContext ** context) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_HAVE_CONTEXT); if (context) gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL); } /** * gst_message_new_device_added: * @src: The #GstObject that created the message * @device: (transfer none): The new #GstDevice * * Creates a new device-added message. The device-added message is produced by * #GstDeviceProvider or a #GstDeviceMonitor. They announce the appearance * of monitored devices. * * Returns: a newly allocated #GstMessage * * Since: 1.4 */ GstMessage * gst_message_new_device_added (GstObject * src, GstDevice * device) { GstMessage *message; GstStructure *structure; g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (GST_IS_DEVICE (device), NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_DEVICE_ADDED), GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL); message = gst_message_new_custom (GST_MESSAGE_DEVICE_ADDED, src, structure); return message; } /** * gst_message_parse_device_added: * @message: a #GstMessage of type %GST_MESSAGE_DEVICE_ADDED * @device: (out) (allow-none) (transfer full): A location where to store a * pointer to the new #GstDevice, or %NULL * * Parses a device-added message. The device-added message is produced by * #GstDeviceProvider or a #GstDeviceMonitor. It announces the appearance * of monitored devices. * * Since: 1.4 */ void gst_message_parse_device_added (GstMessage * message, GstDevice ** device) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_DEVICE_ADDED); if (device) gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL); } /** * gst_message_new_device_removed: * @src: The #GstObject that created the message * @device: (transfer none): The removed #GstDevice * * Creates a new device-removed message. The device-removed message is produced * by #GstDeviceProvider or a #GstDeviceMonitor. They announce the * disappearance of monitored devices. * * Returns: a newly allocated #GstMessage * * Since: 1.4 */ GstMessage * gst_message_new_device_removed (GstObject * src, GstDevice * device) { GstMessage *message; GstStructure *structure; g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (GST_IS_DEVICE (device), NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_DEVICE_REMOVED), GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL); message = gst_message_new_custom (GST_MESSAGE_DEVICE_REMOVED, src, structure); return message; } /** * gst_message_parse_device_removed: * @message: a #GstMessage of type %GST_MESSAGE_DEVICE_REMOVED * @device: (out) (allow-none) (transfer full): A location where to store a * pointer to the removed #GstDevice, or %NULL * * Parses a device-removed message. The device-removed message is produced by * #GstDeviceProvider or a #GstDeviceMonitor. It announces the * disappearance of monitored devices. * * Since: 1.4 */ void gst_message_parse_device_removed (GstMessage * message, GstDevice ** device) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_DEVICE_REMOVED); if (device) gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL); } /** * gst_message_new_property_notify: * @src: The #GstObject whose property changed (may or may not be a #GstElement) * @property_name: name of the property that changed * @val: (allow-none) (transfer full): new property value, or %NULL * * Returns: a newly allocated #GstMessage * * Since: 1.10 */ GstMessage * gst_message_new_property_notify (GstObject * src, const gchar * property_name, GValue * val) { GstStructure *structure; GValue name_val = G_VALUE_INIT; g_return_val_if_fail (property_name != NULL, NULL); structure = gst_structure_new_id_empty (GST_QUARK (MESSAGE_PROPERTY_NOTIFY)); g_value_init (&name_val, G_TYPE_STRING); /* should already be interned, but let's make sure */ g_value_set_static_string (&name_val, g_intern_string (property_name)); gst_structure_id_take_value (structure, GST_QUARK (PROPERTY_NAME), &name_val); if (val != NULL) gst_structure_id_take_value (structure, GST_QUARK (PROPERTY_VALUE), val); return gst_message_new_custom (GST_MESSAGE_PROPERTY_NOTIFY, src, structure); } /** * gst_message_parse_property_notify: * @message: a #GstMessage of type %GST_MESSAGE_PROPERTY_NOTIFY * @object: (out) (allow-none) (transfer none): location where to store a * pointer to the object whose property got changed, or %NULL * @property_name: (out) (transfer none) (allow-none): return location for * the name of the property that got changed, or %NULL * @property_value: (out) (transfer none) (allow-none): return location for * the new value of the property that got changed, or %NULL. This will * only be set if the property notify watch was told to include the value * when it was set up * * Parses a property-notify message. These will be posted on the bus only * when set up with gst_element_add_property_notify_watch() or * gst_element_add_property_deep_notify_watch(). * * Since: 1.10 */ void gst_message_parse_property_notify (GstMessage * message, GstObject ** object, const gchar ** property_name, const GValue ** property_value) { const GstStructure *s = GST_MESSAGE_STRUCTURE (message); g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_PROPERTY_NOTIFY); if (object) *object = GST_MESSAGE_SRC (message); if (property_name) { const GValue *name_value; name_value = gst_structure_id_get_value (s, GST_QUARK (PROPERTY_NAME)); *property_name = g_value_get_string (name_value); } if (property_value) *property_value = gst_structure_id_get_value (s, GST_QUARK (PROPERTY_VALUE)); } /** * gst_message_new_stream_collection: * @src: The #GstObject that created the message * @collection: (transfer none): The #GstStreamCollection * * Creates a new stream-collection message. The message is used to announce new * #GstStreamCollection * * Returns: a newly allocated #GstMessage * * Since: 1.10 */ GstMessage * gst_message_new_stream_collection (GstObject * src, GstStreamCollection * collection) { GstMessage *message; GstStructure *structure; g_return_val_if_fail (collection != NULL, NULL); g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_STREAM_COLLECTION), GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); message = gst_message_new_custom (GST_MESSAGE_STREAM_COLLECTION, src, structure); return message; } /** * gst_message_parse_stream_collection: * @message: a #GstMessage of type %GST_MESSAGE_STREAM_COLLECTION * @collection: (out) (allow-none) (transfer full): A location where to store a * pointer to the #GstStreamCollection, or %NULL * * Parses a stream-collection message. * * Since: 1.10 */ void gst_message_parse_stream_collection (GstMessage * message, GstStreamCollection ** collection) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_COLLECTION); if (collection) gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); } /** * gst_message_new_streams_selected: * @src: The #GstObject that created the message * @collection: (transfer none): The #GstStreamCollection * * Creates a new steams-selected message. The message is used to announce * that an array of streams has been selected. This is generally in response * to a #GST_EVENT_SELECT_STREAMS event, or when an element (such as decodebin3) * makes an initial selection of streams. * * The message also contains the #GstStreamCollection to which the various streams * belong to. * * Users of gst_message_new_streams_selected() can add the selected streams with * gst_message_streams_selected_add(). * * Returns: a newly allocated #GstMessage * * Since: 1.10 */ GstMessage * gst_message_new_streams_selected (GstObject * src, GstStreamCollection * collection) { GstMessage *message; GstStructure *structure; GValue val = G_VALUE_INIT; g_return_val_if_fail (collection != NULL, NULL); g_return_val_if_fail (GST_IS_STREAM_COLLECTION (collection), NULL); structure = gst_structure_new_id (GST_QUARK (MESSAGE_STREAMS_SELECTED), GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); g_value_init (&val, GST_TYPE_ARRAY); gst_structure_id_take_value (structure, GST_QUARK (STREAMS), &val); message = gst_message_new_custom (GST_MESSAGE_STREAMS_SELECTED, src, structure); return message; } /** * gst_message_streams_selected_get_size: * @message: a #GstMessage of type %GST_MESSAGE_STREAMS_SELECTED * * Returns the number of streams contained in the @message. * * Returns: The number of streams contained within. * * Since: 1.10 */ guint gst_message_streams_selected_get_size (GstMessage * msg) { const GValue *val; g_return_val_if_fail (GST_IS_MESSAGE (msg), 0); g_return_val_if_fail (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STREAMS_SELECTED, 0); val = gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (msg), GST_QUARK (STREAMS)); return gst_value_array_get_size (val); } /** * gst_message_streams_selected_add: * @message: a #GstMessage of type %GST_MESSAGE_STREAMS_SELECTED * @stream: (transfer none): a #GstStream to add to @message * * Adds the @stream to the @message. * * Since: 1.10 */ void gst_message_streams_selected_add (GstMessage * msg, GstStream * stream) { GValue *val; GValue to_add = G_VALUE_INIT; g_return_if_fail (GST_IS_MESSAGE (msg)); g_return_if_fail (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STREAMS_SELECTED); g_return_if_fail (GST_IS_STREAM (stream)); val = (GValue *) gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (msg), GST_QUARK (STREAMS)); g_value_init (&to_add, GST_TYPE_STREAM); g_value_set_object (&to_add, stream); gst_value_array_append_and_take_value (val, &to_add); } /** * gst_message_streams_selected_get_stream: * @message: a #GstMessage of type %GST_MESSAGE_STREAMS_SELECTED * @idx: Index of the stream to retrieve * * Retrieves the #GstStream with index @index from the @message. * * Returns: (transfer full) (nullable): A #GstStream * * Since: 1.10 */ GstStream * gst_message_streams_selected_get_stream (GstMessage * msg, guint idx) { const GValue *streams, *val; g_return_val_if_fail (GST_IS_MESSAGE (msg), NULL); g_return_val_if_fail (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STREAMS_SELECTED, NULL); streams = gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (msg), GST_QUARK (STREAMS)); val = gst_value_array_get_value (streams, idx); if (val) { return (GstStream *) g_value_dup_object (val); } return NULL; } /** * gst_message_parse_streams_selected: * @message: a #GstMessage of type %GST_MESSAGE_STREAMS_SELECTED * @collection: (out) (allow-none) (transfer full): A location where to store a * pointer to the #GstStreamCollection, or %NULL * * Parses a streams-selected message. * * Since: 1.10 */ void gst_message_parse_streams_selected (GstMessage * message, GstStreamCollection ** collection) { g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAMS_SELECTED); if (collection) gst_structure_id_get (GST_MESSAGE_STRUCTURE (message), GST_QUARK (COLLECTION), GST_TYPE_STREAM_COLLECTION, collection, NULL); } /** * gst_message_new_redirect: * @src: The #GstObject whose property changed (may or may not be a #GstElement) * @location: (transfer none): location string for the new entry * @tag_list: (transfer full) (allow-none): tag list for the new entry * @entry_struct: (transfer full) (allow-none): structure for the new entry * * Creates a new redirect message and adds a new entry to it. Redirect messages * are posted when an element detects that the actual data has to be retrieved * from a different location. This is useful if such a redirection cannot be * handled inside a source element, for example when HTTP 302/303 redirects * return a non-HTTP URL. * * The redirect message can hold multiple entries. The first one is added * when the redirect message is created, with the given location, tag_list, * entry_struct arguments. Use gst_message_add_redirect_entry() to add more * entries. * * Each entry has a location, a tag list, and a structure. All of these are * optional. The tag list and structure are useful for additional metadata, * such as bitrate statistics for the given location. * * By default, message recipients should treat entries in the order they are * stored. The recipient should therefore try entry #0 first, and if this * entry is not acceptable or working, try entry #1 etc. Senders must make * sure that they add entries in this order. However, recipients are free to * ignore the order and pick an entry that is "best" for them. One example * would be a recipient that scans the entries for the one with the highest * bitrate tag. * * The specified location string is copied. However, ownership over the tag * list and structure are transferred to the message. * * Returns: a newly allocated #GstMessage * * Since: 1.10 */ GstMessage * gst_message_new_redirect (GstObject * src, const gchar * location, GstTagList * tag_list, const GstStructure * entry_struct) { GstStructure *structure; GstMessage *message; GValue entry_locations_gvalue = G_VALUE_INIT; GValue entry_taglists_gvalue = G_VALUE_INIT; GValue entry_structures_gvalue = G_VALUE_INIT; g_return_val_if_fail (location != NULL, NULL); g_value_init (&entry_locations_gvalue, GST_TYPE_LIST); g_value_init (&entry_taglists_gvalue, GST_TYPE_LIST); g_value_init (&entry_structures_gvalue, GST_TYPE_LIST); structure = gst_structure_new_id_empty (GST_QUARK (MESSAGE_REDIRECT)); gst_structure_id_take_value (structure, GST_QUARK (REDIRECT_ENTRY_LOCATIONS), &entry_locations_gvalue); gst_structure_id_take_value (structure, GST_QUARK (REDIRECT_ENTRY_TAGLISTS), &entry_taglists_gvalue); gst_structure_id_take_value (structure, GST_QUARK (REDIRECT_ENTRY_STRUCTURES), &entry_structures_gvalue); message = gst_message_new_custom (GST_MESSAGE_REDIRECT, src, structure); g_assert (message != NULL); gst_message_add_redirect_entry (message, location, tag_list, entry_struct); return message; } /** * gst_message_add_redirect_entry: * @message: a #GstMessage of type %GST_MESSAGE_REDIRECT * @location: (transfer none): location string for the new entry * @tag_list: (transfer full) (allow-none): tag list for the new entry * @entry_struct: (transfer full) (allow-none): structure for the new entry * * Creates and appends a new entry. * * The specified location string is copied. However, ownership over the tag * list and structure are transferred to the message. * * Since: 1.10 */ void gst_message_add_redirect_entry (GstMessage * message, const gchar * location, GstTagList * tag_list, const GstStructure * entry_struct) { GValue val = G_VALUE_INIT; GstStructure *structure; GValue *entry_locations_gvalue; GValue *entry_taglists_gvalue; GValue *entry_structures_gvalue; g_return_if_fail (location != NULL); g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REDIRECT); structure = GST_MESSAGE_STRUCTURE (message); entry_locations_gvalue = (GValue *) gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_LOCATIONS)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_locations_gvalue)); entry_taglists_gvalue = (GValue *) gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_TAGLISTS)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_taglists_gvalue)); entry_structures_gvalue = (GValue *) gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_STRUCTURES)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_structures_gvalue)); g_value_init (&val, G_TYPE_STRING); if (location) g_value_set_string (&val, location); gst_value_list_append_and_take_value (entry_locations_gvalue, &val); g_value_init (&val, GST_TYPE_TAG_LIST); if (tag_list) g_value_take_boxed (&val, tag_list); gst_value_list_append_and_take_value (entry_taglists_gvalue, &val); g_value_init (&val, GST_TYPE_STRUCTURE); if (entry_struct) g_value_take_boxed (&val, entry_struct); gst_value_list_append_and_take_value (entry_structures_gvalue, &val); } /** * gst_message_parse_redirect_entry: * @message: a #GstMessage of type %GST_MESSAGE_REDIRECT * @entry_index: index of the entry to parse * @location: (out) (transfer none) (allow-none): return location for * the pointer to the entry's location string, or %NULL * @tag_list: (out) (transfer none) (allow-none): return location for * the pointer to the entry's tag list, or %NULL * @entry_struct: (out) (transfer none) (allow-none): return location * for the pointer to the entry's structure, or %NULL * * Parses the location and/or structure from the entry with the given index. * The index must be between 0 and gst_message_get_num_redirect_entries() - 1. * Returned pointers are valid for as long as this message exists. * * Since: 1.10 */ void gst_message_parse_redirect_entry (GstMessage * message, gsize entry_index, const gchar ** location, GstTagList ** tag_list, const GstStructure ** entry_struct) { const GValue *val; GstStructure *structure; const GValue *entry_locations_gvalue; const GValue *entry_taglists_gvalue; const GValue *entry_structures_gvalue; g_return_if_fail (GST_IS_MESSAGE (message)); g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REDIRECT); if (G_UNLIKELY (!location && !tag_list && !entry_struct)) return; structure = GST_MESSAGE_STRUCTURE (message); entry_locations_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_LOCATIONS)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_locations_gvalue)); entry_taglists_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_TAGLISTS)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_taglists_gvalue)); entry_structures_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_STRUCTURES)); g_return_if_fail (GST_VALUE_HOLDS_LIST (entry_structures_gvalue)); if (location) { val = gst_value_list_get_value (entry_locations_gvalue, entry_index); g_return_if_fail (val != NULL); *location = g_value_get_string (val); } if (tag_list) { val = gst_value_list_get_value (entry_taglists_gvalue, entry_index); g_return_if_fail (val != NULL); *tag_list = (GstTagList *) g_value_get_boxed (val); } if (entry_struct) { val = gst_value_list_get_value (entry_structures_gvalue, entry_index); g_return_if_fail (val != NULL); *entry_struct = (const GstStructure *) g_value_get_boxed (val); } } /** * gst_message_get_num_redirect_entries: * @message: a #GstMessage of type %GST_MESSAGE_REDIRECT * * Returns: the number of entries stored in the message * * Since: 1.10 */ gsize gst_message_get_num_redirect_entries (GstMessage * message) { GstStructure *structure; const GValue *entry_locations_gvalue; const GValue *entry_taglists_gvalue; const GValue *entry_structures_gvalue; gsize size; g_return_val_if_fail (GST_IS_MESSAGE (message), 0); g_return_val_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_REDIRECT, 0); structure = GST_MESSAGE_STRUCTURE (message); entry_locations_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_LOCATIONS)); g_return_val_if_fail (GST_VALUE_HOLDS_LIST (entry_locations_gvalue), 0); entry_taglists_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_TAGLISTS)); g_return_val_if_fail (GST_VALUE_HOLDS_LIST (entry_taglists_gvalue), 0); entry_structures_gvalue = gst_structure_id_get_value (structure, GST_QUARK (REDIRECT_ENTRY_STRUCTURES)); g_return_val_if_fail (GST_VALUE_HOLDS_LIST (entry_structures_gvalue), 0); size = gst_value_list_get_size (entry_locations_gvalue); g_return_val_if_fail ((size == gst_value_list_get_size (entry_structures_gvalue)) && (size == gst_value_list_get_size (entry_taglists_gvalue)), 0); return size; }