diff --git a/girs/GstPlay-1.0.gir b/girs/GstPlay-1.0.gir index 40bb287587..9fabc6df09 100644 --- a/girs/GstPlay-1.0.gir +++ b/girs/GstPlay-1.0.gir @@ -1900,6 +1900,34 @@ See also #gst_play_get_message_bus() + + Reads the stream ID the play message @msg applies to, if any. + + + The stream ID this message applies to + + + + + A #GstMessage + + + + + + Reads the URI the play message @msg applies to. + + + The URI this message applies to + + + + + A #GstMessage + + + + Parse the given buffering @msg and extract the corresponding value @@ -1971,7 +1999,11 @@ See also #gst_play_get_message_bus() - Parse the given error @msg and extract the corresponding #GError. + Parse the given error @msg and extract the corresponding #GError. + +Since 1.26 the details will always contain the URI this refers to in an +"uri" field of type string, and (if known) the string "stream-id" it is +referring to. @@ -1991,6 +2023,35 @@ See also #gst_play_get_message_bus() + + Parses missing plugin descriptions and installer details from a +GST_PLAY_ERROR_MISSING_PLUGIN error message. + +Both arrays will have the same length, and strings at the same index +correspond to each other. + +The installer details can be passed to gst_install_plugins_sync() or +gst_install_plugins_async(). + + + %TRUE if the message contained a missing-plugin error. + + + + + A #GstMessage + + + + a %NULL-terminated array of descriptions + + + + a %NULL-terminated array of installer details + + + + Parse the given media-info-updated @msg and extract the corresponding media information @@ -2149,7 +2210,11 @@ See also #gst_play_get_message_bus() - Parse the given warning @msg and extract the corresponding #GError + Parse the given warning @msg and extract the corresponding #GError. + +Since 1.26 the details will always contain the URI this refers to in an +"uri" field of type string, and (if known) the string "stream-id" it is +referring to. @@ -2169,6 +2234,35 @@ See also #gst_play_get_message_bus() + + Parses missing plugin descriptions and installer details from a +GST_PLAY_ERROR_MISSING_PLUGIN warning message. + +Both arrays will have the same length, and strings at the same index +correspond to each other. + +The installer details can be passed to gst_install_plugins_sync() or +gst_install_plugins_async(). + + + %TRUE if the message contained a missing-plugin error. + + + + + A #GstMessage + + + + a %NULL-terminated array of descriptions + + + + a %NULL-terminated array of installer details + + + + @@ -2928,6 +3022,34 @@ freed using gst_play_visualization_free(). + + Reads the stream ID the play message @msg applies to, if any. + + + The stream ID this message applies to + + + + + A #GstMessage + + + + + + Reads the URI the play message @msg applies to. + + + The URI this message applies to + + + + + A #GstMessage + + + + Parse the given buffering @msg and extract the corresponding value @@ -2999,7 +3121,11 @@ freed using gst_play_visualization_free(). - Parse the given error @msg and extract the corresponding #GError. + Parse the given error @msg and extract the corresponding #GError. + +Since 1.26 the details will always contain the URI this refers to in an +"uri" field of type string, and (if known) the string "stream-id" it is +referring to. @@ -3019,6 +3145,35 @@ freed using gst_play_visualization_free(). + + Parses missing plugin descriptions and installer details from a +GST_PLAY_ERROR_MISSING_PLUGIN error message. + +Both arrays will have the same length, and strings at the same index +correspond to each other. + +The installer details can be passed to gst_install_plugins_sync() or +gst_install_plugins_async(). + + + %TRUE if the message contained a missing-plugin error. + + + + + A #GstMessage + + + + a %NULL-terminated array of descriptions + + + + a %NULL-terminated array of installer details + + + + Parse the given media-info-updated @msg and extract the corresponding media information @@ -3177,7 +3332,11 @@ freed using gst_play_visualization_free(). - Parse the given warning @msg and extract the corresponding #GError + Parse the given warning @msg and extract the corresponding #GError. + +Since 1.26 the details will always contain the URI this refers to in an +"uri" field of type string, and (if known) the string "stream-id" it is +referring to. @@ -3197,6 +3356,35 @@ freed using gst_play_visualization_free(). + + Parses missing plugin descriptions and installer details from a +GST_PLAY_ERROR_MISSING_PLUGIN warning message. + +Both arrays will have the same length, and strings at the same index +correspond to each other. + +The installer details can be passed to gst_install_plugins_sync() or +gst_install_plugins_async(). + + + %TRUE if the message contained a missing-plugin error. + + + + + A #GstMessage + + + + a %NULL-terminated array of descriptions + + + + a %NULL-terminated array of installer details + + + + Gets a string representing the given state. diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c b/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c index ef93821451..cc02f7ec3b 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c @@ -188,6 +188,8 @@ struct _GstPlay GstStructure *config; + GList *missing_plugin_messages; + /* Protected by lock */ gboolean seek_pending; /* Only set from main context */ GstClockTime last_seek_time; /* Only set from main context */ @@ -273,6 +275,8 @@ static void remove_seek_source (GstPlay * self); static gboolean query_position (GstPlay * self, GstClockTime * position); +static void gst_play_set_uri_details (GstPlay * self, GstStructure * details); + static void gst_play_init (GstPlay * self) { @@ -318,6 +322,7 @@ api_bus_post_message (GstPlay * self, GstPlayMessage message_type, const gchar * firstfield, ...) { GstStructure *message_data = NULL; + GstStructure *details = NULL; GstMessage *msg = NULL; va_list varargs; @@ -332,8 +337,26 @@ api_bus_post_message (GstPlay * self, GstPlayMessage message_type, msg = gst_message_new_custom (GST_MESSAGE_APPLICATION, GST_OBJECT (self), message_data); - GST_DEBUG ("Created message with payload: [ %" GST_PTR_FORMAT " ]", - message_data); + + // ERROR/WARNING messages store the details in differently named fields for + // backwards compatibility + if (message_type == GST_PLAY_MESSAGE_ERROR) { + const GValue *v = gst_structure_get_value (message_data, + GST_PLAY_MESSAGE_DATA_ERROR_DETAILS); + details = g_value_get_boxed (v); + } else if (message_type == GST_PLAY_MESSAGE_WARNING) { + const GValue *v = gst_structure_get_value (message_data, + GST_PLAY_MESSAGE_DATA_WARNING_DETAILS); + details = g_value_get_boxed (v); + } + + if (!details) + details = gst_message_writable_details (msg); + + gst_play_set_uri_details (self, details); + + GST_DEBUG_OBJECT (self, + "Created message with payload: [ %" GST_PTR_FORMAT " ]", message_data); gst_bus_post (self->api_bus, msg); } @@ -931,49 +954,43 @@ remove_ready_timeout_source (GstPlay * self) static void -on_error (GstPlay * self, GError * err, const GstStructure * details) +on_error (GstPlay * self, GError * err, GstStructure * details) { #ifndef GST_DISABLE_GST_DEBUG - GstStructure *extra_details = NULL; gchar *dot_data = NULL; #endif GST_ERROR_OBJECT (self, "Error: %s (%s, %d)", err->message, g_quark_to_string (err->domain), err->code); + if (!details) + details = gst_structure_new_static_str_empty ("error-details"); + #ifndef GST_DISABLE_GST_DEBUG - if (details != NULL) { - extra_details = gst_structure_copy (details); - } else { - extra_details = gst_structure_new_static_str_empty ("error-details"); - } if (gst_play_config_get_pipeline_dump_in_error_details (self->config)) { dot_data = gst_debug_bin_to_dot_data (GST_BIN_CAST (self->playbin), GST_DEBUG_GRAPH_SHOW_ALL); - gst_structure_set (extra_details, "pipeline-dump", G_TYPE_STRING, dot_data, - NULL); + gst_structure_set (details, "pipeline-dump", G_TYPE_STRING, dot_data, NULL); } #endif api_bus_post_message (self, GST_PLAY_MESSAGE_ERROR, GST_PLAY_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, - GST_PLAY_MESSAGE_DATA_ERROR_DETAILS, GST_TYPE_STRUCTURE, -#ifndef GST_DISABLE_GST_DEBUG - extra_details -#else - details -#endif - , NULL); + GST_PLAY_MESSAGE_DATA_ERROR_DETAILS, GST_TYPE_STRUCTURE, details, NULL); #ifndef GST_DISABLE_GST_DEBUG g_free (dot_data); - gst_structure_free (extra_details); #endif + gst_structure_free (details); g_error_free (err); remove_tick_source (self); remove_ready_timeout_source (self); + g_list_free_full (self->missing_plugin_messages, + (GDestroyNotify) gst_message_unref); + self->missing_plugin_messages = NULL; + self->target_state = GST_STATE_NULL; self->current_state = GST_STATE_NULL; self->is_live = FALSE; @@ -1013,18 +1030,109 @@ dump_dot_file (GstPlay * self, const gchar * name) g_free (full_name); } +static void +gst_play_set_missing_plugin_details (GstPlay * self, GstStructure * details) +{ + GValue missing_plugin_details = G_VALUE_INIT; + + g_value_init (&missing_plugin_details, GST_TYPE_ARRAY); + + for (GList * l = self->missing_plugin_messages; l; l = l->next) { + GstMessage *missing_plugin_message = l->data; + GValue v = G_VALUE_INIT; + GstStructure *s; + gchar *description, *installer_details; + + description = + gst_missing_plugin_message_get_description (missing_plugin_message); + installer_details = + gst_missing_plugin_message_get_installer_detail + (missing_plugin_message); + + s = gst_structure_new_static_str ("missing-plugin-detail", "description", + G_TYPE_STRING, description, "installer-details", G_TYPE_STRING, + installer_details, NULL); + g_value_init (&v, GST_TYPE_STRUCTURE); + g_value_take_boxed (&v, s); + gst_value_array_append_and_take_value (&missing_plugin_details, &v); + + g_free (description); + g_free (installer_details); + } + + + gst_structure_take_value_static_str (details, "missing-plugin-details", + &missing_plugin_details); +} + +static void +gst_play_set_uri_details (GstPlay * self, GstStructure * details) +{ + if (!gst_structure_has_field (details, "uri")) { + gchar *uri; + + g_object_get (self->playbin, "current-uri", &uri, NULL); + if (!uri) + g_object_get (self->playbin, "uri", &uri, NULL); + if (!uri) + uri = g_strdup (self->uri); + gst_structure_set (details, "uri", G_TYPE_STRING, uri, NULL); + g_free (uri); + } +} + +static void +gst_play_set_stream_id_details (GstPlay * self, GstMessage * msg, + GstStructure * details) +{ + if (!gst_structure_has_field (details, "stream-id")) { + GstPad *pad = NULL; + gchar *stream_id; + + if (GST_IS_ELEMENT (GST_MESSAGE_SRC (msg))) { + GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (msg)); + + // If the message src has only one sinkpad (or is a source element) + // grab the stream id from there + GST_OBJECT_LOCK (element); + if (element->numsinkpads == 1) { + pad = gst_object_ref (element->sinkpads->data); + } else if (element->numsinkpads == 0 && element->numsrcpads > 0) { + pad = gst_object_ref (element->srcpads->data); + } + GST_OBJECT_UNLOCK (element); + } else if (GST_IS_PAD (GST_MESSAGE_SRC (msg))) { + pad = gst_object_ref (GST_PAD (GST_MESSAGE_SRC (msg))); + } + + if (pad) { + stream_id = gst_pad_get_stream_id (pad); + if (stream_id) + gst_structure_set (details, "stream-id", G_TYPE_STRING, stream_id, + NULL); + g_free (stream_id); + gst_object_unref (pad); + } + } +} + static void error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) { GstPlay *self = GST_PLAY (user_data); GError *err, *play_err; gchar *name, *debug, *message, *full_message; - const GstStructure *details = NULL; + GstStructure *details = NULL; + GstPlayError play_error = GST_PLAY_ERROR_FAILED; dump_dot_file (self, "error"); gst_message_parse_error (msg, &err, &debug); - gst_message_parse_error_details (msg, &details); + gst_message_parse_error_details (msg, (const GstStructure **) &details); + if (details) + details = gst_structure_copy (details); + else + details = gst_structure_new_static_str_empty ("message-details"); name = gst_object_get_path_string (msg->src); message = gst_error_get_message (err->domain, err->code); @@ -1042,8 +1150,15 @@ error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) if (debug != NULL) GST_ERROR_OBJECT (self, "Additional debug info: %s", debug); - play_err = - g_error_new_literal (GST_PLAY_ERROR, GST_PLAY_ERROR_FAILED, full_message); + gst_play_set_stream_id_details (self, msg, details); + if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN) || + g_error_matches (err, GST_STREAM_ERROR, + GST_STREAM_ERROR_CODEC_NOT_FOUND)) { + play_error = GST_PLAY_ERROR_MISSING_PLUGIN; + gst_play_set_missing_plugin_details (self, details); + } + + play_err = g_error_new_literal (GST_PLAY_ERROR, play_error, full_message); on_error (self, play_err, details); g_clear_error (&err); @@ -1059,12 +1174,17 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) GstPlay *self = GST_PLAY (user_data); GError *err, *play_err; gchar *name, *debug, *message, *full_message; - const GstStructure *details = NULL; + GstStructure *details = NULL; + GstPlayError play_error = GST_PLAY_ERROR_FAILED; dump_dot_file (self, "warning"); gst_message_parse_warning (msg, &err, &debug); - gst_message_parse_warning_details (msg, &details); + gst_message_parse_warning_details (msg, (const GstStructure **) &details); + if (details) + details = gst_structure_copy (details); + else + details = gst_structure_new_static_str_empty ("message-details"); name = gst_object_get_path_string (msg->src); message = gst_error_get_message (err->domain, err->code); @@ -1082,22 +1202,24 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) if (debug != NULL) GST_WARNING_OBJECT (self, "Additional debug info: %s", debug); - play_err = - g_error_new_literal (GST_PLAY_ERROR, GST_PLAY_ERROR_FAILED, full_message); + gst_play_set_stream_id_details (self, msg, details); + if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN) || + g_error_matches (err, GST_STREAM_ERROR, + GST_STREAM_ERROR_CODEC_NOT_FOUND)) { + play_error = GST_PLAY_ERROR_MISSING_PLUGIN; + gst_play_set_missing_plugin_details (self, details); + } + + play_err = g_error_new_literal (GST_PLAY_ERROR, play_error, full_message); GST_WARNING_OBJECT (self, "Warning: %s (%s, %d)", err->message, g_quark_to_string (err->domain), err->code); - if (details != NULL) { - api_bus_post_message (self, GST_PLAY_MESSAGE_WARNING, - GST_PLAY_MESSAGE_DATA_WARNING, G_TYPE_ERROR, play_err, - GST_PLAY_MESSAGE_DATA_WARNING_DETAILS, GST_TYPE_STRUCTURE, details, - NULL); - } else { - api_bus_post_message (self, GST_PLAY_MESSAGE_WARNING, - GST_PLAY_MESSAGE_DATA_WARNING, G_TYPE_ERROR, play_err, NULL); - } + api_bus_post_message (self, GST_PLAY_MESSAGE_WARNING, + GST_PLAY_MESSAGE_DATA_WARNING, G_TYPE_ERROR, play_err, + GST_PLAY_MESSAGE_DATA_WARNING_DETAILS, GST_TYPE_STRUCTURE, details, NULL); + gst_structure_free (details); g_clear_error (&play_err); g_clear_error (&err); g_free (debug); @@ -1606,6 +1728,9 @@ element_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) else if (target_state == GST_STATE_PLAYING) gst_play_play_internal (self); } + } else if (gst_is_missing_plugin_message (msg)) { + self->missing_plugin_messages = + g_list_prepend (self->missing_plugin_messages, gst_message_ref (msg)); } } @@ -2472,6 +2597,10 @@ gst_play_main (gpointer data) remove_tick_source (self); remove_ready_timeout_source (self); + g_list_free_full (self->missing_plugin_messages, + (GDestroyNotify) gst_message_unref); + self->missing_plugin_messages = NULL; + g_mutex_lock (&self->lock); if (self->media_info) { g_object_unref (self->media_info); @@ -2718,6 +2847,10 @@ gst_play_stop_internal (GstPlay * self, gboolean transient) tick_cb (self); remove_tick_source (self); + g_list_free_full (self->missing_plugin_messages, + (GDestroyNotify) gst_message_unref); + self->missing_plugin_messages = NULL; + add_ready_timeout_source (self); self->target_state = GST_STATE_NULL; @@ -4337,6 +4470,8 @@ gst_play_error_get_name (GstPlayError error) switch (error) { case GST_PLAY_ERROR_FAILED: return "failed"; + case GST_PLAY_ERROR_MISSING_PLUGIN: + return "missing-plugin"; } g_assert_not_reached (); @@ -4732,6 +4867,94 @@ gst_play_message_parse_type (GstMessage * msg, GstPlayMessage * type) type, NULL); } +/** + * gst_play_message_get_uri: + * @msg: A #GstMessage + * + * Reads the URI the play message @msg applies to. + * + * Returns: (transfer none): The URI this message applies to + * + * Since: 1.26 + */ +const gchar * +gst_play_message_get_uri (GstMessage * msg) +{ + const GstStructure *details = NULL; + const gchar *uri; + GstPlayMessage msg_type; + + g_return_val_if_fail (gst_play_is_play_message (msg), NULL); + + gst_play_message_parse_type (msg, &msg_type); + + // ERROR/WARNING messages store the details in differently named fields for + // backwards compatibility + if (msg_type == GST_PLAY_MESSAGE_ERROR) { + const GstStructure *s = gst_message_get_structure (msg); + const GValue *v = + gst_structure_get_value (s, GST_PLAY_MESSAGE_DATA_ERROR_DETAILS); + details = g_value_get_boxed (v); + } else if (msg_type == GST_PLAY_MESSAGE_WARNING) { + const GstStructure *s = gst_message_get_structure (msg); + const GValue *v = + gst_structure_get_value (s, GST_PLAY_MESSAGE_DATA_WARNING_DETAILS); + details = g_value_get_boxed (v); + } + + if (!details) + details = gst_message_get_details (msg); + + g_return_val_if_fail (details, NULL); + uri = gst_structure_get_string (details, "uri"); + g_return_val_if_fail (uri, NULL); + + return uri; +} + +/** + * gst_play_message_get_stream_id: + * @msg: A #GstMessage + * + * Reads the stream ID the play message @msg applies to, if any. + * + * Returns: (transfer none) (nullable): The stream ID this message applies to + * + * Since: 1.26 + */ +const gchar * +gst_play_message_get_stream_id (GstMessage * msg) +{ + const GstStructure *details = NULL; + const gchar *stream_id; + GstPlayMessage msg_type; + + g_return_val_if_fail (gst_play_is_play_message (msg), NULL); + + gst_play_message_parse_type (msg, &msg_type); + + // ERROR/WARNING messages store the details in differently named fields for + // backwards compatibility + if (msg_type == GST_PLAY_MESSAGE_ERROR) { + const GstStructure *s = gst_message_get_structure (msg); + const GValue *v = + gst_structure_get_value (s, GST_PLAY_MESSAGE_DATA_ERROR_DETAILS); + details = g_value_get_boxed (v); + } else if (msg_type == GST_PLAY_MESSAGE_WARNING) { + const GstStructure *s = gst_message_get_structure (msg); + const GValue *v = + gst_structure_get_value (s, GST_PLAY_MESSAGE_DATA_WARNING_DETAILS); + details = g_value_get_boxed (v); + } + + if (!details) + details = gst_message_get_details (msg); + g_return_val_if_fail (details, NULL); + stream_id = gst_structure_get_string (details, "stream-id"); + + return stream_id; +} + /** * gst_play_message_parse_uri_loaded: * @msg: A #GstMessage @@ -4857,6 +5080,10 @@ gst_play_message_parse_buffering_percent (GstMessage * msg, guint * percent) * * Parse the given error @msg and extract the corresponding #GError. * + * Since 1.26 the details will always contain the URI this refers to in an + * "uri" field of type string, and (if known) the string "stream-id" it is + * referring to. + * * Since: 1.20 */ void @@ -4869,13 +5096,118 @@ gst_play_message_parse_error (GstMessage * msg, GError ** error, GST_PLAY_MESSAGE_DATA_ERROR_DETAILS, GST_TYPE_STRUCTURE, details); } +static gboolean +gst_play_message_parse_missing_plugin (GstMessage * msg, + GstPlayMessage msg_type, gchar *** descriptions, + gchar *** installer_details) +{ + const GError *err; + const GValue *v, *details_array; + const GstStructure *s, *details; + guint n_details; + + if (descriptions) + *descriptions = NULL; + if (installer_details) + *installer_details = NULL; + + s = gst_message_get_structure (msg); + + v = gst_structure_get_value (s, + msg_type == + GST_PLAY_MESSAGE_ERROR ? GST_PLAY_MESSAGE_DATA_ERROR : + GST_PLAY_MESSAGE_DATA_WARNING); + if (!v) + return FALSE; + err = g_value_get_boxed (v); + if (!err) + return FALSE; + + if (!g_error_matches (err, GST_PLAY_ERROR, GST_PLAY_ERROR_MISSING_PLUGIN)) + return FALSE; + + v = gst_structure_get_value (s, + msg_type == + GST_PLAY_MESSAGE_ERROR ? GST_PLAY_MESSAGE_DATA_ERROR_DETAILS : + GST_PLAY_MESSAGE_DATA_WARNING_DETAILS); + if (!v) + return FALSE; + details = g_value_get_boxed (v); + if (!details) + return FALSE; + + details_array = gst_structure_get_value (details, "missing-plugin-details"); + + n_details = gst_value_array_get_size (details_array); + if (descriptions) + *descriptions = g_new0 (gchar *, n_details + 1); + if (installer_details) + *installer_details = g_new0 (gchar *, n_details + 1); + + for (guint i = 0; i < n_details; i++) { + const GValue *details_v = gst_value_array_get_value (details_array, i); + const GstStructure *details_s = g_value_get_boxed (details_v); + gchar *str; + + if (descriptions) { + gst_structure_get (details_s, "description", G_TYPE_STRING, &str, NULL); + (*descriptions)[i] = str; + } + + if (installer_details) { + gst_structure_get (details_s, "installer-details", G_TYPE_STRING, &str, + NULL); + (*installer_details)[i] = str; + } + } + + return TRUE; + +} + +/** + * gst_play_message_parse_error_missing_plugin: + * @msg: A #GstMessage + * @descriptions: (out) (optional) (transfer full): a %NULL-terminated array of descriptions + * @installer_details: (out) (optional) (nullable) (transfer full): a %NULL-terminated array of installer details + * + * Parses missing plugin descriptions and installer details from a + * GST_PLAY_ERROR_MISSING_PLUGIN error message. + * + * Both arrays will have the same length, and strings at the same index + * correspond to each other. + * + * The installer details can be passed to gst_install_plugins_sync() or + * gst_install_plugins_async(). + * + * Returns: %TRUE if the message contained a missing-plugin error. + * + * Since: 1.26 + */ +gboolean +gst_play_message_parse_error_missing_plugin (GstMessage * msg, + gchar *** descriptions, gchar *** installer_details) +{ + GstPlayMessage msg_type; + + gst_play_message_parse_type (msg, &msg_type); + g_return_val_if_fail (msg_type == GST_PLAY_MESSAGE_ERROR, FALSE); + + return gst_play_message_parse_missing_plugin (msg, msg_type, descriptions, + installer_details); +} + /** * gst_play_message_parse_warning: * @msg: A #GstMessage * @error: (out) (optional) (transfer full): the resulting warning * @details: (out) (optional) (nullable) (transfer full): A #GstStructure containing additional details about the warning * - * Parse the given warning @msg and extract the corresponding #GError + * Parse the given warning @msg and extract the corresponding #GError. + * + * Since 1.26 the details will always contain the URI this refers to in an + * "uri" field of type string, and (if known) the string "stream-id" it is + * referring to. * * Since: 1.20 */ @@ -4889,6 +5221,38 @@ gst_play_message_parse_warning (GstMessage * msg, GError ** error, GST_PLAY_MESSAGE_DATA_WARNING_DETAILS, GST_TYPE_STRUCTURE, details); } +/** + * gst_play_message_parse_warning_missing_plugin: + * @msg: A #GstMessage + * @descriptions: (out) (optional) (transfer full): a %NULL-terminated array of descriptions + * @installer_details: (out) (optional) (nullable) (transfer full): a %NULL-terminated array of installer details + * + * Parses missing plugin descriptions and installer details from a + * GST_PLAY_ERROR_MISSING_PLUGIN warning message. + * + * Both arrays will have the same length, and strings at the same index + * correspond to each other. + * + * The installer details can be passed to gst_install_plugins_sync() or + * gst_install_plugins_async(). + * + * Returns: %TRUE if the message contained a missing-plugin error. + * + * Since: 1.26 + */ +gboolean +gst_play_message_parse_warning_missing_plugin (GstMessage * msg, + gchar *** descriptions, gchar *** installer_details) +{ + GstPlayMessage msg_type; + + gst_play_message_parse_type (msg, &msg_type); + g_return_val_if_fail (msg_type == GST_PLAY_MESSAGE_WARNING, FALSE); + + return gst_play_message_parse_missing_plugin (msg, msg_type, descriptions, + installer_details); +} + /** * gst_play_message_parse_video_dimensions_changed: * @msg: A #GstMessage diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h b/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h index 9157414cf4..b82a41eae3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h @@ -137,11 +137,28 @@ GType gst_play_error_get_type (void); /** * GstPlayError: * @GST_PLAY_ERROR_FAILED: generic error. + * @GST_PLAY_ERROR_MISSING_PLUGIN: playback requires additional plugins (Since: 1.26). * * Since: 1.20 */ typedef enum { - GST_PLAY_ERROR_FAILED = 0 + GST_PLAY_ERROR_FAILED = 0, + + /** + * GST_PLAY_ERROR_MISSING_PLUGIN: + * + * Playback requires additional plugins. Information about the missing + * plugins can be retrieved from the message details. + * + * The details will contain the the missing plugin details in a field of + * type %GstArray named "missing-plugin-details". This array will contain + * %GstStructure with string "description" and a string "installer-details". + * + * The "installer-details" can be passed to gst_install_plugins_async(). + * + * Since: 1.26 + */ + GST_PLAY_ERROR_MISSING_PLUGIN } GstPlayError; GST_PLAY_API @@ -431,6 +448,12 @@ gboolean gst_play_is_play_message (GstMessage *ms GST_PLAY_API void gst_play_message_parse_type (GstMessage *msg, GstPlayMessage *type); +GST_PLAY_API +const gchar * gst_play_message_get_uri (GstMessage *msg); + +GST_PLAY_API +const gchar * gst_play_message_get_stream_id (GstMessage *msg); + GST_PLAY_API void gst_play_message_parse_uri_loaded (GstMessage *msg, gchar **uri); @@ -455,9 +478,15 @@ void gst_play_message_parse_buffering (GstMessage *ms GST_PLAY_API void gst_play_message_parse_error (GstMessage *msg, GError **error, GstStructure **details); +GST_PLAY_API +gboolean gst_play_message_parse_error_missing_plugin (GstMessage *msg, gchar *** descriptions, gchar *** installer_details); + GST_PLAY_API void gst_play_message_parse_warning (GstMessage *msg, GError **error, GstStructure **details); +GST_PLAY_API +gboolean gst_play_message_parse_warning_missing_plugin (GstMessage *msg, gchar *** descriptions, gchar *** installer_details); + GST_PLAY_API void gst_play_message_parse_video_dimensions_changed (GstMessage *msg, guint *width, guint *height);