Coverage Report

Created: 2026-02-24 07:11

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