1 /* GStreamer base utils library missing plugins support
2 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:gstpbutilsmissingplugins
22 * @short_description: Create, recognise and parse missing-plugins messages
26 * Functions to create, recognise and parse missing-plugins messages for
27 * applications and elements.
30 * Missing-plugin messages are posted on the bus by elements like decodebin
31 * or playbin if they can't find an appropriate source element or decoder
32 * element. The application can use these messages for two things:
35 * concise error/problem reporting to the user mentioning what exactly
36 * is missing, see gst_missing_plugin_message_get_description()
39 * initiate installation of missing plugins, see
40 * gst_missing_plugin_message_get_installer_detail() and
41 * gst_install_plugins_async()
46 * Applications may also create missing-plugin messages themselves to install
47 * required elements that are missing, using the install mechanism mentioned
57 #ifdef HAVE_SYS_TYPES_H
58 # include <sys/types.h>
61 # include <unistd.h> /* getpid on UNIX */
64 # include <process.h> /* getpid on win32 */
67 #include "gst/gst-i18n-plugin.h"
70 #include "pbutils-private.h"
74 #define GST_DETAIL_STRING_MARKER "gstreamer"
78 GST_MISSING_TYPE_UNKNOWN = 0,
79 GST_MISSING_TYPE_URISOURCE,
80 GST_MISSING_TYPE_URISINK,
81 GST_MISSING_TYPE_ELEMENT,
82 GST_MISSING_TYPE_DECODER,
83 GST_MISSING_TYPE_ENCODER
89 const gchar type_string[12];
90 } missing_type_mapping[] = {
92 GST_MISSING_TYPE_URISOURCE, "urisource"}, {
93 GST_MISSING_TYPE_URISINK, "urisink"}, {
94 GST_MISSING_TYPE_ELEMENT, "element"}, {
95 GST_MISSING_TYPE_DECODER, "decoder"}, {
96 GST_MISSING_TYPE_ENCODER, "encoder"}
100 missing_structure_get_type (const GstStructure * s)
105 type = gst_structure_get_string (s, "type");
106 g_return_val_if_fail (type != NULL, GST_MISSING_TYPE_UNKNOWN);
108 for (i = 0; i < G_N_ELEMENTS (missing_type_mapping); ++i) {
109 if (strcmp (missing_type_mapping[i].type_string, type) == 0)
110 return missing_type_mapping[i].type;
113 return GST_MISSING_TYPE_UNKNOWN;
117 copy_and_clean_caps (const GstCaps * caps)
122 ret = gst_caps_copy (caps);
124 /* make caps easier to interpret, remove common fields that are likely
125 * to be irrelevant for determining the right plugin (ie. mostly fields
126 * where template caps usually have the standard MIN - MAX range as value) */
127 s = gst_caps_get_structure (ret, 0);
128 gst_structure_remove_field (s, "codec_data");
129 gst_structure_remove_field (s, "palette_data");
130 gst_structure_remove_field (s, "pixel-aspect-ratio");
131 gst_structure_remove_field (s, "framerate");
132 gst_structure_remove_field (s, "leaf_size");
133 gst_structure_remove_field (s, "packet_size");
134 gst_structure_remove_field (s, "block_align");
135 gst_structure_remove_field (s, "metadata-interval"); /* icy caps */
136 /* decoders/encoders almost always handle the usual width/height/channel/rate
137 * range (and if we don't remove this then the app will have a much harder
138 * time blacklisting formats it has unsuccessfully tried to install before) */
139 gst_structure_remove_field (s, "width");
140 gst_structure_remove_field (s, "depth");
141 gst_structure_remove_field (s, "height");
142 gst_structure_remove_field (s, "channels");
143 gst_structure_remove_field (s, "rate");
145 gst_structure_remove_field (s, "config");
146 gst_structure_remove_field (s, "clock-rate");
147 gst_structure_remove_field (s, "clock-base");
148 gst_structure_remove_field (s, "maxps");
149 gst_structure_remove_field (s, "seqnum-base");
150 gst_structure_remove_field (s, "npt-start");
151 gst_structure_remove_field (s, "npt-stop");
152 gst_structure_remove_field (s, "play-speed");
153 gst_structure_remove_field (s, "play-scale");
154 gst_structure_remove_field (s, "dynamic_range");
160 * gst_missing_uri_source_message_new:
161 * @element: the #GstElement posting the message
162 * @protocol: the URI protocol the missing source needs to implement,
163 * e.g. "http" or "mms"
165 * Creates a missing-plugin message for @element to notify the application
166 * that a source element for a particular URI protocol is missing. This
167 * function is mainly for use in plugins.
169 * Returns: (transfer full): a new #GstMessage, or NULL on error
172 gst_missing_uri_source_message_new (GstElement * element,
173 const gchar * protocol)
178 g_return_val_if_fail (element != NULL, NULL);
179 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
180 g_return_val_if_fail (protocol != NULL, NULL);
182 description = gst_pb_utils_get_source_description (protocol);
184 s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
185 "urisource", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
188 g_free (description);
189 return gst_message_new_element (GST_OBJECT_CAST (element), s);
193 * gst_missing_uri_sink_message_new:
194 * @element: the #GstElement posting the message
195 * @protocol: the URI protocol the missing sink needs to implement,
196 * e.g. "http" or "smb"
198 * Creates a missing-plugin message for @element to notify the application
199 * that a sink element for a particular URI protocol is missing. This
200 * function is mainly for use in plugins.
202 * Returns: (transfer full): a new #GstMessage, or NULL on error
205 gst_missing_uri_sink_message_new (GstElement * element, const gchar * protocol)
210 g_return_val_if_fail (element != NULL, NULL);
211 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
212 g_return_val_if_fail (protocol != NULL, NULL);
214 description = gst_pb_utils_get_sink_description (protocol);
216 s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
217 "urisink", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
220 g_free (description);
221 return gst_message_new_element (GST_OBJECT_CAST (element), s);
225 * gst_missing_element_message_new:
226 * @element: the #GstElement posting the message
227 * @factory_name: the name of the missing element (element factory),
228 * e.g. "videoscale" or "cdparanoiasrc"
230 * Creates a missing-plugin message for @element to notify the application
231 * that a certain required element is missing. This function is mainly for
234 * Returns: (transfer full): a new #GstMessage, or NULL on error
237 gst_missing_element_message_new (GstElement * element,
238 const gchar * factory_name)
243 g_return_val_if_fail (element != NULL, NULL);
244 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
245 g_return_val_if_fail (factory_name != NULL, NULL);
247 description = gst_pb_utils_get_element_description (factory_name);
249 s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
250 "element", "detail", G_TYPE_STRING, factory_name, "name", G_TYPE_STRING,
253 g_free (description);
254 return gst_message_new_element (GST_OBJECT_CAST (element), s);
258 * gst_missing_decoder_message_new:
259 * @element: the #GstElement posting the message
260 * @decode_caps: the (fixed) caps for which a decoder element is needed
262 * Creates a missing-plugin message for @element to notify the application
263 * that a decoder element for a particular set of (fixed) caps is missing.
264 * This function is mainly for use in plugins.
266 * Returns: (transfer full): a new #GstMessage, or NULL on error
269 gst_missing_decoder_message_new (GstElement * element,
270 const GstCaps * decode_caps)
276 g_return_val_if_fail (element != NULL, NULL);
277 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
278 g_return_val_if_fail (decode_caps != NULL, NULL);
279 g_return_val_if_fail (GST_IS_CAPS (decode_caps), NULL);
280 g_return_val_if_fail (!gst_caps_is_any (decode_caps), NULL);
281 g_return_val_if_fail (!gst_caps_is_empty (decode_caps), NULL);
282 g_return_val_if_fail (gst_caps_is_fixed (decode_caps), NULL);
284 description = gst_pb_utils_get_decoder_description (decode_caps);
285 caps = copy_and_clean_caps (decode_caps);
287 s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
288 "decoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
291 gst_caps_unref (caps);
292 g_free (description);
294 return gst_message_new_element (GST_OBJECT_CAST (element), s);
298 * gst_missing_encoder_message_new:
299 * @element: the #GstElement posting the message
300 * @encode_caps: the (fixed) caps for which an encoder element is needed
302 * Creates a missing-plugin message for @element to notify the application
303 * that an encoder element for a particular set of (fixed) caps is missing.
304 * This function is mainly for use in plugins.
306 * Returns: (transfer full): a new #GstMessage, or NULL on error
309 gst_missing_encoder_message_new (GstElement * element,
310 const GstCaps * encode_caps)
316 g_return_val_if_fail (element != NULL, NULL);
317 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
318 g_return_val_if_fail (encode_caps != NULL, NULL);
319 g_return_val_if_fail (GST_IS_CAPS (encode_caps), NULL);
320 g_return_val_if_fail (!gst_caps_is_any (encode_caps), NULL);
321 g_return_val_if_fail (!gst_caps_is_empty (encode_caps), NULL);
322 g_return_val_if_fail (gst_caps_is_fixed (encode_caps), NULL);
324 description = gst_pb_utils_get_encoder_description (encode_caps);
325 caps = copy_and_clean_caps (encode_caps);
327 s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
328 "encoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
331 gst_caps_unref (caps);
332 g_free (description);
334 return gst_message_new_element (GST_OBJECT_CAST (element), s);
338 missing_structure_get_string_detail (const GstStructure * s, gchar ** p_detail)
345 detail_type = gst_structure_get_field_type (s, "detail");
346 if (!g_type_is_a (detail_type, G_TYPE_STRING)) {
347 GST_WARNING ("expected 'detail' field to be of G_TYPE_STRING");
351 detail = gst_structure_get_string (s, "detail");
352 if (detail == NULL || *detail == '\0') {
353 GST_WARNING ("empty 'detail' field");
356 *p_detail = g_strdup (detail);
361 missing_structure_get_caps_detail (const GstStructure * s, GstCaps ** p_caps)
369 detail_type = gst_structure_get_field_type (s, "detail");
370 if (!g_type_is_a (detail_type, GST_TYPE_CAPS)) {
371 GST_WARNING ("expected 'detail' field to be of GST_TYPE_CAPS");
375 val = gst_structure_get_value (s, "detail");
376 caps = gst_value_get_caps (val);
377 if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
378 GST_WARNING ("EMPTY or ANY caps not allowed");
382 *p_caps = gst_caps_copy (caps);
387 * gst_missing_plugin_message_get_installer_detail:
388 * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
390 * Returns an opaque string containing all the details about the missing
391 * element to be passed to an external installer called via
392 * gst_install_plugins_async() or gst_install_plugins_sync().
394 * This function is mainly for applications that call external plugin
395 * installation mechanisms using one of the two above-mentioned functions.
397 * Returns: a newly-allocated detail string, or NULL on error. Free string
398 * with g_free() when not needed any longer.
401 gst_missing_plugin_message_get_installer_detail (GstMessage * msg)
403 GstMissingType missing_type;
404 const gchar *progname;
407 gchar *detail = NULL;
410 g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
412 GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
414 missing_type = missing_structure_get_type (msg->structure);
415 if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
416 GST_WARNING ("couldn't parse 'type' field");
420 type = gst_structure_get_string (msg->structure, "type");
421 g_assert (type != NULL); /* validity already checked above */
423 /* FIXME: use gst_installer_detail_new() here too */
424 str = g_string_new (GST_DETAIL_STRING_MARKER "|");
425 g_string_append_printf (str, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
427 progname = (const gchar *) g_get_prgname ();
429 g_string_append_printf (str, "%s|", progname);
431 g_string_append_printf (str, "pid/%lu|", (gulong) getpid ());
434 desc = gst_missing_plugin_message_get_description (msg);
436 g_strdelimit (desc, "|", '#');
437 g_string_append_printf (str, "%s|", desc);
440 g_string_append (str, "|");
443 switch (missing_type) {
444 case GST_MISSING_TYPE_URISOURCE:
445 case GST_MISSING_TYPE_URISINK:
446 case GST_MISSING_TYPE_ELEMENT:
447 if (!missing_structure_get_string_detail (msg->structure, &detail))
450 case GST_MISSING_TYPE_DECODER:
451 case GST_MISSING_TYPE_ENCODER:{
452 GstCaps *caps = NULL;
454 if (!missing_structure_get_caps_detail (msg->structure, &caps))
457 detail = gst_caps_to_string (caps);
458 gst_caps_unref (caps);
462 g_return_val_if_reached (NULL);
465 g_string_append_printf (str, "%s-%s", type, detail);
468 return g_string_free (str, FALSE);
473 GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
475 g_string_free (str, TRUE);
481 * gst_missing_plugin_message_get_description:
482 * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
484 * Returns a localised string describing the missing feature, for use in
485 * error dialogs and the like. Should never return NULL unless @msg is not
486 * a valid missing-plugin message.
488 * This function is mainly for applications that need a human-readable string
489 * describing a missing plugin, given a previously collected missing-plugin
492 * Returns: a newly-allocated description string, or NULL on error. Free
493 * string with g_free() when not needed any longer.
496 gst_missing_plugin_message_get_description (GstMessage * msg)
498 GstMissingType missing_type;
502 g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
504 GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
506 desc = gst_structure_get_string (msg->structure, "name");
507 if (desc != NULL && *desc != '\0') {
508 ret = g_strdup (desc);
513 missing_type = missing_structure_get_type (msg->structure);
515 switch (missing_type) {
516 case GST_MISSING_TYPE_URISOURCE:
517 case GST_MISSING_TYPE_URISINK:
518 case GST_MISSING_TYPE_ELEMENT:{
519 gchar *detail = NULL;
521 if (missing_structure_get_string_detail (msg->structure, &detail)) {
522 if (missing_type == GST_MISSING_TYPE_URISOURCE)
523 ret = gst_pb_utils_get_source_description (detail);
524 else if (missing_type == GST_MISSING_TYPE_URISINK)
525 ret = gst_pb_utils_get_sink_description (detail);
527 ret = gst_pb_utils_get_sink_description (detail);
532 case GST_MISSING_TYPE_DECODER:
533 case GST_MISSING_TYPE_ENCODER:{
534 GstCaps *caps = NULL;
536 if (missing_structure_get_caps_detail (msg->structure, &caps)) {
537 if (missing_type == GST_MISSING_TYPE_DECODER)
538 ret = gst_pb_utils_get_decoder_description (caps);
540 ret = gst_pb_utils_get_encoder_description (caps);
541 gst_caps_unref (caps);
553 switch (missing_type) {
554 case GST_MISSING_TYPE_URISOURCE:
555 desc = _("Unknown source element");
557 case GST_MISSING_TYPE_URISINK:
558 desc = _("Unknown sink element");
560 case GST_MISSING_TYPE_ELEMENT:
561 desc = _("Unknown element");
563 case GST_MISSING_TYPE_DECODER:
564 desc = _("Unknown decoder element");
566 case GST_MISSING_TYPE_ENCODER:
567 desc = _("Unknown encoder element");
570 /* we should really never get here, but we better still return
571 * something if we do */
572 desc = _("Plugin or element of unknown type");
575 ret = g_strdup (desc);
579 GST_LOG ("returning '%s'", ret);
584 * gst_is_missing_plugin_message:
585 * @msg: a #GstMessage
587 * Checks whether @msg is a missing plugins message.
589 * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
592 gst_is_missing_plugin_message (GstMessage * msg)
594 g_return_val_if_fail (msg != NULL, FALSE);
595 g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
597 if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL)
600 return gst_structure_has_name (msg->structure, "missing-plugin");
603 /* takes ownership of the description */
605 gst_installer_detail_new (gchar * description, const gchar * type,
606 const gchar * detail)
608 const gchar *progname;
611 s = g_string_new (GST_DETAIL_STRING_MARKER "|");
612 g_string_append_printf (s, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
614 progname = (const gchar *) g_get_prgname ();
616 g_string_append_printf (s, "%s|", progname);
618 g_string_append_printf (s, "pid/%lu|", (gulong) getpid ());
622 g_strdelimit (description, "|", '#');
623 g_string_append_printf (s, "%s|", description);
624 g_free (description);
626 g_string_append (s, "|");
629 g_string_append_printf (s, "%s-%s", type, detail);
631 return g_string_free (s, FALSE);
635 * gst_missing_uri_source_installer_detail_new:
636 * @protocol: the URI protocol the missing source needs to implement,
637 * e.g. "http" or "mms"
639 * Returns an opaque string containing all the details about the missing
640 * element to be passed to an external installer called via
641 * gst_install_plugins_async() or gst_install_plugins_sync().
643 * This function is mainly for applications that call external plugin
644 * installation mechanisms using one of the two above-mentioned functions in
645 * the case where the application knows exactly what kind of plugin it is
648 * Returns: a newly-allocated detail string, or NULL on error. Free string
649 * with g_free() when not needed any longer.
654 gst_missing_uri_source_installer_detail_new (const gchar * protocol)
658 g_return_val_if_fail (protocol != NULL, NULL);
660 desc = gst_pb_utils_get_source_description (protocol);
661 return gst_installer_detail_new (desc, "urisource", protocol);
665 * gst_missing_uri_sink_installer_detail_new:
666 * @protocol: the URI protocol the missing source needs to implement,
667 * e.g. "http" or "mms"
669 * Returns an opaque string containing all the details about the missing
670 * element to be passed to an external installer called via
671 * gst_install_plugins_async() or gst_install_plugins_sync().
673 * This function is mainly for applications that call external plugin
674 * installation mechanisms using one of the two above-mentioned functions in
675 * the case where the application knows exactly what kind of plugin it is
678 * Returns: a newly-allocated detail string, or NULL on error. Free string
679 * with g_free() when not needed any longer.
684 gst_missing_uri_sink_installer_detail_new (const gchar * protocol)
688 g_return_val_if_fail (protocol != NULL, NULL);
690 desc = gst_pb_utils_get_sink_description (protocol);
691 return gst_installer_detail_new (desc, "urisink", protocol);
695 * gst_missing_element_installer_detail_new:
696 * @factory_name: the name of the missing element (element factory),
697 * e.g. "videoscale" or "cdparanoiasrc"
699 * Returns an opaque string containing all the details about the missing
700 * element to be passed to an external installer called via
701 * gst_install_plugins_async() or gst_install_plugins_sync().
703 * This function is mainly for applications that call external plugin
704 * installation mechanisms using one of the two above-mentioned functions in
705 * the case where the application knows exactly what kind of plugin it is
708 * Returns: a newly-allocated detail string, or NULL on error. Free string
709 * with g_free() when not needed any longer.
714 gst_missing_element_installer_detail_new (const gchar * factory_name)
718 g_return_val_if_fail (factory_name != NULL, NULL);
720 desc = gst_pb_utils_get_element_description (factory_name);
721 return gst_installer_detail_new (desc, "element", factory_name);
725 * gst_missing_decoder_installer_detail_new:
726 * @decode_caps: the (fixed) caps for which a decoder element is needed
728 * Returns an opaque string containing all the details about the missing
729 * element to be passed to an external installer called via
730 * gst_install_plugins_async() or gst_install_plugins_sync().
732 * This function is mainly for applications that call external plugin
733 * installation mechanisms using one of the two above-mentioned functions in
734 * the case where the application knows exactly what kind of plugin it is
737 * Returns: a newly-allocated detail string, or NULL on error. Free string
738 * with g_free() when not needed any longer.
743 gst_missing_decoder_installer_detail_new (const GstCaps * decode_caps)
746 gchar *detail_str, *caps_str, *desc;
748 g_return_val_if_fail (decode_caps != NULL, NULL);
749 g_return_val_if_fail (GST_IS_CAPS (decode_caps), NULL);
750 g_return_val_if_fail (!gst_caps_is_any (decode_caps), NULL);
751 g_return_val_if_fail (!gst_caps_is_empty (decode_caps), NULL);
752 g_return_val_if_fail (gst_caps_is_fixed (decode_caps), NULL);
754 desc = gst_pb_utils_get_decoder_description (decode_caps);
755 caps = copy_and_clean_caps (decode_caps);
756 caps_str = gst_caps_to_string (caps);
757 detail_str = gst_installer_detail_new (desc, "decoder", caps_str);
759 gst_caps_unref (caps);
765 * gst_missing_encoder_installer_detail_new:
766 * @encode_caps: the (fixed) caps for which an encoder element is needed
768 * Returns an opaque string containing all the details about the missing
769 * element to be passed to an external installer called via
770 * gst_install_plugins_async() or gst_install_plugins_sync().
772 * This function is mainly for applications that call external plugin
773 * installation mechanisms using one of the two above-mentioned functions in
774 * the case where the application knows exactly what kind of plugin it is
777 * Returns: a newly-allocated detail string, or NULL on error. Free string
778 * with g_free() when not needed any longer.
783 gst_missing_encoder_installer_detail_new (const GstCaps * encode_caps)
786 gchar *detail_str, *caps_str, *desc;
788 g_return_val_if_fail (encode_caps != NULL, NULL);
789 g_return_val_if_fail (GST_IS_CAPS (encode_caps), NULL);
790 g_return_val_if_fail (!gst_caps_is_any (encode_caps), NULL);
791 g_return_val_if_fail (!gst_caps_is_empty (encode_caps), NULL);
792 g_return_val_if_fail (gst_caps_is_fixed (encode_caps), NULL);
794 desc = gst_pb_utils_get_encoder_description (encode_caps);
795 caps = copy_and_clean_caps (encode_caps);
796 caps_str = gst_caps_to_string (caps);
797 detail_str = gst_installer_detail_new (desc, "encoder", caps_str);
799 gst_caps_unref (caps);