gstmessage: Allow retrieving and setting details on messages

This was only available on warning/error/info messages creator/parsers. These
new functions make it more generic and also add a writable variant for users who
want to add/extend the details

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6929>
This commit is contained in:
Edward Hervey 2024-05-21 11:31:34 +02:00 committed by GStreamer Marge Bot
parent fe1a7edda2
commit 1f4c1c18ca
4 changed files with 387 additions and 42 deletions

View file

@ -24121,6 +24121,22 @@ MT safe</doc>
</instance-parameter>
</parameters>
</method>
<method name="get_details" c:identifier="gst_message_get_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Returns the optional details structure of the message. May be NULL if none.
The returned structure must not be freed.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">The details, or NULL if none.</doc>
<type name="Structure" c:type="const GstStructure*"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A #GstMessage</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
</parameters>
</method>
<method name="get_num_redirect_entries" c:identifier="gst_message_get_num_redirect_entries" version="1.10">
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none">
@ -24477,6 +24493,24 @@ The returned structure must not be freed.</doc>
</parameter>
</parameters>
</method>
<method name="parse_error_writable_details" c:identifier="gst_message_parse_error_writable_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Returns the details structure if present or will create one if not present.
The returned structure must not be freed.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">The writable message object</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
<parameter name="structure" direction="out" caller-allocates="0" transfer-ownership="none" nullable="1" optional="1" allow-none="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A pointer to the returned details</doc>
<type name="Structure" c:type="GstStructure**"/>
</parameter>
</parameters>
</method>
<method name="parse_group_id" c:identifier="gst_message_parse_group_id" version="1.2">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Extract the group from the STREAM_START message.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
@ -24561,6 +24595,24 @@ The returned structure must not be freed.</doc>
</parameter>
</parameters>
</method>
<method name="parse_info_writable_details" c:identifier="gst_message_parse_info_writable_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Returns the details structure if present or will create one if not present.
The returned structure must not be freed.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">The writable message object</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
<parameter name="structure" direction="out" caller-allocates="0" transfer-ownership="none" nullable="1" optional="1" allow-none="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A pointer to the returned details</doc>
<type name="Structure" c:type="GstStructure**"/>
</parameter>
</parameters>
</method>
<method name="parse_instant_rate_request" c:identifier="gst_message_parse_instant_rate_request" version="1.18">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Parses the rate_multiplier from the instant-rate-request message.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
@ -25209,6 +25261,24 @@ The returned structure must not be freed.</doc>
</parameter>
</parameters>
</method>
<method name="parse_warning_writable_details" c:identifier="gst_message_parse_warning_writable_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Returns the details structure if present or will create one if not present.
The returned structure must not be freed.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">The writable message object</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
<parameter name="structure" direction="out" caller-allocates="0" transfer-ownership="none" nullable="1" optional="1" allow-none="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A pointer to the returned details</doc>
<type name="Structure" c:type="GstStructure**"/>
</parameter>
</parameters>
</method>
<method name="ref" c:identifier="gst_message_ref" introspectable="0">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Convenience macro to increase the reference count of the message.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
@ -25252,6 +25322,24 @@ The returned structure must not be freed.</doc>
</parameter>
</parameters>
</method>
<method name="set_details" c:identifier="gst_message_set_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Add @details to @message. Will fail if the message already has details set on
it or if it is not writable.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A #GstMessage</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
<parameter name="details" transfer-ownership="full" nullable="1" allow-none="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A GstStructure with details</doc>
<type name="Structure" c:type="GstStructure*"/>
</parameter>
</parameters>
</method>
<method name="set_group_id" c:identifier="gst_message_set_group_id" version="1.2">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Sets the group id on the stream-start message.
@ -25445,6 +25533,24 @@ freeing it.</doc>
</instance-parameter>
</parameters>
</method>
<method name="writable_details" c:identifier="gst_message_writable_details" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Returns the details structure of the @message. If not present it will be
created. Use this function (instead of gst_message_get_details()) if you
want to write to the @details structure.
The returned structure must not be freed.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>
<return-value transfer-ownership="none" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">The details, or NULL if none.</doc>
<type name="Structure" c:type="GstStructure*"/>
</return-value>
<parameters>
<instance-parameter name="message" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">A writable #GstMessage</doc>
<type name="Message" c:type="GstMessage*"/>
</instance-parameter>
</parameters>
</method>
<method name="writable_structure" c:identifier="gst_message_writable_structure" version="1.14">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstmessage.c">Get a writable version of the structure.</doc>
<source-position filename="../subprojects/gstreamer/gst/gstmessage.h"/>

View file

@ -399,6 +399,138 @@ gst_message_new_eos (GstObject * src)
return message;
}
/* Internal function for setting details on a message. Checks for valid
* arguments should be done before calling this.
*
* Will create a message structure if it doesn't have one already
**/
static void
message_set_details (GstMessage * message, GstStructure * details)
{
GValue v = G_VALUE_INIT;
if (GST_MESSAGE_STRUCTURE (message) == NULL) {
GQuark message_quark = gst_message_type_to_quark (message->type);
g_return_if_fail (message_quark);
GstStructure *structure = gst_structure_new_id_empty (message_quark);
gst_structure_set_parent_refcount (structure,
&message->mini_object.refcount);
GST_MESSAGE_STRUCTURE (message) = structure;
}
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);
}
/**
* gst_message_set_details:
* @message: A #GstMessage
* @details: (transfer full) (nullable): A GstStructure with details
*
* Add @details to @message. Will fail if the message already has details set on
* it or if it is not writable.
*
* Since: 1.26
*/
void
gst_message_set_details (GstMessage * message, GstStructure * details)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (gst_message_is_writable (message));
g_return_if_fail (details);
if (GST_MESSAGE_STRUCTURE (message)
&& gst_structure_id_has_field (GST_MESSAGE_STRUCTURE (message),
details_quark)) {
gst_structure_free (details);
g_critical ("Message already has details");
return;
}
message_set_details (message, details);
}
/* Internal function for parsing details of a message.
* Checks for valid arguments should be done before calling this.
*
* Will create a details structure if create_if_missing is TRUE
*/
static void
message_parse_details (GstMessage * message, GstStructure ** details,
gboolean create_if_missing)
{
*details = NULL;
if (GST_MESSAGE_STRUCTURE (message) == NULL && !create_if_missing)
return;
if (GST_MESSAGE_STRUCTURE (message) &&
gst_structure_id_has_field (GST_MESSAGE_STRUCTURE (message),
details_quark)) {
const GValue *v =
gst_structure_id_get_value (GST_MESSAGE_STRUCTURE (message),
details_quark);
if (v && G_VALUE_TYPE (v) == GST_TYPE_STRUCTURE) {
*details = g_value_get_boxed (v);
}
} else if (create_if_missing) {
*details = gst_structure_new_empty ("message-details");
message_set_details (message, (GstStructure *) * details);
}
}
/**
* gst_message_get_details:
* @message: A #GstMessage
*
* Returns the optional details structure of the message. May be NULL if none.
*
* The returned structure must not be freed.
*
* Returns: (transfer none) (nullable): The details, or NULL if none.
*
* Since: 1.26
*/
const GstStructure *
gst_message_get_details (GstMessage * message)
{
const GstStructure *details;
g_return_val_if_fail (GST_IS_MESSAGE (message), NULL);
message_parse_details (message, (GstStructure **) & details, FALSE);
return details;
}
/**
* gst_message_writable_details:
* @message: A writable #GstMessage
*
* Returns the details structure of the @message. If not present it will be
* created. Use this function (instead of gst_message_get_details()) if you
* want to write to the @details structure.
*
* The returned structure must not be freed.
*
* Returns: (transfer none) (nullable): The details, or NULL if none.
*
* Since: 1.26
*/
GstStructure *
gst_message_writable_details (GstMessage * message)
{
GstStructure *details;
g_return_val_if_fail (GST_IS_MESSAGE (message), NULL);
g_return_val_if_fail (gst_message_is_writable (message), NULL);
message_parse_details (message, &details, TRUE);
return details;
}
/**
* gst_message_new_error_with_details:
* @src: (transfer none) (nullable): The object originating the message.
@ -433,12 +565,7 @@ gst_message_new_error_with_details (GstObject * src, GError * 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);
message_set_details (message, details);
}
return message;
@ -479,18 +606,33 @@ 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);
}
message_parse_details (message, (GstStructure **) structure, FALSE);
}
/**
* gst_message_parse_error_writable_details:
* @message: The writable message object
* @structure: (optional) (nullable) (transfer none) (out): A pointer to the returned details
*
* Returns the details structure if present or will create one if not present.
* The returned structure must not be freed.
*
* Since: 1.26
*/
void
gst_message_parse_error_writable_details (GstMessage * message,
GstStructure ** structure)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR);
g_return_if_fail (gst_message_is_writable (message));
g_return_if_fail (structure != NULL);
message_parse_details (message, (GstStructure **) structure, TRUE);
}
/**
@ -525,12 +667,7 @@ gst_message_new_warning_with_details (GstObject * src, GError * 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);
message_set_details (message, details);
}
return message;
@ -569,18 +706,33 @@ 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);
}
message_parse_details (message, (GstStructure **) structure, FALSE);
}
/**
* gst_message_parse_warning_writable_details:
* @message: The writable message object
* @structure: (optional) (nullable) (transfer none) (out): A pointer to the returned details
*
* Returns the details structure if present or will create one if not present.
* The returned structure must not be freed.
*
* Since: 1.26
*/
void
gst_message_parse_warning_writable_details (GstMessage * message,
GstStructure ** structure)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING);
g_return_if_fail (gst_message_is_writable (message));
g_return_if_fail (structure != NULL);
message_parse_details (message, (GstStructure **) structure, TRUE);
}
/**
@ -615,12 +767,7 @@ gst_message_new_info_with_details (GstObject * src, GError * 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);
message_set_details (message, details);
}
return message;
@ -659,18 +806,33 @@ 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);
}
message_parse_details (message, (GstStructure **) structure, FALSE);
}
/**
* gst_message_parse_info_writable_details:
* @message: The writable message object
* @structure: (optional) (nullable) (transfer none) (out): A pointer to the returned details
*
* Returns the details structure if present or will create one if not present.
* The returned structure must not be freed.
*
* Since: 1.26
*/
void
gst_message_parse_info_writable_details (GstMessage * message,
GstStructure ** structure)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_INFO);
g_return_if_fail (gst_message_is_writable (message));
g_return_if_fail (structure != NULL);
message_parse_details (message, (GstStructure **) structure, TRUE);
}
/**

View file

@ -462,6 +462,16 @@ GstStructure * gst_message_writable_structure (GstMessage *message);
GST_API
gboolean gst_message_has_name (GstMessage *message, const gchar *name);
GST_API
void gst_message_set_details (GstMessage *message, GstStructure *details);
GST_API
const GstStructure *
gst_message_get_details (GstMessage *message);
GST_API
GstStructure * gst_message_writable_details (GstMessage *message);
/* identifiers for events and messages */
GST_API
@ -489,6 +499,9 @@ void gst_message_parse_error (GstMessage *message, GError **g
GST_API
void gst_message_parse_error_details (GstMessage *message, const GstStructure **structure);
GST_API
void gst_message_parse_error_writable_details (GstMessage *message, GstStructure **structure);
/* WARNING */
GST_API
@ -503,6 +516,9 @@ void gst_message_parse_warning (GstMessage *message, GError **g
GST_API
void gst_message_parse_warning_details (GstMessage *message, const GstStructure **structure);
GST_API
void gst_message_parse_warning_writable_details (GstMessage *message, GstStructure **structure);
/* INFO */
GST_API
@ -517,6 +533,9 @@ void gst_message_parse_info (GstMessage *message, GError **g
GST_API
void gst_message_parse_info_details (GstMessage *message, const GstStructure **structure);
GST_API
void gst_message_parse_info_writable_details (GstMessage *message, GstStructure **structure);
/* TAG */
GST_API

View file

@ -85,6 +85,7 @@ GST_START_TEST (test_parsing)
gchar *debug;
GstStructure *d;
const GstStructure *dc;
GstStructure *writable_dc;
error = g_error_new (domain, 10, "test error");
fail_if (error == NULL);
@ -115,6 +116,15 @@ GST_START_TEST (test_parsing)
G_TYPE_STRING));
fail_unless (gst_structure_get_string (dc, "test-field"), "test-contents");
/* Check writable variant */
gst_message_ref (message);
/* Should fail if message is not writable */
ASSERT_CRITICAL (gst_message_parse_error_writable_details (message,
&writable_dc));
gst_message_unref (message);
gst_message_parse_error_writable_details (message, &writable_dc);
fail_unless (dc == writable_dc);
gst_message_unref (message);
g_error_free (error);
g_free (debug);
@ -625,6 +635,54 @@ GST_START_TEST (test_parsing)
gst_message_parse_instant_rate_request (message, &rate_multiplier);
fail_unless (rate_multiplier == 1.5);
gst_message_unref (message);
}
/* Message details */
{
GstStructure *details = NULL;
const GstStructure *message_structure = NULL;
/* create a message without a pre-existing structure */
message = gst_message_new_eos (NULL);
details = gst_message_writable_details (message);
fail_unless (details != NULL);
fail_unless (GST_IS_STRUCTURE (details));
/* The message (which initially did not have a supporting structure) should
* now has a structure whose name should be the message type name */
message_structure = gst_message_get_structure (message);
fail_if (message_structure == NULL);
fail_unless_equals_string (gst_structure_get_name (message_structure),
gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
gst_message_unref (message);
/* Same thing but when trying to set details */
message = gst_message_new_eos (NULL);
details =
gst_structure_new ("awesome-details", "something", G_TYPE_INT, 42,
NULL);
gst_message_set_details (message, details);
details = gst_message_writable_details (message);
fail_unless (details != NULL);
fail_unless (GST_IS_STRUCTURE (details));
gst_message_unref (message);
/* Make sure we can't set details on a message which already has details */
message = gst_message_new_eos (NULL);
details =
gst_structure_new ("awesome-details", "something", G_TYPE_INT, 42,
NULL);
gst_message_set_details (message, details);
details = NULL;
details = gst_structure_new_empty ("some-other-details");
ASSERT_CRITICAL (gst_message_set_details (message, details));
/* No need to free structure on failures, it will be freed */
gst_message_unref (message);
}
}