1 /*
2 * Copyright (C) 2000-2020 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 *
21 * Load input/demux/audio_out/video_out/codec plugins
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <inttypes.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <pthread.h>
33 #ifdef HAVE_DIRENT_H
34 #include <dirent.h>
35 #endif
36 #include <dlfcn.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <signal.h>
43
44 #include <basedir.h>
45
46 #define LOG_MODULE "load_plugins"
47 #define LOG_VERBOSE
48
49 /*
50 #define LOG
51 #define DEBUG
52 */
53
54 #define XINE_ENABLE_EXPERIMENTAL_FEATURES 1
55
56 /* save 1 lookup per entry by caching entry pointers not keys. */
57 #define FAST_SCAN_PLUGINS
58
59 #include <xine/xine_internal.h>
60 #include <xine/xine_plugin.h>
61 #include <xine/plugin_catalog.h>
62 #include <xine/demux.h>
63 #include <xine/input_plugin.h>
64 #include <xine/video_out.h>
65 #include <xine/post.h>
66 #include <xine/xine_module.h>
67 #include <xine/metronom.h>
68 #include <xine/configfile.h>
69 #include <xine/xineutils.h>
70 #include <xine/compat.h>
71
72 #include "xine_private.h"
73
74 #ifdef XINE_MAKE_BUILTINS
75 #include "builtins.h"
76 #endif
77
78 #if 0
79
80 static char *plugin_name;
81
82 #if DONT_CATCH_SIGSEGV
83
84 #define install_segv_handler()
85 #define remove_segv_handler()
86
87 #else
88
89 void (*old_segv_handler)(int);
90
91 static void segv_handler (int hubba) {
92 printf ("\nload_plugins: Initialization of plugin '%s' failed (segmentation fault).\n",plugin_name);
93 printf ("load_plugins: You probably need to remove the offending file.\n");
94 printf ("load_plugins: (This error is usually due an incorrect plugin version)\n");
95 _x_abort();
96 }
97
98 static void install_segv_handler(void){
99 old_segv_handler = signal (SIGSEGV, segv_handler);
100 }
101
102 static void remove_segv_handler(void){
103 signal (SIGSEGV, old_segv_handler );
104 }
105
106 #endif
107 #endif /* 0 */
108
109 #define CACHE_CATALOG_VERSION 4
110 #define CACHE_CATALOG_VERSION_STR "4"
111
112 #define __Max(a,b) ((a) > (b) ? (a) : (b))
113 static const uint8_t plugin_iface_versions[__Max(PLUGIN_TYPE_MAX, PLUGIN_XINE_MODULE) + 1] = {
114 [PLUGIN_INPUT] = INPUT_PLUGIN_IFACE_VERSION,
115 [PLUGIN_DEMUX] = DEMUXER_PLUGIN_IFACE_VERSION,
116 [PLUGIN_AUDIO_DECODER] = AUDIO_DECODER_IFACE_VERSION,
117 [PLUGIN_VIDEO_DECODER] = VIDEO_DECODER_IFACE_VERSION,
118 [PLUGIN_SPU_DECODER] = SPU_DECODER_IFACE_VERSION,
119 [PLUGIN_AUDIO_OUT] = AUDIO_OUT_IFACE_VERSION,
120 [PLUGIN_VIDEO_OUT] = VIDEO_OUT_DRIVER_IFACE_VERSION,
121 [PLUGIN_POST] = POST_PLUGIN_IFACE_VERSION,
122 [PLUGIN_XINE_MODULE] = XINE_MODULE_IFACE_VERSION,
123 };
124
125 typedef union {
126 vo_info_t vo_info;
127 ao_info_t ao_info;
128 demuxer_info_t demuxer_info;
129 input_info_t input_info;
130 decoder_info_t decoder_info;
131 post_info_t post_info;
132 xine_module_info_t module_info;
133 } all_info_t;
134
135 typedef struct fat_node_st {
136 plugin_node_t node;
137 plugin_info_t info[2];
138 all_info_t ainfo;
139 plugin_file_t file;
140 struct fat_node_st *nextplugin, *lastplugin;
141 xine_t *xine;
142 uint32_t supported_types[1];
143 } fat_node_t;
144 /* effectively next:
145 uint32_t supported_types[num_supported_types];
146 char id[idlen + 1];
147 char filename[fnlen + 1];
148 */
149
150 #define IS_FAT_NODE(_node) (_node->node.info == &_node->info[0])
151
_fat_node_init(fat_node_t * node)152 static void _fat_node_init (fat_node_t *node) {
153 #ifdef HAVE_ZERO_SAFE_MEM
154 memset (node, 0, sizeof (*node));
155 #else
156 node->node.file = NULL;
157 node->node.info = NULL;
158 node->node.plugin_class = NULL;
159 node->node.config_entry_list = NULL;
160 node->node.ref = 0;
161 node->node.priority = 0;
162 node->info[0].type = 0;
163 node->info[0].API = 0;
164 node->info[0].id = NULL;
165 node->info[0].version = 0;
166 node->info[0].special_info = NULL;
167 node->info[0].init = NULL;
168 node->info[1].type = 0;
169 node->ainfo.decoder_info.supported_types = NULL;
170 node->ainfo.decoder_info.priority = 0;
171 node->file.filename = NULL;
172 node->file.filesize = 0;
173 node->file.filemtime = 0;
174 node->file.lib_handle = NULL;
175 node->file.ref = 0;
176 node->file.no_unload = 0;
177 node->supported_types[0] = 0;
178 node->nextplugin = NULL;
179 node->xine = NULL;
180 #endif
181 node->lastplugin = node;
182 }
183
_fat_node_file_cmp(void * a_gen,void * b_gen)184 static int _fat_node_file_cmp (void *a_gen, void *b_gen) {
185 fat_node_t *a = a_gen, *b = b_gen;
186 if (a->file.filesize != b->file.filesize)
187 return a->file.filesize < b->file.filesize ? -1 : 1;
188 if (a->file.filemtime != b->file.filemtime)
189 return a->file.filemtime < b->file.filemtime ? -1 : 1;
190 return strcmp (a->file.filename, b->file.filename);
191 }
192
193
194 /* Note const char * --> void * is ok here as the strings are never written to. */
195 typedef int (_cmp_func_t) (void *a, void *b);
196
_build_list_typed_plugins(xine_t * xine,int type)197 static const char * const *_build_list_typed_plugins (xine_t *xine, int type) {
198 plugin_catalog_t *catalog = xine->plugin_catalog;
199 xine_sarray_t *a, *list;
200 plugin_node_t *node;
201 int list_id, list_size, i;
202
203 pthread_mutex_lock (&catalog->lock);
204 list = catalog->plugin_lists[type - 1];
205 list_size = xine_sarray_size (list);
206 a = xine_sarray_new (list_size, (_cmp_func_t *)strcmp);
207 if (!a) {
208 catalog->ids[0] = NULL;
209 pthread_mutex_unlock (&catalog->lock);
210 return catalog->ids;
211 }
212 xine_sarray_set_mode (a, XINE_SARRAY_MODE_UNIQUE);
213 for (list_id = 0, i = 0; list_id < list_size; list_id++) {
214 node = xine_sarray_get (list, list_id);
215 /* add only unique ids to the list */
216 if (xine_sarray_add (a, (void *)node->info->id) >= 0)
217 catalog->ids[i++] = node->info->id;
218 }
219 catalog->ids[i] = NULL;
220 pthread_mutex_unlock (&catalog->lock);
221
222 xine_sarray_delete (a);
223 return catalog->ids;
224 }
225
inc_file_ref(plugin_file_t * file)226 static void inc_file_ref(plugin_file_t *file) {
227 /* all users do dereference "file" before calling this
228 _x_assert(file); */
229 file->ref++;
230 }
231
dec_file_ref(plugin_file_t * file)232 static void dec_file_ref(plugin_file_t *file) {
233 /* all users do test "file" before calling this
234 _x_assert(file); */
235 _x_assert(file->ref > 0);
236
237 file->ref--;
238 lprintf("file %s referenced %d time(s)\n", file->filename, file->ref);
239 }
240
inc_node_ref(plugin_node_t * node)241 static void inc_node_ref(plugin_node_t *node) {
242 /* all users do dereference "node" before calling this
243 _x_assert(node); */
244 node->ref++;
245 }
246
dec_node_ref(plugin_node_t * node)247 static void dec_node_ref(plugin_node_t *node) {
248 /* all users do test "node" before calling this
249 _x_assert(node); */
250 _x_assert(node->ref > 0);
251
252 node->ref--;
253 lprintf("node %s referenced %d time(s)\n", node->info->id, node->ref);
254 }
255
256 #ifndef FAST_SCAN_PLUGINS
_free_string_list(xine_list_t ** plist)257 static void _free_string_list(xine_list_t **plist) {
258 xine_list_t *list = *plist;
259
260 if (list) {
261 char *key;
262 xine_list_iterator_t ite = NULL;
263 while ((key = xine_list_next_value (list, &ite)))
264 free (key);
265 xine_list_delete(list);
266 *plist = NULL;
267 }
268 }
269 #endif
270
271 /*
272 * plugin list/catalog management functions
273 */
274
map_decoder_list(xine_t * this,xine_sarray_t * decoder_list,plugin_node_t * decoder_map[DECODER_MAX][PLUGINS_PER_TYPE])275 static void map_decoder_list (xine_t *this,
276 xine_sarray_t *decoder_list,
277 plugin_node_t *decoder_map[DECODER_MAX][PLUGINS_PER_TYPE]) {
278 int i;
279 int list_id, list_size;
280
281 /* init */
282 for (i = 0; i < DECODER_MAX; i++) {
283 decoder_map[i][0] = NULL;
284 }
285
286 /*
287 * map decoders
288 */
289 list_size = xine_sarray_size(decoder_list);
290 /* this is sorted by falling priorities */
291 for (list_id = 0; list_id < list_size; list_id++) {
292
293 plugin_node_t *node = xine_sarray_get(decoder_list, list_id);
294 const uint32_t *type = ((const decoder_info_t *)node->info->special_info)->supported_types;
295
296 lprintf ("mapping decoder %s\n", node->info->id);
297
298 while (type && (*type)) {
299
300 int pos;
301 int streamtype = ((*type)>>16) & 0xFF;
302
303 lprintf ("load_plugins: decoder handles stream type %02x, priority %d\n", streamtype, node->priority);
304
305 /* find the right place based on the priority */
306 for (pos = 0; pos < PLUGINS_PER_TYPE; pos++) {
307 if (!decoder_map[streamtype][pos])
308 break;
309 }
310
311 if ( pos == PLUGINS_PER_TYPE ) {
312 xine_log (this, XINE_LOG_PLUGIN,
313 _("map_decoder_list: no space for decoder, skipped.\n"));
314 type++;
315 continue;
316 }
317
318 /* shift the decoder list for this type by one to make room for new decoder */
319 if (pos < PLUGINS_PER_TYPE - 1)
320 decoder_map[streamtype][pos + 1] = NULL;
321
322 /* insert new decoder */
323 decoder_map[streamtype][pos] = node;
324
325 lprintf("decoder inserted in decoder map at %d\n", pos);
326
327 type++;
328 }
329 }
330 }
331
map_decoders(xine_t * this)332 static void map_decoders (xine_t *this) {
333
334 plugin_catalog_t *catalog = this->plugin_catalog;
335
336 lprintf ("map_decoders\n");
337
338 /*
339 * map audio decoders
340 */
341 map_decoder_list(this, catalog->plugin_lists[PLUGIN_AUDIO_DECODER - 1], catalog->audio_decoder_map);
342 map_decoder_list(this, catalog->plugin_lists[PLUGIN_VIDEO_DECODER - 1], catalog->video_decoder_map);
343 map_decoder_list(this, catalog->plugin_lists[PLUGIN_SPU_DECODER - 1], catalog->spu_decoder_map);
344
345 }
346
347 /* Decoder priority callback */
_decoder_priority_cb(void * data,xine_cfg_entry_t * cfg)348 static void _decoder_priority_cb (void *data, xine_cfg_entry_t *cfg) {
349 /* sort decoders by priority */
350 xine_sarray_t *list;
351 int type;
352 fat_node_t *node = data;
353
354 if (!node)
355 return;
356
357 type = node->info->type & PLUGIN_TYPE_MASK;
358 list = node->xine->plugin_catalog->plugin_lists[type - 1];
359
360 if (xine_sarray_remove_ptr (list, node) == ~0)
361 /* callback was triggered before the entry was added to plugin list */
362 return;
363 {
364 int user_prio = cfg->num_value;
365 /* user given priorities should definitely override defaults, so multiply them */
366 node->node.priority = user_prio ? user_prio * 100 : node->ainfo.decoder_info.priority;
367 }
368 xine_sarray_add (list, node);
369 map_decoder_list (node->xine, list,
370 type == PLUGIN_AUDIO_DECODER ? node->xine->plugin_catalog->audio_decoder_map
371 : type == PLUGIN_VIDEO_DECODER ? node->xine->plugin_catalog->video_decoder_map
372 : node->xine->plugin_catalog->spu_decoder_map);
373 }
374
375
_insert_file(xine_list_t * list,const char * filename,const struct stat * statbuffer,void * lib)376 static plugin_file_t *_insert_file (xine_list_t *list,
377 const char *filename,
378 const struct stat *statbuffer,
379 void *lib) {
380 size_t name_len = strlen(filename);
381 plugin_file_t *entry;
382 char *p;
383
384 /* create the file entry */
385 p = malloc(sizeof(*entry) + name_len + 1);
386 if (!p)
387 return NULL;
388 entry = (plugin_file_t *)p;
389 entry->filename = p + sizeof(*entry);
390 entry->filesize = statbuffer->st_size;
391 entry->filemtime = statbuffer->st_mtime;
392 entry->lib_handle = lib;
393 entry->ref = 0;
394 entry->no_unload = 0;
395 xine_small_memcpy (entry->filename, filename, name_len + 1);
396
397 xine_list_push_back (list, entry);
398 return entry;
399 }
400
_insert_node(xine_t * this,plugin_file_t * file,fat_node_t * node_cache,const plugin_info_t * info)401 static int _insert_node (xine_t *this, plugin_file_t *file, fat_node_t *node_cache, const plugin_info_t *info) {
402
403 fat_node_t *entry;
404 const all_info_t *ainfo;
405 unsigned int num_supported_types = 0;
406 unsigned int plugin_type = info->type & PLUGIN_TYPE_MASK;
407 int left;
408 const char *what;
409
410 /* sanity test */
411 left = PLUGIN_MAX - this->plugin_catalog->plugin_count;
412 do {
413 unsigned int flag;
414 if ((plugin_type <= 0) || ((plugin_type > PLUGIN_TYPE_MAX) && plugin_type != PLUGIN_XINE_MODULE)) {
415 if (file)
416 xine_log (this, XINE_LOG_PLUGIN,
417 _("load_plugins: unknown plugin type %d in %s\n"), plugin_type, file->filename);
418 else
419 xine_log (this, XINE_LOG_PLUGIN,
420 _("load_plugins: unknown statically linked plugin type %d\n"), plugin_type);
421 return 1;
422 }
423 if (!info->id) {
424 what = "id";
425 break;
426 }
427 if (info->API != plugin_iface_versions[plugin_type]) {
428 xine_log (this, XINE_LOG_PLUGIN,
429 _("load_plugins: ignoring plugin %s, wrong iface version %d (should be %d)\n"),
430 info->id, info->API, plugin_iface_versions[plugin_type]);
431 return 1;
432 }
433 if (!node_cache && !info->init) {
434 what = "init";
435 break;
436 }
437 ainfo = info->special_info;
438 flag = 1u << plugin_type;
439 if (flag & ((1u << PLUGIN_VIDEO_OUT) | (1u << PLUGIN_AUDIO_OUT) | (1u << PLUGIN_POST) |
440 (1u << PLUGIN_AUDIO_DECODER) | (1u << PLUGIN_VIDEO_DECODER) |
441 (1u << PLUGIN_SPU_DECODER) | (1u << PLUGIN_XINE_MODULE))) {
442 if (!ainfo) {
443 what = "special_info";
444 break;
445 }
446 }
447 if (flag & ((1u << PLUGIN_AUDIO_DECODER) | (1u << PLUGIN_VIDEO_DECODER) | (1u << PLUGIN_SPU_DECODER))) {
448 if (!ainfo->decoder_info.supported_types) {
449 what = "supported_types";
450 break;
451 }
452 if (!node_cache) {
453 while (ainfo->decoder_info.supported_types[num_supported_types])
454 num_supported_types++;
455 }
456 if (left > DECODER_MAX - this->plugin_catalog->decoder_count)
457 left = DECODER_MAX - this->plugin_catalog->decoder_count;
458 }
459 what = NULL;
460 } while (0);
461 if (what) {
462 xine_log (this, XINE_LOG_PLUGIN,
463 "load_plugins: plugin %s from %s is broken: %s = NULL\n",
464 info->id ? info->id : "??", file ? file->filename : "user", what);
465 return 1;
466 }
467 if (left <= 0) {
468 if (file)
469 xine_log (this, XINE_LOG_PLUGIN,
470 _("load_plugins: plugin limit reached, %s could not be loaded\n"), file->filename);
471 else
472 xine_log (this, XINE_LOG_PLUGIN,
473 _("load_plugins: plugin limit reached, static plugin could not be loaded\n"));
474 return 2;
475 }
476
477 /* get target */
478 if (node_cache) {
479 entry = node_cache;
480 } else {
481 size_t idlen = strlen (info->id) + 1;
482 char *q;
483 entry = malloc (sizeof (*entry) + num_supported_types * sizeof (uint32_t) + idlen);
484 if (!entry)
485 return 2;
486 _fat_node_init (entry);
487 entry->node.info = &entry->info[0];
488 entry->info[0] = *info;
489 q = (char *)entry + sizeof (*entry) + num_supported_types * sizeof (uint32_t);
490 entry->info[0].id = q;
491 xine_small_memcpy (q, info->id, idlen);
492 }
493 entry->lastplugin = entry;
494 entry->xine = this;
495 entry->node.file = file;
496
497 /* type specific stuff */
498 switch (plugin_type) {
499
500 case PLUGIN_VIDEO_OUT:
501 entry->node.priority = entry->ainfo.vo_info.priority = ainfo->vo_info.priority;
502 entry->ainfo.vo_info.visual_type = ainfo->vo_info.visual_type;
503 break;
504
505 case PLUGIN_AUDIO_OUT:
506 entry->node.priority = entry->ainfo.ao_info.priority = ainfo->ao_info.priority;
507 break;
508
509 case PLUGIN_AUDIO_DECODER:
510 case PLUGIN_VIDEO_DECODER:
511 case PLUGIN_SPU_DECODER:
512 if (num_supported_types)
513 memcpy (&entry->supported_types[0], ainfo->decoder_info.supported_types, (num_supported_types + 1) * sizeof (uint32_t));
514 entry->ainfo.decoder_info.supported_types = &entry->supported_types[0];
515 entry->ainfo.decoder_info.priority = ainfo->decoder_info.priority;
516
517 {
518 /* cnfig does dup all strings. no need to keep them here. */
519 char key[128], desc[256];
520 int user_prio;
521 snprintf (key, sizeof (key) - 1, "engine.decoder_priorities.%s", info->id);
522 snprintf (desc, sizeof (desc) - 1, _("priority for %s decoder"), info->id);
523 user_prio = this->config->register_num (this->config, key, 0, desc,
524 _("The priority provides a ranking in case some media "
525 "can be handled by more than one decoder.\n"
526 "A priority of 0 enables the decoder's default priority."), 20,
527 _decoder_priority_cb, entry);
528 /* reset priority on old config files */
529 if (this->config->current_version < 1) {
530 this->config->update_num (this->config, key, 0);
531 user_prio = 0;
532 }
533 entry->node.priority = user_prio ? user_prio * 100 : entry->ainfo.decoder_info.priority;
534 }
535 this->plugin_catalog->decoder_count++;
536 break;
537
538 case PLUGIN_POST:
539 entry->ainfo.post_info.type = ainfo->post_info.type;
540 break;
541
542 case PLUGIN_DEMUX:
543 if (ainfo) {
544 entry->node.priority = entry->ainfo.demuxer_info.priority = ainfo->demuxer_info.priority;
545 lprintf("demux: %s, priority: %d\n", info->id, entry->node.priority);
546 } else {
547 xprintf(this, XINE_VERBOSITY_LOG,
548 _("load_plugins: demuxer plugin %s does not provide a priority,"
549 " xine-lib will use the default priority.\n"),
550 info->id);
551 entry->node.priority = entry->ainfo.demuxer_info.priority = 0;
552 }
553 break;
554
555 case PLUGIN_INPUT:
556 if (ainfo) {
557 entry->node.priority = entry->ainfo.input_info.priority = ainfo->input_info.priority;
558 lprintf("input: %s, priority: %d\n", info->id, entry->node.priority);
559 } else {
560 xprintf(this, XINE_VERBOSITY_LOG,
561 _("load_plugins: input plugin %s does not provide a priority,"
562 " xine-lib will use the default priority.\n"),
563 info->id);
564 entry->node.priority = entry->ainfo.input_info.priority = 0;
565 }
566 break;
567 case PLUGIN_XINE_MODULE:
568 entry->node.priority = ainfo->module_info.priority;
569 entry->ainfo.module_info = ainfo->module_info;
570 break;
571 }
572 entry->info[0].special_info = &entry->ainfo;
573
574 if (file && (info->type & PLUGIN_NO_UNLOAD)) {
575 file->no_unload = 1;
576 }
577
578 if (plugin_type == PLUGIN_XINE_MODULE)
579 xine_sarray_add (this->plugin_catalog->modules_list, &entry->node);
580 else
581 xine_sarray_add (this->plugin_catalog->plugin_lists[plugin_type - 1], &entry->node);
582 this->plugin_catalog->plugin_count++;
583 return 0;
584 }
585
586
_plugin_node_comparator(void * a,void * b)587 static int _plugin_node_comparator(void *a, void *b) {
588 const plugin_node_t *node_a = (const plugin_node_t *)a;
589 const plugin_node_t *node_b = (const plugin_node_t *)b;
590
591 return (node_a->priority < node_b->priority) - (node_a->priority > node_b->priority);
592 }
593
594 /* xine-ui simply makes a user config enum from post plugin list, and assumes the first one
595 * as the default. This effectively becomes a random choice, depending on the presence of
596 * other plugins, and of the order the file system returns them. So lets sort them by name
597 * as well here. */
_post_plugin_node_comparator(void * a,void * b)598 static int _post_plugin_node_comparator (void *a, void *b) {
599 const plugin_node_t *node_a = (const plugin_node_t *)a;
600 const plugin_node_t *node_b = (const plugin_node_t *)b;
601
602 if (node_a->priority != node_b->priority)
603 return node_a->priority < node_b->priority ? 1 : -1;
604 return strcmp (node_a->info->id, node_b->info->id);
605 }
606
_new_catalog(void)607 static plugin_catalog_t *_new_catalog(void){
608 plugin_catalog_t *catalog;
609
610 catalog = calloc (1, sizeof (plugin_catalog_t));
611 if (catalog) {
612 int i;
613 for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
614 catalog->plugin_lists[i] = xine_sarray_new (0,
615 i == PLUGIN_POST - 1 ? _post_plugin_node_comparator : _plugin_node_comparator);
616 if (!catalog->plugin_lists[i])
617 break;
618 }
619 if (i == PLUGIN_TYPE_MAX) {
620 catalog->cache_list = xine_sarray_new (0, _fat_node_file_cmp);
621 if (catalog->cache_list) {
622 xine_sarray_set_mode (catalog->cache_list, XINE_SARRAY_MODE_UNIQUE);
623 catalog->file_list = xine_list_new ();
624 if (catalog->file_list) {
625 catalog->modules_list = xine_sarray_new (0, _plugin_node_comparator);
626 if (catalog->modules_list) {
627 pthread_mutexattr_t attr;
628 pthread_mutexattr_init (&attr);
629 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
630 pthread_mutex_init (&catalog->lock, &attr);
631 pthread_mutexattr_destroy (&attr);
632 return catalog;
633 }
634 xine_list_delete (catalog->file_list);
635 }
636 xine_sarray_delete (catalog->cache_list);
637 }
638 }
639 for (--i; i >= 0; i--)
640 xine_sarray_delete (catalog->plugin_lists[i]);
641 free (catalog);
642 }
643 return NULL;
644 }
645
_register_plugins_internal(xine_t * this,plugin_file_t * file,fat_node_t * node_cache,const plugin_info_t * info)646 static void _register_plugins_internal (xine_t *this, plugin_file_t *file,
647 fat_node_t *node_cache, const plugin_info_t *info) {
648 /* user supplied xine_register_plugins () */
649 static const char * const st_names[10] = {
650 "user/none",
651 "user/input",
652 "user/demux",
653 "user/audio_decoder",
654 "user/video_decoder",
655 "user/spu_decoder",
656 "user/audio_out",
657 "user/video_out",
658 "user/post",
659 "user"
660 };
661 const char * const *names = st_names;
662 #ifdef XINE_MAKE_BUILTINS
663 static const char * const builtin_names[10] = {
664 "libxine/builtins/none",
665 "libxine/builtins/input",
666 "libxine/builtins/demux",
667 "libxine/builtins/audio_decoder",
668 "libxine/builtins/video_decoder",
669 "libxine/builtins/spu_decoder",
670 "libxine/builtins/audio_out",
671 "libxine/builtins/video_out",
672 "libxine/builtins/post",
673 "libxine/builtins"
674 };
675 if (info == xine_builtin_plugin_info)
676 names = builtin_names;
677 #endif
678 /* we had worse NOPs before ;-)
679 _x_assert(info); */
680
681 while ( info && info->type != PLUGIN_NONE ) {
682 fat_node_t *cache_next = node_cache ? node_cache->nextplugin : NULL;
683 const char *fn;
684 int status;
685 if (file) {
686 fn = file->filename;
687 } else {
688 int n = info->type & PLUGIN_TYPE_MASK;
689 if (n > 9)
690 n = 9;
691 fn = names[n];
692 }
693 xine_log (this, XINE_LOG_PLUGIN, _("load_plugins: plugin %s:%s found\n"), fn, info->id);
694 status = _insert_node (this, file, node_cache, info);
695 /* get next info */
696 if( file && !file->lib_handle ) {
697 lprintf("get cached info\n");
698 if (status)
699 free (node_cache);
700 node_cache = cache_next;
701 info = node_cache ? node_cache->node.info : NULL;
702 } else {
703 info++;
704 }
705 }
706 }
707
xine_register_plugins(xine_t * self,const plugin_info_t * info)708 void xine_register_plugins(xine_t *self, const plugin_info_t *info) {
709 if (self)
710 _register_plugins_internal (self, NULL, NULL, info);
711 }
712
713 /*
714 * First stage plugin loader (catalog builder)
715 *
716 ***************************************************************************/
717
collect_plugins(xine_t * this,const char * path,char * stop,char * pend)718 static void collect_plugins (xine_t *this, const char *path, char *stop, char *pend) {
719
720 char *adds[5];
721 DIR *dirs[5];
722 struct stat statbuf;
723 int level;
724
725 lprintf ("collect_plugins in %s\n", path);
726
727 /* we need a dir to start */
728 if (stat (path, &statbuf))
729 return;
730 if (!S_ISDIR (statbuf.st_mode))
731 return;
732
733 adds[0] = stop;
734 dirs[0] = NULL;
735 level = 0;
736 while (1) {
737 struct dirent *dent;
738
739 /* enter dir */
740 if (!dirs[level]) {
741 dirs[level] = opendir (path);
742 if (!dirs[level]) {
743 xine_log (this, XINE_LOG_PLUGIN,
744 _("load_plugins: skipping unreadable plugin directory %s.\n"), path);
745 level--;
746 if (level < 0)
747 break;
748 continue;
749 }
750 }
751
752 /* get entry */
753 dent = readdir (dirs[level]);
754 if (!dent) {
755 closedir (dirs[level]);
756 level--;
757 if (level < 0)
758 break;
759 continue;
760 }
761
762 {
763 void *lib = NULL;
764 const plugin_info_t *info = NULL;
765 fat_node_t *fatn_found;
766 char *part = adds[level], *q;
767
768 *part++ = '/';
769 q = part + strlcpy (part, dent->d_name, pend - part);
770 if (q >= pend)
771 continue;
772
773 if (stat (path, &statbuf)) {
774 xine_log (this, XINE_LOG_PLUGIN, _("load_plugins: unable to stat %s\n"), path);
775 continue;
776 }
777 switch (statbuf.st_mode & S_IFMT) {
778
779 case S_IFREG:
780 /* regular file, ie. plugin library, found => load it */
781
782 /* this will fail whereever shared libs are called *.dll or such
783 * better solutions:
784 * a) don't install .la files on user's system
785 * b) also cache negative hits, ie. files that failed to dlopen()
786 */
787 #if defined(__hpux)
788 if (!strstr (part, ".sl")
789 #elif defined(__CYGWIN__) || defined(WIN32)
790 if (!strstr (part, ".dll") || strstr (part, ".dll.a")
791 #else
792 if (!strstr (part, ".so")
793 #endif
794 #ifdef HOST_OS_DARWIN
795 && !strcasestr (part, ".xineplugin")
796 #endif
797 )
798 break;
799
800 lib = NULL;
801
802 /* get the first plugin_info_t */
803 {
804 fat_node_t fatn_try;
805 int index;
806 fatn_try.file.filename = (char *)path; /* will not be written to */
807 fatn_try.file.filesize = statbuf.st_size;
808 fatn_try.file.filemtime = statbuf.st_mtime;
809 index = xine_sarray_binary_search (this->plugin_catalog->cache_list, &fatn_try);
810 if (index >= 0) {
811 fatn_found = xine_sarray_get (this->plugin_catalog->cache_list, index);
812 xine_sarray_remove (this->plugin_catalog->cache_list, index);
813 } else {
814 fatn_found = NULL;
815 }
816 }
817 info = fatn_found ? fatn_found->node.info : NULL;
818 #ifdef LOG
819 if( info )
820 printf ("load_plugins: using cached %s\n", path);
821 else
822 printf ("load_plugins: %s not cached\n", path);
823 #endif
824
825 if (!info && (lib = dlopen (path, RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
826 const char *error = dlerror();
827 /* too noisy -- but good to catch unresolved references */
828 xprintf (this, XINE_VERBOSITY_LOG,
829 _("load_plugins: cannot open plugin lib %s:\n%s\n"), path, error);
830
831 } else {
832
833 if (info || (info = dlsym(lib, "xine_plugin_info"))) {
834 plugin_file_t *file;
835
836 file = _insert_file (this->plugin_catalog->file_list, path, &statbuf, lib);
837 if (file) {
838 _register_plugins_internal (this, file, fatn_found, info);
839 } else {
840 if (lib != NULL)
841 dlclose(lib);
842 }
843 }
844 else {
845 const char *error = dlerror();
846
847 xine_log (this, XINE_LOG_PLUGIN,
848 _("load_plugins: can't get plugin info from %s:\n%s\n"), path, error);
849 dlclose(lib);
850 }
851 }
852 break;
853 case S_IFDIR:
854
855 /* unless ".", "..", ".hidden" or vidix driver dirs */
856 if ((part[0] != '.') && strcmp (part, "vidix")) {
857 if (level < 4) {
858 level++;
859 adds[level] = q;
860 dirs[level] = NULL;
861 }
862 }
863 } /* switch */
864 }
865 } /* while */
866 } /* collect_plugins */
867
868 /*
869 * generic 2nd stage plugin loader
870 */
871
_plugin_info_equal(const plugin_info_t * a,const plugin_info_t * b)872 static inline int _plugin_info_equal(const plugin_info_t *a,
873 const plugin_info_t *b) {
874 if (a->type != b->type ||
875 a->API != b->API ||
876 strcasecmp(a->id, b->id) ||
877 a->version != b->version)
878 return 0;
879
880 switch (a->type & PLUGIN_TYPE_MASK) {
881 case PLUGIN_VIDEO_OUT:
882 /* FIXME: Could special_info be NULL? */
883 if (a->special_info && b->special_info) {
884 return (((const vo_info_t*)a->special_info)->visual_type ==
885 ((const vo_info_t*)b->special_info)->visual_type);
886 }
887 /* if special info is missing, plugin file is broken ... */
888 return 0; /* skip it */
889 case PLUGIN_XINE_MODULE:
890 if (a->special_info && b->special_info) {
891 return !strcmp(((const xine_module_info_t*)a->special_info)->type,
892 ((const xine_module_info_t*)b->special_info)->type);
893 }
894 return !(!a->special_info - !b->special_info);
895 default:
896 break;
897 }
898
899 return 1;
900 }
901
902 #ifdef FAST_SCAN_PLUGINS
903 typedef struct {
904 config_values_t *v;
905 plugin_node_t *node;
906 } new_entry_data_t;
907 #else
_attach_entry_to_node(plugin_node_t * node,char * key)908 static void _attach_entry_to_node (plugin_node_t *node, char *key) {
909
910 if (!node->config_entry_list) {
911 node->config_entry_list = xine_list_new();
912 }
913
914 xine_list_push_back(node->config_entry_list, key);
915 }
916 #endif
917
918 /*
919 * This callback is called by the config entry system when a plugin register a
920 * new config entry.
921 */
_new_entry_cb(void * user_data,xine_cfg_entry_t * entry)922 static void _new_entry_cb (void *user_data, xine_cfg_entry_t *entry) {
923 #ifdef FAST_SCAN_PLUGINS
924 new_entry_data_t *d = user_data;
925 if (!d->node->config_entry_list)
926 d->node->config_entry_list = xine_list_new ();
927 if (d->node->config_entry_list && d->v->cur && !xine_list_find (d->node->config_entry_list, d->v->cur))
928 xine_list_push_back (d->node->config_entry_list, d->v->cur);
929 (void)entry;
930 #else
931 plugin_node_t *node = (plugin_node_t *)user_data;
932
933 _attach_entry_to_node(node, strdup(entry->key));
934 #endif
935 }
936
_load_plugin_class(xine_t * this,plugin_node_t * node,const void * data)937 static int _load_plugin_class(xine_t *this,
938 plugin_node_t *node,
939 const void *data) {
940 if (node->file) {
941 const char *filename = node->file->filename;
942 const plugin_info_t *target = node->info;
943 const plugin_info_t *info;
944 void *lib;
945
946 /* load the dynamic library if needed */
947 if (!node->file->lib_handle) {
948 lprintf("dlopen %s\n", filename);
949 if ((lib = dlopen (filename, RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
950 const char *error = dlerror();
951
952 xine_log (this, XINE_LOG_PLUGIN,
953 _("load_plugins: cannot (stage 2) open plugin lib %s:\n%s\n"), filename, error);
954 return 0;
955 } else {
956 node->file->lib_handle = lib;
957 }
958 } else {
959 lprintf("%s already loaded\n", filename);
960 }
961
962 if ((info = dlsym(node->file->lib_handle, "xine_plugin_info"))) {
963 /* TODO: use sigsegv handler */
964 while (info->type != PLUGIN_NONE) {
965 if (_plugin_info_equal(info, target)) {
966 config_values_t *config = this->config;
967 #ifdef FAST_SCAN_PLUGINS
968 new_entry_data_t d;
969 d.v = config;
970 d.node = node;
971 #endif
972 /* the callback is called for each entry registered by this plugin */
973 lprintf("plugin init %s\n", node->info->id);
974 if (info->init) {
975 #ifdef FAST_SCAN_PLUGINS
976 config->set_new_entry_callback (config, _new_entry_cb, &d);
977 #else
978 config->set_new_entry_callback (config, _new_entry_cb, node);
979 #endif
980 node->plugin_class = info->init(this, data);
981 config->unset_new_entry_callback (config);
982 }
983
984 if (node->plugin_class) {
985 inc_file_ref(node->file);
986 return 1;
987 } else {
988 return 0;
989 }
990 }
991 info++;
992 }
993 lprintf("plugin not found\n");
994
995 } else {
996 xine_log (this, XINE_LOG_PLUGIN,
997 _("load_plugins: Yikes! %s doesn't contain plugin info.\n"), filename);
998 }
999 } else {
1000 /* statically linked plugin */
1001 lprintf("statically linked plugin\n");
1002 if (node->info->init) {
1003 node->plugin_class = node->info->init(this, data);
1004 return 1;
1005 }
1006 }
1007 return 0; /* something failed if we came here... */
1008 }
1009
_dispose_plugin_class(plugin_node_t * node)1010 static void _dispose_plugin_class(plugin_node_t *node) {
1011
1012 if (node->plugin_class) {
1013 void *cls = node->plugin_class;
1014
1015 _x_assert(node->info);
1016 /* dispose of plugin class */
1017 switch (node->info->type & PLUGIN_TYPE_MASK) {
1018 case PLUGIN_INPUT:
1019 if (((input_class_t *)cls)->dispose)
1020 ((input_class_t *)cls)->dispose ((input_class_t *)cls);
1021 break;
1022 case PLUGIN_DEMUX:
1023 if (((demux_class_t *)cls)->dispose)
1024 ((demux_class_t *)cls)->dispose ((demux_class_t *)cls);
1025 break;
1026 case PLUGIN_SPU_DECODER:
1027 if (((spu_decoder_class_t *)cls)->dispose)
1028 ((spu_decoder_class_t *)cls)->dispose ((spu_decoder_class_t *)cls);
1029 break;
1030 case PLUGIN_AUDIO_DECODER:
1031 if (((audio_decoder_class_t *)cls)->dispose)
1032 ((audio_decoder_class_t *)cls)->dispose ((audio_decoder_class_t *)cls);
1033 break;
1034 case PLUGIN_VIDEO_DECODER:
1035 if (((video_decoder_class_t *)cls)->dispose)
1036 ((video_decoder_class_t *)cls)->dispose ((video_decoder_class_t *)cls);
1037 break;
1038 case PLUGIN_AUDIO_OUT:
1039 if (((audio_driver_class_t *)cls)->dispose)
1040 ((audio_driver_class_t *)cls)->dispose ((audio_driver_class_t *)cls);
1041 break;
1042 case PLUGIN_VIDEO_OUT:
1043 if (((video_driver_class_t *)cls)->dispose)
1044 ((video_driver_class_t *)cls)->dispose ((video_driver_class_t *)cls);
1045 break;
1046 case PLUGIN_POST:
1047 if (((post_class_t *)cls)->dispose)
1048 ((post_class_t *)cls)->dispose ((post_class_t *)cls);
1049 break;
1050 case PLUGIN_XINE_MODULE:
1051 if (((xine_module_class_t *)cls)->dispose)
1052 ((xine_module_class_t *)cls)->dispose (cls);
1053 break;
1054 }
1055 node->plugin_class = NULL;
1056 if (node->file)
1057 dec_file_ref(node->file);
1058 }
1059 }
1060
1061 /*
1062 * load input+demuxer plugins
1063 * load plugins that asked to be initialized
1064 */
_load_required_plugins(xine_t * this,xine_sarray_t * list)1065 static void _load_required_plugins(xine_t *this, xine_sarray_t *list) {
1066
1067 int list_id = 0;
1068 int list_size;
1069
1070 list_size = xine_sarray_size(list);
1071 while (list_id < list_size) {
1072 plugin_node_t *node = xine_sarray_get(list, list_id);
1073
1074 /*
1075 * preload plugins if not cached
1076 */
1077 do {
1078 if (!(node->info->type & PLUGIN_MUST_PRELOAD)) /* no preload needed */
1079 break;
1080 if (node->plugin_class) /* is already loaded */
1081 break;
1082 if (node->file && !node->file->lib_handle) /* lib unavailable */
1083 break;
1084
1085 lprintf ("preload plugin %s from %s\n", node->info->id, node->file ? node->file->filename : "libxine/builtins");
1086
1087 if (! _load_plugin_class (this, node, NULL)) {
1088 /* in case of failure remove from list */
1089
1090 xine_sarray_remove(list, list_id);
1091 list_size = xine_sarray_size(list);
1092 list_id--;
1093 }
1094 } while (0);
1095 list_id++;
1096 }
1097 }
1098
load_required_plugins(xine_t * this)1099 static void load_required_plugins(xine_t *this) {
1100 int i;
1101
1102 for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
1103 _load_required_plugins (this, this->plugin_catalog->plugin_lists[i]);
1104 }
1105 }
1106
1107 /*
1108 * save plugin list information to file (cached catalog)
1109 */
save_plugin_list(xine_t * this,FILE * fp,xine_sarray_t * list)1110 static void save_plugin_list(xine_t *this, FILE *fp, xine_sarray_t *list) {
1111
1112 int list_id = 0;
1113 int list_size;
1114 #define SAVE_PLUGIN_BUF_SIZE 4096
1115 char b[SAVE_PLUGIN_BUF_SIZE];
1116 char *e = b + SAVE_PLUGIN_BUF_SIZE - 78 - 2 * XINE_MAX_INT64_STR - 5 * XINE_MAX_INT32_STR;
1117
1118 list_size = xine_sarray_size (list);
1119 while (list_id < list_size) {
1120 int pri;
1121 char *q = b;
1122 const plugin_node_t *node = xine_sarray_get (list, list_id);
1123 const plugin_file_t *file = node->file;
1124 if (file) {
1125 *q++ = '[';
1126 q += strlcpy (q, file->filename, e - q);
1127 if (q >= e)
1128 q = e - 1;
1129 memcpy (q, "]\nsize=", 7); q += 7;
1130 xine_uint2str (&q, file->filesize);
1131 memcpy (q, "\nmtime=", 7); q += 7;
1132 xine_uint2str (&q, file->filemtime);
1133 *q++ = '\n';
1134 } else {
1135 /* dump builtins for debugging */
1136 memcpy (q, "[libxine/builtins]\n", 20); q += 19;
1137 }
1138 memcpy (q, "type=", 5); q += 5;
1139 xine_uint32_2str (&q, node->info->type);
1140 memcpy (q, "\napi=", 5); q += 5;
1141 xine_uint32_2str (&q, node->info->API);
1142 memcpy (q, "\nid=", 4); q += 4;
1143 q += strlcpy (q, node->info->id, e - q);
1144 if (q >= e)
1145 q = e - 1;
1146 memcpy (q, "\nversion=", 9); q += 9;
1147 xine_uint32_2str (&q, node->info->version);
1148 *q++ = '\n';
1149
1150 switch (node->info->type & PLUGIN_TYPE_MASK){
1151
1152 case PLUGIN_VIDEO_OUT: {
1153 const vo_info_t *vo_info = node->info->special_info;
1154 memcpy (q, "visual_type=", 12); q += 12;
1155 xine_int32_2str (&q, vo_info->visual_type);
1156 memcpy (q, "\nvo_priority=", 13); q += 13;
1157 pri = vo_info->priority;
1158 goto write_pri;
1159 }
1160 case PLUGIN_AUDIO_OUT: {
1161 const ao_info_t *ao_info = node->info->special_info;
1162 memcpy (q, "ao_priority=", 12); q += 12;
1163 pri = ao_info->priority;
1164 goto write_pri;
1165 }
1166 case PLUGIN_AUDIO_DECODER:
1167 case PLUGIN_VIDEO_DECODER:
1168 case PLUGIN_SPU_DECODER: {
1169 const decoder_info_t *decoder_info = node->info->special_info;
1170 const uint32_t *t;
1171 memcpy (q, "supported_types=", 16); q += 16;
1172 t = decoder_info->supported_types;
1173 while (*t) {
1174 xine_uint32_2str (&q, *t++);
1175 if (q >= e) {
1176 fwrite (b, 1, q - b, fp);
1177 q = b;
1178 }
1179 *q++ = ' ';
1180 }
1181 q[-1] = '\n';
1182 memcpy (q, "decoder_priority=", 17); q += 17;
1183 pri = decoder_info->priority;
1184 goto write_pri;
1185 }
1186 case PLUGIN_DEMUX: {
1187 const demuxer_info_t *demuxer_info = node->info->special_info;
1188 memcpy (q, "demuxer_priority=", 17); q += 17;
1189 pri = demuxer_info->priority;
1190 goto write_pri;
1191 }
1192 case PLUGIN_INPUT: {
1193 const input_info_t *input_info = node->info->special_info;
1194 memcpy (q, "input_priority=", 15); q += 15;
1195 pri = input_info->priority;
1196 goto write_pri;
1197 }
1198 case PLUGIN_POST: {
1199 const post_info_t *post_info = node->info->special_info;
1200 memcpy (q, "post_type=", 10); q += 10;
1201 xine_uint32_2str (&q, post_info->type);
1202 *q++ = '\n';
1203 break;
1204 }
1205 case PLUGIN_XINE_MODULE: {
1206 const xine_module_info_t *module_info = node->info->special_info;
1207 size_t type_len = strlen(module_info->type);
1208 memcpy (q, "module_type=", 12); q += 12;
1209 memcpy (q, module_info->type, type_len); q += type_len;
1210 memcpy (q, "\nmodule_sub_type=", 17); q += 17;
1211 xine_int32_2str (&q, module_info->sub_type);
1212 memcpy (q, "\nmodule_priority=", 17); q += 17;
1213 pri = module_info->priority;
1214 goto write_pri;
1215 }
1216 write_pri:
1217 xine_int32_2str (&q, pri);
1218 *q++ = '\n';
1219 }
1220 fwrite (b, 1, q - b, fp);
1221
1222 /* config entries */
1223 if (node->config_entry_list) {
1224 xine_list_iterator_t ite = NULL;
1225 #ifdef FAST_SCAN_PLUGINS
1226 cfg_entry_t *entry;
1227 #else
1228 const char *entry;
1229 #endif
1230 while ((entry = xine_list_next_value (node->config_entry_list, &ite))) {
1231 char *key_value;
1232 #ifdef FAST_SCAN_PLUGINS
1233 pthread_mutex_lock (&this->config->config_lock);
1234 this->config->cur = entry;
1235 key_value = this->config->get_serialized_entry (this->config, NULL);
1236 pthread_mutex_unlock (&this->config->config_lock);
1237 #else
1238 /* now serialize the config key */
1239 key_value = this->config->get_serialized_entry (this->config, entry);
1240 #endif
1241 if (key_value) {
1242 size_t slen = strlen (key_value);
1243 #ifdef FAST_SCAN_PLUGINS
1244 lprintf (" config key: %s, serialization: %zu bytes\n", entry->key, slen);
1245 #else
1246 lprintf (" config key: %s, serialization: %zu bytes\n", entry, slen);
1247 #endif
1248 fwrite ("config_key=", 1, 11, fp);
1249 key_value[slen] = '\n';
1250 fwrite (key_value, 1, slen + 1, fp);
1251 free (key_value);
1252 }
1253 }
1254 }
1255
1256 fwrite ("\n", 1, 1, fp);
1257 list_id++;
1258 }
1259 }
1260
1261 /*
1262 * load plugin list information from file (cached catalog)
1263 */
load_plugin_list(xine_t * this,FILE * fp,xine_sarray_t * plugins)1264 static void load_plugin_list (xine_t *this, FILE *fp, xine_sarray_t *plugins) {
1265
1266 fat_node_t node;
1267 size_t stlen, fnlen, idlen;
1268 /* We dont have that many types yet ;-) */
1269 uint32_t supported_types[256];
1270 char *cfgentries[256];
1271 int numcfgs;
1272
1273 char *buf, *line, *nextline, *stop;
1274 int version_ok = 0;
1275 int skip = 0;
1276
1277 {
1278 long int flen;
1279 fseek (fp, 0, SEEK_END);
1280 flen = ftell (fp);
1281 if (flen < 0)
1282 return;
1283 /* TJ. I got far less than 100k, so > 2M is probably insane. */
1284 if (flen > (2 << 20))
1285 flen = 2 << 20;
1286 buf = malloc (flen + 22);
1287 if (!buf)
1288 return;
1289 fseek (fp, 0, SEEK_SET);
1290 flen = fread (buf, 1, flen, fp);
1291 /* HACK: provoke clean exit */
1292 stop = buf + flen;
1293 memcpy (stop, "\n[libxine/builtins]\n\n", 22);
1294 }
1295
1296 _fat_node_init (&node);
1297 stlen = 0;
1298 idlen = 0;
1299 fnlen = 0;
1300 numcfgs = 0;
1301
1302 for (line = buf; line[0]; line = nextline) {
1303 char *value;
1304 /* make string from line */
1305 char *lend = strchr (line, '\n');
1306 if (!lend) { /* should not happen ('\0' in file) */
1307 nextline = stop;
1308 continue;
1309 }
1310 nextline = lend + 1;
1311 if ((lend > line) && (lend[-1] == '\r'))
1312 lend--;
1313 lend[0] = 0;
1314
1315 /* skip comments */
1316 if (line[0] == '#')
1317 continue;
1318 /* skip (almost) empty lines */
1319 if (lend - line < 3)
1320 continue;
1321
1322 /* file name */
1323 if (line[0] == '[' && version_ok) {
1324
1325 if (node.file.filename) {
1326 fat_node_t *n;
1327 char *q;
1328 /* get mem for new node */
1329 n = malloc (sizeof (node) + stlen + idlen + fnlen);
1330 if (!n)
1331 break;
1332 /* fill in */
1333 *n = node;
1334 n->node.info = &n->info[0];
1335 q = (char *)n + sizeof (*n);
1336 if (stlen) {
1337 memcpy (&n->supported_types[0], &supported_types[0], stlen);
1338 q += stlen;
1339 n->ainfo.decoder_info.supported_types = &n->supported_types[0];
1340 }
1341 if (node.info[0].id) {
1342 xine_small_memcpy (q, node.info[0].id, idlen);
1343 n->info[0].id = q;
1344 q += idlen;
1345 }
1346 xine_small_memcpy (q, node.file.filename, fnlen);
1347 n->file.filename = q;
1348 n->node.file = &n->file;
1349 n->info[0].special_info = &n->ainfo;
1350 /* register */
1351 {
1352 int index = xine_sarray_add (plugins, n);
1353 if (index >= 0) { /* new file */
1354 n->lastplugin = n;
1355 } else {
1356 fat_node_t *first_in_file = xine_sarray_get (plugins, ~index);
1357 first_in_file->lastplugin->nextplugin = n;
1358 first_in_file->lastplugin = n;
1359 }
1360 }
1361 if (numcfgs) {
1362 char **cfgentry;
1363 #ifdef FAST_SCAN_PLUGINS
1364 new_entry_data_t ned;
1365 ned.v = this->config;
1366 ned.node = &n->node;
1367 this->config->set_new_entry_callback (this->config, _new_entry_cb, &ned);
1368 #endif
1369 cfgentries[numcfgs] = NULL;
1370 for (cfgentry = cfgentries; *cfgentry; cfgentry++) {
1371 char *cfg_key = this->config->register_serialized_entry (this->config, *cfgentry);
1372 if (cfg_key) {
1373 /* this node is a cached node */
1374 #ifdef FAST_SCAN_PLUGINS
1375 free (cfg_key);
1376 #else
1377 _attach_entry_to_node (&n->node, cfg_key);
1378 #endif
1379 } else {
1380 lprintf("failed to deserialize config entry key\n");
1381 }
1382 }
1383 #ifdef FAST_SCAN_PLUGINS
1384 this->config->unset_new_entry_callback (this->config);
1385 #endif
1386 }
1387 /* reset */
1388 _fat_node_init (&node);
1389 stlen = 0;
1390 numcfgs = 0;
1391 }
1392
1393 value = strchr (line, ']');
1394 if (value)
1395 lend = value;
1396 lend[0] = 0;
1397 fnlen = lend - line /* - 1 + 1 */;
1398 line++;
1399
1400 if (!strcmp (line, "libxine/builtins")) {
1401 skip = 1;
1402 continue;
1403 }
1404 skip = 0;
1405
1406 node.file.filename = line;
1407 continue;
1408 }
1409
1410 if (skip)
1411 continue;
1412
1413 if ((value = strchr (line, '='))) {
1414 unsigned int index = 0;
1415 const char *val;
1416 *value++ = 0;
1417 val = value;
1418 /* get known key */
1419 {
1420 static const char * const known_keys[] = {
1421 "\x0b""ao_priority",
1422 "\x05""api",
1423 "\x01""cache_catalog_version",
1424 "\x10""config_key",
1425 "\x0c""decoder_priority",
1426 "\x0d""demuxer_priority",
1427 "\x06""id",
1428 "\x0e""input_priority",
1429 "\x11""module_priority",
1430 "\x12""module_sub_type",
1431 "\x13""module_type",
1432 "\x03""mtime",
1433 "\x0f""post_type",
1434 "\x02""size",
1435 "\x09""supported_types",
1436 "\x04""type",
1437 "\x07""version",
1438 "\x08""visual_type",
1439 "\x0a""vo_priority"
1440 };
1441 unsigned int b = 0, e = sizeof (known_keys) / sizeof (known_keys[0]), m = e >> 1;
1442 do {
1443 int d = strcmp (line, known_keys[m] + 1);
1444 if (d == 0) {
1445 index = known_keys[m][0];
1446 break;
1447 }
1448 if (d < 0)
1449 e = m;
1450 else
1451 b = m + 1;
1452 m = (b + e) >> 1;
1453 } while (b != e);
1454 }
1455 if( !version_ok ) {
1456 if (index == 1) { /* "cache_catalog_version" */
1457 if (xine_str2uint32 (&val) == CACHE_CATALOG_VERSION)
1458 version_ok = 1;
1459 else {
1460 free (buf);
1461 return;
1462 }
1463 }
1464 } else if (node.file.filename) {
1465 union {
1466 uint64_t llu;
1467 unsigned int u;
1468 int i;
1469 } v = {0};
1470 unsigned int mask = 1u << index;
1471 if (0x027d30 & mask) /* 17,14,13,12,11,10,8,5,4 */
1472 v.i = xine_str2int32 (&val);
1473 else if (0x048080 & mask) /* 18,15,7 */
1474 v.u = xine_str2uint32 (&val);
1475 else if (0x0000c & mask) /* 3,2 */
1476 v.llu = xine_str2uint64 (&val);
1477 switch (index) {
1478 case 2: /* "size" */
1479 node.file.filesize = v.llu;
1480 break;
1481 case 3: /* "mtime" */
1482 node.file.filemtime = v.llu;
1483 break;
1484 case 4: /* "type" */
1485 node.info[0].type = v.i;
1486 break;
1487 case 5: /* "api" */
1488 node.info[0].API = v.i;
1489 break;
1490 case 6: /* "id" */
1491 node.info[0].id = value;
1492 idlen = lend - value + 1;
1493 break;
1494 case 7: /* "version" */
1495 node.info[0].version = v.u;
1496 break;
1497 case 8: /* "visual_type" */
1498 node.ainfo.vo_info.visual_type = v.i;
1499 break;
1500 case 9: { /* "supported_types" */
1501 int i;
1502 for (i = 0; i < 255; i++) {
1503 if ((supported_types[i] = xine_str2uint32 (&val)) == 0)
1504 break;
1505 }
1506 supported_types[i++] = 0;
1507 stlen = i * sizeof (*supported_types);
1508 break;
1509 }
1510 case 10: /* "vo_priority" */
1511 node.ainfo.vo_info.priority = v.i;
1512 break;
1513 case 11: /* "ao_priority" */
1514 node.ainfo.ao_info.priority = v.i;
1515 break;
1516 case 12: /* "decoder_priority" */
1517 node.ainfo.decoder_info.priority = v.i;
1518 break;
1519 case 13: /* "demuxer_priority" */
1520 node.ainfo.demuxer_info.priority = v.i;
1521 break;
1522 case 14: /* "input_priority" */
1523 node.ainfo.input_info.priority = v.i;
1524 break;
1525 case 15: /* "post_type" */
1526 node.ainfo.post_info.type = v.u;
1527 break;
1528 case 16: /* "config_key" */
1529 if (numcfgs < 255)
1530 cfgentries[numcfgs++] = value;
1531 break;
1532 case 17: /* "module_priority" */
1533 node.ainfo.module_info.priority = v.i;
1534 break;
1535 case 18: /* "module_sub_type" */
1536 node.ainfo.module_info.sub_type = v.u;
1537 break;
1538 case 19: /* "module_type" */
1539 strlcpy(node.ainfo.module_info.type, value, sizeof(node.ainfo.module_info.type));
1540 default: ;
1541 }
1542 }
1543 }
1544 }
1545
1546 free (buf);
1547 }
1548
1549 /**
1550 * @brief Returns the complete filename for the plugins' cache file
1551 * @param this Instance pointer, used for logging and libxdg-basedir.
1552 * @param createdir If not zero, create the directory structure in which
1553 * the file has to reside.
1554 * @return If createdir was not zero, returns NULL if the directory hasn't
1555 * been created; otherwise always returns a new string with the
1556 * name of the cachefile.
1557 * @internal
1558 *
1559 * @see XDG Base Directory specification:
1560 * http://standards.freedesktop.org/basedir-spec/latest/index.html
1561 */
catalog_filename(xine_t * this,int createdir)1562 static char *catalog_filename(xine_t *this, int createdir) {
1563 const char *const xdg_cache_home = xdgCacheHome(&this->basedir_handle);
1564 char *cachefile;
1565
1566 if (!xdg_cache_home)
1567 return NULL;
1568
1569 cachefile = malloc( strlen(xdg_cache_home) + sizeof("/"PACKAGE"/plugins.cache") );
1570 if (!cachefile)
1571 return NULL;
1572 strcpy(cachefile, xdg_cache_home);
1573
1574 /* If we're going to create the directory structure, we concatenate
1575 * piece by piece the path, so that we can try to create all the
1576 * directories.
1577 * If we don't need to create anything, we just concatenate the
1578 * whole path at once.
1579 */
1580 if ( createdir ) {
1581 int result = 0;
1582
1583 result = mkdir( cachefile, 0700 );
1584 if ( result != 0 && errno != EEXIST ) {
1585 xprintf (this, XINE_VERBOSITY_LOG, _("Unable to create %s directory: %s\n"), cachefile, strerror(errno));
1586 free(cachefile);
1587 return NULL;
1588 }
1589
1590 strcat(cachefile, "/"PACKAGE);
1591 result = mkdir( cachefile, 0700 );
1592 if ( result != 0 && errno != EEXIST ) {
1593 xprintf (this, XINE_VERBOSITY_LOG, _("Unable to create %s directory: %s\n"), cachefile, strerror(errno));
1594 free(cachefile);
1595 return NULL;
1596 }
1597
1598 strcat(cachefile, "/plugins.cache");
1599
1600 } else
1601 strcat(cachefile, "/"PACKAGE"/plugins.cache");
1602
1603 return cachefile;
1604 }
1605
1606 /*
1607 * save catalog to cache file
1608 */
save_catalog(xine_t * this)1609 static void save_catalog (xine_t *this) {
1610 FILE *fp;
1611 char *const cachefile = catalog_filename(this, 1);
1612 char *cachefile_new;
1613
1614 if ( ! cachefile ) return;
1615
1616 cachefile_new = _x_asprintf("%s.new", cachefile);
1617
1618 if ((fp = fopen (cachefile_new, "wb")) != NULL) {
1619 int i;
1620
1621 fwrite ("# this file is automatically created by xine, do not edit.\n\n"
1622 "cache_catalog_version=" CACHE_CATALOG_VERSION_STR "\n\n", 1, 85, fp);
1623
1624 for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
1625 save_plugin_list (this, fp, this->plugin_catalog->plugin_lists[i]);
1626 }
1627 save_plugin_list (this, fp, this->plugin_catalog->modules_list);
1628 if (fclose(fp))
1629 {
1630 const char *err = strerror (errno);
1631 xine_log (this, XINE_LOG_MSG,
1632 _("failed to save catalogue cache: %s\n"), err);
1633 goto do_unlink;
1634 }
1635 else if (rename (cachefile_new, cachefile))
1636 {
1637 const char *err = strerror (errno);
1638 xine_log (this, XINE_LOG_MSG,
1639 _("failed to replace catalogue cache: %s\n"), err);
1640 do_unlink:
1641 if (unlink (cachefile_new) && errno != ENOENT)
1642 {
1643 err = strerror (errno);
1644 xine_log (this, XINE_LOG_MSG,
1645 _("failed to remove new catalogue cache: %s\n"), err);
1646 }
1647 }
1648 }
1649 free(cachefile);
1650 free(cachefile_new);
1651 }
1652
1653 /*
1654 * load cached catalog from file
1655 */
load_cached_catalog(xine_t * this)1656 static void load_cached_catalog (xine_t *this) {
1657
1658 FILE *fp;
1659 char *const cachefile = catalog_filename(this, 0);
1660 /* It can't return NULL without creating directories */
1661
1662 if ((fp = fopen (cachefile, "rb")) != NULL) {
1663 load_plugin_list (this, fp, this->plugin_catalog->cache_list);
1664 fclose(fp);
1665 }
1666 free(cachefile);
1667 }
1668
1669
1670 /*
1671 * initialize catalog, load all plugins into new catalog
1672 */
_x_scan_plugins(xine_t * this_gen)1673 int _x_scan_plugins (xine_t *this_gen) {
1674 #define XSP_BUFSIZE 4096
1675 xine_private_t *this = (xine_private_t *)this_gen;
1676 char buf[XSP_BUFSIZE], *homeend, *bufend = buf + XSP_BUFSIZE - 16;
1677 const char *pluginpath = NULL;
1678 const char *homedir;
1679
1680 lprintf("_x_scan_plugins()\n");
1681
1682 _x_assert(this);
1683 _x_assert (this->x.config);
1684 _x_assert (!this->x.plugin_catalog);
1685
1686 homedir = xine_get_homedir ();
1687 if (!homedir)
1688 return -1;
1689 {
1690 size_t len = strlen (homedir);
1691 if (len > XSP_BUFSIZE - 16)
1692 len = XSP_BUFSIZE - 16;
1693 xine_small_memcpy (buf, homedir, len);
1694 homeend = buf + len;
1695 }
1696
1697 this->x.plugin_catalog = _new_catalog();
1698 if (!this->x.plugin_catalog)
1699 return -1;
1700
1701 XINE_PROFILE (load_cached_catalog (&this->x));
1702
1703 #ifdef XINE_MAKE_BUILTINS
1704 lprintf ("collect_plugins in libxine\n");
1705 _register_plugins_internal (&this->x, NULL, NULL , xine_builtin_plugin_info);
1706 #endif
1707
1708 if ((pluginpath = getenv("XINE_PLUGIN_PATH")) != NULL && *pluginpath) {
1709
1710 const char *start = pluginpath, *stop, *try;
1711 char *q;
1712 size_t len;
1713 while (1) {
1714 try = homeend;
1715 q = homeend;
1716 if ((start[0] == '~') && (start[1] == '/')) {
1717 start += 1;
1718 try = buf;
1719 }
1720 stop = strchr (start, XINE_PATH_SEPARATOR_CHAR);
1721 if (!stop)
1722 break;
1723 len = stop - start;
1724 if (len > (size_t)(bufend - q))
1725 len = bufend - q;
1726 xine_small_memcpy (q, start, len); q += len;
1727 q[0] = 0;
1728 start = stop + 1;
1729 collect_plugins (&this->x, try, q, bufend);
1730 }
1731 len = strlen (start);
1732 if (len > (size_t)(bufend - q))
1733 len = bufend - q;
1734 xine_small_memcpy (q, start, len); q += len;
1735 q[0] = 0;
1736 collect_plugins (&this->x, try, q, bufend);
1737
1738 } else {
1739
1740 const char *p;
1741 size_t len;
1742 int i;
1743
1744 memcpy (homeend, "/.xine/plugins", 15);
1745 collect_plugins (&this->x, buf, homeend + 15, bufend);
1746
1747 p = XINE_PLUGINROOT;
1748 len = strlen (p);
1749 xine_small_memcpy (buf, p, len);
1750 buf[len++] = '.';
1751 for (i = XINE_LT_AGE; i >= 0; i--) {
1752 char *q = buf + len;
1753 xine_uint32_2str (&q, i);
1754 collect_plugins (&this->x, buf, q, bufend);
1755 }
1756 }
1757
1758 load_required_plugins (&this->x);
1759
1760 if ((this->flags & XINE_FLAG_NO_WRITE_CACHE) == 0)
1761 XINE_PROFILE (save_catalog (&this->x));
1762
1763 map_decoders (&this->x);
1764
1765 return 0;
1766 }
1767
1768 /*
1769 * generic module loading
1770 */
_x_find_module(xine_t * xine,const char * type,const char * id,unsigned sub_type,const void * params)1771 xine_module_t *_x_find_module(xine_t *xine, const char *type, const char *id,
1772 unsigned sub_type, const void *params) {
1773
1774 plugin_catalog_t *catalog = xine->plugin_catalog;
1775 plugin_node_t *node;
1776 xine_module_t *plugin = NULL;
1777 int list_id, list_size;
1778 const xine_module_info_t *info;
1779
1780 pthread_mutex_lock (&catalog->lock);
1781
1782 list_size = xine_sarray_size(catalog->modules_list);
1783 for (list_id = 0; list_id < list_size; list_id++) {
1784 node = xine_sarray_get (catalog->modules_list, list_id);
1785
1786 if (id && strcmp (node->info->id, id))
1787 continue;
1788
1789 info = node->info->special_info;
1790 if (sub_type != info->sub_type)
1791 continue;
1792 if (type && strcmp (info->type, type))
1793 continue;
1794
1795 if (node->plugin_class || _load_plugin_class(xine, node, params)) {
1796 if ((plugin = ((xine_module_class_t *)node->plugin_class)->get_instance(node->plugin_class, params))) {
1797 inc_node_ref(node);
1798 plugin->node = node;
1799 break;
1800 }
1801 }
1802 }
1803
1804 pthread_mutex_unlock (&catalog->lock);
1805
1806 return plugin;
1807 }
1808
_x_free_module(xine_t * xine,xine_module_t ** pmodule)1809 void _x_free_module(xine_t *xine, xine_module_t **pmodule) {
1810
1811 xine_module_t *module = *pmodule;
1812 plugin_catalog_t *catalog = xine->plugin_catalog;
1813 plugin_node_t *node = module->node;
1814
1815 *pmodule = NULL;
1816
1817 module->dispose(module);
1818
1819 if (node) {
1820 pthread_mutex_lock(&catalog->lock);
1821 dec_node_ref(node);
1822 pthread_mutex_unlock(&catalog->lock);
1823 }
1824 }
1825
1826 /*
1827 * input / demuxer plugin loading
1828 */
1829
_x_find_input_plugin(xine_stream_t * stream,const char * mrl)1830 input_plugin_t *_x_find_input_plugin (xine_stream_t *stream, const char *mrl) {
1831
1832 xine_stream_private_t *s;
1833 xine_t *xine;
1834 plugin_catalog_t *catalog;
1835 input_plugin_t *plugin;
1836 uint32_t n;
1837
1838 if (!stream || !mrl)
1839 return NULL;
1840
1841 s = (xine_stream_private_t *)stream;
1842 xine = s->s.xine;
1843 catalog = xine->plugin_catalog;
1844 plugin = NULL;
1845
1846 pthread_mutex_lock (&catalog->lock);
1847
1848 n = !s->query_input_plugins[0] ? 0
1849 : !s->query_input_plugins[1] ? 1 : 2;
1850 if (n != 2) {
1851 int list_id, list_size;
1852 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
1853 for (list_id = 0; list_id < list_size; list_id++) {
1854 plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
1855 input_class_t *class = (input_class_t *)node->plugin_class;
1856 if (!class) {
1857 _load_plugin_class (xine, node, NULL);
1858 class = (input_class_t *)node->plugin_class;
1859 }
1860 if (class) {
1861 s->query_input_plugins[n] = class;
1862 if (s->query_input_plugins[0] != s->query_input_plugins[1]) {
1863 plugin = class->get_instance (class, stream, mrl);
1864 if (plugin) {
1865 inc_node_ref (node);
1866 plugin->node = node;
1867 break;
1868 }
1869 }
1870 }
1871 }
1872 s->query_input_plugins[n] = NULL;
1873 }
1874
1875 pthread_mutex_unlock (&catalog->lock);
1876
1877 return plugin;
1878 }
1879
1880
_x_free_input_plugin(xine_stream_t * stream,input_plugin_t * input)1881 void _x_free_input_plugin (xine_stream_t *stream, input_plugin_t *input) {
1882 plugin_catalog_t *catalog;
1883 plugin_node_t *node;
1884
1885 if (!input)
1886 return;
1887 node = input->node;
1888 input->dispose (input);
1889
1890 if (!stream)
1891 return;
1892 catalog = stream->xine->plugin_catalog;
1893 if (node) {
1894 pthread_mutex_lock(&catalog->lock);
1895 dec_node_ref(node);
1896 pthread_mutex_unlock(&catalog->lock);
1897 }
1898 }
1899
probe_mime_type(xine_t * self,plugin_node_t * node,const char * mime_type)1900 static int probe_mime_type (xine_t *self, plugin_node_t *node, const char *mime_type)
1901 {
1902 /* catalog->lock is expected to be locked */
1903 if (node->plugin_class || _load_plugin_class(self, node, NULL))
1904 {
1905 const unsigned int mime_type_len = strlen (mime_type);
1906 demux_class_t *cls = (demux_class_t *)node->plugin_class;
1907 const char *mime = cls->mimetypes;
1908 while (mime)
1909 {
1910 while (*mime == ';' || isspace (*mime))
1911 ++mime;
1912 if (!strncasecmp (mime, mime_type, mime_type_len) &&
1913 (!mime[mime_type_len] || mime[mime_type_len] == ':' || mime[mime_type_len] == ';'))
1914 return 1;
1915 mime = strchr (mime, ';');
1916 }
1917 }
1918 return 0;
1919 }
1920
probe_demux(xine_stream_t * stream,int method1,int method2,input_plugin_t * input)1921 static demux_plugin_t *probe_demux (xine_stream_t *stream, int method1, int method2,
1922 input_plugin_t *input) {
1923
1924 int i;
1925 int methods[3];
1926 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
1927 demux_plugin_t *plugin = NULL;
1928
1929 methods[0] = method1;
1930 methods[1] = method2;
1931 methods[2] = -1;
1932
1933 i = 0;
1934 while (methods[i] != -1 && !plugin) {
1935 int list_id, list_size;
1936
1937 pthread_mutex_lock (&catalog->lock);
1938
1939 list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
1940 for(list_id = 0; list_id < list_size; list_id++) {
1941 plugin_node_t *node;
1942
1943 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
1944
1945 xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "load_plugins: probing demux '%s'\n", node->info->id);
1946
1947 if (node->plugin_class || _load_plugin_class(stream->xine, node, NULL)) {
1948 const char *mime_type;
1949
1950 /* If detecting by MRL, try the MIME type first (but not text/plain)... */
1951 stream->content_detection_method = METHOD_EXPLICIT;
1952 if (methods[i] == METHOD_BY_MRL &&
1953 stream->input_plugin->get_optional_data &&
1954 stream->input_plugin->get_optional_data (stream->input_plugin, NULL, INPUT_OPTIONAL_DATA_DEMUX_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
1955 stream->input_plugin->get_optional_data (stream->input_plugin, &mime_type, INPUT_OPTIONAL_DATA_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
1956 mime_type && strcasecmp (mime_type, "text/plain") &&
1957 probe_mime_type (stream->xine, node, mime_type) &&
1958 (plugin = ((demux_class_t *)node->plugin_class)->open_plugin (node->plugin_class, stream, input)))
1959 {
1960 inc_node_ref(node);
1961 plugin->node = node;
1962 break;
1963 }
1964
1965 /* ... then try the extension */
1966 stream->content_detection_method = methods[i];
1967 if ( stream->content_detection_method == METHOD_BY_MRL &&
1968 ! _x_demux_check_extension(input->get_mrl(input),
1969 ((demux_class_t *)node->plugin_class)->extensions)
1970 )
1971 continue;
1972
1973 if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
1974 inc_node_ref(node);
1975 plugin->node = node;
1976 break;
1977 }
1978 }
1979 }
1980
1981 pthread_mutex_unlock (&catalog->lock);
1982
1983 i++;
1984 }
1985
1986 return plugin;
1987 }
1988
_x_find_demux_plugin(xine_stream_t * stream,input_plugin_t * input)1989 demux_plugin_t *_x_find_demux_plugin (xine_stream_t *stream, input_plugin_t *input) {
1990
1991 switch (stream->xine->demux_strategy) {
1992
1993 default:
1994 xprintf (stream->xine, XINE_VERBOSITY_LOG,
1995 _("load_plugins: unknown content detection strategy %d\n"),
1996 stream->xine->demux_strategy);
1997 /* fall through */
1998 case XINE_DEMUX_DEFAULT_STRATEGY:
1999 return probe_demux (stream, METHOD_BY_CONTENT, METHOD_BY_MRL, input);
2000
2001 case XINE_DEMUX_REVERT_STRATEGY:
2002 return probe_demux (stream, METHOD_BY_MRL, METHOD_BY_CONTENT, input);
2003
2004 case XINE_DEMUX_CONTENT_STRATEGY:
2005 return probe_demux (stream, METHOD_BY_CONTENT, -1, input);
2006
2007 case XINE_DEMUX_EXTENSION_STRATEGY:
2008 return probe_demux (stream, METHOD_BY_MRL, -1, input);
2009 }
2010
2011 return NULL;
2012 }
2013
_x_find_demux_plugin_by_name(xine_stream_t * stream,const char * name,input_plugin_t * input)2014 demux_plugin_t *_x_find_demux_plugin_by_name(xine_stream_t *stream, const char *name, input_plugin_t *input) {
2015
2016 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2017 plugin_node_t *node;
2018 demux_plugin_t *plugin = NULL;
2019 int list_id, list_size;
2020
2021 pthread_mutex_lock(&catalog->lock);
2022
2023 stream->content_detection_method = METHOD_EXPLICIT;
2024
2025 list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
2026 for (list_id = 0; list_id < list_size; list_id++) {
2027
2028 node = xine_sarray_get(catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
2029
2030 if (strcasecmp(node->info->id, name) == 0) {
2031 if (node->plugin_class || _load_plugin_class(stream->xine, node, NULL)) {
2032 #if 0
2033 /* never triggered (method is set to EXPLICIT few lines earlier) */
2034 if ( stream->content_detection_method == METHOD_BY_MRL &&
2035 ! _x_demux_check_extension(input->get_mrl(input),
2036 ((demux_class_t *)node->plugin_class)->extensions)
2037 )
2038 continue;
2039 #endif
2040 if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
2041 inc_node_ref(node);
2042 plugin->node = node;
2043 break;
2044 }
2045 }
2046 }
2047 }
2048
2049 pthread_mutex_unlock(&catalog->lock);
2050 return plugin;
2051 }
2052
2053 /*
2054 * this is a special test mode for content detection: all demuxers are probed
2055 * by content and extension except last_demux_name which is tested after
2056 * every other demuxer.
2057 *
2058 * this way we can make sure no demuxer will interfere on probing of a
2059 * known stream.
2060 */
2061
_x_find_demux_plugin_last_probe(xine_stream_t * stream,const char * last_demux_name,input_plugin_t * input)2062 demux_plugin_t *_x_find_demux_plugin_last_probe(xine_stream_t *stream, const char *last_demux_name, input_plugin_t *input) {
2063
2064 int i;
2065 int methods[3];
2066 xine_t *xine = stream->xine;
2067 plugin_catalog_t *catalog = xine->plugin_catalog;
2068 plugin_node_t *last_demux = NULL;
2069 demux_plugin_t *plugin = NULL;
2070
2071 methods[0] = METHOD_BY_CONTENT;
2072 methods[1] = METHOD_BY_MRL;
2073 methods[2] = -1;
2074
2075 i = 0;
2076 while (methods[i] != -1 && !plugin) {
2077 int list_id, list_size;
2078
2079 stream->content_detection_method = methods[i];
2080
2081 pthread_mutex_lock (&catalog->lock);
2082
2083 list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
2084 for (list_id = 0; list_id < list_size; list_id++) {
2085 plugin_node_t *node;
2086
2087 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
2088
2089 lprintf ("probing demux '%s'\n", node->info->id);
2090
2091 if (strcasecmp(node->info->id, last_demux_name) == 0) {
2092 last_demux = node;
2093 } else {
2094 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2095 "load_plugin: probing '%s' (method %d)...\n", node->info->id, stream->content_detection_method );
2096 if (node->plugin_class || _load_plugin_class(xine, node, NULL)) {
2097
2098 if ( stream->content_detection_method == METHOD_BY_MRL &&
2099 ! _x_demux_check_extension(input->get_mrl(input),
2100 ((demux_class_t *)node->plugin_class)->extensions)
2101 )
2102 continue;
2103
2104
2105 if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
2106 xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
2107 "load_plugins: using demuxer '%s' (instead of '%s')\n", node->info->id, last_demux_name);
2108 inc_node_ref(node);
2109 plugin->node = node;
2110 break;
2111 }
2112 }
2113 }
2114 }
2115
2116 pthread_mutex_unlock (&catalog->lock);
2117
2118 i++;
2119 }
2120
2121 if( plugin )
2122 return plugin;
2123
2124 if( !last_demux )
2125 return NULL;
2126
2127 stream->content_detection_method = METHOD_BY_CONTENT;
2128
2129 pthread_mutex_lock (&catalog->lock);
2130 if (last_demux->plugin_class || _load_plugin_class(xine, last_demux, NULL)) {
2131
2132 if ((plugin = ((demux_class_t *)last_demux->plugin_class)->open_plugin(last_demux->plugin_class, stream, input))) {
2133 xprintf (stream->xine, XINE_VERBOSITY_LOG, _("load_plugins: using demuxer '%s'\n"), last_demux_name);
2134 inc_node_ref(last_demux);
2135 plugin->node = last_demux;
2136 }
2137 }
2138 pthread_mutex_unlock (&catalog->lock);
2139
2140 return plugin;
2141 }
2142
2143
_x_free_demux_plugin(xine_stream_t * stream,demux_plugin_t ** pdemux)2144 void _x_free_demux_plugin (xine_stream_t *stream, demux_plugin_t **pdemux) {
2145 demux_plugin_t *demux = *pdemux;
2146 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2147 plugin_node_t *node = demux->node;
2148
2149 *pdemux = NULL;
2150
2151 demux->dispose(demux);
2152
2153 if (node) {
2154 pthread_mutex_lock(&catalog->lock);
2155 dec_node_ref(node);
2156 pthread_mutex_unlock(&catalog->lock);
2157 }
2158 }
2159
2160
xine_get_autoplay_input_plugin_ids(xine_t * this)2161 const char *const *xine_get_autoplay_input_plugin_ids(xine_t *this) {
2162 const char **last, **end, *test;
2163 int list_id, list_size;
2164 plugin_catalog_t *catalog = this->plugin_catalog;
2165
2166 pthread_mutex_lock (&catalog->lock);
2167 end = &catalog->ids[0] + sizeof (catalog->ids) / sizeof (catalog->ids[0]) - 1;
2168 last = &catalog->ids[0];
2169 *last = NULL;
2170 test = NULL;
2171
2172 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2173 for (list_id = 0; list_id < list_size; list_id++) {
2174
2175 plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2176 input_class_t *ic = node->plugin_class;
2177 if (!ic) {
2178 _load_plugin_class (this, node, NULL);
2179 ic = node->plugin_class;
2180 }
2181 if (ic && ic->get_autoplay_list) {
2182 if (!strcasecmp (node->info->id, "TEST")) {
2183 /* dont let TEST push user media devices out of xine-ui 1 click list. */
2184 test = node->info->id;
2185 } else {
2186 const char **here = &catalog->ids[0], **p;
2187 while (*here && strcasecmp (*here, node->info->id) < 0)
2188 here++;
2189 last++;
2190 for (p = last; p > here; p--)
2191 p[0] = p[-1];
2192 *here = node->info->id;
2193 }
2194 if (last >= end)
2195 break;
2196 }
2197
2198 }
2199
2200 if (last < end) {
2201 *last++ = test;
2202 *last = NULL;
2203 }
2204
2205 pthread_mutex_unlock (&catalog->lock);
2206
2207 return catalog->ids;
2208 }
2209
xine_get_browsable_input_plugin_ids(xine_t * this)2210 const char *const *xine_get_browsable_input_plugin_ids(xine_t *this) {
2211 const char **last, **end, *test;
2212 int list_id, list_size;
2213 plugin_catalog_t *catalog = this->plugin_catalog;
2214
2215 pthread_mutex_lock (&catalog->lock);
2216 end = &catalog->ids[0] + sizeof (catalog->ids) / sizeof (catalog->ids[0]) - 1;
2217 last = &catalog->ids[0];
2218 *last = NULL;
2219 test = NULL;
2220
2221 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2222 for (list_id = 0; list_id < list_size; list_id++) {
2223
2224 plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2225 input_class_t *ic = node->plugin_class;
2226 if (!ic) {
2227 _load_plugin_class (this, node, NULL);
2228 ic = node->plugin_class;
2229 }
2230 if (ic && ic->get_dir) {
2231 if (!strcasecmp (node->info->id, "TEST")) {
2232 /* dont let TEST push user media devices out of xine-ui 1 click list. */
2233 test = node->info->id;
2234 } else {
2235 const char **here = &catalog->ids[0], **p;
2236 while (*here && strcasecmp (*here, node->info->id) < 0)
2237 here++;
2238 last++;
2239 for (p = last; p > here; p--)
2240 p[0] = p[-1];
2241 *here = node->info->id;
2242 }
2243 if (last >= end)
2244 break;
2245 }
2246
2247 }
2248
2249 if (last < end) {
2250 *last++ = test;
2251 *last = NULL;
2252 }
2253
2254 pthread_mutex_unlock (&catalog->lock);
2255
2256 return catalog->ids;
2257 }
2258
2259 /*
2260 * video out plugins section
2261 */
2262
_load_video_driver(xine_t * this,plugin_node_t * node,const void * data)2263 static vo_driver_t *_load_video_driver (xine_t *this, plugin_node_t *node,
2264 const void *data) {
2265
2266 vo_driver_t *driver;
2267
2268 if (!node->plugin_class && !_load_plugin_class (this, node, data))
2269 return NULL;
2270
2271 driver = ((video_driver_class_t *)node->plugin_class)->open_plugin(node->plugin_class, data);
2272
2273 if (driver) {
2274 inc_node_ref(node);
2275 driver->node = node;
2276 }
2277
2278 return driver;
2279 }
2280
_x_load_video_output_plugin(xine_t * this,const char * id,int visual_type,const void * visual)2281 vo_driver_t *_x_load_video_output_plugin(xine_t *this,
2282 const char *id,
2283 int visual_type,
2284 const void *visual) {
2285
2286 plugin_node_t *node;
2287 vo_driver_t *driver = NULL;
2288 const vo_info_t *vo_info;
2289 plugin_catalog_t *catalog = this->plugin_catalog;
2290 int list_id, list_size;
2291
2292 if (id && !strcasecmp(id, "auto"))
2293 id = NULL;
2294
2295 pthread_mutex_lock (&catalog->lock);
2296
2297 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2298 for (list_id = 0; list_id < list_size; list_id++) {
2299
2300 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2301
2302 vo_info = (const vo_info_t *)node->info->special_info;
2303 if (vo_info->visual_type == visual_type) {
2304 if (id) {
2305 if (!strcasecmp (node->info->id, id)) {
2306 driver = _load_video_driver (this, node, visual);
2307 break;
2308 }
2309
2310 } else {
2311
2312 driver = _load_video_driver (this, node, visual);
2313
2314 if (driver) {
2315
2316 break;
2317 }
2318 }
2319 }
2320 }
2321
2322 pthread_mutex_unlock (&catalog->lock);
2323
2324 return driver;
2325 }
2326
xine_open_video_driver(xine_t * this,const char * id,int visual_type,const void * visual)2327 xine_video_port_t *xine_open_video_driver (xine_t *this,
2328 const char *id,
2329 int visual_type,
2330 const void *visual) {
2331
2332 vo_driver_t *driver;
2333 xine_video_port_t *port;
2334
2335 driver = _x_load_video_output_plugin(this, id, visual_type, visual);
2336
2337 if (!driver) {
2338 lprintf ("failed to load video output plugin <%s>\n", id);
2339 return NULL;
2340 }
2341
2342 port = _x_vo_new_port(this, driver, 0);
2343
2344 return port;
2345 }
2346
xine_new_framegrab_video_port(xine_t * this)2347 xine_video_port_t *xine_new_framegrab_video_port (xine_t *this) {
2348
2349 plugin_node_t *node;
2350 vo_driver_t *driver;
2351 xine_video_port_t *port;
2352 plugin_catalog_t *catalog = this->plugin_catalog;
2353 const char *id;
2354 int list_id, list_size;
2355
2356 driver = NULL;
2357 id = "none";
2358
2359 pthread_mutex_lock (&catalog->lock);
2360
2361 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2362 for (list_id = 0; list_id < list_size; list_id++) {
2363
2364 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2365
2366 if (!strcasecmp (node->info->id, id)) {
2367 driver = _load_video_driver (this, node, NULL);
2368 break;
2369 }
2370 }
2371
2372 pthread_mutex_unlock (&catalog->lock);
2373
2374 if (!driver) {
2375 lprintf ("failed to load video output plugin <%s>\n", id);
2376 return NULL;
2377 }
2378
2379 port = _x_vo_new_port(this, driver, 1);
2380
2381 return port;
2382 }
2383
2384 /*
2385 * audio output plugins section
2386 */
2387
xine_list_audio_output_plugins(xine_t * xine)2388 const char *const *xine_list_audio_output_plugins (xine_t *xine) {
2389 return _build_list_typed_plugins (xine, PLUGIN_AUDIO_OUT);
2390 }
2391
xine_list_video_output_plugins(xine_t * xine)2392 const char *const *xine_list_video_output_plugins (xine_t *xine) {
2393 return _build_list_typed_plugins (xine, PLUGIN_VIDEO_OUT);
2394 }
2395
xine_list_video_output_plugins_typed(xine_t * xine,uint64_t typemask)2396 const char *const *xine_list_video_output_plugins_typed(xine_t *xine, uint64_t typemask)
2397 {
2398 plugin_catalog_t *catalog = xine->plugin_catalog;
2399 plugin_node_t *node;
2400 int list_id, list_size, i;
2401
2402 pthread_mutex_lock (&catalog->lock);
2403
2404 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2405
2406 for (list_id = i = 0; list_id < list_size; list_id++)
2407 {
2408 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2409 if (typemask & (1ULL << ((const vo_info_t *)node->info->special_info)->visual_type))
2410 {
2411 const char *id = node->info->id;
2412 int j = i;
2413 while (--j >= 0)
2414 if (!strcmp (catalog->ids[j], id))
2415 goto ignore; /* already listed */
2416 catalog->ids[i++] = id;
2417 }
2418 ignore: ;
2419 }
2420 catalog->ids[i] = NULL;
2421
2422 pthread_mutex_unlock (&catalog->lock);
2423 return catalog->ids;
2424 }
2425
_load_audio_driver(xine_t * this,plugin_node_t * node,const void * data)2426 static ao_driver_t *_load_audio_driver (xine_t *this, plugin_node_t *node,
2427 const void *data) {
2428
2429 ao_driver_t *driver;
2430
2431 if (!node->plugin_class && !_load_plugin_class (this, node, data))
2432 return NULL;
2433
2434 driver = ((audio_driver_class_t *)node->plugin_class)->open_plugin(node->plugin_class, data);
2435
2436 if (driver) {
2437 inc_node_ref(node);
2438 driver->node = node;
2439 }
2440
2441 return driver;
2442 }
2443
_x_load_audio_output_plugin(xine_t * this,const char * id)2444 ao_driver_t *_x_load_audio_output_plugin (xine_t *this, const char *id)
2445 {
2446 plugin_node_t *node;
2447 ao_driver_t *driver = NULL;
2448 plugin_catalog_t *catalog = this->plugin_catalog;
2449 int list_id, list_size;
2450
2451 pthread_mutex_lock (&catalog->lock);
2452
2453 list_size = xine_sarray_size (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1]);
2454 for (list_id = 0; list_id < list_size; list_id++) {
2455
2456 node = xine_sarray_get (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1], list_id);
2457
2458 if (!strcasecmp(node->info->id, id)) {
2459 driver = _load_audio_driver (this, node, NULL);
2460 break;
2461 }
2462 }
2463
2464 pthread_mutex_unlock (&catalog->lock);
2465
2466 if (!driver) {
2467 xprintf (this, XINE_VERBOSITY_LOG,
2468 _("load_plugins: failed to load audio output plugin <%s>\n"), id);
2469 }
2470 return driver;
2471 }
2472
xine_open_audio_driver(xine_t * this,const char * id,const void * data)2473 xine_audio_port_t *xine_open_audio_driver (xine_t *this, const char *id,
2474 const void *data) {
2475
2476 plugin_node_t *node;
2477 ao_driver_t *driver = NULL;
2478 xine_audio_port_t *port;
2479 const ao_info_t *ao_info;
2480 plugin_catalog_t *catalog = this->plugin_catalog;
2481 int list_id, list_size;
2482
2483 if (id && !strcasecmp(id, "auto") )
2484 id = NULL;
2485
2486 pthread_mutex_lock (&catalog->lock);
2487
2488 list_size = xine_sarray_size (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1]);
2489 for (list_id = 0; list_id < list_size; list_id++) {
2490
2491 node = xine_sarray_get (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1], list_id);
2492
2493 ao_info = (const ao_info_t *)node->info->special_info;
2494
2495 if (id) {
2496 if (!strcasecmp(node->info->id, id)) {
2497 driver = _load_audio_driver (this, node, data);
2498 break;
2499 }
2500 } else if( ao_info->priority >= 0 ) {
2501 driver = _load_audio_driver (this, node, data);
2502 if (driver) {
2503 break;
2504 }
2505 }
2506 }
2507
2508 pthread_mutex_unlock (&catalog->lock);
2509
2510 if (!driver) {
2511 if (id)
2512 xprintf (this, XINE_VERBOSITY_LOG,
2513 _("load_plugins: failed to load audio output plugin <%s>\n"), id);
2514 else
2515 xprintf (this, XINE_VERBOSITY_LOG,
2516 _("load_plugins: audio output auto-probing didn't find any usable audio driver.\n"));
2517 return NULL;
2518 }
2519
2520 port = _x_ao_new_port(this, driver, 0);
2521
2522 return port;
2523 }
2524
xine_new_framegrab_audio_port(xine_t * this)2525 xine_audio_port_t *xine_new_framegrab_audio_port (xine_t *this) {
2526
2527 xine_audio_port_t *port;
2528
2529 port = _x_ao_new_port (this, NULL, 1);
2530
2531 return port;
2532 }
2533
_x_free_audio_driver(xine_t * xine,ao_driver_t ** pdriver)2534 void _x_free_audio_driver (xine_t *xine, ao_driver_t **pdriver) {
2535
2536 ao_driver_t *driver = *pdriver;
2537 plugin_catalog_t *catalog = xine->plugin_catalog;
2538 plugin_node_t *node = driver->node;
2539
2540 *pdriver = NULL;
2541
2542 driver->exit(driver);
2543
2544 if (node) {
2545 pthread_mutex_lock(&catalog->lock);
2546 dec_node_ref(node);
2547 pthread_mutex_unlock(&catalog->lock);
2548 }
2549 }
2550
_x_free_video_driver(xine_t * xine,vo_driver_t ** pdriver)2551 void _x_free_video_driver (xine_t *xine, vo_driver_t **pdriver) {
2552
2553 vo_driver_t *driver = *pdriver;
2554 plugin_catalog_t *catalog = xine->plugin_catalog;
2555 plugin_node_t *node = driver->node;
2556
2557 *pdriver = NULL;
2558
2559 driver->dispose (driver);
2560
2561 if (node) {
2562 pthread_mutex_lock(&catalog->lock);
2563 dec_node_ref(node);
2564 pthread_mutex_unlock(&catalog->lock);
2565 }
2566 }
2567
xine_close_audio_driver(xine_t * this,xine_audio_port_t * ao_port)2568 void xine_close_audio_driver (xine_t *this, xine_audio_port_t *ao_port) {
2569
2570 (void)this;
2571 if( ao_port )
2572 ao_port->exit(ao_port);
2573
2574 }
2575
xine_close_video_driver(xine_t * this,xine_video_port_t * vo_port)2576 void xine_close_video_driver (xine_t *this, xine_video_port_t *vo_port) {
2577
2578 (void)this;
2579 if( vo_port )
2580 vo_port->exit(vo_port);
2581
2582 }
2583
2584
2585 /*
2586 * get autoplay mrl list from input plugin
2587 */
2588
_get_input_class(xine_t * this,const char * plugin_id)2589 static input_class_t *_get_input_class (xine_t *this, const char *plugin_id) {
2590
2591 plugin_catalog_t *catalog;
2592 plugin_node_t *node;
2593 int list_id, list_size;
2594
2595 catalog = this->plugin_catalog;
2596
2597 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2598 for (list_id = 0; list_id < list_size; list_id++) {
2599
2600 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2601
2602 if (!strcasecmp (node->info->id, plugin_id)) {
2603 if (node->plugin_class || _load_plugin_class (this, node, NULL)) {
2604 return node->plugin_class;
2605 }
2606 }
2607 }
2608 return NULL;
2609 }
2610
xine_get_autoplay_mrls(xine_t * this,const char * plugin_id,int * num_mrls)2611 const char * const *xine_get_autoplay_mrls (xine_t *this, const char *plugin_id,
2612 int *num_mrls) {
2613
2614 plugin_catalog_t *catalog;
2615 input_class_t *ic;
2616 const char * const *mrls = NULL;
2617
2618 catalog = this->plugin_catalog;
2619
2620 pthread_mutex_lock (&catalog->lock);
2621
2622 ic = _get_input_class(this, plugin_id);
2623 if (ic && ic->get_autoplay_list)
2624 mrls = ic->get_autoplay_list (ic, num_mrls);
2625
2626 pthread_mutex_unlock (&catalog->lock);
2627
2628 return mrls;
2629 }
2630
2631 /*
2632 * input plugin mrl browser support
2633 */
2634
xine_get_browse_mrls(xine_t * this,const char * plugin_id,const char * start_mrl,int * num_mrls)2635 xine_mrl_t **xine_get_browse_mrls (xine_t *this, const char *plugin_id,
2636 const char *start_mrl, int *num_mrls) {
2637 plugin_catalog_t *catalog;
2638 input_class_t *ic;
2639 xine_mrl_t **mrls = NULL;
2640
2641 catalog = this->plugin_catalog;
2642
2643 pthread_mutex_lock (&catalog->lock);
2644
2645 ic = _get_input_class (this, plugin_id);
2646 if (ic && ic->get_dir)
2647 mrls = ic->get_dir (ic, start_mrl, num_mrls);
2648
2649 pthread_mutex_unlock (&catalog->lock);
2650
2651 return mrls;
2652 }
2653
_x_get_video_decoder(xine_stream_t * stream,uint8_t stream_type)2654 video_decoder_t *_x_get_video_decoder (xine_stream_t *stream, uint8_t stream_type) {
2655
2656 plugin_node_t *node;
2657 int i, j;
2658 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2659 video_decoder_t *vd = NULL;
2660
2661 lprintf ("looking for video decoder for streamtype %02x\n", stream_type);
2662 _x_assert(stream_type < DECODER_MAX);
2663
2664 pthread_mutex_lock (&catalog->lock);
2665
2666 for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2667
2668 node = catalog->video_decoder_map[stream_type][i];
2669
2670 if (!node) {
2671 break;
2672 }
2673
2674 if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2675 /* remove non working plugin from catalog */
2676 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2677 "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2678 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2679 catalog->video_decoder_map[stream_type][j - 1] =
2680 catalog->video_decoder_map[stream_type][j];
2681 catalog->video_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2682 i--;
2683 continue;
2684 }
2685
2686 vd = ((video_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2687
2688 if (vd == (video_decoder_t*)1) {
2689 /* HACK: plugin failed to instantiate because required resources are unavailable at that time,
2690 but may be available later, so don't remove this plugin from catalog. */
2691 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2692 "load_plugins: plugin %s failed to instantiate, resources temporarily unavailable.\n", node->info->id);
2693 }
2694 else if (vd) {
2695 inc_node_ref(node);
2696 vd->node = node;
2697 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2698 "load_plugins: plugin %s will be used for video streamtype %02x.\n",
2699 node->info->id, stream_type);
2700
2701 break;
2702 } else {
2703 /* remove non working plugin from catalog */
2704 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2705 "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2706 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2707 catalog->video_decoder_map[stream_type][j - 1] =
2708 catalog->video_decoder_map[stream_type][j];
2709 catalog->video_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2710 i--;
2711 }
2712 }
2713
2714 pthread_mutex_unlock (&catalog->lock);
2715 return vd;
2716 }
2717
_x_free_video_decoder(xine_stream_t * stream,video_decoder_t * vd)2718 void _x_free_video_decoder (xine_stream_t *stream, video_decoder_t *vd) {
2719 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2720 plugin_node_t *node = vd->node;
2721
2722 vd->dispose (vd);
2723
2724 if (node) {
2725 pthread_mutex_lock (&catalog->lock);
2726 dec_node_ref(node);
2727 pthread_mutex_unlock (&catalog->lock);
2728 }
2729 }
2730
2731
_x_get_audio_decoder(xine_stream_t * stream,uint8_t stream_type)2732 audio_decoder_t *_x_get_audio_decoder (xine_stream_t *stream, uint8_t stream_type) {
2733
2734 plugin_node_t *node;
2735 int i, j;
2736 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2737 audio_decoder_t *ad = NULL;
2738
2739 lprintf ("looking for audio decoder for streamtype %02x\n", stream_type);
2740 _x_assert(stream_type < DECODER_MAX);
2741
2742 pthread_mutex_lock (&catalog->lock);
2743
2744 for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2745
2746 node = catalog->audio_decoder_map[stream_type][i];
2747
2748 if (!node) {
2749 break;
2750 }
2751
2752 if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2753 /* remove non working plugin from catalog */
2754 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2755 "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2756 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2757 catalog->audio_decoder_map[stream_type][j - 1] =
2758 catalog->audio_decoder_map[stream_type][j];
2759 catalog->audio_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2760 i--;
2761 continue;
2762 }
2763
2764 ad = ((audio_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2765
2766 if (ad == (audio_decoder_t*)1) {
2767 /* HACK: plugin failed to instantiate because required resources are unavailable at that time,
2768 but may be available later, so don't remove this plugin from catalog. */
2769 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2770 "load_plugins: plugin %s failed to instantiate, resources temporarily unavailable.\n", node->info->id);
2771 }
2772 else if (ad) {
2773 inc_node_ref(node);
2774 ad->node = node;
2775 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2776 "load_plugins: plugin %s will be used for audio streamtype %02x.\n",
2777 node->info->id, stream_type);
2778 break;
2779 } else {
2780 /* remove non working plugin from catalog */
2781 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2782 "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2783 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2784 catalog->audio_decoder_map[stream_type][j - 1] =
2785 catalog->audio_decoder_map[stream_type][j];
2786 catalog->audio_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2787 i--;
2788 }
2789 }
2790
2791 pthread_mutex_unlock (&catalog->lock);
2792 return ad;
2793 }
2794
_x_free_audio_decoder(xine_stream_t * stream,audio_decoder_t * ad)2795 void _x_free_audio_decoder (xine_stream_t *stream, audio_decoder_t *ad) {
2796 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2797 plugin_node_t *node = ad->node;
2798
2799 ad->dispose (ad);
2800
2801 if (node) {
2802 pthread_mutex_lock (&catalog->lock);
2803 dec_node_ref(node);
2804 pthread_mutex_unlock (&catalog->lock);
2805 }
2806 }
2807
_x_decoder_available(xine_t * xine,uint32_t buftype)2808 int _x_decoder_available (xine_t *xine, uint32_t buftype)
2809 {
2810 plugin_catalog_t *catalog = xine->plugin_catalog;
2811 int stream_type = (buftype>>16) & 0xFF;
2812
2813 _x_assert(stream_type < DECODER_MAX);
2814
2815 if ( (buftype & 0xFF000000) == BUF_VIDEO_BASE ) {
2816 if( catalog->video_decoder_map[stream_type][0] )
2817 return 1;
2818 } else
2819 if ( (buftype & 0xFF000000) == BUF_AUDIO_BASE ) {
2820 if( catalog->audio_decoder_map[stream_type][0] )
2821 return 1;
2822 } else
2823 if ( (buftype & 0xFF000000) == BUF_SPU_BASE ) {
2824 if( catalog->spu_decoder_map[stream_type][0] )
2825 return 1;
2826 }
2827
2828 return 0;
2829 }
2830
2831 #ifdef LOG
_display_file_plugin_list(xine_list_t * list,plugin_file_t * file)2832 static void _display_file_plugin_list (xine_list_t *list, plugin_file_t *file) {
2833 xine_list_iterator_t ite = NULL;
2834 plugin_node_t *node;
2835 while ((node = xine_list_next_value (list, &ite))) {
2836 if ((node->file == file) && (node->ref)) {
2837 printf(" plugin: %s, class: %p , %d instance(s)\n",
2838 node->info->id, node->plugin_class, node->ref);
2839 }
2840 }
2841 }
2842 #endif
2843
_unload_unref_plugin(xine_t * xine,plugin_node_t * node)2844 static void _unload_unref_plugin(xine_t *xine, plugin_node_t *node) {
2845 if (node->ref == 0) {
2846 plugin_file_t *file = node->file;
2847
2848 /* no plugin of this class is instancied */
2849 _dispose_plugin_class(node);
2850
2851 /* check file references */
2852 if (file && !file->ref && file->lib_handle && !file->no_unload) {
2853 /* unload this file */
2854 lprintf("unloading plugin %s\n", file->filename);
2855 if (dlclose(file->lib_handle)) {
2856 const char *error = dlerror();
2857
2858 xine_log (xine, XINE_LOG_PLUGIN,
2859 _("load_plugins: cannot unload plugin lib %s:\n%s\n"), file->filename, error);
2860 }
2861 file->lib_handle = NULL;
2862 }
2863 }
2864 }
2865
_unload_unref_plugins(xine_t * xine,xine_sarray_t * list)2866 static void _unload_unref_plugins(xine_t *xine, xine_sarray_t *list) {
2867
2868 plugin_node_t *node;
2869 int list_id, list_size;
2870
2871 list_size = xine_sarray_size (list);
2872 for (list_id = 0; list_id < list_size; list_id++) {
2873
2874 node = xine_sarray_get (list, list_id);
2875
2876 _unload_unref_plugin(xine, node);
2877 }
2878 }
2879
xine_plugins_garbage_collector(xine_t * self)2880 void xine_plugins_garbage_collector(xine_t *self) {
2881 plugin_catalog_t *catalog = self->plugin_catalog;
2882 int i;
2883
2884 pthread_mutex_lock (&catalog->lock);
2885 for(i = 0; i < PLUGIN_TYPE_MAX; i++) {
2886 _unload_unref_plugins(self, self->plugin_catalog->plugin_lists[i]);
2887 }
2888
2889 #if 0
2890 {
2891 plugin_file_t *file;
2892
2893 printf("\nPlugin summary after garbage collection : \n");
2894 file = xine_list_first_content(self->plugin_catalog->file);
2895 while (file) {
2896 if (file->ref) {
2897 printf("\n file %s referenced %d time(s)\n", file->filename, file->ref);
2898
2899 for(i = 0; i < PLUGIN_TYPE_MAX; i++) {
2900 _display_file_plugin_list (self->plugin_catalog->plugin_lists[i], file)
2901 }
2902 }
2903 file = xine_list_next_content(self->plugin_catalog->file);
2904 }
2905 printf("End of plugin summary\n\n");
2906 }
2907 #endif
2908
2909 pthread_mutex_unlock (&catalog->lock);
2910 }
2911
_x_get_spu_decoder(xine_stream_t * stream,uint8_t stream_type)2912 spu_decoder_t *_x_get_spu_decoder (xine_stream_t *stream, uint8_t stream_type) {
2913
2914 plugin_node_t *node;
2915 int i, j;
2916 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2917 spu_decoder_t *sd = NULL;
2918
2919 lprintf ("looking for spu decoder for streamtype %02x\n", stream_type);
2920 _x_assert(stream_type < DECODER_MAX);
2921
2922 pthread_mutex_lock (&catalog->lock);
2923
2924 for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2925
2926 node = catalog->spu_decoder_map[stream_type][i];
2927
2928 if (!node) {
2929 break;
2930 }
2931
2932 if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2933 /* remove non working plugin from catalog */
2934 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2935 "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2936 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2937 catalog->spu_decoder_map[stream_type][j - 1] =
2938 catalog->spu_decoder_map[stream_type][j];
2939 catalog->spu_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2940 i--;
2941 continue;
2942 }
2943
2944 sd = ((spu_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2945
2946 if (sd) {
2947 inc_node_ref(node);
2948 sd->node = node;
2949 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2950 "load_plugins: plugin %s will be used for spu streamtype %02x.\n",
2951 node->info->id, stream_type);
2952 break;
2953 } else {
2954 /* remove non working plugin from catalog */
2955 xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2956 "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2957 for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2958 catalog->spu_decoder_map[stream_type][j - 1] =
2959 catalog->spu_decoder_map[stream_type][j];
2960 catalog->spu_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2961 i--;
2962 }
2963 }
2964
2965 pthread_mutex_unlock (&catalog->lock);
2966 return sd;
2967 }
2968
_x_free_spu_decoder(xine_stream_t * stream,spu_decoder_t * sd)2969 void _x_free_spu_decoder (xine_stream_t *stream, spu_decoder_t *sd) {
2970 plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2971 plugin_node_t *node = sd->node;
2972
2973 sd->dispose (sd);
2974
2975 if (node) {
2976 pthread_mutex_lock (&catalog->lock);
2977 dec_node_ref(node);
2978 pthread_mutex_unlock (&catalog->lock);
2979 }
2980 }
2981
xine_list_demuxer_plugins(xine_t * xine)2982 const char *const *xine_list_demuxer_plugins(xine_t *xine) {
2983 return _build_list_typed_plugins (xine, PLUGIN_DEMUX);
2984 }
2985
xine_list_input_plugins(xine_t * xine)2986 const char *const *xine_list_input_plugins(xine_t *xine) {
2987 return _build_list_typed_plugins (xine, PLUGIN_INPUT);
2988 }
2989
xine_list_spu_plugins(xine_t * xine)2990 const char *const *xine_list_spu_plugins(xine_t *xine) {
2991 return _build_list_typed_plugins (xine, PLUGIN_SPU_DECODER);
2992 }
2993
xine_list_audio_decoder_plugins(xine_t * xine)2994 const char *const *xine_list_audio_decoder_plugins(xine_t *xine) {
2995 return _build_list_typed_plugins (xine, PLUGIN_AUDIO_DECODER);
2996 }
2997
xine_list_video_decoder_plugins(xine_t * xine)2998 const char *const *xine_list_video_decoder_plugins(xine_t *xine) {
2999 return _build_list_typed_plugins (xine, PLUGIN_VIDEO_DECODER);
3000 }
3001
xine_list_post_plugins(xine_t * xine)3002 const char *const *xine_list_post_plugins(xine_t *xine) {
3003 return _build_list_typed_plugins (xine, PLUGIN_POST);
3004 }
3005
xine_list_post_plugins_typed(xine_t * xine,uint32_t type)3006 const char *const *xine_list_post_plugins_typed(xine_t *xine, uint32_t type) {
3007 plugin_catalog_t *catalog = xine->plugin_catalog;
3008 plugin_node_t *node;
3009 int i;
3010 int list_id, list_size;
3011
3012 pthread_mutex_lock (&catalog->lock);
3013
3014 i = 0;
3015 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_POST - 1]);
3016
3017 for (list_id = 0; list_id < list_size; list_id++) {
3018 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_POST - 1], list_id);
3019 if (((const post_info_t *)node->info->special_info)->type == type)
3020 catalog->ids[i++] = node->info->id;
3021 }
3022 catalog->ids[i] = NULL;
3023
3024 pthread_mutex_unlock (&catalog->lock);
3025 return catalog->ids;
3026 }
3027
3028 #define GET_PLUGIN_DESC(NAME,TYPE,CATITEM) \
3029 const char *xine_get_##NAME##_plugin_description (xine_t *this, const char *plugin_id) { \
3030 plugin_catalog_t *catalog = this->plugin_catalog; \
3031 plugin_node_t *node; \
3032 int list_id, list_size; \
3033 pthread_mutex_lock (&catalog->lock); \
3034 list_size = xine_sarray_size (catalog->plugin_lists[CATITEM - 1]); \
3035 for (list_id = 0; list_id < list_size; list_id++) { \
3036 node = xine_sarray_get (catalog->plugin_lists[CATITEM - 1], list_id); \
3037 if (!strcasecmp (node->info->id, plugin_id)) { \
3038 TYPE##_class_t *ic = (TYPE##_class_t *) node->plugin_class; \
3039 const char *ret = NULL; \
3040 if (!ic) { \
3041 if (_load_plugin_class (this, node, NULL)) \
3042 ic = node->plugin_class; \
3043 } \
3044 if (ic) \
3045 ret = dgettext(ic->text_domain ? ic->text_domain : XINE_TEXTDOMAIN, ic->description); \
3046 pthread_mutex_unlock (&catalog->lock); \
3047 return ret; \
3048 } \
3049 } \
3050 pthread_mutex_unlock (&catalog->lock); \
3051 return NULL; \
3052 }
3053
GET_PLUGIN_DESC(input,input,PLUGIN_INPUT)3054 GET_PLUGIN_DESC (input, input, PLUGIN_INPUT)
3055 GET_PLUGIN_DESC (demux, demux, PLUGIN_DEMUX)
3056 GET_PLUGIN_DESC (spu, spu_decoder, PLUGIN_SPU_DECODER)
3057 GET_PLUGIN_DESC (audio, audio_decoder, PLUGIN_AUDIO_DECODER)
3058 GET_PLUGIN_DESC (video, video_decoder, PLUGIN_VIDEO_DECODER)
3059 GET_PLUGIN_DESC (audio_driver, audio_driver, PLUGIN_AUDIO_OUT)
3060 GET_PLUGIN_DESC (video_driver, video_driver, PLUGIN_VIDEO_OUT)
3061 GET_PLUGIN_DESC (post, post, PLUGIN_POST)
3062
3063 xine_post_t *xine_post_init (xine_t *xine_gen, const char *name, int inputs,
3064 xine_audio_port_t **audio_target,
3065 xine_video_port_t **video_target) {
3066 xine_private_t *xine = (xine_private_t *)xine_gen;
3067 plugin_catalog_t *catalog = xine->x.plugin_catalog;
3068 plugin_node_t *node;
3069 post_plugin_t *post = NULL;
3070 int list_id, list_size;
3071
3072 if( !name )
3073 return NULL;
3074
3075 pthread_mutex_lock(&catalog->lock);
3076
3077 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_POST - 1]);
3078
3079 for (list_id = 0; list_id < list_size; list_id++) {
3080 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_POST - 1], list_id);
3081
3082 if (strcmp(node->info->id, name) == 0) {
3083
3084 if (!node->plugin_class && !_load_plugin_class (&xine->x, node, NULL)) {
3085 xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
3086 "load_plugins: requested post plugin %s failed to load\n", name);
3087 break;
3088 }
3089
3090 post = ((post_class_t *)node->plugin_class)->open_plugin(node->plugin_class,
3091 inputs, audio_target, video_target);
3092
3093 if (post) {
3094 post->running_ticket = xine->port_ticket;
3095 post->xine = &xine->x;
3096 post->node = node;
3097 inc_node_ref(node);
3098
3099 /* init the lists of announced connections */
3100 post->input_ids = malloc (sizeof (char *) * (xine_list_size (post->input) + 1));
3101 if (post->input_ids) {
3102 int i = 0;
3103 xine_list_iterator_t ite = NULL;
3104 xine_post_in_t *input;
3105 while ((input = xine_list_next_value (post->input, &ite)))
3106 post->input_ids[i++] = input->name;
3107 post->input_ids[i] = NULL;
3108 }
3109 post->output_ids = malloc (sizeof (char *) * (xine_list_size (post->output) + 1));
3110 if (post->output_ids) {
3111 int i = 0;
3112 xine_list_iterator_t ite = NULL;
3113 xine_post_out_t *output;
3114 while ((output = xine_list_next_value (post->output, &ite)))
3115 post->output_ids[i++] = output->name;
3116 post->output_ids[i] = NULL;
3117 }
3118 /* copy the post plugin type to the public part */
3119 post->xine_post.type = ((const post_info_t *)node->info->special_info)->type;
3120
3121 break;
3122 } else {
3123 xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
3124 "load_plugins: post plugin %s failed to instantiate itself\n", name);
3125 break;
3126 }
3127 }
3128 }
3129
3130 pthread_mutex_unlock(&catalog->lock);
3131
3132 if(post)
3133 return &post->xine_post;
3134 else {
3135 xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "load_plugins: no post plugin named %s found\n", name);
3136 return NULL;
3137 }
3138 }
3139
xine_post_dispose(xine_t * xine,xine_post_t * post_gen)3140 void xine_post_dispose(xine_t *xine, xine_post_t *post_gen) {
3141 post_plugin_t *post = (post_plugin_t *)post_gen;
3142 (void)xine;
3143 post->dispose(post);
3144 /* we cannot decrement the reference counter, since post plugins can delay
3145 * their disposal if they are still in use => post.c handles the counting for us */
3146 }
3147
_get_demux_strings(xine_t * self,int kind)3148 static char *_get_demux_strings (xine_t *self, int kind) {
3149 plugin_catalog_t *catalog = self->plugin_catalog;
3150 struct {
3151 const char *s;
3152 size_t len;
3153 } *slist = NULL, *slitem, *slend;
3154 char *res = NULL;
3155
3156 pthread_mutex_lock (&catalog->lock);
3157 do {
3158 {
3159 int num, list_id;
3160 size_t size;
3161
3162 num = xine_sarray_size (catalog->plugin_lists[PLUGIN_DEMUX - 1]);
3163 if (num <= 0)
3164 break;
3165 slist = malloc (num * sizeof (*slist));
3166 if (!slist)
3167 break;
3168
3169 slitem = slist;
3170 size = 0;
3171 for (list_id = 0; list_id < num; list_id++) {
3172 plugin_node_t *const node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
3173 if (!node->plugin_class)
3174 _load_plugin_class (self, node, NULL);
3175 if (node->plugin_class) {
3176 demux_class_t *const cls = (demux_class_t *)node->plugin_class;
3177 const char *s = kind ? cls->extensions : cls->mimetypes;
3178 if (s) {
3179 slitem->s = s;
3180 size += (slitem->len = strlen (s));
3181 slitem++;
3182 }
3183 }
3184 }
3185 slend = slitem;
3186 if (slend == slist)
3187 break;
3188 res = malloc (size + (slend - slist) * (kind ? 1 : 0) + 1);
3189 if (!res)
3190 break;
3191 }
3192
3193 {
3194 char *q = res;
3195 slitem = slist;
3196 if (kind) {
3197 do {
3198 xine_small_memcpy (q, slitem->s, slitem->len);
3199 q += slitem->len;
3200 *q++ = ' ';
3201 slitem++;
3202 } while (slitem < slend);
3203 q[-1] = 0;
3204 } else {
3205 do {
3206 xine_small_memcpy (q, slitem->s, slitem->len);
3207 q += slitem->len;
3208 slitem++;
3209 } while (slitem < slend);
3210 q[0] = 0;
3211 }
3212 }
3213 } while (0);
3214 pthread_mutex_unlock (&catalog->lock);
3215 free (slist);
3216 return res;
3217 }
3218
3219 /* get a list of file extensions for file types supported by xine
3220 * the list is separated by spaces
3221 *
3222 * the pointer returned can be free()ed when no longer used */
xine_get_file_extensions(xine_t * self)3223 char *xine_get_file_extensions (xine_t *self) {
3224 return _get_demux_strings (self, 1);
3225 }
3226
3227 /* get a list of mime types supported by xine
3228 *
3229 * the pointer returned can be free()ed when no longer used */
xine_get_mime_types(xine_t * self)3230 char *xine_get_mime_types (xine_t *self) {
3231 return _get_demux_strings (self, 0);
3232 }
3233
3234
3235 /* get the demuxer identifier that handles a given mime type
3236 *
3237 * the pointer returned can be free()ed when no longer used
3238 * returns NULL if no demuxer is available to handle this. */
xine_get_demux_for_mime_type(xine_t * self,const char * mime_type)3239 char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type) {
3240
3241 plugin_catalog_t *catalog = self->plugin_catalog;
3242 plugin_node_t *node;
3243 char *id = NULL;
3244 int list_id, list_size;
3245
3246 pthread_mutex_lock (&catalog->lock);
3247
3248 list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_DEMUX - 1]);
3249
3250 for (list_id = 0; (list_id < list_size) && !id; list_id++) {
3251
3252 node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
3253 if (probe_mime_type (self, node, mime_type))
3254 id = strdup(node->info->id);
3255 }
3256
3257 pthread_mutex_unlock (&catalog->lock);
3258
3259 return id;
3260 }
3261
dispose_plugin_list(xine_sarray_t * list,int is_cache)3262 static int dispose_plugin_list (xine_sarray_t *list, int is_cache) {
3263
3264 decoder_info_t *decoder_info;
3265 int list_id, list_size;
3266 int num = 0;
3267
3268 if (!list)
3269 return 0;
3270
3271 list_size = xine_sarray_size (list);
3272 for (list_id = 0; list_id < list_size; list_id++) {
3273
3274 fat_node_t *node, *nextnode;
3275 for (node = xine_sarray_get (list, list_id); node; node = nextnode) {
3276
3277 nextnode = is_cache && (node->node.file == &node->file) ? node->nextplugin : NULL;
3278
3279 if (node->node.ref == 0)
3280 _dispose_plugin_class (&node->node);
3281 else {
3282 lprintf ("node \"%s\" still referenced %d time(s)\n", node->node.info->id, node->node.ref);
3283 continue;
3284 }
3285
3286 /* free special info */
3287 switch (node->info->type & PLUGIN_TYPE_MASK) {
3288 case PLUGIN_SPU_DECODER:
3289 case PLUGIN_AUDIO_DECODER:
3290 case PLUGIN_VIDEO_DECODER:
3291 decoder_info = (decoder_info_t *)node->node.info->special_info;
3292 if (!(IS_FAT_NODE (node) && (decoder_info->supported_types == &node->supported_types[0])))
3293 _x_freep (&decoder_info->supported_types);
3294 /* fall thru */
3295 default:
3296 if (!(IS_FAT_NODE (node) && node->node.info->special_info == &node->ainfo))
3297 _x_freep (&node->node.info->special_info);
3298 break;
3299 }
3300
3301 /* free info structure and string copies */
3302 if (!IS_FAT_NODE (node)) {
3303 _x_freep (&node->node.info->id);
3304 _x_freep (&node->node.info);
3305 }
3306 #ifdef FAST_SCAN_PLUGINS
3307 if (node->node.config_entry_list) {
3308 xine_list_delete (node->node.config_entry_list);
3309 node->node.config_entry_list = NULL;
3310 }
3311 #else
3312 _free_string_list (&node->node.config_entry_list);
3313 #endif
3314 /* file entries in cache list are "dummies" (do not refer to opened files) */
3315 /* those are not in file list, so free here */
3316 if (is_cache && node->node.file) {
3317 _x_assert (node->node.file->lib_handle == NULL);
3318 _x_assert (node->node.file->ref == 0);
3319 if (node->node.file != &node->file) {
3320 _x_freep (&node->node.file->filename);
3321 _x_freep (&node->node.file);
3322 }
3323 }
3324 free (node);
3325 num++;
3326 }
3327 }
3328 xine_sarray_delete (list);
3329 return num;
3330 }
3331
3332
dispose_plugin_file_list(xine_list_t * list)3333 static void dispose_plugin_file_list (xine_list_t *list) {
3334 plugin_file_t *file;
3335 xine_list_iterator_t ite = NULL;
3336
3337 while ((file = xine_list_next_value (list, &ite))) {
3338 if ((char *)file + sizeof (*file) != file->filename) {
3339 _x_freep (&file->filename);
3340 }
3341 free (file);
3342 }
3343 xine_list_delete (list);
3344 }
3345
3346
3347 /*
3348 * dispose all currently loaded plugins (shutdown)
3349 */
3350
_x_dispose_plugins(xine_t * this)3351 void _x_dispose_plugins (xine_t *this) {
3352
3353 if(this->plugin_catalog) {
3354 int i;
3355
3356 if (this->config) {
3357 i = this->config->unregister_callbacks (this->config, NULL, _decoder_priority_cb, NULL, 0);
3358 if (i)
3359 xprintf (this, XINE_VERBOSITY_DEBUG,
3360 "load_plugins: unregistered %d decoder priority callbacks.\n", i);
3361 }
3362
3363 for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
3364 dispose_plugin_list (this->plugin_catalog->plugin_lists[i], 0);
3365 }
3366 dispose_plugin_list (this->plugin_catalog->modules_list, 0);
3367
3368 i = dispose_plugin_list (this->plugin_catalog->cache_list, 1);
3369 if (i)
3370 xprintf (this, XINE_VERBOSITY_DEBUG,
3371 "load_plugins: dropped %d outdated cache entries.\n", i);
3372 dispose_plugin_file_list (this->plugin_catalog->file_list);
3373
3374 for (i = 0; this->plugin_catalog->prio_desc[i]; i++)
3375 _x_freep(&this->plugin_catalog->prio_desc[i]);
3376
3377 pthread_mutex_destroy(&this->plugin_catalog->lock);
3378
3379 _x_freep (&this->plugin_catalog);
3380 }
3381 }
3382
3383