tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.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
410   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
411
412   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
413
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");
417     goto error;
418   }
419
420   type = gst_structure_get_string (msg->structure, "type");
421   g_assert (type != NULL);      /* validity already checked above */
422
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);
426
427   progname = (const gchar *) g_get_prgname ();
428   if (progname) {
429     g_string_append_printf (str, "%s|", progname);
430   } else {
431     g_string_append_printf (str, "pid/%lu|", (gulong) getpid ());
432   }
433
434   desc = gst_missing_plugin_message_get_description (msg);
435   if (desc) {
436     g_strdelimit (desc, "|", '#');
437     g_string_append_printf (str, "%s|", desc);
438     g_free (desc);
439   } else {
440     g_string_append (str, "|");
441   }
442
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))
448         goto error;
449       break;
450     case GST_MISSING_TYPE_DECODER:
451     case GST_MISSING_TYPE_ENCODER:{
452       GstCaps *caps = NULL;
453
454       if (!missing_structure_get_caps_detail (msg->structure, &caps))
455         goto error;
456
457       detail = gst_caps_to_string (caps);
458       gst_caps_unref (caps);
459       break;
460     }
461     default:
462       g_return_val_if_reached (NULL);
463   }
464
465   g_string_append_printf (str, "%s-%s", type, detail);
466   g_free (detail);
467
468   return g_string_free (str, FALSE);
469
470 /* ERRORS */
471 error:
472   {
473     GST_WARNING ("Failed to parse missing-plugin msg: %" GST_PTR_FORMAT, msg);
474     if (str)
475       g_string_free (str, TRUE);
476     return NULL;
477   }
478 }
479
480 /**
481  * gst_missing_plugin_message_get_description:
482  * @msg: a missing-plugin #GstMessage of type #GST_MESSAGE_ELEMENT
483  *
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.
487  *
488  * This function is mainly for applications that need a human-readable string
489  * describing a missing plugin, given a previously collected missing-plugin
490  * message
491  *
492  * Returns: a newly-allocated description string, or NULL on error. Free
493  *          string with g_free() when not needed any longer.
494  */
495 gchar *
496 gst_missing_plugin_message_get_description (GstMessage * msg)
497 {
498   GstMissingType missing_type;
499   const gchar *desc;
500   gchar *ret = NULL;
501
502   g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
503
504   GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
505
506   desc = gst_structure_get_string (msg->structure, "name");
507   if (desc != NULL && *desc != '\0') {
508     ret = g_strdup (desc);
509     goto done;
510   }
511
512   /* fallback #1 */
513   missing_type = missing_structure_get_type (msg->structure);
514
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;
520
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);
526         else
527           ret = gst_pb_utils_get_sink_description (detail);
528         g_free (detail);
529       }
530       break;
531     }
532     case GST_MISSING_TYPE_DECODER:
533     case GST_MISSING_TYPE_ENCODER:{
534       GstCaps *caps = NULL;
535
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);
539         else
540           ret = gst_pb_utils_get_encoder_description (caps);
541         gst_caps_unref (caps);
542       }
543       break;
544     }
545     default:
546       break;
547   }
548
549   if (ret)
550     goto done;
551
552   /* fallback #2 */
553   switch (missing_type) {
554     case GST_MISSING_TYPE_URISOURCE:
555       desc = _("Unknown source element");
556       break;
557     case GST_MISSING_TYPE_URISINK:
558       desc = _("Unknown sink element");
559       break;
560     case GST_MISSING_TYPE_ELEMENT:
561       desc = _("Unknown element");
562       break;
563     case GST_MISSING_TYPE_DECODER:
564       desc = _("Unknown decoder element");
565       break;
566     case GST_MISSING_TYPE_ENCODER:
567       desc = _("Unknown encoder element");
568       break;
569     default:
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");
573       break;
574   }
575   ret = g_strdup (desc);
576
577 done:
578
579   GST_LOG ("returning '%s'", ret);
580   return ret;
581 }
582
583 /**
584  * gst_is_missing_plugin_message:
585  * @msg: a #GstMessage
586  *
587  * Checks whether @msg is a missing plugins message.
588  *
589  * Returns: %TRUE if @msg is a missing-plugins message, otherwise %FALSE.
590  */
591 gboolean
592 gst_is_missing_plugin_message (GstMessage * msg)
593 {
594   g_return_val_if_fail (msg != NULL, FALSE);
595   g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
596
597   if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL)
598     return FALSE;
599
600   return gst_structure_has_name (msg->structure, "missing-plugin");
601 }
602
603 /* takes ownership of the description */
604 static gchar *
605 gst_installer_detail_new (gchar * description, const gchar * type,
606     const gchar * detail)
607 {
608   const gchar *progname;
609   GString *s;
610
611   s = g_string_new (GST_DETAIL_STRING_MARKER "|");
612   g_string_append_printf (s, "%u.%u|", GST_VERSION_MAJOR, GST_VERSION_MINOR);
613
614   progname = (const gchar *) g_get_prgname ();
615   if (progname) {
616     g_string_append_printf (s, "%s|", progname);
617   } else {
618     g_string_append_printf (s, "pid/%lu|", (gulong) getpid ());
619   }
620
621   if (description) {
622     g_strdelimit (description, "|", '#');
623     g_string_append_printf (s, "%s|", description);
624     g_free (description);
625   } else {
626     g_string_append (s, "|");
627   }
628
629   g_string_append_printf (s, "%s-%s", type, detail);
630
631   return g_string_free (s, FALSE);
632 }
633
634 /**
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"
638  *
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().
642  * 
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
646  * missing.
647  *
648  * Returns: a newly-allocated detail string, or NULL on error. Free string
649  *          with g_free() when not needed any longer.
650  *
651  * Since: 0.10.15
652  */
653 gchar *
654 gst_missing_uri_source_installer_detail_new (const gchar * protocol)
655 {
656   gchar *desc;
657
658   g_return_val_if_fail (protocol != NULL, NULL);
659
660   desc = gst_pb_utils_get_source_description (protocol);
661   return gst_installer_detail_new (desc, "urisource", protocol);
662 }
663
664 /**
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"
668  *
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().
672  * 
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
676  * missing.
677  *
678  * Returns: a newly-allocated detail string, or NULL on error. Free string
679  *          with g_free() when not needed any longer.
680  *
681  * Since: 0.10.15
682  */
683 gchar *
684 gst_missing_uri_sink_installer_detail_new (const gchar * protocol)
685 {
686   gchar *desc;
687
688   g_return_val_if_fail (protocol != NULL, NULL);
689
690   desc = gst_pb_utils_get_sink_description (protocol);
691   return gst_installer_detail_new (desc, "urisink", protocol);
692 }
693
694 /**
695  * gst_missing_element_installer_detail_new:
696  * @factory_name: the name of the missing element (element factory),
697  *            e.g. "videoscale" or "cdparanoiasrc"
698  *
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().
702  * 
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
706  * missing.
707  *
708  * Returns: a newly-allocated detail string, or NULL on error. Free string
709  *          with g_free() when not needed any longer.
710  *
711  * Since: 0.10.15
712  */
713 gchar *
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  * Since: 0.10.15
741  */
742 gchar *
743 gst_missing_decoder_installer_detail_new (const GstCaps * decode_caps)
744 {
745   GstCaps *caps;
746   gchar *detail_str, *caps_str, *desc;
747
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);
753
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);
758   g_free (caps_str);
759   gst_caps_unref (caps);
760
761   return detail_str;
762 }
763
764 /**
765  * gst_missing_encoder_installer_detail_new:
766  * @encode_caps: the (fixed) caps for which an encoder element is needed
767  *
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().
771  * 
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
775  * missing.
776  *
777  * Returns: a newly-allocated detail string, or NULL on error. Free string
778  *          with g_free() when not needed any longer.
779  *
780  * Since: 0.10.15
781  */
782 gchar *
783 gst_missing_encoder_installer_detail_new (const GstCaps * encode_caps)
784 {
785   GstCaps *caps;
786   gchar *detail_str, *caps_str, *desc;
787
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);
793
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);
798   g_free (caps_str);
799   gst_caps_unref (caps);
800
801   return detail_str;
802 }