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