rtsp: Port to GIO
[platform/upstream/gstreamer.git] / gst-libs / gst / pbutils / missing-plugins.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:gstpbutilsmissingplugins
22  * @short_description: Create, recognise and parse missing-plugins messages
23  *
24  * <refsect2>
25  * <para>
26  * Functions to create, recognise and parse missing-plugins messages for
27  * applications and elements.
28  * </para>
29  * <para>
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:
33  * <itemizedlist>
34  *   <listitem><para>
35  *     concise error/problem reporting to the user mentioning what exactly
36  *     is missing, see gst_missing_plugin_message_get_description()
37  *   </para></listitem>
38  *   <listitem><para>
39  *     initiate installation of missing plugins, see
40  *     gst_missing_plugin_message_get_installer_detail() and
41  *     gst_install_plugins_async()
42  *   </para></listitem>
43  * </itemizedlist>
44  * </para>
45  * <para>
46  * Applications may also create missing-plugin messages themselves to install
47  * required elements that are missing, using the install mechanism mentioned
48  * above.
49  * </para>
50  * </refsect2>
51  */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif
56
57 #ifdef HAVE_SYS_TYPES_H
58 # include <sys/types.h>
59 #endif
60 #ifdef HAVE_UNISTD_H
61 # include <unistd.h>            /* getpid on UNIX */
62 #endif
63 #ifdef HAVE_PROCESS_H
64 # include <process.h>           /* getpid on win32 */
65 #endif
66
67 #include "gst/gst-i18n-plugin.h"
68
69 #include "pbutils.h"
70 #include "pbutils-private.h"
71
72 #include <string.h>
73
74 #define GST_DETAIL_STRING_MARKER "gstreamer"
75
76 typedef enum
77 {
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
84 } GstMissingType;
85
86 static const struct
87 {
88   GstMissingType type;
89   const gchar type_string[12];
90 } missing_type_mapping[] = {
91   {
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"}
97 };
98
99 static GstMissingType
100 missing_structure_get_type (const GstStructure * s)
101 {
102   const gchar *type;
103   guint i;
104
105   type = gst_structure_get_string (s, "type");
106   g_return_val_if_fail (type != NULL, GST_MISSING_TYPE_UNKNOWN);
107
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;
111   }
112
113   return GST_MISSING_TYPE_UNKNOWN;
114 }
115
116 GstCaps *
117 copy_and_clean_caps (const GstCaps * caps)
118 {
119   GstStructure *s;
120   GstCaps *ret;
121
122   ret = gst_caps_copy (caps);
123
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");
144   /* rtp fields */
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");
155
156   return ret;
157 }
158
159 /**
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"
164  *
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.
168  *
169  * Returns: (transfer full): a new #GstMessage, or NULL on error
170  */
171 GstMessage *
172 gst_missing_uri_source_message_new (GstElement * element,
173     const gchar * protocol)
174 {
175   GstStructure *s;
176   gchar *description;
177
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);
181
182   description = gst_pb_utils_get_source_description (protocol);
183
184   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
185       "urisource", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
186       description, NULL);
187
188   g_free (description);
189   return gst_message_new_element (GST_OBJECT_CAST (element), s);
190 }
191
192 /**
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"
197  *
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.
201  *
202  * Returns: (transfer full): a new #GstMessage, or NULL on error
203  */
204 GstMessage *
205 gst_missing_uri_sink_message_new (GstElement * element, const gchar * protocol)
206 {
207   GstStructure *s;
208   gchar *description;
209
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);
213
214   description = gst_pb_utils_get_sink_description (protocol);
215
216   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
217       "urisink", "detail", G_TYPE_STRING, protocol, "name", G_TYPE_STRING,
218       description, NULL);
219
220   g_free (description);
221   return gst_message_new_element (GST_OBJECT_CAST (element), s);
222 }
223
224 /**
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"
229  *
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
232  * use in plugins.
233  *
234  * Returns: (transfer full): a new #GstMessage, or NULL on error
235  */
236 GstMessage *
237 gst_missing_element_message_new (GstElement * element,
238     const gchar * factory_name)
239 {
240   GstStructure *s;
241   gchar *description;
242
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);
246
247   description = gst_pb_utils_get_element_description (factory_name);
248
249   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
250       "element", "detail", G_TYPE_STRING, factory_name, "name", G_TYPE_STRING,
251       description, NULL);
252
253   g_free (description);
254   return gst_message_new_element (GST_OBJECT_CAST (element), s);
255 }
256
257 /**
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
261  *
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.
265  *
266  * Returns: (transfer full): a new #GstMessage, or NULL on error
267  */
268 GstMessage *
269 gst_missing_decoder_message_new (GstElement * element,
270     const GstCaps * decode_caps)
271 {
272   GstStructure *s;
273   GstCaps *caps;
274   gchar *description;
275
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);
283
284   description = gst_pb_utils_get_decoder_description (decode_caps);
285   caps = copy_and_clean_caps (decode_caps);
286
287   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
288       "decoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
289       description, NULL);
290
291   gst_caps_unref (caps);
292   g_free (description);
293
294   return gst_message_new_element (GST_OBJECT_CAST (element), s);
295 }
296
297 /**
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
301  *
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.
305  *
306  * Returns: (transfer full): a new #GstMessage, or NULL on error
307  */
308 GstMessage *
309 gst_missing_encoder_message_new (GstElement * element,
310     const GstCaps * encode_caps)
311 {
312   GstStructure *s;
313   GstCaps *caps;
314   gchar *description;
315
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);
323
324   description = gst_pb_utils_get_encoder_description (encode_caps);
325   caps = copy_and_clean_caps (encode_caps);
326
327   s = gst_structure_new ("missing-plugin", "type", G_TYPE_STRING,
328       "encoder", "detail", GST_TYPE_CAPS, caps, "name", G_TYPE_STRING,
329       description, NULL);
330
331   gst_caps_unref (caps);
332   g_free (description);
333
334   return gst_message_new_element (GST_OBJECT_CAST (element), s);
335 }
336
337 static gboolean
338 missing_structure_get_string_detail (const GstStructure * s, gchar ** p_detail)
339 {
340   const gchar *detail;
341   GType detail_type;
342
343   *p_detail = NULL;
344
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");
348     return FALSE;
349   }
350
351   detail = gst_structure_get_string (s, "detail");
352   if (detail == NULL || *detail == '\0') {
353     GST_WARNING ("empty 'detail' field");
354     return FALSE;
355   }
356   *p_detail = g_strdup (detail);
357   return TRUE;
358 }
359
360 static gboolean
361 missing_structure_get_caps_detail (const GstStructure * s, GstCaps ** p_caps)
362 {
363   const GstCaps *caps;
364   const GValue *val;
365   GType detail_type;
366
367   *p_caps = NULL;
368
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");
372     return FALSE;
373   }
374
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");
379     return FALSE;
380   }
381
382   *p_caps = gst_caps_copy (caps);
383   return TRUE;
384 }
385
386 /**
387  * gst_missing_plugin_message_get_installer_detail:
388  * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
389  *
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().
393  * 
394  * This function is mainly for applications that call external plugin
395  * installation mechanisms using one of the two above-mentioned functions.
396  *
397  * Returns: a newly-allocated detail string, or NULL on error. Free string
398  *          with g_free() when not needed any longer.
399  */
400 gchar *
401 gst_missing_plugin_message_get_installer_detail (GstMessage * msg)
402 {
403   GstMissingType missing_type;
404   const gchar *progname;
405   const gchar *type;
406   GString *str = NULL;
407   gchar *detail = NULL;
408   gchar *desc;
409   const GstStructure *structure;
410
411   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
412
413   structure = gst_message_get_structure (msg);
414   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
415
416   missing_type = missing_structure_get_type (structure);
417   if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
418     GST_WARNING ("couldn't parse 'type' field");
419     goto error;
420   }
421
422   type = gst_structure_get_string (structure, "type");
423   g_assert (type != NULL);      /* validity already checked above */
424
425   /* FIXME: use gst_installer_detail_new() here too */
426   str = g_string_new (GST_DETAIL_STRING_MARKER "|");
427   g_string_append_printf (str, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
428
429   progname = (const gchar *) g_get_prgname ();
430   if (progname) {
431     g_string_append_printf (str, "%s|", progname);
432   } else {
433     g_string_append_printf (str, "pid/%lu|", (gulong) getpid ());
434   }
435
436   desc = gst_missing_plugin_message_get_description (msg);
437   if (desc) {
438     g_strdelimit (desc, "|", '#');
439     g_string_append_printf (str, "%s|", desc);
440     g_free (desc);
441   } else {
442     g_string_append (str, "|");
443   }
444
445   switch (missing_type) {
446     case GST_MISSING_TYPE_URISOURCE:
447     case GST_MISSING_TYPE_URISINK:
448     case GST_MISSING_TYPE_ELEMENT:
449       if (!missing_structure_get_string_detail (structure, &detail))
450         goto error;
451       break;
452     case GST_MISSING_TYPE_DECODER:
453     case GST_MISSING_TYPE_ENCODER:{
454       GstCaps *caps = NULL;
455
456       if (!missing_structure_get_caps_detail (structure, &caps))
457         goto error;
458
459       detail = gst_caps_to_string (caps);
460       gst_caps_unref (caps);
461       break;
462     }
463     default:
464       g_return_val_if_reached (NULL);
465   }
466
467   g_string_append_printf (str, "%s-%s", type, detail);
468   g_free (detail);
469
470   return g_string_free (str, FALSE);
471
472 /* ERRORS */
473 error:
474   {
475     GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
476     if (str)
477       g_string_free (str, TRUE);
478     return NULL;
479   }
480 }
481
482 /**
483  * gst_missing_plugin_message_get_description:
484  * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
485  *
486  * Returns a localised string describing the missing feature, for use in
487  * error dialogs and the like. Should never return NULL unless @msg is not
488  * a valid missing-plugin message.
489  *
490  * This function is mainly for applications that need a human-readable string
491  * describing a missing plugin, given a previously collected missing-plugin
492  * message
493  *
494  * Returns: a newly-allocated description string, or NULL on error. Free
495  *          string with g_free() when not needed any longer.
496  */
497 gchar *
498 gst_missing_plugin_message_get_description (GstMessage * msg)
499 {
500   GstMissingType missing_type;
501   const gchar *desc;
502   gchar *ret = NULL;
503   const GstStructure *structure;
504
505   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
506
507   structure = gst_message_get_structure (msg);
508   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
509
510   desc = gst_structure_get_string (structure, "name");
511   if (desc != NULL && *desc != '\0') {
512     ret = g_strdup (desc);
513     goto done;
514   }
515
516   /* fallback #1 */
517   missing_type = missing_structure_get_type (structure);
518
519   switch (missing_type) {
520     case GST_MISSING_TYPE_URISOURCE:
521     case GST_MISSING_TYPE_URISINK:
522     case GST_MISSING_TYPE_ELEMENT:{
523       gchar *detail = NULL;
524
525       if (missing_structure_get_string_detail (structure, &detail)) {
526         if (missing_type == GST_MISSING_TYPE_URISOURCE)
527           ret = gst_pb_utils_get_source_description (detail);
528         else if (missing_type == GST_MISSING_TYPE_URISINK)
529           ret = gst_pb_utils_get_sink_description (detail);
530         else
531           ret = gst_pb_utils_get_sink_description (detail);
532         g_free (detail);
533       }
534       break;
535     }
536     case GST_MISSING_TYPE_DECODER:
537     case GST_MISSING_TYPE_ENCODER:{
538       GstCaps *caps = NULL;
539
540       if (missing_structure_get_caps_detail (structure, &caps)) {
541         if (missing_type == GST_MISSING_TYPE_DECODER)
542           ret = gst_pb_utils_get_decoder_description (caps);
543         else
544           ret = gst_pb_utils_get_encoder_description (caps);
545         gst_caps_unref (caps);
546       }
547       break;
548     }
549     default:
550       break;
551   }
552
553   if (ret)
554     goto done;
555
556   /* fallback #2 */
557   switch (missing_type) {
558     case GST_MISSING_TYPE_URISOURCE:
559       desc = _("Unknown source element");
560       break;
561     case GST_MISSING_TYPE_URISINK:
562       desc = _("Unknown sink element");
563       break;
564     case GST_MISSING_TYPE_ELEMENT:
565       desc = _("Unknown element");
566       break;
567     case GST_MISSING_TYPE_DECODER:
568       desc = _("Unknown decoder element");
569       break;
570     case GST_MISSING_TYPE_ENCODER:
571       desc = _("Unknown encoder element");
572       break;
573     default:
574       /* we should really never get here, but we better still return
575        * something if we do */
576       desc = _("Plugin or element of unknown type");
577       break;
578   }
579   ret = g_strdup (desc);
580
581 done:
582
583   GST_LOG ("returning '%s'", ret);
584   return ret;
585 }
586
587 /**
588  * gst_is_missing_plugin_message:
589  * @msg: a #GstMessage
590  *
591  * Checks whether @msg is a missing plugins message.
592  *
593  * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
594  */
595 gboolean
596 gst_is_missing_plugin_message (GstMessage * msg)
597 {
598   const GstStructure *structure;
599
600   g_return_val_if_fail (msg != NULL, FALSE);
601   g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
602
603   structure = gst_message_get_structure (msg);
604   if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || structure == NULL)
605     return FALSE;
606
607   return gst_structure_has_name (structure, "missing-plugin");
608 }
609
610 /* takes ownership of the description */
611 static gchar *
612 gst_installer_detail_new (gchar * description, const gchar * type,
613     const gchar * detail)
614 {
615   const gchar *progname;
616   GString *s;
617
618   s = g_string_new (GST_DETAIL_STRING_MARKER "|");
619   g_string_append_printf (s, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
620
621   progname = (const gchar *) g_get_prgname ();
622   if (progname) {
623     g_string_append_printf (s, "%s|", progname);
624   } else {
625     g_string_append_printf (s, "pid/%lu|", (gulong) getpid ());
626   }
627
628   if (description) {
629     g_strdelimit (description, "|", '#');
630     g_string_append_printf (s, "%s|", description);
631     g_free (description);
632   } else {
633     g_string_append (s, "|");
634   }
635
636   g_string_append_printf (s, "%s-%s", type, detail);
637
638   return g_string_free (s, FALSE);
639 }
640
641 /**
642  * gst_missing_uri_source_installer_detail_new:
643  * @protocol: the URI protocol the missing source needs to implement,
644  *            e.g. "http" or "mms"
645  *
646  * Returns an opaque string containing all the details about the missing
647  * element to be passed to an external installer called via
648  * gst_install_plugins_async() or gst_install_plugins_sync().
649  * 
650  * This function is mainly for applications that call external plugin
651  * installation mechanisms using one of the two above-mentioned functions in
652  * the case where the application knows exactly what kind of plugin it is
653  * missing.
654  *
655  * Returns: a newly-allocated detail string, or NULL on error. Free string
656  *          with g_free() when not needed any longer.
657  *
658  * Since: 0.10.15
659  */
660 gchar *
661 gst_missing_uri_source_installer_detail_new (const gchar * protocol)
662 {
663   gchar *desc;
664
665   g_return_val_if_fail (protocol != NULL, NULL);
666
667   desc = gst_pb_utils_get_source_description (protocol);
668   return gst_installer_detail_new (desc, "urisource", protocol);
669 }
670
671 /**
672  * gst_missing_uri_sink_installer_detail_new:
673  * @protocol: the URI protocol the missing source needs to implement,
674  *            e.g. "http" or "mms"
675  *
676  * Returns an opaque string containing all the details about the missing
677  * element to be passed to an external installer called via
678  * gst_install_plugins_async() or gst_install_plugins_sync().
679  * 
680  * This function is mainly for applications that call external plugin
681  * installation mechanisms using one of the two above-mentioned functions in
682  * the case where the application knows exactly what kind of plugin it is
683  * missing.
684  *
685  * Returns: a newly-allocated detail string, or NULL on error. Free string
686  *          with g_free() when not needed any longer.
687  *
688  * Since: 0.10.15
689  */
690 gchar *
691 gst_missing_uri_sink_installer_detail_new (const gchar * protocol)
692 {
693   gchar *desc;
694
695   g_return_val_if_fail (protocol != NULL, NULL);
696
697   desc = gst_pb_utils_get_sink_description (protocol);
698   return gst_installer_detail_new (desc, "urisink", protocol);
699 }
700
701 /**
702  * gst_missing_element_installer_detail_new:
703  * @factory_name: the name of the missing element (element factory),
704  *            e.g. "videoscale" or "cdparanoiasrc"
705  *
706  * Returns an opaque string containing all the details about the missing
707  * element to be passed to an external installer called via
708  * gst_install_plugins_async() or gst_install_plugins_sync().
709  * 
710  * This function is mainly for applications that call external plugin
711  * installation mechanisms using one of the two above-mentioned functions in
712  * the case where the application knows exactly what kind of plugin it is
713  * missing.
714  *
715  * Returns: a newly-allocated detail string, or NULL on error. Free string
716  *          with g_free() when not needed any longer.
717  *
718  * Since: 0.10.15
719  */
720 gchar *
721 gst_missing_element_installer_detail_new (const gchar * factory_name)
722 {
723   gchar *desc;
724
725   g_return_val_if_fail (factory_name != NULL, NULL);
726
727   desc = gst_pb_utils_get_element_description (factory_name);
728   return gst_installer_detail_new (desc, "element", factory_name);
729 }
730
731 /**
732  * gst_missing_decoder_installer_detail_new:
733  * @decode_caps: the (fixed) caps for which a decoder element is needed
734  *
735  * Returns an opaque string containing all the details about the missing
736  * element to be passed to an external installer called via
737  * gst_install_plugins_async() or gst_install_plugins_sync().
738  * 
739  * This function is mainly for applications that call external plugin
740  * installation mechanisms using one of the two above-mentioned functions in
741  * the case where the application knows exactly what kind of plugin it is
742  * missing.
743  *
744  * Returns: a newly-allocated detail string, or NULL on error. Free string
745  *          with g_free() when not needed any longer.
746  *
747  * Since: 0.10.15
748  */
749 gchar *
750 gst_missing_decoder_installer_detail_new (const GstCaps * decode_caps)
751 {
752   GstCaps *caps;
753   gchar *detail_str, *caps_str, *desc;
754
755   g_return_val_if_fail (decode_caps != NULL, NULL);
756   g_return_val_if_fail (GST_IS_CAPS (decode_caps), NULL);
757   g_return_val_if_fail (!gst_caps_is_any (decode_caps), NULL);
758   g_return_val_if_fail (!gst_caps_is_empty (decode_caps), NULL);
759   g_return_val_if_fail (gst_caps_is_fixed (decode_caps), NULL);
760
761   desc = gst_pb_utils_get_decoder_description (decode_caps);
762   caps = copy_and_clean_caps (decode_caps);
763   caps_str = gst_caps_to_string (caps);
764   detail_str = gst_installer_detail_new (desc, "decoder", caps_str);
765   g_free (caps_str);
766   gst_caps_unref (caps);
767
768   return detail_str;
769 }
770
771 /**
772  * gst_missing_encoder_installer_detail_new:
773  * @encode_caps: the (fixed) caps for which an encoder element is needed
774  *
775  * Returns an opaque string containing all the details about the missing
776  * element to be passed to an external installer called via
777  * gst_install_plugins_async() or gst_install_plugins_sync().
778  * 
779  * This function is mainly for applications that call external plugin
780  * installation mechanisms using one of the two above-mentioned functions in
781  * the case where the application knows exactly what kind of plugin it is
782  * missing.
783  *
784  * Returns: a newly-allocated detail string, or NULL on error. Free string
785  *          with g_free() when not needed any longer.
786  *
787  * Since: 0.10.15
788  */
789 gchar *
790 gst_missing_encoder_installer_detail_new (const GstCaps * encode_caps)
791 {
792   GstCaps *caps;
793   gchar *detail_str, *caps_str, *desc;
794
795   g_return_val_if_fail (encode_caps != NULL, NULL);
796   g_return_val_if_fail (GST_IS_CAPS (encode_caps), NULL);
797   g_return_val_if_fail (!gst_caps_is_any (encode_caps), NULL);
798   g_return_val_if_fail (!gst_caps_is_empty (encode_caps), NULL);
799   g_return_val_if_fail (gst_caps_is_fixed (encode_caps), NULL);
800
801   desc = gst_pb_utils_get_encoder_description (encode_caps);
802   caps = copy_and_clean_caps (encode_caps);
803   caps_str = gst_caps_to_string (caps);
804   detail_str = gst_installer_detail_new (desc, "encoder", caps_str);
805   g_free (caps_str);
806   gst_caps_unref (caps);
807
808   return detail_str;
809 }