From 65ad29846084755eef3f4bcec761bed921563a24 Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Sun, 30 May 2010 08:59:00 -0700 Subject: [PATCH 01/28] Modify version string to post-release version 0.15.11~git --- NEWS | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ca4e7ecc4..ef5cc0091 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +ver 0.15.11 (2010/??/??) + + ver 0.15.10 (2010/05/30) * input: - mms: fix memory leak in error handler diff --git a/configure.ac b/configure.ac index fbe1de92f..9249ada70 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.15.10, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.15.11~git, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2]) AM_CONFIG_HEADER(config.h) From c7e89ea3a38b8c022a754d779e6ae1100a2b19af Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 19 Jul 2009 17:59:35 +0200 Subject: [PATCH 02/28] tag_ape: converted apeItems and tagItems to global vars Don't initialize those arrays each time tag_ape_load() is called. --- src/tag_ape.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/tag_ape.c b/src/tag_ape.c index 7cbf32208..2ffc9b80b 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -25,6 +25,26 @@ #include #include +static const char *const apeItems[7] = { + "title", + "artist", + "album", + "comment", + "genre", + "track", + "year" +}; + +static const int tagItems[7] = { + TAG_ITEM_TITLE, + TAG_ITEM_ARTIST, + TAG_ITEM_ALBUM, + TAG_ITEM_COMMENT, + TAG_ITEM_GENRE, + TAG_ITEM_TRACK, + TAG_ITEM_DATE, +}; + struct tag * tag_ape_load(const char *file) { @@ -48,26 +68,6 @@ tag_ape_load(const char *file) unsigned char reserved[8]; } footer; - const char *apeItems[7] = { - "title", - "artist", - "album", - "comment", - "genre", - "track", - "year" - }; - - int tagItems[7] = { - TAG_ITEM_TITLE, - TAG_ITEM_ARTIST, - TAG_ITEM_ALBUM, - TAG_ITEM_COMMENT, - TAG_ITEM_GENRE, - TAG_ITEM_TRACK, - TAG_ITEM_DATE, - }; - fp = fopen(file, "r"); if (!fp) return NULL; From 7cca55549b247f14e40d4d5f21aceb88d0261b12 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 19 Jul 2009 17:59:36 +0200 Subject: [PATCH 03/28] tag_ape: moved code to tag_ape_import_item() Improve code readability. --- src/tag_ape.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/tag_ape.c b/src/tag_ape.c index 2ffc9b80b..5dc13d9c5 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -45,6 +45,26 @@ static const int tagItems[7] = { TAG_ITEM_DATE, }; +static struct tag * +tag_ape_import_item(struct tag *tag, unsigned long flags, + const char *key, const char *value, size_t value_length) +{ + /* we only care about utf-8 text tags */ + if ((flags & (0x3 << 1)) != 0) + return tag; + + for (unsigned i = 0; i < 7; i++) { + if (g_ascii_strcasecmp(key, apeItems[i]) == 0) { + if (tag == NULL) + tag = tag_new(); + tag_add_item_n(tag, tagItems[i], + value, value_length); + } + } + + return tag; +} + struct tag * tag_ape_load(const char *file) { @@ -56,7 +76,6 @@ tag_ape_load(const char *file) size_t tagLen; size_t size; unsigned long flags; - int i; char *key; struct { @@ -127,17 +146,8 @@ tag_ape_load(const char *file) if (tagLen < size) goto fail; - /* we only care about utf-8 text tags */ - if (!(flags & (0x3 << 1))) { - for (i = 0; i < 7; i++) { - if (g_ascii_strcasecmp(key, apeItems[i]) == 0) { - if (!ret) - ret = tag_new(); - tag_add_item_n(ret, tagItems[i], - p, size); - } - } - } + ret = tag_ape_import_item(ret, flags, key, p, size); + p += size; tagLen -= size; } From 026bd158724886026b16245093e749cbe47d24bd Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 19 Jul 2009 18:04:42 +0200 Subject: [PATCH 04/28] tag_ape: simplified the apeItems array Make "enum tag_type" the array index, and convert apeItems to a sparse array. --- src/tag_ape.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/tag_ape.c b/src/tag_ape.c index 5dc13d9c5..e3b848bfc 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -25,24 +25,14 @@ #include #include -static const char *const apeItems[7] = { - "title", - "artist", - "album", - "comment", - "genre", - "track", - "year" -}; - -static const int tagItems[7] = { - TAG_ITEM_TITLE, - TAG_ITEM_ARTIST, - TAG_ITEM_ALBUM, - TAG_ITEM_COMMENT, - TAG_ITEM_GENRE, - TAG_ITEM_TRACK, - TAG_ITEM_DATE, +static const char *const ape_tag_names[] = { + [TAG_ITEM_TITLE] = "title", + [TAG_ITEM_ARTIST] = "artist", + [TAG_ITEM_ALBUM] = "album", + [TAG_ITEM_COMMENT] = "comment", + [TAG_ITEM_GENRE] = "genre", + [TAG_ITEM_TRACK] = "track", + [TAG_ITEM_DATE] = "year" }; static struct tag * @@ -53,12 +43,12 @@ tag_ape_import_item(struct tag *tag, unsigned long flags, if ((flags & (0x3 << 1)) != 0) return tag; - for (unsigned i = 0; i < 7; i++) { - if (g_ascii_strcasecmp(key, apeItems[i]) == 0) { + for (unsigned i = 0; i < G_N_ELEMENTS(ape_tag_names); i++) { + if (ape_tag_names[i] != NULL && + g_ascii_strcasecmp(key, ape_tag_names[i]) == 0) { if (tag == NULL) tag = tag_new(); - tag_add_item_n(tag, tagItems[i], - value, value_length); + tag_add_item_n(tag, i, value, value_length); } } From 9328558fc7245613a620ea77e26d19861a23f1ce Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 30 May 2010 22:29:48 +0200 Subject: [PATCH 05/28] tag_ape: support album artist I took this tag name from a MusePack sample file I got from a user. It is not documented in the APE specification: http://wiki.hydrogenaudio.org/index.php?title=APE_key People seem to be using undocumented extensions to the specification anyway, and the best we can do is attempt to support them. --- NEWS | 2 ++ src/tag_ape.c | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index ef5cc0091..fe0ec6e6b 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.15.11 (2010/??/??) +* tags: + - ape: support album artist ver 0.15.10 (2010/05/30) diff --git a/src/tag_ape.c b/src/tag_ape.c index e3b848bfc..6d8e0c743 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -29,6 +29,7 @@ static const char *const ape_tag_names[] = { [TAG_ITEM_TITLE] = "title", [TAG_ITEM_ARTIST] = "artist", [TAG_ITEM_ALBUM] = "album", + [TAG_ITEM_ALBUM_ARTIST] = "album artist", [TAG_ITEM_COMMENT] = "comment", [TAG_ITEM_GENRE] = "genre", [TAG_ITEM_TRACK] = "track", From 5092eaf1ccf7785c70d21a814f44a4b9437f63c0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:18:27 +0200 Subject: [PATCH 06/28] tag_ape: move table lookup to tag_table.h Allow code sharing. --- Makefile.am | 1 + src/tag_ape.c | 18 +++++++++--------- src/tag_table.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 src/tag_table.h diff --git a/Makefile.am b/Makefile.am index 6e7827785..083c72a5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -142,6 +142,7 @@ mpd_headers = \ src/tag.h \ src/tag_internal.h \ src/tag_pool.h \ + src/tag_table.h \ src/tag_ape.h \ src/tag_id3.h \ src/tag_print.h \ diff --git a/src/tag_ape.c b/src/tag_ape.c index 6d8e0c743..0e8f67456 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -19,13 +19,14 @@ #include "tag_ape.h" #include "tag.h" +#include "tag_table.h" #include #include #include -static const char *const ape_tag_names[] = { +static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = { [TAG_ITEM_TITLE] = "title", [TAG_ITEM_ARTIST] = "artist", [TAG_ITEM_ALBUM] = "album", @@ -44,14 +45,13 @@ tag_ape_import_item(struct tag *tag, unsigned long flags, if ((flags & (0x3 << 1)) != 0) return tag; - for (unsigned i = 0; i < G_N_ELEMENTS(ape_tag_names); i++) { - if (ape_tag_names[i] != NULL && - g_ascii_strcasecmp(key, ape_tag_names[i]) == 0) { - if (tag == NULL) - tag = tag_new(); - tag_add_item_n(tag, i, value, value_length); - } - } + enum tag_type type = tag_table_lookup(ape_tag_names, key); + if (type == TAG_NUM_OF_ITEM_TYPES) + return tag; + + if (tag == NULL) + tag = tag_new(); + tag_add_item_n(tag, type, value, value_length); return tag; } diff --git a/src/tag_table.h b/src/tag_table.h new file mode 100644 index 000000000..ce47d69fc --- /dev/null +++ b/src/tag_table.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TAG_TABLE_H +#define MPD_TAG_TABLE_H + +#include "tag.h" + +#include + +/** + * Looks up a string in a tag translation table (case insensitive). + * Returns TAG_NUM_OF_ITEM_TYPES if the specified name was not found + * in the table. + */ +static inline enum tag_type +tag_table_lookup(const char *const* table, const char *name) +{ + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) + if (table[i] != NULL && + g_ascii_strcasecmp(name, table[i]) == 0) + return (enum tag_type)i; + + return TAG_NUM_OF_ITEM_TYPES; +} + +#endif From cfcd84655c5988716229d3f8e8e30949cb1708ac Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:19:30 +0200 Subject: [PATCH 07/28] decoder/mp4ff: use tag_table.h to parse tag names Convert if/else/else/... to a loop. --- src/decoder/mp4ff_plugin.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index cf9382904..a330763ca 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -19,6 +19,7 @@ #include "../decoder_api.h" #include "config.h" +#include "tag_table.h" #include @@ -339,6 +340,17 @@ mp4_decode(struct decoder *mpd_decoder, struct input_stream *input_stream) mp4ff_close(mp4fh); } +static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { + [TAG_ITEM_TITLE] = "title", + [TAG_ITEM_ARTIST] = "artist", + [TAG_ITEM_ALBUM] = "album", + [TAG_ITEM_TRACK] = "track", + [TAG_ITEM_DISC] = "disc", + [TAG_ITEM_GENRE] = "genre", + [TAG_ITEM_DATE] = "date", + [TAG_ITEM_COMPOSER] = "writer", +}; + static struct tag * mp4_tag_dup(const char *file) { @@ -394,24 +406,9 @@ mp4_tag_dup(const char *file) mp4ff_meta_get_by_index(mp4fh, i, &item, &value); - if (0 == g_ascii_strcasecmp("artist", item)) { - tag_add_item(ret, TAG_ITEM_ARTIST, value); - } else if (0 == g_ascii_strcasecmp("title", item)) { - tag_add_item(ret, TAG_ITEM_TITLE, value); - } else if (0 == g_ascii_strcasecmp("album", item)) { - tag_add_item(ret, TAG_ITEM_ALBUM, value); - } else if (0 == g_ascii_strcasecmp("track", item)) { - tag_add_item(ret, TAG_ITEM_TRACK, value); - } else if (0 == g_ascii_strcasecmp("disc", item)) { - /* Is that the correct id? */ - tag_add_item(ret, TAG_ITEM_DISC, value); - } else if (0 == g_ascii_strcasecmp("genre", item)) { - tag_add_item(ret, TAG_ITEM_GENRE, value); - } else if (0 == g_ascii_strcasecmp("date", item)) { - tag_add_item(ret, TAG_ITEM_DATE, value); - } else if (0 == g_ascii_strcasecmp("writer", item)) { - tag_add_item(ret, TAG_ITEM_COMPOSER, value); - } + enum tag_type type = tag_table_lookup(mp4ff_tag_names, item); + if (type != TAG_NUM_OF_ITEM_TYPES) + tag_add_item(ret, type, value); free(item); free(value); From 0aeec9059053bf724942831a45e07d43b99b5955 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:22:13 +0200 Subject: [PATCH 08/28] decoder/mp4ff: support tags "albumartist", "band" I'm not sure if mapping "band" to TAG_PERFORMER is correct, but it might be better than nothing. --- NEWS | 2 ++ src/decoder/mp4ff_plugin.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index fe0ec6e6b..6f499856d 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ ver 0.15.11 (2010/??/??) * tags: - ape: support album artist +* decoders: + - mp4ff: support tags "albumartist", "band" ver 0.15.10 (2010/05/30) diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index a330763ca..5e1251d82 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -344,11 +344,13 @@ static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { [TAG_ITEM_TITLE] = "title", [TAG_ITEM_ARTIST] = "artist", [TAG_ITEM_ALBUM] = "album", + [TAG_ITEM_ALBUM_ARTIST] = "albumartist", [TAG_ITEM_TRACK] = "track", [TAG_ITEM_DISC] = "disc", [TAG_ITEM_GENRE] = "genre", [TAG_ITEM_DATE] = "date", [TAG_ITEM_COMPOSER] = "writer", + [TAG_ITEM_PERFORMER] = "band", }; static struct tag * From 4d6d372a5b8f7903bbcbec943587c593ac08df3c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 19:24:41 +0000 Subject: [PATCH 09/28] decoder/vorbis: use single global ov_callbacks constant Initialize the ov_callbacks struct at compile time. --- src/decoder/vorbis_plugin.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/decoder/vorbis_plugin.c b/src/decoder/vorbis_plugin.c index 0ff898647..3da56bd5c 100644 --- a/src/decoder/vorbis_plugin.c +++ b/src/decoder/vorbis_plugin.c @@ -97,6 +97,13 @@ static long ogg_tell_cb(void *vdata) return (long)data->input_stream->offset; } +static const ov_callbacks vorbis_is_callbacks = { + .read_func = ogg_read_cb, + .seek_func = ogg_seek_cb, + .close_func = ogg_close_cb, + .tell_func = ogg_tell_cb, +}; + static const char * vorbis_comment_value(const char *comment, const char *needle) { @@ -241,7 +248,6 @@ vorbis_stream_decode(struct decoder *decoder, struct input_stream *input_stream) { OggVorbis_File vf; - ov_callbacks callbacks; OggCallbackData data; struct audio_format audio_format; int current_section; @@ -266,13 +272,9 @@ vorbis_stream_decode(struct decoder *decoder, data.input_stream = input_stream; data.seekable = input_stream->seekable && oggvorbis_seekable(decoder); - callbacks.read_func = ogg_read_cb; - callbacks.seek_func = ogg_seek_cb; - callbacks.close_func = ogg_close_cb; - callbacks.tell_func = ogg_tell_cb; - if ((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) { + if ((ret = ov_open_callbacks(&data, &vf, NULL, 0, + vorbis_is_callbacks)) < 0) { const char *error; - if (decoder_get_command(decoder) != DECODE_COMMAND_NONE) return; From e223e8a5b58509287098cb1deffb9655c7249a0c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:30:21 +0200 Subject: [PATCH 10/28] tag_ape: move code to tag_ape_name_parse() --- src/tag_ape.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tag_ape.c b/src/tag_ape.c index 0e8f67456..733dab35a 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -37,6 +37,12 @@ static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = { [TAG_ITEM_DATE] = "year" }; +static enum tag_type +tag_ape_name_parse(const char *name) +{ + return tag_table_lookup(ape_tag_names, name); +} + static struct tag * tag_ape_import_item(struct tag *tag, unsigned long flags, const char *key, const char *value, size_t value_length) @@ -45,7 +51,7 @@ tag_ape_import_item(struct tag *tag, unsigned long flags, if ((flags & (0x3 << 1)) != 0) return tag; - enum tag_type type = tag_table_lookup(ape_tag_names, key); + enum tag_type type = tag_ape_name_parse(key); if (type == TAG_NUM_OF_ITEM_TYPES) return tag; From 9550c87327cdb0c97ca855bc5d77d28cbbb723d5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:31:45 +0200 Subject: [PATCH 11/28] tag: added function tag_name_parse() Convert a string into a tag_type enum. --- src/locate.c | 6 +++--- src/tag.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- src/tag.h | 16 ++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/locate.c b/src/locate.c index 175bca35a..7b4721fa9 100644 --- a/src/locate.c +++ b/src/locate.c @@ -42,9 +42,9 @@ locate_parse_type(const char *str) if (0 == g_ascii_strcasecmp(str, LOCATE_TAG_ANY_KEY)) return LOCATE_TAG_ANY_TYPE; - for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) - if (0 == g_ascii_strcasecmp(str, tag_item_names[i])) - return i; + i = tag_name_parse_i(str); + if (i != TAG_NUM_OF_ITEM_TYPES) + return i; return -1; } diff --git a/src/tag.c b/src/tag.c index c34256b78..b228480c8 100644 --- a/src/tag.c +++ b/src/tag.c @@ -64,6 +64,36 @@ const char *tag_item_names[TAG_NUM_OF_ITEM_TYPES] = { bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES]; +enum tag_type +tag_name_parse(const char *name) +{ + assert(name != NULL); + + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { + assert(tag_item_names[i] != NULL); + + if (strcmp(name, tag_item_names[i]) == 0) + return (enum tag_type)i; + } + + return TAG_NUM_OF_ITEM_TYPES; +} + +enum tag_type +tag_name_parse_i(const char *name) +{ + assert(name != NULL); + + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { + assert(tag_item_names[i] != NULL); + + if (g_ascii_strcasecmp(name, tag_item_names[i]) == 0) + return (enum tag_type)i; + } + + return TAG_NUM_OF_ITEM_TYPES; +} + static size_t items_size(const struct tag *tag) { return tag->num_items * sizeof(struct tag_item *); @@ -76,7 +106,7 @@ void tag_lib_init(void) char *temp; char *s; char *c; - int i; + enum tag_type type; /* parse the "metadata_to_use" config parameter below */ @@ -98,16 +128,18 @@ void tag_lib_init(void) if (*s == '\0') quit = 1; *s = '\0'; - for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) { - if (g_ascii_strcasecmp(c, tag_item_names[i]) == 0) { - ignore_tag_items[i] = false; - break; - } - } - if (strlen(c) && i == TAG_NUM_OF_ITEM_TYPES) { + + c = g_strstrip(c); + if (*c == 0) + continue; + + type = tag_name_parse_i(c); + if (type == TAG_NUM_OF_ITEM_TYPES) g_error("error parsing metadata item \"%s\"", c); - } + + ignore_tag_items[type] = false; + s++; c = s; } diff --git a/src/tag.h b/src/tag.h index 75a86b387..8d968c254 100644 --- a/src/tag.h +++ b/src/tag.h @@ -93,6 +93,22 @@ struct tag { unsigned num_items; }; +/** + * Parse the string, and convert it into a #tag_type. Returns + * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized. + */ +enum tag_type +tag_name_parse(const char *name); + +/** + * Parse the string, and convert it into a #tag_type. Returns + * #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized. + * + * Case does not matter. + */ +enum tag_type +tag_name_parse_i(const char *name); + /** * Creates an empty #tag. */ From 284659034d7ec0add185e03a27434b2bd7d88216 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:30:31 +0200 Subject: [PATCH 12/28] tag_ape: remove duplicate entries in the tag name table Reuse the function tag_name_parse_i(). --- src/tag_ape.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tag_ape.c b/src/tag_ape.c index 733dab35a..babefcda3 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -27,20 +27,18 @@ #include static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = { - [TAG_ITEM_TITLE] = "title", - [TAG_ITEM_ARTIST] = "artist", - [TAG_ITEM_ALBUM] = "album", [TAG_ITEM_ALBUM_ARTIST] = "album artist", - [TAG_ITEM_COMMENT] = "comment", - [TAG_ITEM_GENRE] = "genre", - [TAG_ITEM_TRACK] = "track", [TAG_ITEM_DATE] = "year" }; static enum tag_type tag_ape_name_parse(const char *name) { - return tag_table_lookup(ape_tag_names, name); + enum tag_type type = tag_table_lookup(ape_tag_names, name); + if (type == TAG_NUM_OF_ITEM_TYPES) + type = tag_name_parse_i(name); + + return type; } static struct tag * From 8e3eace289e2e2481221426ea9e6ab38d80be5fe Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:36:00 +0200 Subject: [PATCH 13/28] decoder/mp4ff: moved code to mp4ff_tag_name_parse() --- src/decoder/mp4ff_plugin.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index 5e1251d82..d94084e90 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -353,6 +353,12 @@ static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { [TAG_ITEM_PERFORMER] = "band", }; +static enum tag_type +mp4ff_tag_name_parse(const char *name) +{ + return tag_table_lookup(mp4ff_tag_names, name); +} + static struct tag * mp4_tag_dup(const char *file) { @@ -408,7 +414,7 @@ mp4_tag_dup(const char *file) mp4ff_meta_get_by_index(mp4fh, i, &item, &value); - enum tag_type type = tag_table_lookup(mp4ff_tag_names, item); + enum tag_type type = mp4ff_tag_name_parse(item); if (type != TAG_NUM_OF_ITEM_TYPES) tag_add_item(ret, type, value); From 5ebe33653c162a3a07a9a1fd71201e22fa152c6c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:36:15 +0200 Subject: [PATCH 14/28] decoder/mp4ff: remove duplicate entries in the tag name table Reuse the function tag_name_parse_i(). --- src/decoder/mp4ff_plugin.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index d94084e90..d34080493 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -341,14 +341,6 @@ mp4_decode(struct decoder *mpd_decoder, struct input_stream *input_stream) } static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { - [TAG_ITEM_TITLE] = "title", - [TAG_ITEM_ARTIST] = "artist", - [TAG_ITEM_ALBUM] = "album", - [TAG_ITEM_ALBUM_ARTIST] = "albumartist", - [TAG_ITEM_TRACK] = "track", - [TAG_ITEM_DISC] = "disc", - [TAG_ITEM_GENRE] = "genre", - [TAG_ITEM_DATE] = "date", [TAG_ITEM_COMPOSER] = "writer", [TAG_ITEM_PERFORMER] = "band", }; @@ -356,7 +348,11 @@ static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { static enum tag_type mp4ff_tag_name_parse(const char *name) { - return tag_table_lookup(mp4ff_tag_names, name); + enum tag_type type = tag_table_lookup(mp4ff_tag_names, name); + if (type == TAG_NUM_OF_ITEM_TYPES) + type = tag_name_parse_i(name); + + return type; } static struct tag * From 77e6810c14e3b47f27a385e2fd9e8760710d0a99 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 19:37:36 +0000 Subject: [PATCH 15/28] decoder/mikmod: fix memory leak The return value of Player_LoadTitle() is allocated with malloc(), and must be freed by the caller. --- NEWS | 1 + src/decoder/mikmod_plugin.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 6f499856d..eaaa24b9f 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.15.11 (2010/??/??) - ape: support album artist * decoders: - mp4ff: support tags "albumartist", "band" + - mikmod: fix memory leak ver 0.15.10 (2010/05/30) diff --git a/src/decoder/mikmod_plugin.c b/src/decoder/mikmod_plugin.c index 065c34319..f60dcbc61 100644 --- a/src/decoder/mikmod_plugin.c +++ b/src/decoder/mikmod_plugin.c @@ -219,10 +219,12 @@ static struct tag *modTagDup(const char *file) ret->time = 0; path2 = g_strdup(file); - title = g_strdup(Player_LoadTitle(path2)); + title = Player_LoadTitle(path2); g_free(path2); - if (title) + if (title) { tag_add_item(ret, TAG_ITEM_TITLE, title); + free(title); + } return ret; } From 1bffdabe41471b994f43809d3ca18fd54ac8bf66 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:39:34 +0200 Subject: [PATCH 16/28] directory_print: return void There is no useful return value here. --- src/directory_print.c | 8 ++------ src/directory_print.h | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/directory_print.c b/src/directory_print.c index e0575e80f..1c9f23d69 100644 --- a/src/directory_print.c +++ b/src/directory_print.c @@ -22,7 +22,7 @@ #include "client.h" #include "song_print.h" -static int +static void dirvec_print(struct client *client, const struct dirvec *dv) { size_t i; @@ -30,15 +30,11 @@ dirvec_print(struct client *client, const struct dirvec *dv) for (i = 0; i < dv->nr; ++i) client_printf(client, DIRECTORY_DIR "%s\n", directory_get_path(dv->base[i])); - - return 0; } -int +void directory_print(struct client *client, const struct directory *directory) { dirvec_print(client, &directory->children); songvec_print(client, &directory->songs); - - return 0; } diff --git a/src/directory_print.h b/src/directory_print.h index 6dd099241..7c0110502 100644 --- a/src/directory_print.h +++ b/src/directory_print.h @@ -23,7 +23,7 @@ struct client; struct directory; -int +void directory_print(struct client *client, const struct directory *directory); #endif From 0a0c78674f8ca6ffce08feabd7c292133fd2d86e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:40:33 +0200 Subject: [PATCH 17/28] playlist: emit IDLE_OPTIONS when resetting single mode --- NEWS | 1 + src/playlist_control.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index eaaa24b9f..4a4c4405f 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.15.11 (2010/??/??) * decoders: - mp4ff: support tags "albumartist", "band" - mikmod: fix memory leak +* playlist: emit IDLE_OPTIONS when resetting single mode ver 0.15.10 (2010/05/30) diff --git a/src/playlist_control.c b/src/playlist_control.c index 4359611fd..4c156f0f5 100644 --- a/src/playlist_control.c +++ b/src/playlist_control.c @@ -24,6 +24,7 @@ #include "playlist_internal.h" #include "player_control.h" +#include "idle.h" #include @@ -156,6 +157,8 @@ nextSongInPlaylist(struct playlist *playlist) if (next_order < 0) { /* cancel single */ playlist->queue.single = false; + idle_add(IDLE_OPTIONS); + /* no song after this one: stop playback */ stopPlaylist(playlist); From 34415bf0b60738b22099023af5cd2cd1d202bf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20V=C3=B6gele?= Date: Wed, 30 Jun 2010 21:42:01 +0200 Subject: [PATCH 18/28] Make get_remote_uid() work on BSD I've attached a patch that will make file URIs work on operating systems that provide the getpeereid() function call to check the user ID of the peer connected to a UNIX domain socket. --- NEWS | 1 + configure.ac | 1 + src/listen.c | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 4a4c4405f..6e1c41076 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.15.11 (2010/??/??) - mp4ff: support tags "albumartist", "band" - mikmod: fix memory leak * playlist: emit IDLE_OPTIONS when resetting single mode +* listen: make get_remote_uid() work on BSD ver 0.15.10 (2010/05/30) diff --git a/configure.ac b/configure.ac index 9249ada70..1043b2f65 100644 --- a/configure.ac +++ b/configure.ac @@ -177,6 +177,7 @@ AC_ARG_ENABLE(un, if test x$enable_un = xyes; then AC_DEFINE(HAVE_UN, 1, [Define if unix domain socket support is enabled]) STRUCT_UCRED + AC_CHECK_FUNCS(getpeereid) fi diff --git a/src/listen.c b/src/listen.c index 98108d9da..d6cade855 100644 --- a/src/listen.c +++ b/src/listen.c @@ -407,7 +407,13 @@ static int get_remote_uid(int fd) return cred.uid; #else - (void)fd; +#ifdef HAVE_GETPEEREID + uid_t euid; + gid_t egid; + + if (getpeereid(fd, &euid, &egid) == 0) + return euid; +#endif return -1; #endif } From ec89ce5a8a3a609c5ecd725560304c9686726fa7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:55:03 +0200 Subject: [PATCH 19/28] decoder/mp4ff: support tag "album artist" We already supported "albumartist", but it seems some folks also use "album artist" (with a space). --- NEWS | 2 +- src/decoder/mp4ff_plugin.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 6e1c41076..1a8cf2364 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,7 @@ ver 0.15.11 (2010/??/??) * tags: - ape: support album artist * decoders: - - mp4ff: support tags "albumartist", "band" + - mp4ff: support tags "album artist", "albumartist", "band" - mikmod: fix memory leak * playlist: emit IDLE_OPTIONS when resetting single mode * listen: make get_remote_uid() work on BSD diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index d34080493..d5afe084b 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -341,6 +341,7 @@ mp4_decode(struct decoder *mpd_decoder, struct input_stream *input_stream) } static const char *const mp4ff_tag_names[TAG_NUM_OF_ITEM_TYPES] = { + [TAG_ITEM_ALBUM_ARTIST] = "album artist", [TAG_ITEM_COMPOSER] = "writer", [TAG_ITEM_PERFORMER] = "band", }; From 768be22f7ca3ef129a86dae23d51e2b34f5b4bc1 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:55:46 +0200 Subject: [PATCH 20/28] pcm_buffer: make the buffer pointer "void" --- src/pcm_buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcm_buffer.h b/src/pcm_buffer.h index 1d2a57310..b143bd98f 100644 --- a/src/pcm_buffer.h +++ b/src/pcm_buffer.h @@ -28,7 +28,7 @@ * would put too much stress on the allocator. */ struct pcm_buffer { - char *buffer; + void *buffer; size_t size; }; From 0d03bdce6d590429143e821e2bcf34142b57b8fa Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 21:56:04 +0200 Subject: [PATCH 21/28] configure.ac: check ffmpeg version number with pkg-config Replace the check for avcodec_decode_audio2(), assume it's present in libavcodec version 51. --- configure.ac | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 1043b2f65..f2a013720 100644 --- a/configure.ac +++ b/configure.ac @@ -914,17 +914,9 @@ fi AM_CONDITIONAL(HAVE_AUDIOFILE, test x$enable_audiofile = xyes) -MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat libavcodec libavutil], +MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat >= 52 libavcodec >= 51 libavutil >= 49], [ffmpeg decoder library], [libavformat+libavcodec+libavutil not found]) -if test x$enable_ffmpeg = xyes; then - old_LIBS=$LIBS - LIBS="$LIBS $FFMPEG_LIBS" - AC_CHECK_LIB(avcodec, avcodec_decode_audio2,, - enable_ffmpeg=no) - LIBS=$old_LIBS -fi - if test x$enable_ffmpeg = xyes; then # prior to ffmpeg svn12865, you had to specify include files # without path prefix From 814daac5bae1e7e3a67cd7ed727bd1fe6b9a3889 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 18 Jan 2010 11:05:15 +0100 Subject: [PATCH 22/28] decoder/ffmpeg: free AVFormatContext on error Fix a memory leak in some code paths. --- NEWS | 1 + src/decoder/ffmpeg_plugin.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 1a8cf2364..d0b8788a7 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.15.11 (2010/??/??) * decoders: - mp4ff: support tags "album artist", "albumartist", "band" - mikmod: fix memory leak + - ffmpeg: free AVFormatContext on error * playlist: emit IDLE_OPTIONS when resetting single mode * listen: make get_remote_uid() work on BSD diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index 2a46601f4..2e06c13f8 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -192,12 +192,14 @@ ffmpeg_helper(const char *uri, struct input_stream *input, if (av_find_stream_info(format_context)<0) { g_warning("Couldn't find stream info\n"); + av_close_input_file(format_context); return false; } audio_stream = ffmpeg_find_audio_stream(format_context); if (audio_stream == -1) { g_warning("No audio stream inside\n"); + av_close_input_file(format_context); return false; } @@ -209,11 +211,13 @@ ffmpeg_helper(const char *uri, struct input_stream *input, if (!codec) { g_warning("Unsupported audio codec\n"); + av_close_input_file(format_context); return false; } if (avcodec_open(codec_context, codec)<0) { g_warning("Could not open codec\n"); + av_close_input_file(format_context); return false; } From c3569814bda057142da3f02a8d0cccb35184e396 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 2 Feb 2010 12:35:08 +0100 Subject: [PATCH 23/28] ffmpeg: read more metadata. --- NEWS | 1 + src/decoder/ffmpeg_plugin.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d0b8788a7..14465cad5 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.15.11 (2010/??/??) - mp4ff: support tags "album artist", "albumartist", "band" - mikmod: fix memory leak - ffmpeg: free AVFormatContext on error + - ffmpeg: read more metadata * playlist: emit IDLE_OPTIONS when resetting single mode * listen: make get_remote_uid() work on BSD diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index 2e06c13f8..7f2207669 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -405,12 +405,21 @@ static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx) av_metadata_conv(f, NULL, f->iformat->metadata_conv); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_TITLE, "title"); +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(50<<8)) + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ARTIST, "artist"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_DATE, "date"); +#else ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ARTIST, "author"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_DATE, "year"); +#endif ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ALBUM, "album"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_COMMENT, "comment"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_GENRE, "genre"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_TRACK, "track"); - ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_DATE, "year"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ALBUM_ARTIST, "album_artist"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_COMPOSER, "composer"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_PERFORMER, "performer"); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_DISC, "disc"); #else if (f->author[0]) tag_add_item(tag, TAG_ITEM_ARTIST, f->author); From a1882f48beee0c1b6750ec03f8b133e7325057a9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 23:38:49 +0200 Subject: [PATCH 24/28] decoder/vorbis: handle uri==NULL This fixes a theoretical crash, which has never occurred in practice. --- NEWS | 1 + src/decoder/vorbis_plugin.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 14465cad5..fac8ec6fd 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.15.11 (2010/??/??) * decoders: - mp4ff: support tags "album artist", "albumartist", "band" - mikmod: fix memory leak + - vorbis: handle uri==NULL - ffmpeg: free AVFormatContext on error - ffmpeg: read more metadata * playlist: emit IDLE_OPTIONS when resetting single mode diff --git a/src/decoder/vorbis_plugin.c b/src/decoder/vorbis_plugin.c index 3da56bd5c..7c782a779 100644 --- a/src/decoder/vorbis_plugin.c +++ b/src/decoder/vorbis_plugin.c @@ -233,6 +233,9 @@ oggvorbis_seekable(struct decoder *decoder) bool seekable; uri = decoder_get_uri(decoder); + if (uri == NULL) + return false; + /* disable seeking on remote streams, because libvorbis seeks around like crazy, and due to being very expensive, this delays song playback my 10 or 20 seconds */ From 0265c34bed4bdfd45a4ef1b5ff73071c5d5a5e10 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 23:40:04 +0200 Subject: [PATCH 25/28] decoder/ffmpeg: free URI, fix memory leak Free the string allocated by decoder_get_uri(). --- NEWS | 1 + src/decoder/ffmpeg_plugin.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index fac8ec6fd..3ae9fc7f3 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.15.11 (2010/??/??) - mp4ff: support tags "album artist", "albumartist", "band" - mikmod: fix memory leak - vorbis: handle uri==NULL + - ffmpeg: fix memory leak - ffmpeg: free AVFormatContext on error - ffmpeg: read more metadata * playlist: emit IDLE_OPTIONS when resetting single mode diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index 7f2207669..fc402ca04 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -376,8 +376,10 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) ctx.input = input; ctx.decoder = decoder; - ffmpeg_helper(decoder_get_uri(decoder), input, + char *uri = decoder_get_uri(decoder); + ffmpeg_helper(uri, input, ffmpeg_decode_internal, &ctx); + g_free(uri); } #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) From 375a09d6f6d09fc132976e1f82647cc56fb33640 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 20:32:29 +0200 Subject: [PATCH 26/28] decoder/ffmpeg: manual format probing Use the libavformat function av_probe_input_format() to probe the AVInputFormat, instead of letting av_open_input_file() do it implicitly. We will switch to av_open_input_stream() very soon, which does not have the probing code. Loosely based on a patch from Jasper St. Pierre. --- src/decoder/ffmpeg_plugin.c | 51 ++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index fc402ca04..f7218e238 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -160,11 +160,53 @@ append_uri_suffix(struct ffmpeg_stream *stream, const char *uri) g_free(base); } +static AVInputFormat * +ffmpeg_probe(struct decoder *decoder, struct input_stream *is, + const char *uri) +{ + enum { + BUFFER_SIZE = 16384, + PADDING = 16, + }; + + unsigned char *buffer = g_malloc(BUFFER_SIZE); + size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE); + if (nbytes <= PADDING || !input_stream_seek(is, 0, SEEK_SET)) { + g_free(buffer); + return NULL; + } + + /* some ffmpeg parsers (e.g. ac3_parser.c) read a few bytes + beyond the declared buffer limit, which makes valgrind + angry; this workaround removes some padding from the buffer + size */ + nbytes -= PADDING; + + AVProbeData avpd = { + .buf = buffer, + .buf_size = nbytes, + .filename = uri, + }; + + AVInputFormat *format = av_probe_input_format(&avpd, true); + g_free(buffer); + + return format; +} + static bool -ffmpeg_helper(const char *uri, struct input_stream *input, +ffmpeg_helper(const char *uri, + struct decoder *decoder, struct input_stream *input, bool (*callback)(struct ffmpeg_context *ctx), struct ffmpeg_context *ctx) { + AVInputFormat *input_format = ffmpeg_probe(decoder, input, uri); + if (input_format == NULL) + return false; + + g_debug("detected input format '%s' (%s)", + input_format->name, input_format->long_name); + AVFormatContext *format_context; AVCodecContext *codec_context; AVCodec *codec; @@ -185,7 +227,8 @@ ffmpeg_helper(const char *uri, struct input_stream *input, } //ffmpeg works with ours "fileops" helper - if (av_open_input_file(&format_context, stream.url, NULL, 0, NULL) != 0) { + if (av_open_input_file(&format_context, stream.url, input_format, + 0, NULL) != 0) { g_warning("Open failed\n"); return false; } @@ -377,7 +420,7 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) ctx.decoder = decoder; char *uri = decoder_get_uri(decoder); - ffmpeg_helper(uri, input, + ffmpeg_helper(uri, decoder, input, ffmpeg_decode_internal, &ctx); g_free(uri); } @@ -465,7 +508,7 @@ static struct tag *ffmpeg_tag(const char *file) ctx.decoder = NULL; ctx.tag = tag_new(); - ret = ffmpeg_helper(file, &input, ffmpeg_tag_internal, &ctx); + ret = ffmpeg_helper(file, NULL, &input, ffmpeg_tag_internal, &ctx); if (!ret) { tag_free(ctx.tag); ctx.tag = NULL; From 49bc317fb8b5dad101eb0d995167ce0ccaf9f7fc Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 30 Jun 2010 23:27:45 +0200 Subject: [PATCH 27/28] decoder/ffmpeg: fix libavformat 0.6 by using av_open_input_stream() libavformat 0.6 does not pass the original URI pointer to the "open" method, which leads to a crash because MPD was using a dirty hack to pass a pointer to that method. This patch switches to av_open_input_stream() with a custom ByteIOContext class, instead of doing the URI string hack with av_open_input_file(). Loosely based on a patch from Jasper St. Pierre. --- NEWS | 1 + src/decoder/ffmpeg_plugin.c | 134 ++++++++++++++---------------------- 2 files changed, 53 insertions(+), 82 deletions(-) diff --git a/NEWS b/NEWS index 3ae9fc7f3..a68abb0ed 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ ver 0.15.11 (2010/??/??) - ffmpeg: fix memory leak - ffmpeg: free AVFormatContext on error - ffmpeg: read more metadata + - ffmpeg: fix libavformat 0.6 by using av_open_input_stream() * playlist: emit IDLE_OPTIONS when resetting single mode * listen: make get_remote_uid() work on BSD diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index f7218e238..9bae39793 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -53,48 +53,27 @@ struct ffmpeg_context { struct tag *tag; }; -struct ffmpeg_stream { - /** hack - see url_to_struct() */ - char url[64]; - +struct mpd_ffmpeg_stream { struct decoder *decoder; struct input_stream *input; + + ByteIOContext *io; + unsigned char buffer[8192]; }; -/** - * Convert a faked mpd:// URL to a ffmpeg_stream structure. This is a - * hack because ffmpeg does not provide a nice API for passing a - * user-defined pointer to mpdurl_open(). - */ -static struct ffmpeg_stream *url_to_struct(const char *url) +static int +mpd_ffmpeg_stream_read(void *opaque, uint8_t *buf, int size) { - union { - const char *in; - struct ffmpeg_stream *out; - } u = { .in = url }; - return u.out; -} - -static int mpd_ffmpeg_open(URLContext *h, const char *filename, - G_GNUC_UNUSED int flags) -{ - struct ffmpeg_stream *stream = url_to_struct(filename); - h->priv_data = stream; - h->is_streamed = stream->input->seekable ? 0 : 1; - return 0; -} - -static int mpd_ffmpeg_read(URLContext *h, unsigned char *buf, int size) -{ - struct ffmpeg_stream *stream = (struct ffmpeg_stream *) h->priv_data; + struct mpd_ffmpeg_stream *stream = opaque; return decoder_read(stream->decoder, stream->input, (void *)buf, size); } -static int64_t mpd_ffmpeg_seek(URLContext *h, int64_t pos, int whence) +static int64_t +mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence) { - struct ffmpeg_stream *stream = (struct ffmpeg_stream *) h->priv_data; + struct mpd_ffmpeg_stream *stream = opaque; bool ret; if (whence == AVSEEK_SIZE) @@ -107,25 +86,36 @@ static int64_t mpd_ffmpeg_seek(URLContext *h, int64_t pos, int whence) return stream->input->offset; } -static int mpd_ffmpeg_close(URLContext *h) +static struct mpd_ffmpeg_stream * +mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input) { - h->priv_data = NULL; - return 0; + struct mpd_ffmpeg_stream *stream = g_new(struct mpd_ffmpeg_stream, 1); + stream->decoder = decoder; + stream->input = input; + stream->io = av_alloc_put_byte(stream->buffer, sizeof(stream->buffer), + false, stream, + mpd_ffmpeg_stream_read, NULL, + input->seekable + ? mpd_ffmpeg_stream_seek : NULL); + if (stream->io == NULL) { + g_free(stream); + return NULL; + } + + return stream; } -static URLProtocol mpd_ffmpeg_fileops = { - .name = "mpd", - .url_open = mpd_ffmpeg_open, - .url_read = mpd_ffmpeg_read, - .url_seek = mpd_ffmpeg_seek, - .url_close = mpd_ffmpeg_close, -}; +static void +mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream) +{ + av_free(stream->io); + g_free(stream); +} static bool ffmpeg_init(G_GNUC_UNUSED const struct config_param *param) { av_register_all(); - register_protocol(&mpd_ffmpeg_fileops); return true; } @@ -140,26 +130,6 @@ ffmpeg_find_audio_stream(const AVFormatContext *format_context) return -1; } -/** - * Append the suffix of the original URI to the virtual stream URI. - * Without this, libavformat cannot detect some of the codecs - * (e.g. "shorten"). - */ -static void -append_uri_suffix(struct ffmpeg_stream *stream, const char *uri) -{ - assert(stream != NULL); - assert(uri != NULL); - - char *base = g_path_get_basename(uri); - - const char *suffix = strrchr(base, '.'); - if (suffix != NULL && suffix[1] != 0) - g_strlcat(stream->url, suffix, sizeof(stream->url)); - - g_free(base); -} - static AVInputFormat * ffmpeg_probe(struct decoder *decoder, struct input_stream *is, const char *uri) @@ -207,42 +177,39 @@ ffmpeg_helper(const char *uri, g_debug("detected input format '%s' (%s)", input_format->name, input_format->long_name); + struct mpd_ffmpeg_stream *stream = + mpd_ffmpeg_stream_open(decoder, input); + if (stream == NULL) { + g_warning("Failed to open stream"); + return false; + } + AVFormatContext *format_context; AVCodecContext *codec_context; AVCodec *codec; int audio_stream; - struct ffmpeg_stream stream = { - .url = "mpd://X", /* only the mpd:// prefix matters */ - }; bool ret; - if (uri != NULL) - append_uri_suffix(&stream, uri); - - stream.input = input; - if (ctx && ctx->decoder) { - stream.decoder = ctx->decoder; //are we in decoding loop ? - } else { - stream.decoder = NULL; - } - //ffmpeg works with ours "fileops" helper - if (av_open_input_file(&format_context, stream.url, input_format, - 0, NULL) != 0) { + if (av_open_input_stream(&format_context, stream->io, uri, + input_format, NULL) != 0) { g_warning("Open failed\n"); + mpd_ffmpeg_stream_close(stream); return false; } if (av_find_stream_info(format_context)<0) { g_warning("Couldn't find stream info\n"); - av_close_input_file(format_context); + av_close_input_stream(format_context); + mpd_ffmpeg_stream_close(stream); return false; } audio_stream = ffmpeg_find_audio_stream(format_context); if (audio_stream == -1) { g_warning("No audio stream inside\n"); - av_close_input_file(format_context); + av_close_input_stream(format_context); + mpd_ffmpeg_stream_close(stream); return false; } @@ -254,13 +221,15 @@ ffmpeg_helper(const char *uri, if (!codec) { g_warning("Unsupported audio codec\n"); - av_close_input_file(format_context); + av_close_input_stream(format_context); + mpd_ffmpeg_stream_close(stream); return false; } if (avcodec_open(codec_context, codec)<0) { g_warning("Could not open codec\n"); - av_close_input_file(format_context); + av_close_input_stream(format_context); + mpd_ffmpeg_stream_close(stream); return false; } @@ -274,7 +243,8 @@ ffmpeg_helper(const char *uri, ret = true; avcodec_close(codec_context); - av_close_input_file(format_context); + av_close_input_stream(format_context); + mpd_ffmpeg_stream_close(stream); return ret; } From 56bf4ede1896708c50df864521bd71aebf25aa02 Mon Sep 17 00:00:00 2001 From: Avuton Olrich Date: Wed, 14 Jul 2010 17:33:28 -0700 Subject: [PATCH 28/28] mpd version 0.15.11 --- NEWS | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a68abb0ed..65d693166 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.15.11 (2010/??/??) +ver 0.15.11 (2010/06/14) * tags: - ape: support album artist * decoders: diff --git a/configure.ac b/configure.ac index f2a013720..60901a3f6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.15.11~git, musicpd-dev-team@lists.sourceforge.net) +AC_INIT(mpd, 0.15.11, musicpd-dev-team@lists.sourceforge.net) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2]) AM_CONFIG_HEADER(config.h)