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