|
1 /* GStreamer |
|
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * 2000 Wim Taymans <wtay@chello.be> |
|
4 * |
|
5 * gsturi.c: register URI handlers |
|
6 * |
|
7 * This library is free software; you can redistribute it and/or |
|
8 * modify it under the terms of the GNU Library General Public |
|
9 * License as published by the Free Software Foundation; either |
|
10 * version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This library is distributed in the hope that it will be useful, |
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 * Library General Public License for more details. |
|
16 * |
|
17 * You should have received a copy of the GNU Library General Public |
|
18 * License along with this library; if not, write to the |
|
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
20 * Boston, MA 02111-1307, USA. |
|
21 */ |
|
22 |
|
23 /** |
|
24 * SECTION:gsturihandler |
|
25 * @short_description: Interface to ease URI handling in plugins. |
|
26 * |
|
27 * The URIHandler is an interface that is implemented by Source and Sink |
|
28 * #GstElement to simplify then handling of URI. |
|
29 * |
|
30 * An application can use the following functions to quickly get an element |
|
31 * that handles the given URI for reading or writing |
|
32 * (gst_element_make_from_uri()). |
|
33 * |
|
34 * Source and Sink plugins should implement this interface when possible. |
|
35 * |
|
36 * Last reviewed on 2005-11-09 (0.9.4) |
|
37 */ |
|
38 |
|
39 #ifdef HAVE_CONFIG_H |
|
40 # include "config.h" |
|
41 #endif |
|
42 |
|
43 #include "gst_private.h" |
|
44 #include "gsturi.h" |
|
45 #include "gstinfo.h" |
|
46 #include "gstmarshal.h" |
|
47 #include "gstregistry.h" |
|
48 |
|
49 #include <string.h> |
|
50 |
|
51 #ifdef __SYMBIAN32__ |
|
52 #include <glib_global.h> |
|
53 #endif |
|
54 |
|
55 GST_DEBUG_CATEGORY_STATIC (gst_uri_handler_debug); |
|
56 #define GST_CAT_DEFAULT gst_uri_handler_debug |
|
57 |
|
58 static void gst_uri_handler_base_init (gpointer g_class); |
|
59 #ifdef __SYMBIAN32__ |
|
60 EXPORT_C |
|
61 #endif |
|
62 |
|
63 |
|
64 GType |
|
65 gst_uri_handler_get_type (void) |
|
66 { |
|
67 static GType urihandler_type = 0; |
|
68 |
|
69 if (G_UNLIKELY (urihandler_type == 0)) { |
|
70 static const GTypeInfo urihandler_info = { |
|
71 sizeof (GstURIHandlerInterface), |
|
72 gst_uri_handler_base_init, |
|
73 NULL, |
|
74 NULL, |
|
75 NULL, |
|
76 NULL, |
|
77 0, |
|
78 0, |
|
79 NULL, |
|
80 NULL |
|
81 }; |
|
82 |
|
83 urihandler_type = g_type_register_static (G_TYPE_INTERFACE, |
|
84 "GstURIHandler", &urihandler_info, 0); |
|
85 |
|
86 GST_DEBUG_CATEGORY_INIT (gst_uri_handler_debug, "GST_URI", GST_DEBUG_BOLD, |
|
87 "handling of URIs"); |
|
88 } |
|
89 return urihandler_type; |
|
90 } |
|
91 static void |
|
92 gst_uri_handler_base_init (gpointer g_class) |
|
93 { |
|
94 static gboolean initialized = FALSE; |
|
95 |
|
96 if (G_UNLIKELY (!initialized)) { |
|
97 |
|
98 /** |
|
99 * GstURIHandler::new-uri: |
|
100 * @handler: The #GstURIHandler which emitted the signal |
|
101 * @uri: The new URI, or NULL if the URI was removed |
|
102 * |
|
103 * The URI of the given @handler has changed. |
|
104 */ |
|
105 |
|
106 g_signal_new ("new-uri", GST_TYPE_URI_HANDLER, G_SIGNAL_RUN_LAST, |
|
107 G_STRUCT_OFFSET (GstURIHandlerInterface, new_uri), NULL, NULL, |
|
108 gst_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); |
|
109 initialized = TRUE; |
|
110 } |
|
111 } |
|
112 |
|
113 static const guchar acceptable[96] = { /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ |
|
114 0x00, 0x3F, 0x20, 0x20, 0x20, 0x00, 0x2C, 0x3F, 0x3F, 0x3F, 0x3F, 0x22, 0x20, 0x3F, 0x3F, 0x1C, /* 2X !"#$%&'()*+,-./ */ |
|
115 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x38, 0x20, 0x20, 0x2C, 0x20, 0x2C, /* 3X 0123456789:;<=>? */ |
|
116 0x30, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, /* 4X @ABCDEFGHIJKLMNO */ |
|
117 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x3F, /* 5X PQRSTUVWXYZ[\]^_ */ |
|
118 0x20, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, /* 6X `abcdefghijklmno */ |
|
119 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x20, 0x20, 0x20, 0x3F, 0x20 /* 7X pqrstuvwxyz{|}~DEL */ |
|
120 }; |
|
121 |
|
122 typedef enum |
|
123 { |
|
124 UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ |
|
125 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ |
|
126 UNSAFE_PATH = 0x4, /* Allows '/' and '?' and '&' and '=' */ |
|
127 UNSAFE_DOS_PATH = 0x8, /* Allows '/' and '?' and '&' and '=' and ':' */ |
|
128 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ |
|
129 UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ |
|
130 } UnsafeCharacterSet; |
|
131 |
|
132 #define HEX_ESCAPE '%' |
|
133 |
|
134 /* Escape undesirable characters using % |
|
135 * ------------------------------------- |
|
136 * |
|
137 * This function takes a pointer to a string in which |
|
138 * some characters may be unacceptable unescaped. |
|
139 * It returns a string which has these characters |
|
140 * represented by a '%' character followed by two hex digits. |
|
141 * |
|
142 * This routine returns a g_malloced string. |
|
143 */ |
|
144 |
|
145 static const gchar hex[16] = "0123456789ABCDEF"; |
|
146 |
|
147 static gchar * |
|
148 escape_string_internal (const gchar * string, UnsafeCharacterSet mask) |
|
149 { |
|
150 #define ACCEPTABLE_CHAR(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) |
|
151 |
|
152 const gchar *p; |
|
153 gchar *q; |
|
154 gchar *result; |
|
155 guchar c; |
|
156 gint unacceptable; |
|
157 UnsafeCharacterSet use_mask; |
|
158 |
|
159 g_return_val_if_fail (mask == UNSAFE_ALL |
|
160 || mask == UNSAFE_ALLOW_PLUS |
|
161 || mask == UNSAFE_PATH |
|
162 || mask == UNSAFE_DOS_PATH |
|
163 || mask == UNSAFE_HOST || mask == UNSAFE_SLASHES, NULL); |
|
164 |
|
165 if (string == NULL) { |
|
166 return NULL; |
|
167 } |
|
168 |
|
169 unacceptable = 0; |
|
170 use_mask = mask; |
|
171 for (p = string; *p != '\0'; p++) { |
|
172 c = *p; |
|
173 if (!ACCEPTABLE_CHAR (c)) { |
|
174 unacceptable++; |
|
175 } |
|
176 if ((use_mask == UNSAFE_HOST) && (unacceptable || (c == '/'))) { |
|
177 /* when escaping a host, if we hit something that needs to be escaped, or we finally |
|
178 * hit a path separator, revert to path mode (the host segment of the url is over). |
|
179 */ |
|
180 use_mask = UNSAFE_PATH; |
|
181 } |
|
182 } |
|
183 |
|
184 result = g_malloc (p - string + unacceptable * 2 + 1); |
|
185 |
|
186 use_mask = mask; |
|
187 for (q = result, p = string; *p != '\0'; p++) { |
|
188 c = *p; |
|
189 |
|
190 if (!ACCEPTABLE_CHAR (c)) { |
|
191 *q++ = HEX_ESCAPE; /* means hex coming */ |
|
192 *q++ = hex[c >> 4]; |
|
193 *q++ = hex[c & 15]; |
|
194 } else { |
|
195 *q++ = c; |
|
196 } |
|
197 if ((use_mask == UNSAFE_HOST) && (!ACCEPTABLE_CHAR (c) || (c == '/'))) { |
|
198 use_mask = UNSAFE_PATH; |
|
199 } |
|
200 } |
|
201 |
|
202 *q = '\0'; |
|
203 |
|
204 return result; |
|
205 } |
|
206 |
|
207 /** |
|
208 * escape_string: |
|
209 * @string: string to be escaped |
|
210 * |
|
211 * Escapes @string, replacing any and all special characters |
|
212 * with equivalent escape sequences. |
|
213 * |
|
214 * Return value: a newly allocated string equivalent to @string |
|
215 * but with all special characters escaped |
|
216 **/ |
|
217 static gchar * |
|
218 escape_string (const gchar * string) |
|
219 { |
|
220 return escape_string_internal (string, UNSAFE_ALL); |
|
221 } |
|
222 |
|
223 static int |
|
224 hex_to_int (gchar c) |
|
225 { |
|
226 return c >= '0' && c <= '9' ? c - '0' |
|
227 : c >= 'A' && c <= 'F' ? c - 'A' + 10 |
|
228 : c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1; |
|
229 } |
|
230 |
|
231 static int |
|
232 unescape_character (const char *scanner) |
|
233 { |
|
234 int first_digit; |
|
235 int second_digit; |
|
236 |
|
237 first_digit = hex_to_int (*scanner++); |
|
238 if (first_digit < 0) { |
|
239 return -1; |
|
240 } |
|
241 |
|
242 second_digit = hex_to_int (*scanner++); |
|
243 if (second_digit < 0) { |
|
244 return -1; |
|
245 } |
|
246 |
|
247 return (first_digit << 4) | second_digit; |
|
248 } |
|
249 |
|
250 /** |
|
251 * unescape_string: |
|
252 * @escaped_string: an escaped URI, path, or other string |
|
253 * @illegal_characters: a string containing a sequence of characters |
|
254 * considered "illegal", '\0' is automatically in this list. |
|
255 * |
|
256 * Decodes escaped characters (i.e. PERCENTxx sequences) in @escaped_string. |
|
257 * Characters are encoded in PERCENTxy form, where xy is the ASCII hex code |
|
258 * for character 16x+y. |
|
259 * |
|
260 * Return value: a newly allocated string with the unescaped equivalents, |
|
261 * or %NULL if @escaped_string contained one of the characters |
|
262 * in @illegal_characters. |
|
263 **/ |
|
264 static char * |
|
265 unescape_string (const gchar * escaped_string, const gchar * illegal_characters) |
|
266 { |
|
267 const gchar *in; |
|
268 gchar *out, *result; |
|
269 gint character; |
|
270 |
|
271 if (escaped_string == NULL) { |
|
272 return NULL; |
|
273 } |
|
274 |
|
275 result = g_malloc (strlen (escaped_string) + 1); |
|
276 |
|
277 out = result; |
|
278 for (in = escaped_string; *in != '\0'; in++) { |
|
279 character = *in; |
|
280 if (*in == HEX_ESCAPE) { |
|
281 character = unescape_character (in + 1); |
|
282 |
|
283 /* Check for an illegal character. We consider '\0' illegal here. */ |
|
284 if (character <= 0 |
|
285 || (illegal_characters != NULL |
|
286 && strchr (illegal_characters, (char) character) != NULL)) { |
|
287 g_free (result); |
|
288 return NULL; |
|
289 } |
|
290 in += 2; |
|
291 } |
|
292 *out++ = (char) character; |
|
293 } |
|
294 |
|
295 *out = '\0'; |
|
296 g_assert ((gsize) (out - result) <= strlen (escaped_string)); |
|
297 return result; |
|
298 |
|
299 } |
|
300 |
|
301 |
|
302 static void |
|
303 gst_uri_protocol_check_internal (const gchar * uri, gchar ** endptr) |
|
304 { |
|
305 gchar *check = (gchar *) uri; |
|
306 |
|
307 g_assert (uri != NULL); |
|
308 g_assert (endptr != NULL); |
|
309 |
|
310 if (g_ascii_isalpha (*check)) { |
|
311 check++; |
|
312 while (g_ascii_isalnum (*check)) |
|
313 check++; |
|
314 } |
|
315 |
|
316 *endptr = check; |
|
317 } |
|
318 |
|
319 /** |
|
320 * gst_uri_protocol_is_valid: |
|
321 * @protocol: A string |
|
322 * |
|
323 * Tests if the given string is a valid protocol identifier. Protocols |
|
324 * must consist of alphanumeric characters and not start with a number. |
|
325 * |
|
326 * Returns: TRUE if the string is a valid protocol identifier, FALSE otherwise. |
|
327 */ |
|
328 #ifdef __SYMBIAN32__ |
|
329 EXPORT_C |
|
330 #endif |
|
331 |
|
332 gboolean |
|
333 gst_uri_protocol_is_valid (const gchar * protocol) |
|
334 { |
|
335 gchar *endptr; |
|
336 |
|
337 g_return_val_if_fail (protocol != NULL, FALSE); |
|
338 |
|
339 gst_uri_protocol_check_internal (protocol, &endptr); |
|
340 |
|
341 return *endptr == '\0' && endptr != protocol; |
|
342 } |
|
343 |
|
344 /** |
|
345 * gst_uri_is_valid: |
|
346 * @uri: A URI string |
|
347 * |
|
348 * Tests if the given string is a valid URI identifier. URIs start with a valid |
|
349 * protocol followed by "://" and maybe a string identifying the location. |
|
350 * |
|
351 * Returns: TRUE if the string is a valid URI |
|
352 */ |
|
353 #ifdef __SYMBIAN32__ |
|
354 EXPORT_C |
|
355 #endif |
|
356 |
|
357 gboolean |
|
358 gst_uri_is_valid (const gchar * uri) |
|
359 { |
|
360 gchar *endptr; |
|
361 |
|
362 g_return_val_if_fail (uri != NULL, FALSE); |
|
363 |
|
364 gst_uri_protocol_check_internal (uri, &endptr); |
|
365 |
|
366 return (*endptr == ':' && *(endptr + 1) == '/' && *(endptr + 2) == '/'); |
|
367 } |
|
368 |
|
369 /** |
|
370 * gst_uri_get_protocol: |
|
371 * @uri: A URI string |
|
372 * |
|
373 * Extracts the protocol out of a given valid URI. The returned string must be |
|
374 * freed using g_free(). |
|
375 * |
|
376 * Returns: The protocol for this URI. |
|
377 */ |
|
378 #ifdef __SYMBIAN32__ |
|
379 EXPORT_C |
|
380 #endif |
|
381 |
|
382 gchar * |
|
383 gst_uri_get_protocol (const gchar * uri) |
|
384 { |
|
385 gchar *colon; |
|
386 |
|
387 g_return_val_if_fail (uri != NULL, NULL); |
|
388 g_return_val_if_fail (gst_uri_is_valid (uri), NULL); |
|
389 |
|
390 colon = strstr (uri, "://"); |
|
391 |
|
392 return g_strdown (g_strndup (uri, colon - uri)); |
|
393 } |
|
394 |
|
395 /** |
|
396 * gst_uri_has_protocol: |
|
397 * @uri: an URI string |
|
398 * @protocol: a protocol string (e.g. "http") |
|
399 * |
|
400 * Checks if the protocol of a given valid URI matches @protocol. |
|
401 * |
|
402 * Returns: %TRUE if the protocol matches. |
|
403 * |
|
404 * Since: 0.10.4 |
|
405 */ |
|
406 #ifdef __SYMBIAN32__ |
|
407 EXPORT_C |
|
408 #endif |
|
409 |
|
410 gboolean |
|
411 gst_uri_has_protocol (const gchar * uri, const gchar * protocol) |
|
412 { |
|
413 gchar *colon; |
|
414 |
|
415 g_return_val_if_fail (uri != NULL, FALSE); |
|
416 g_return_val_if_fail (protocol != NULL, FALSE); |
|
417 g_return_val_if_fail (gst_uri_is_valid (uri), FALSE); |
|
418 |
|
419 colon = strstr (uri, "://"); |
|
420 |
|
421 if (colon == NULL) |
|
422 return FALSE; |
|
423 |
|
424 return (strncmp (uri, protocol, (gsize) (colon - uri)) == 0); |
|
425 } |
|
426 |
|
427 /** |
|
428 * gst_uri_get_location: |
|
429 * @uri: A URI string |
|
430 * |
|
431 * Extracts the location out of a given valid URI, ie. the protocol and "://" |
|
432 * are stripped from the URI, which means that the location returned includes |
|
433 * the hostname if one is specified. The returned string must be freed using |
|
434 * g_free(). |
|
435 * |
|
436 * Returns: The location for this URI. Returns NULL if the URI isn't valid. If |
|
437 * the URI does not contain a location, an empty string is returned. |
|
438 */ |
|
439 #ifdef __SYMBIAN32__ |
|
440 EXPORT_C |
|
441 #endif |
|
442 |
|
443 gchar * |
|
444 gst_uri_get_location (const gchar * uri) |
|
445 { |
|
446 const gchar *colon; |
|
447 gchar *unescaped = NULL; |
|
448 |
|
449 g_return_val_if_fail (uri != NULL, NULL); |
|
450 g_return_val_if_fail (gst_uri_is_valid (uri), NULL); |
|
451 |
|
452 colon = strstr (uri, "://"); |
|
453 |
|
454 unescaped = unescape_string (colon + 3, "/"); |
|
455 |
|
456 /* On Windows an URI might look like file:///c:/foo/bar.txt or |
|
457 * file:///c|/foo/bar.txt (some Netscape versions) and we want to |
|
458 * return c:/foo/bar.txt as location rather than /c:/foo/bar.txt. |
|
459 * Can't use g_filename_from_uri() here because it will only handle the |
|
460 * file:// protocol */ |
|
461 #ifdef G_OS_WIN32 |
|
462 if (unescaped != NULL && unescaped[0] == '/' && |
|
463 g_ascii_isalpha (unescaped[1]) && |
|
464 (unescaped[2] == ':' || unescaped[2] == '|')) { |
|
465 unescaped[2] = ':'; |
|
466 g_memmove (unescaped, unescaped + 1, strlen (unescaped + 1) + 1); |
|
467 } |
|
468 #endif |
|
469 |
|
470 GST_LOG ("extracted location '%s' from URI '%s'", GST_STR_NULL (unescaped), |
|
471 uri);; |
|
472 return unescaped; |
|
473 } |
|
474 |
|
475 /** |
|
476 * gst_uri_construct: |
|
477 * @protocol: Protocol for URI |
|
478 * @location: Location for URI |
|
479 * |
|
480 * Constructs a URI for a given valid protocol and location. |
|
481 * |
|
482 * Returns: a new string for this URI. Returns NULL if the given URI protocol |
|
483 * is not valid, or the given location is NULL. |
|
484 */ |
|
485 #ifdef __SYMBIAN32__ |
|
486 EXPORT_C |
|
487 #endif |
|
488 |
|
489 gchar * |
|
490 gst_uri_construct (const gchar * protocol, const gchar * location) |
|
491 { |
|
492 char *escaped; |
|
493 char *retval; |
|
494 |
|
495 g_return_val_if_fail (gst_uri_protocol_is_valid (protocol), NULL); |
|
496 g_return_val_if_fail (location != NULL, NULL); |
|
497 |
|
498 escaped = escape_string (location); |
|
499 retval = g_strdup_printf ("%s://%s", protocol, escaped); |
|
500 g_free (escaped); |
|
501 |
|
502 return retval; |
|
503 } |
|
504 |
|
505 typedef struct |
|
506 { |
|
507 GstURIType type; |
|
508 const gchar *protocol; |
|
509 } |
|
510 SearchEntry; |
|
511 |
|
512 static gboolean |
|
513 search_by_entry (GstPluginFeature * feature, gpointer search_entry) |
|
514 { |
|
515 gchar **protocols; |
|
516 GstElementFactory *factory; |
|
517 SearchEntry *entry = (SearchEntry *) search_entry; |
|
518 |
|
519 if (!GST_IS_ELEMENT_FACTORY (feature)) |
|
520 return FALSE; |
|
521 factory = GST_ELEMENT_FACTORY (feature); |
|
522 |
|
523 if (gst_element_factory_get_uri_type (factory) != entry->type) |
|
524 return FALSE; |
|
525 |
|
526 protocols = gst_element_factory_get_uri_protocols (factory); |
|
527 |
|
528 if (protocols == NULL) { |
|
529 g_warning ("Factory '%s' implements GstUriHandler interface but returned " |
|
530 "no supported protocols!", gst_plugin_feature_get_name (feature)); |
|
531 return FALSE; |
|
532 } |
|
533 |
|
534 while (*protocols != NULL) { |
|
535 if (g_ascii_strcasecmp (*protocols, entry->protocol) == 0) |
|
536 return TRUE; |
|
537 protocols++; |
|
538 } |
|
539 return FALSE; |
|
540 } |
|
541 |
|
542 static gint |
|
543 sort_by_rank (gconstpointer a, gconstpointer b) |
|
544 { |
|
545 GstPluginFeature *first = GST_PLUGIN_FEATURE (a); |
|
546 GstPluginFeature *second = GST_PLUGIN_FEATURE (b); |
|
547 |
|
548 return gst_plugin_feature_get_rank (second) - |
|
549 gst_plugin_feature_get_rank (first); |
|
550 } |
|
551 |
|
552 static GList * |
|
553 get_element_factories_from_uri_protocol (const GstURIType type, |
|
554 const gchar * protocol) |
|
555 { |
|
556 GList *possibilities; |
|
557 SearchEntry entry; |
|
558 |
|
559 g_return_val_if_fail (protocol, NULL); |
|
560 |
|
561 entry.type = type; |
|
562 entry.protocol = protocol; |
|
563 possibilities = gst_registry_feature_filter (gst_registry_get_default (), |
|
564 search_by_entry, FALSE, &entry); |
|
565 |
|
566 return possibilities; |
|
567 } |
|
568 |
|
569 /** |
|
570 * gst_uri_protocol_is_supported: |
|
571 * @type: Whether to check for a source or a sink |
|
572 * @protocol: Protocol that should be checked for (e.g. "http" or "smb") |
|
573 * |
|
574 * Checks if an element exists that supports the given URI protocol. Note |
|
575 * that a positive return value does not imply that a subsequent call to |
|
576 * gst_element_make_from_uri() is guaranteed to work. |
|
577 * |
|
578 * Returns: TRUE |
|
579 * |
|
580 * Since: 0.10.13 |
|
581 */ |
|
582 #ifdef __SYMBIAN32__ |
|
583 EXPORT_C |
|
584 #endif |
|
585 |
|
586 gboolean |
|
587 gst_uri_protocol_is_supported (const GstURIType type, const gchar * protocol) |
|
588 { |
|
589 GList *possibilities; |
|
590 |
|
591 g_return_val_if_fail (protocol, FALSE); |
|
592 |
|
593 possibilities = get_element_factories_from_uri_protocol (type, protocol); |
|
594 |
|
595 if (possibilities) { |
|
596 g_list_free (possibilities); |
|
597 return TRUE; |
|
598 } else |
|
599 return FALSE; |
|
600 } |
|
601 |
|
602 /** |
|
603 * gst_element_make_from_uri: |
|
604 * @type: Whether to create a source or a sink |
|
605 * @uri: URI to create an element for |
|
606 * @elementname: Name of created element, can be NULL. |
|
607 * |
|
608 * Creates an element for handling the given URI. |
|
609 * |
|
610 * Returns: a new element or NULL if none could be created |
|
611 */ |
|
612 #ifdef __SYMBIAN32__ |
|
613 EXPORT_C |
|
614 #endif |
|
615 |
|
616 GstElement * |
|
617 gst_element_make_from_uri (const GstURIType type, const gchar * uri, |
|
618 const gchar * elementname) |
|
619 { |
|
620 GList *possibilities, *walk; |
|
621 gchar *protocol; |
|
622 GstElement *ret = NULL; |
|
623 |
|
624 g_return_val_if_fail (GST_URI_TYPE_IS_VALID (type), NULL); |
|
625 g_return_val_if_fail (gst_uri_is_valid (uri), NULL); |
|
626 |
|
627 protocol = gst_uri_get_protocol (uri); |
|
628 possibilities = get_element_factories_from_uri_protocol (type, protocol); |
|
629 g_free (protocol); |
|
630 |
|
631 if (!possibilities) { |
|
632 GST_DEBUG ("No %s for URI '%s'", type == GST_URI_SINK ? "sink" : "source", |
|
633 uri); |
|
634 return NULL; |
|
635 } |
|
636 |
|
637 possibilities = g_list_sort (possibilities, sort_by_rank); |
|
638 walk = possibilities; |
|
639 while (walk) { |
|
640 if ((ret = gst_element_factory_create (GST_ELEMENT_FACTORY (walk->data), |
|
641 elementname)) != NULL) { |
|
642 GstURIHandler *handler = GST_URI_HANDLER (ret); |
|
643 |
|
644 if (gst_uri_handler_set_uri (handler, uri)) |
|
645 break; |
|
646 gst_object_unref (ret); |
|
647 ret = NULL; |
|
648 } |
|
649 walk = walk->next; |
|
650 } |
|
651 gst_plugin_feature_list_free (possibilities); |
|
652 |
|
653 GST_LOG_OBJECT (ret, "created %s for URL '%s'", |
|
654 type == GST_URI_SINK ? "sink" : "source", uri); |
|
655 return ret; |
|
656 } |
|
657 |
|
658 /** |
|
659 * gst_uri_handler_get_uri_type: |
|
660 * @handler: A #GstURIHandler. |
|
661 * |
|
662 * Gets the type of the given URI handler |
|
663 * |
|
664 * Returns: the #GstURIType of the URI handler. |
|
665 * Returns #GST_URI_UNKNOWN if the @handler isn't implemented correctly. |
|
666 */ |
|
667 #ifdef __SYMBIAN32__ |
|
668 EXPORT_C |
|
669 #endif |
|
670 |
|
671 guint |
|
672 gst_uri_handler_get_uri_type (GstURIHandler * handler) |
|
673 { |
|
674 GstURIHandlerInterface *iface; |
|
675 guint ret; |
|
676 |
|
677 g_return_val_if_fail (GST_IS_URI_HANDLER (handler), GST_URI_UNKNOWN); |
|
678 |
|
679 iface = GST_URI_HANDLER_GET_INTERFACE (handler); |
|
680 g_return_val_if_fail (iface != NULL, GST_URI_UNKNOWN); |
|
681 g_return_val_if_fail (iface->get_type != NULL, GST_URI_UNKNOWN); |
|
682 ret = iface->get_type (); |
|
683 g_return_val_if_fail (GST_URI_TYPE_IS_VALID (ret), GST_URI_UNKNOWN); |
|
684 |
|
685 return ret; |
|
686 } |
|
687 |
|
688 /** |
|
689 * gst_uri_handler_get_protocols: |
|
690 * @handler: A #GstURIHandler. |
|
691 * |
|
692 * Gets the list of protocols supported by @handler. This list may not be |
|
693 * modified. |
|
694 * |
|
695 * Returns: the supported protocols. |
|
696 * Returns NULL if the @handler isn't implemented properly, or the @handler |
|
697 * doesn't support any protocols. |
|
698 */ |
|
699 #ifdef __SYMBIAN32__ |
|
700 EXPORT_C |
|
701 #endif |
|
702 |
|
703 gchar ** |
|
704 gst_uri_handler_get_protocols (GstURIHandler * handler) |
|
705 { |
|
706 GstURIHandlerInterface *iface; |
|
707 gchar **ret; |
|
708 |
|
709 g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL); |
|
710 |
|
711 iface = GST_URI_HANDLER_GET_INTERFACE (handler); |
|
712 g_return_val_if_fail (iface != NULL, NULL); |
|
713 g_return_val_if_fail (iface->get_protocols != NULL || |
|
714 iface->get_protocols_full != NULL, NULL); |
|
715 |
|
716 if (iface->get_protocols != NULL) { |
|
717 ret = iface->get_protocols (); |
|
718 } else { |
|
719 ret = iface->get_protocols_full (G_OBJECT_TYPE (handler)); |
|
720 } |
|
721 g_return_val_if_fail (ret != NULL, NULL); |
|
722 |
|
723 return ret; |
|
724 } |
|
725 |
|
726 /** |
|
727 * gst_uri_handler_get_uri: |
|
728 * @handler: A #GstURIHandler |
|
729 * |
|
730 * Gets the currently handled URI. |
|
731 * |
|
732 * Returns: the URI currently handled by the @handler. |
|
733 * Returns NULL if there are no URI currently handled. The returned |
|
734 * string must not be modified or freed. |
|
735 */ |
|
736 #ifdef __SYMBIAN32__ |
|
737 EXPORT_C |
|
738 #endif |
|
739 |
|
740 G_CONST_RETURN gchar * |
|
741 gst_uri_handler_get_uri (GstURIHandler * handler) |
|
742 { |
|
743 GstURIHandlerInterface *iface; |
|
744 const gchar *ret; |
|
745 |
|
746 g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL); |
|
747 |
|
748 iface = GST_URI_HANDLER_GET_INTERFACE (handler); |
|
749 g_return_val_if_fail (iface != NULL, NULL); |
|
750 g_return_val_if_fail (iface->get_uri != NULL, NULL); |
|
751 ret = iface->get_uri (handler); |
|
752 if (ret != NULL) |
|
753 g_return_val_if_fail (gst_uri_is_valid (ret), NULL); |
|
754 |
|
755 return ret; |
|
756 } |
|
757 |
|
758 /** |
|
759 * gst_uri_handler_set_uri: |
|
760 * @handler: A #GstURIHandler |
|
761 * @uri: URI to set |
|
762 * |
|
763 * Tries to set the URI of the given handler. |
|
764 * |
|
765 * Returns: TRUE if the URI was set successfully, else FALSE. |
|
766 */ |
|
767 #ifdef __SYMBIAN32__ |
|
768 EXPORT_C |
|
769 #endif |
|
770 |
|
771 gboolean |
|
772 gst_uri_handler_set_uri (GstURIHandler * handler, const gchar * uri) |
|
773 { |
|
774 GstURIHandlerInterface *iface; |
|
775 |
|
776 g_return_val_if_fail (GST_IS_URI_HANDLER (handler), FALSE); |
|
777 g_return_val_if_fail (gst_uri_is_valid (uri), FALSE); |
|
778 |
|
779 iface = GST_URI_HANDLER_GET_INTERFACE (handler); |
|
780 g_return_val_if_fail (iface != NULL, FALSE); |
|
781 g_return_val_if_fail (iface->set_uri != NULL, FALSE); |
|
782 return iface->set_uri (handler, uri); |
|
783 } |
|
784 |
|
785 /** |
|
786 * gst_uri_handler_new_uri: |
|
787 * @handler: A #GstURIHandler |
|
788 * @uri: new URI or NULL if it was unset |
|
789 * |
|
790 * Emits the new-uri signal for a given handler, when that handler has a new URI. |
|
791 * This function should only be called by URI handlers themselves. |
|
792 */ |
|
793 #ifdef __SYMBIAN32__ |
|
794 EXPORT_C |
|
795 #endif |
|
796 |
|
797 void |
|
798 gst_uri_handler_new_uri (GstURIHandler * handler, const gchar * uri) |
|
799 { |
|
800 g_return_if_fail (GST_IS_URI_HANDLER (handler)); |
|
801 |
|
802 g_signal_emit_by_name (handler, "new-uri", uri); |
|
803 } |