• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer base utils library missing plugins support
2  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
3  *
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.
8  *
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.
13  *
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:gstpbutilsmissingplugins
22  * @title: Missing plugins
23  * @short_description: Create, recognise and parse missing-plugins messages
24  *
25  * Functions to create, recognise and parse missing-plugins messages for
26  * applications and elements.
27  *
28  * Missing-plugin messages are posted on the bus by elements like decodebin
29  * or playbin if they can't find an appropriate source element or decoder
30  * element. The application can use these messages for two things:
31  *
32  *   * concise error/problem reporting to the user mentioning what exactly
33  *     is missing, see gst_missing_plugin_message_get_description()
34  *
35  *   * initiate installation of missing plugins, see
36  *     gst_missing_plugin_message_get_installer_detail() and
37  *     gst_install_plugins_async()
38  *
39  * Applications may also create missing-plugin messages themselves to install
40  * required elements that are missing, using the install mechanism mentioned
41  * above.
42  *
43  */
44 
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
48 
49 #ifdef HAVE_SYS_TYPES_H
50 # include <sys/types.h>
51 #endif
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>            /* getpid on UNIX */
54 #endif
55 #ifdef HAVE_PROCESS_H
56 # include <process.h>           /* getpid on win32 */
57 #endif
58 
59 #include "gst/gst-i18n-plugin.h"
60 
61 #include "pbutils.h"
62 #include "pbutils-private.h"
63 
64 #include <string.h>
65 
66 #ifndef GST_DISABLE_GST_DEBUG
67 #define GST_CAT_DEFAULT gst_pb_utils_missing_plugins_ensure_debug_category()
68 
69 static GstDebugCategory *
gst_pb_utils_missing_plugins_ensure_debug_category(void)70 gst_pb_utils_missing_plugins_ensure_debug_category (void)
71 {
72   static gsize cat_gonce = 0;
73 
74   if (g_once_init_enter (&cat_gonce)) {
75     GstDebugCategory *cat = NULL;
76 
77     GST_DEBUG_CATEGORY_INIT (cat, "missing-plugins", 0,
78         "GstPbUtils missing plugins helper");
79 
80     g_once_init_leave (&cat_gonce, (gsize) cat);
81   }
82 
83   return (GstDebugCategory *) cat_gonce;
84 }
85 #endif /* GST_DISABLE_GST_DEBUG */
86 
87 #define GST_DETAIL_STRING_MARKER "gstreamer"
88 
89 typedef enum
90 {
91   GST_MISSING_TYPE_UNKNOWN = 0,
92   GST_MISSING_TYPE_URISOURCE,
93   GST_MISSING_TYPE_URISINK,
94   GST_MISSING_TYPE_ELEMENT,
95   GST_MISSING_TYPE_DECODER,
96   GST_MISSING_TYPE_ENCODER
97 } GstMissingType;
98 
99 static const struct
100 {
101   GstMissingType type;
102   const gchar type_string[12];
103 } missing_type_mapping[] = {
104   {
105   GST_MISSING_TYPE_URISOURCE, "urisource"}, {
106   GST_MISSING_TYPE_URISINK, "urisink"}, {
107   GST_MISSING_TYPE_ELEMENT, "element"}, {
108   GST_MISSING_TYPE_DECODER, "decoder"}, {
109   GST_MISSING_TYPE_ENCODER, "encoder"}
110 };
111 
112 static GstMissingType
missing_structure_get_type(const GstStructure * s)113 missing_structure_get_type (const GstStructure * s)
114 {
115   const gchar *type;
116   guint i;
117 
118   type = gst_structure_get_string (s, "type");
119   g_return_val_if_fail (type != NULL, GST_MISSING_TYPE_UNKNOWN);
120 
121   for (i = 0; i < G_N_ELEMENTS (missing_type_mapping); ++i) {
122     if (strcmp (missing_type_mapping[i].type_string, type) == 0)
123       return missing_type_mapping[i].type;
124   }
125 
126   return GST_MISSING_TYPE_UNKNOWN;
127 }
128 
129 GstCaps *
copy_and_clean_caps(const GstCaps * caps)130 copy_and_clean_caps (const GstCaps * caps)
131 {
132   GstStructure *s;
133   GstCaps *ret;
134 
135   ret = gst_caps_copy (caps);
136 
137   /* make caps easier to interpret, remove common fields that are likely
138    * to be irrelevant for determining the right plugin (ie. mostly fields
139    * where template caps usually have the standard MIN - MAX range as value) */
140   s = gst_caps_get_structure (ret, 0);
141   gst_structure_remove_field (s, "codec_data");
142   gst_structure_remove_field (s, "streamheader");
143   gst_structure_remove_field (s, "palette_data");
144   gst_structure_remove_field (s, "pixel-aspect-ratio");
145   gst_structure_remove_field (s, "framerate");
146   gst_structure_remove_field (s, "leaf_size");
147   gst_structure_remove_field (s, "packet_size");
148   gst_structure_remove_field (s, "block_align");
149   gst_structure_remove_field (s, "metadata-interval");  /* icy caps */
150   /* decoders/encoders almost always handle the usual width/height/channel/rate
151    * range (and if we don't remove this then the app will have a much harder
152    * time blacklisting formats it has unsuccessfully tried to install before) */
153   gst_structure_remove_field (s, "width");
154   gst_structure_remove_field (s, "depth");
155   gst_structure_remove_field (s, "height");
156   gst_structure_remove_field (s, "channels");
157   gst_structure_remove_field (s, "rate");
158   /* parsed, framed, stream-format and alignment are going to be handled by
159    * parsers and not relevant for decoders/encoders usually */
160   gst_structure_remove_field (s, "parsed");
161   gst_structure_remove_field (s, "framed");
162   gst_structure_remove_field (s, "stream-format");
163   gst_structure_remove_field (s, "alignment");
164   /* rtp fields */
165   gst_structure_remove_field (s, "config");
166   gst_structure_remove_field (s, "clock-rate");
167   gst_structure_remove_field (s, "timestamp-offset");
168   gst_structure_remove_field (s, "maxps");
169   gst_structure_remove_field (s, "seqnum-offset");
170   gst_structure_remove_field (s, "npt-start");
171   gst_structure_remove_field (s, "npt-stop");
172   gst_structure_remove_field (s, "play-speed");
173   gst_structure_remove_field (s, "play-scale");
174   gst_structure_remove_field (s, "dynamic_range");
175 
176   return ret;
177 }
178 
179 /**
180  * gst_missing_uri_source_message_new:
181  * @element: the #GstElement posting the message
182  * @protocol: the URI protocol the missing source needs to implement,
183  *            e.g. "http" or "mms"
184  *
185  * Creates a missing-plugin message for @element to notify the application
186  * that a source element for a particular URI protocol is missing. This
187  * function is mainly for use in plugins.
188  *
189  * Returns: (transfer full): a new #GstMessage, or NULL on error
190  */
191 GstMessage *
gst_missing_uri_source_message_new(GstElement * element,const gchar * protocol)192 gst_missing_uri_source_message_new (GstElement * element,
193     const gchar * protocol)
194 {
195   GstStructure *s;
196   gchar *description;
197 
198   g_return_val_if_fail (element != NULL, NULL);
199   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
200   g_return_val_if_fail (protocol != NULL, NULL);
201 
202   description = gst_pb_utils_get_source_description (protocol);
203 
204   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
205       "urisource", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
206       description, NULL);
207 
208   g_free (description);
209   return gst_message_new_element (GST_OBJECT_CAST (element), s);
210 }
211 
212 /**
213  * gst_missing_uri_sink_message_new:
214  * @element: the #GstElement posting the message
215  * @protocol: the URI protocol the missing sink needs to implement,
216  *            e.g. "http" or "smb"
217  *
218  * Creates a missing-plugin message for @element to notify the application
219  * that a sink element for a particular URI protocol is missing. This
220  * function is mainly for use in plugins.
221  *
222  * Returns: (transfer full): a new #GstMessage, or NULL on error
223  */
224 GstMessage *
gst_missing_uri_sink_message_new(GstElement * element,const gchar * protocol)225 gst_missing_uri_sink_message_new (GstElement * element, const gchar * protocol)
226 {
227   GstStructure *s;
228   gchar *description;
229 
230   g_return_val_if_fail (element != NULL, NULL);
231   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
232   g_return_val_if_fail (protocol != NULL, NULL);
233 
234   description = gst_pb_utils_get_sink_description (protocol);
235 
236   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
237       "urisink", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
238       description, NULL);
239 
240   g_free (description);
241   return gst_message_new_element (GST_OBJECT_CAST (element), s);
242 }
243 
244 /**
245  * gst_missing_element_message_new:
246  * @element: the #GstElement posting the message
247  * @factory_name: the name of the missing element (element factory),
248  *            e.g. "videoscale" or "cdparanoiasrc"
249  *
250  * Creates a missing-plugin message for @element to notify the application
251  * that a certain required element is missing. This function is mainly for
252  * use in plugins.
253  *
254  * Returns: (transfer full): a new #GstMessage, or NULL on error
255  */
256 GstMessage *
gst_missing_element_message_new(GstElement * element,const gchar * factory_name)257 gst_missing_element_message_new (GstElement * element,
258     const gchar * factory_name)
259 {
260   GstStructure *s;
261   gchar *description;
262 
263   g_return_val_if_fail (element != NULL, NULL);
264   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
265   g_return_val_if_fail (factory_name != NULL, NULL);
266 
267   description = gst_pb_utils_get_element_description (factory_name);
268 
269   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
270       "element", "detail", G_TYPE_STRING, factory_name, "name", G_TYPE_STRING,
271       description, NULL);
272 
273   g_free (description);
274   return gst_message_new_element (GST_OBJECT_CAST (element), s);
275 }
276 
277 /**
278  * gst_missing_decoder_message_new:
279  * @element: the #GstElement posting the message
280  * @decode_caps: the (fixed) caps for which a decoder element is needed
281  *
282  * Creates a missing-plugin message for @element to notify the application
283  * that a decoder element for a particular set of (fixed) caps is missing.
284  * This function is mainly for use in plugins.
285  *
286  * Returns: (transfer full): a new #GstMessage, or NULL on error
287  */
288 GstMessage *
gst_missing_decoder_message_new(GstElement * element,const GstCaps * decode_caps)289 gst_missing_decoder_message_new (GstElement * element,
290     const GstCaps * decode_caps)
291 {
292   GstStructure *s;
293   GstCaps *caps;
294   gchar *description;
295 
296   g_return_val_if_fail (element != NULL, NULL);
297   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
298   g_return_val_if_fail (decode_caps != NULL, NULL);
299   g_return_val_if_fail (GST_IS_CAPS (decode_caps), NULL);
300   g_return_val_if_fail (!gst_caps_is_any (decode_caps), NULL);
301   g_return_val_if_fail (!gst_caps_is_empty (decode_caps), NULL);
302   g_return_val_if_fail (gst_caps_is_fixed (decode_caps), NULL);
303 
304   description = gst_pb_utils_get_decoder_description (decode_caps);
305   caps = copy_and_clean_caps (decode_caps);
306 
307   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
308       "decoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
309       description, NULL);
310 
311   gst_caps_unref (caps);
312   g_free (description);
313 
314   return gst_message_new_element (GST_OBJECT_CAST (element), s);
315 }
316 
317 /**
318  * gst_missing_encoder_message_new:
319  * @element: the #GstElement posting the message
320  * @encode_caps: the (fixed) caps for which an encoder element is needed
321  *
322  * Creates a missing-plugin message for @element to notify the application
323  * that an encoder element for a particular set of (fixed) caps is missing.
324  * This function is mainly for use in plugins.
325  *
326  * Returns: (transfer full): a new #GstMessage, or NULL on error
327  */
328 GstMessage *
gst_missing_encoder_message_new(GstElement * element,const GstCaps * encode_caps)329 gst_missing_encoder_message_new (GstElement * element,
330     const GstCaps * encode_caps)
331 {
332   GstStructure *s;
333   GstCaps *caps;
334   gchar *description;
335 
336   g_return_val_if_fail (element != NULL, NULL);
337   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
338   g_return_val_if_fail (encode_caps != NULL, NULL);
339   g_return_val_if_fail (GST_IS_CAPS (encode_caps), NULL);
340   g_return_val_if_fail (!gst_caps_is_any (encode_caps), NULL);
341   g_return_val_if_fail (!gst_caps_is_empty (encode_caps), NULL);
342   g_return_val_if_fail (gst_caps_is_fixed (encode_caps), NULL);
343 
344   description = gst_pb_utils_get_encoder_description (encode_caps);
345   caps = copy_and_clean_caps (encode_caps);
346 
347   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
348       "encoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
349       description, NULL);
350 
351   gst_caps_unref (caps);
352   g_free (description);
353 
354   return gst_message_new_element (GST_OBJECT_CAST (element), s);
355 }
356 
357 static gboolean
missing_structure_get_string_detail(const GstStructure * s,gchar ** p_detail)358 missing_structure_get_string_detail (const GstStructure * s, gchar ** p_detail)
359 {
360   const gchar *detail;
361   GType detail_type;
362 
363   *p_detail = NULL;
364 
365   detail_type = gst_structure_get_field_type (s, "detail");
366   if (!g_type_is_a (detail_type, G_TYPE_STRING)) {
367     GST_WARNING ("expected 'detail' field to be of G_TYPE_STRING");
368     return FALSE;
369   }
370 
371   detail = gst_structure_get_string (s, "detail");
372   if (detail == NULL || *detail == '\0') {
373     GST_WARNING ("empty 'detail' field");
374     return FALSE;
375   }
376   *p_detail = g_strdup (detail);
377   return TRUE;
378 }
379 
380 static gboolean
missing_structure_get_caps_detail(const GstStructure * s,GstCaps ** p_caps)381 missing_structure_get_caps_detail (const GstStructure * s, GstCaps ** p_caps)
382 {
383   const GstCaps *caps;
384   const GValue *val;
385   GType detail_type;
386 
387   *p_caps = NULL;
388 
389   detail_type = gst_structure_get_field_type (s, "detail");
390   if (!g_type_is_a (detail_type, GST_TYPE_CAPS)) {
391     GST_WARNING ("expected 'detail' field to be of GST_TYPE_CAPS");
392     return FALSE;
393   }
394 
395   val = gst_structure_get_value (s, "detail");
396   caps = gst_value_get_caps (val);
397   if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
398     GST_WARNING ("EMPTY or ANY caps not allowed");
399     return FALSE;
400   }
401 
402   *p_caps = gst_caps_copy (caps);
403   return TRUE;
404 }
405 
406 /**
407  * gst_missing_plugin_message_get_installer_detail:
408  * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
409  *
410  * Returns an opaque string containing all the details about the missing
411  * element to be passed to an external installer called via
412  * gst_install_plugins_async() or gst_install_plugins_sync().
413  *
414  * This function is mainly for applications that call external plugin
415  * installation mechanisms using one of the two above-mentioned functions.
416  *
417  * Returns: a newly-allocated detail string, or NULL on error. Free string
418  *          with g_free() when not needed any longer.
419  */
420 gchar *
gst_missing_plugin_message_get_installer_detail(GstMessage * msg)421 gst_missing_plugin_message_get_installer_detail (GstMessage * msg)
422 {
423   GstMissingType missing_type;
424   const gchar *progname;
425   const gchar *type;
426   GString *str = NULL;
427   gchar *detail = NULL;
428   gchar *desc;
429   const GstStructure *structure;
430 
431   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
432 
433   structure = gst_message_get_structure (msg);
434   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
435 
436   missing_type = missing_structure_get_type (structure);
437   if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
438     GST_WARNING ("couldn't parse 'type' field");
439     goto error;
440   }
441 
442   type = gst_structure_get_string (structure, "type");
443   g_assert (type != NULL);      /* validity already checked above */
444 
445   /* FIXME: use gst_installer_detail_new() here too */
446   str = g_string_new (GST_DETAIL_STRING_MARKER "|");
447   g_string_append_printf (str, "%s|", GST_API_VERSION);
448 
449   progname = (const gchar *) g_get_prgname ();
450   if (progname) {
451     g_string_append_printf (str, "%s|", progname);
452   } else {
453     g_string_append_printf (str, "pid/%lu|", (gulong) getpid ());
454   }
455 
456   desc = gst_missing_plugin_message_get_description (msg);
457   if (desc) {
458     g_strdelimit (desc, "|", '#');
459     g_string_append_printf (str, "%s|", desc);
460     g_free (desc);
461   } else {
462     g_string_append (str, "|");
463   }
464 
465   switch (missing_type) {
466     case GST_MISSING_TYPE_URISOURCE:
467     case GST_MISSING_TYPE_URISINK:
468     case GST_MISSING_TYPE_ELEMENT:
469       if (!missing_structure_get_string_detail (structure, &detail))
470         goto error;
471       break;
472     case GST_MISSING_TYPE_DECODER:
473     case GST_MISSING_TYPE_ENCODER:{
474       GstCaps *caps = NULL;
475 
476       if (!missing_structure_get_caps_detail (structure, &caps))
477         goto error;
478 
479       detail = gst_caps_to_string (caps);
480       gst_caps_unref (caps);
481       break;
482     }
483     default:
484       g_return_val_if_reached (NULL);
485   }
486 
487   g_string_append_printf (str, "%s-%s", type, detail);
488   g_free (detail);
489 
490   return g_string_free (str, FALSE);
491 
492 /* ERRORS */
493 error:
494   {
495     GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
496     if (str)
497       g_string_free (str, TRUE);
498     return NULL;
499   }
500 }
501 
502 /**
503  * gst_missing_plugin_message_get_description:
504  * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
505  *
506  * Returns a localised string describing the missing feature, for use in
507  * error dialogs and the like. Should never return NULL unless @msg is not
508  * a valid missing-plugin message.
509  *
510  * This function is mainly for applications that need a human-readable string
511  * describing a missing plugin, given a previously collected missing-plugin
512  * message
513  *
514  * Returns: a newly-allocated description string, or NULL on error. Free
515  *          string with g_free() when not needed any longer.
516  */
517 gchar *
gst_missing_plugin_message_get_description(GstMessage * msg)518 gst_missing_plugin_message_get_description (GstMessage * msg)
519 {
520   GstMissingType missing_type;
521   const gchar *desc;
522   gchar *ret = NULL;
523   const GstStructure *structure;
524 
525   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
526 
527   structure = gst_message_get_structure (msg);
528   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
529 
530   desc = gst_structure_get_string (structure, "name");
531   if (desc != NULL && *desc != '\0') {
532     ret = g_strdup (desc);
533     goto done;
534   }
535 
536   /* fallback #1 */
537   missing_type = missing_structure_get_type (structure);
538 
539   switch (missing_type) {
540     case GST_MISSING_TYPE_URISOURCE:
541     case GST_MISSING_TYPE_URISINK:
542     case GST_MISSING_TYPE_ELEMENT:{
543       gchar *detail = NULL;
544 
545       if (missing_structure_get_string_detail (structure, &detail)) {
546         if (missing_type == GST_MISSING_TYPE_URISOURCE)
547           ret = gst_pb_utils_get_source_description (detail);
548         else if (missing_type == GST_MISSING_TYPE_URISINK)
549           ret = gst_pb_utils_get_sink_description (detail);
550         else
551           ret = gst_pb_utils_get_element_description (detail);
552         g_free (detail);
553       }
554       break;
555     }
556     case GST_MISSING_TYPE_DECODER:
557     case GST_MISSING_TYPE_ENCODER:{
558       GstCaps *caps = NULL;
559 
560       if (missing_structure_get_caps_detail (structure, &caps)) {
561         if (missing_type == GST_MISSING_TYPE_DECODER)
562           ret = gst_pb_utils_get_decoder_description (caps);
563         else
564           ret = gst_pb_utils_get_encoder_description (caps);
565         gst_caps_unref (caps);
566       }
567       break;
568     }
569     default:
570       break;
571   }
572 
573   if (ret)
574     goto done;
575 
576   /* fallback #2 */
577   switch (missing_type) {
578     case GST_MISSING_TYPE_URISOURCE:
579       desc = _("Unknown source element");
580       break;
581     case GST_MISSING_TYPE_URISINK:
582       desc = _("Unknown sink element");
583       break;
584     case GST_MISSING_TYPE_ELEMENT:
585       desc = _("Unknown element");
586       break;
587     case GST_MISSING_TYPE_DECODER:
588       desc = _("Unknown decoder element");
589       break;
590     case GST_MISSING_TYPE_ENCODER:
591       desc = _("Unknown encoder element");
592       break;
593     default:
594       /* we should really never get here, but we better still return
595        * something if we do */
596       desc = _("Plugin or element of unknown type");
597       break;
598   }
599   ret = g_strdup (desc);
600 
601 done:
602 
603   GST_LOG ("returning '%s'", ret);
604   return ret;
605 }
606 
607 /**
608  * gst_is_missing_plugin_message:
609  * @msg: a #GstMessage
610  *
611  * Checks whether @msg is a missing plugins message.
612  *
613  * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
614  */
615 gboolean
gst_is_missing_plugin_message(GstMessage * msg)616 gst_is_missing_plugin_message (GstMessage * msg)
617 {
618   const GstStructure *structure;
619 
620   g_return_val_if_fail (msg != NULL, FALSE);
621   g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
622 
623   structure = gst_message_get_structure (msg);
624   if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || structure == NULL)
625     return FALSE;
626 
627   return gst_structure_has_name (structure, "missing-plugin");
628 }
629 
630 /* takes ownership of the description */
631 static gchar *
gst_installer_detail_new(gchar * description,const gchar * type,const gchar * detail)632 gst_installer_detail_new (gchar * description, const gchar * type,
633     const gchar * detail)
634 {
635   const gchar *progname;
636   GString *s;
637 
638   s = g_string_new (GST_DETAIL_STRING_MARKER "|");
639   g_string_append_printf (s, "%s|", GST_API_VERSION);
640 
641   progname = (const gchar *) g_get_prgname ();
642   if (progname) {
643     g_string_append_printf (s, "%s|", progname);
644   } else {
645     g_string_append_printf (s, "pid/%lu|", (gulong) getpid ());
646   }
647 
648   if (description) {
649     g_strdelimit (description, "|", '#');
650     g_string_append_printf (s, "%s|", description);
651     g_free (description);
652   } else {
653     g_string_append (s, "|");
654   }
655 
656   g_string_append_printf (s, "%s-%s", type, detail);
657 
658   return g_string_free (s, FALSE);
659 }
660 
661 /**
662  * gst_missing_uri_source_installer_detail_new:
663  * @protocol: the URI protocol the missing source needs to implement,
664  *            e.g. "http" or "mms"
665  *
666  * Returns an opaque string containing all the details about the missing
667  * element to be passed to an external installer called via
668  * gst_install_plugins_async() or gst_install_plugins_sync().
669  *
670  * This function is mainly for applications that call external plugin
671  * installation mechanisms using one of the two above-mentioned functions in
672  * the case where the application knows exactly what kind of plugin it is
673  * missing.
674  *
675  * Returns: a newly-allocated detail string, or NULL on error. Free string
676  *          with g_free() when not needed any longer.
677  */
678 gchar *
gst_missing_uri_source_installer_detail_new(const gchar * protocol)679 gst_missing_uri_source_installer_detail_new (const gchar * protocol)
680 {
681   gchar *desc;
682 
683   g_return_val_if_fail (protocol != NULL, NULL);
684 
685   desc = gst_pb_utils_get_source_description (protocol);
686   return gst_installer_detail_new (desc, "urisource", protocol);
687 }
688 
689 /**
690  * gst_missing_uri_sink_installer_detail_new:
691  * @protocol: the URI protocol the missing source needs to implement,
692  *            e.g. "http" or "mms"
693  *
694  * Returns an opaque string containing all the details about the missing
695  * element to be passed to an external installer called via
696  * gst_install_plugins_async() or gst_install_plugins_sync().
697  *
698  * This function is mainly for applications that call external plugin
699  * installation mechanisms using one of the two above-mentioned functions in
700  * the case where the application knows exactly what kind of plugin it is
701  * missing.
702  *
703  * Returns: a newly-allocated detail string, or NULL on error. Free string
704  *          with g_free() when not needed any longer.
705  */
706 gchar *
gst_missing_uri_sink_installer_detail_new(const gchar * protocol)707 gst_missing_uri_sink_installer_detail_new (const gchar * protocol)
708 {
709   gchar *desc;
710 
711   g_return_val_if_fail (protocol != NULL, NULL);
712 
713   desc = gst_pb_utils_get_sink_description (protocol);
714   return gst_installer_detail_new (desc, "urisink", protocol);
715 }
716 
717 /**
718  * gst_missing_element_installer_detail_new:
719  * @factory_name: the name of the missing element (element factory),
720  *            e.g. "videoscale" or "cdparanoiasrc"
721  *
722  * Returns an opaque string containing all the details about the missing
723  * element to be passed to an external installer called via
724  * gst_install_plugins_async() or gst_install_plugins_sync().
725  *
726  * This function is mainly for applications that call external plugin
727  * installation mechanisms using one of the two above-mentioned functions in
728  * the case where the application knows exactly what kind of plugin it is
729  * missing.
730  *
731  * Returns: a newly-allocated detail string, or NULL on error. Free string
732  *          with g_free() when not needed any longer.
733  */
734 gchar *
gst_missing_element_installer_detail_new(const gchar * factory_name)735 gst_missing_element_installer_detail_new (const gchar * factory_name)
736 {
737   gchar *desc;
738 
739   g_return_val_if_fail (factory_name != NULL, NULL);
740 
741   desc = gst_pb_utils_get_element_description (factory_name);
742   return gst_installer_detail_new (desc, "element", factory_name);
743 }
744 
745 /**
746  * gst_missing_decoder_installer_detail_new:
747  * @decode_caps: the (fixed) caps for which a decoder element is needed
748  *
749  * Returns an opaque string containing all the details about the missing
750  * element to be passed to an external installer called via
751  * gst_install_plugins_async() or gst_install_plugins_sync().
752  *
753  * This function is mainly for applications that call external plugin
754  * installation mechanisms using one of the two above-mentioned functions in
755  * the case where the application knows exactly what kind of plugin it is
756  * missing.
757  *
758  * Returns: a newly-allocated detail string, or NULL on error. Free string
759  *          with g_free() when not needed any longer.
760  */
761 gchar *
gst_missing_decoder_installer_detail_new(const GstCaps * decode_caps)762 gst_missing_decoder_installer_detail_new (const GstCaps * decode_caps)
763 {
764   GstCaps *caps;
765   gchar *detail_str, *caps_str, *desc;
766 
767   g_return_val_if_fail (decode_caps != NULL, NULL);
768   g_return_val_if_fail (GST_IS_CAPS (decode_caps), NULL);
769   g_return_val_if_fail (!gst_caps_is_any (decode_caps), NULL);
770   g_return_val_if_fail (!gst_caps_is_empty (decode_caps), NULL);
771   g_return_val_if_fail (gst_caps_is_fixed (decode_caps), NULL);
772 
773   desc = gst_pb_utils_get_decoder_description (decode_caps);
774   caps = copy_and_clean_caps (decode_caps);
775   caps_str = gst_caps_to_string (caps);
776   detail_str = gst_installer_detail_new (desc, "decoder", caps_str);
777   g_free (caps_str);
778   gst_caps_unref (caps);
779 
780   return detail_str;
781 }
782 
783 /**
784  * gst_missing_encoder_installer_detail_new:
785  * @encode_caps: the (fixed) caps for which an encoder element is needed
786  *
787  * Returns an opaque string containing all the details about the missing
788  * element to be passed to an external installer called via
789  * gst_install_plugins_async() or gst_install_plugins_sync().
790  *
791  * This function is mainly for applications that call external plugin
792  * installation mechanisms using one of the two above-mentioned functions in
793  * the case where the application knows exactly what kind of plugin it is
794  * missing.
795  *
796  * Returns: a newly-allocated detail string, or NULL on error. Free string
797  *          with g_free() when not needed any longer.
798  */
799 gchar *
gst_missing_encoder_installer_detail_new(const GstCaps * encode_caps)800 gst_missing_encoder_installer_detail_new (const GstCaps * encode_caps)
801 {
802   GstCaps *caps;
803   gchar *detail_str, *caps_str, *desc;
804 
805   g_return_val_if_fail (encode_caps != NULL, NULL);
806   g_return_val_if_fail (GST_IS_CAPS (encode_caps), NULL);
807   g_return_val_if_fail (!gst_caps_is_any (encode_caps), NULL);
808   g_return_val_if_fail (!gst_caps_is_empty (encode_caps), NULL);
809   g_return_val_if_fail (gst_caps_is_fixed (encode_caps), NULL);
810 
811   desc = gst_pb_utils_get_encoder_description (encode_caps);
812   caps = copy_and_clean_caps (encode_caps);
813   caps_str = gst_caps_to_string (caps);
814   detail_str = gst_installer_detail_new (desc, "encoder", caps_str);
815   g_free (caps_str);
816   gst_caps_unref (caps);
817 
818   return detail_str;
819 }
820