From 8ac776c58b69a94fce793d16e477a88207ce0d27 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 17 Jan 2010 16:47:04 +0100 Subject: [PATCH] decoder_thread: don't try a plugin twice (MIME type & suffix) Manage a linked list of plugins which were already tried. --- NEWS | 1 + src/decoder_thread.c | 66 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 0702c9436..7cc085e57 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,7 @@ ver 0.16 (20??/??/??) - added tags "ArtistSort", "AlbumArtistSort" - id3: revised "performer" tag support * decoders: + - don't try a plugin twice (MIME type & suffix) - ffmpeg: support multiple tags - ffmpeg: convert metadata to generic format - sndfile: new decoder plugin based on libsndfile diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 1539117f4..631a7a0e3 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -156,45 +156,86 @@ decoder_file_decode(const struct decoder_plugin *plugin, return decoder->dc->state != DECODE_STATE_START; } +/** + * Hack to allow tracking const decoder plugins in a GSList. + */ +static inline gpointer +deconst_plugin(const struct decoder_plugin *plugin) +{ + union { + const struct decoder_plugin *in; + gpointer out; + } u = { .in = plugin }; + + return u.out; +} + /** * Try decoding a stream, using plugins matching the stream's MIME type. + * + * @param tried_r a list of plugins which were tried */ static bool -decoder_run_stream_mime_type(struct decoder *decoder, struct input_stream *is) +decoder_run_stream_mime_type(struct decoder *decoder, struct input_stream *is, + GSList **tried_r) { + assert(tried_r != NULL); + const struct decoder_plugin *plugin; unsigned int next = 0; if (is->mime == NULL) return false; - while ((plugin = decoder_plugin_from_mime_type(is->mime, next++))) - if (plugin->stream_decode != NULL && - decoder_stream_decode(plugin, decoder, is)) + while ((plugin = decoder_plugin_from_mime_type(is->mime, next++))) { + if (plugin->stream_decode == NULL) + continue; + + if (g_slist_find(*tried_r, plugin) != NULL) + /* don't try a plugin twice */ + continue; + + if (decoder_stream_decode(plugin, decoder, is)) return true; + *tried_r = g_slist_prepend(*tried_r, deconst_plugin(plugin)); + } + return false; } /** * Try decoding a stream, using plugins matching the stream's URI * suffix. + * + * @param tried_r a list of plugins which were tried */ static bool decoder_run_stream_suffix(struct decoder *decoder, struct input_stream *is, - const char *uri) + const char *uri, GSList **tried_r) { + assert(tried_r != NULL); + const char *suffix = uri_get_suffix(uri); const struct decoder_plugin *plugin = NULL; if (suffix == NULL) return false; - while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) - if (plugin->stream_decode != NULL && - decoder_stream_decode(plugin, decoder, is)) + while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) { + if (plugin->stream_decode == NULL) + continue; + + if (g_slist_find(*tried_r, plugin) != NULL) + /* don't try a plugin twice */ + continue; + + if (decoder_stream_decode(plugin, decoder, is)) return true; + *tried_r = g_slist_prepend(*tried_r, deconst_plugin(plugin)); + } + return false; } @@ -231,15 +272,20 @@ decoder_run_stream(struct decoder *decoder, const char *uri) decoder_lock(dc); + GSList *tried = NULL; + success = dc->command == DECODE_COMMAND_STOP || /* first we try mime types: */ - decoder_run_stream_mime_type(decoder, input_stream) || + decoder_run_stream_mime_type(decoder, input_stream, &tried) || /* if that fails, try suffix matching the URL: */ - decoder_run_stream_suffix(decoder, input_stream, uri) || + decoder_run_stream_suffix(decoder, input_stream, uri, + &tried) || /* fallback to mp3: this is needed for bastard streams that don't have a suffix or set the mimeType */ decoder_run_stream_fallback(decoder, input_stream); + g_slist_free(tried); + decoder_unlock(dc); input_stream_close(input_stream); decoder_lock(dc);