Compare commits

...

34 Commits

Author SHA1 Message Date
Avuton Olrich
56bf4ede18 mpd version 0.15.11 2010-07-14 17:33:28 -07:00
Max Kellermann
49bc317fb8 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.
2010-06-30 23:41:32 +02:00
Max Kellermann
375a09d6f6 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.
2010-06-30 23:40:31 +02:00
Max Kellermann
0265c34bed decoder/ffmpeg: free URI, fix memory leak
Free the string allocated by decoder_get_uri().
2010-06-30 23:40:04 +02:00
Max Kellermann
a1882f48be decoder/vorbis: handle uri==NULL
This fixes a theoretical crash, which has never occurred in practice.
2010-06-30 23:38:49 +02:00
Anton Khirnov
c3569814bd ffmpeg: read more metadata. 2010-06-30 23:18:45 +02:00
Max Kellermann
814daac5ba decoder/ffmpeg: free AVFormatContext on error
Fix a memory leak in some code paths.
2010-06-30 23:14:43 +02:00
Max Kellermann
0d03bdce6d configure.ac: check ffmpeg version number with pkg-config
Replace the check for avcodec_decode_audio2(), assume it's present in
libavcodec version 51.
2010-06-30 21:56:04 +02:00
Max Kellermann
768be22f7c pcm_buffer: make the buffer pointer "void" 2010-06-30 21:55:46 +02:00
Max Kellermann
ec89ce5a8a decoder/mp4ff: support tag "album artist"
We already supported "albumartist", but it seems some folks also use
"album artist" (with a space).
2010-06-30 21:55:03 +02:00
Andreas Vögele
34415bf0b6 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.
2010-06-30 21:42:01 +02:00
Max Kellermann
0a0c78674f playlist: emit IDLE_OPTIONS when resetting single mode 2010-06-30 21:40:33 +02:00
Max Kellermann
1bffdabe41 directory_print: return void
There is no useful return value here.
2010-06-30 21:39:34 +02:00
Max Kellermann
77e6810c14 decoder/mikmod: fix memory leak
The return value of Player_LoadTitle() is allocated with malloc(), and
must be freed by the caller.
2010-06-30 19:37:36 +00:00
Max Kellermann
5ebe33653c decoder/mp4ff: remove duplicate entries in the tag name table
Reuse the function tag_name_parse_i().
2010-06-30 21:36:15 +02:00
Max Kellermann
8e3eace289 decoder/mp4ff: moved code to mp4ff_tag_name_parse() 2010-06-30 21:36:00 +02:00
Max Kellermann
284659034d tag_ape: remove duplicate entries in the tag name table
Reuse the function tag_name_parse_i().
2010-06-30 21:33:19 +02:00
Max Kellermann
9550c87327 tag: added function tag_name_parse()
Convert a string into a tag_type enum.
2010-06-30 21:31:45 +02:00
Max Kellermann
e223e8a5b5 tag_ape: move code to tag_ape_name_parse() 2010-06-30 21:30:21 +02:00
Max Kellermann
4d6d372a5b decoder/vorbis: use single global ov_callbacks constant
Initialize the ov_callbacks struct at compile time.
2010-06-30 19:24:41 +00:00
Max Kellermann
0aeec90590 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.
2010-06-30 21:22:13 +02:00
Max Kellermann
cfcd84655c decoder/mp4ff: use tag_table.h to parse tag names
Convert if/else/else/... to a loop.
2010-06-30 21:19:30 +02:00
Max Kellermann
5092eaf1cc tag_ape: move table lookup to tag_table.h
Allow code sharing.
2010-06-30 21:18:27 +02:00
Max Kellermann
9328558fc7 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.
2010-06-30 21:16:28 +02:00
Max Kellermann
026bd15872 tag_ape: simplified the apeItems array
Make "enum tag_type" the array index, and convert apeItems to a sparse
array.
2010-06-30 21:15:52 +02:00
Max Kellermann
7cca55549b tag_ape: moved code to tag_ape_import_item()
Improve code readability.
2010-06-30 21:15:39 +02:00
Max Kellermann
c7e89ea3a3 tag_ape: converted apeItems and tagItems to global vars
Don't initialize those arrays each time tag_ape_load() is called.
2010-06-30 21:15:14 +02:00
Avuton Olrich
65ad298460 Modify version string to post-release version 0.15.11~git 2010-05-30 08:59:00 -07:00
Avuton Olrich
57e95ea6f4 mpd version 0.15.10 2010-05-30 08:59:00 -07:00
Max Kellermann
442d2e74e3 decoder/mad: fix buffer variable name on !HAVE_ID3TAG 2010-05-30 17:27:03 +02:00
Max Kellermann
28736414a8 input/mms: initialize the "eof" attribute 2010-05-18 21:11:00 +02:00
Max Kellermann
e98bd55cbf input/mms: fix memory leak in error handler 2010-05-18 20:57:57 +02:00
Max Kellermann
a1a03deed2 decoder/mad: properly calculate ID3 size without libid3tag
Without libid3tag, we were trying to skip the ID3 frame (since
0.15.2).  Its length however was not calculated at all, we were just
dropping everything from the current input buffer.  This lead to the
first few seconds of the file being skipped.  This patch attempts to
calculate the ID3v2 frame size with the formula from:

 http://www.id3.org/id3v2.4.0-structure 3.1 and 6.2
2010-04-13 08:51:29 +02:00
Avuton Olrich
0dcd865c2e Modify version string to post-release version 0.15.10~git 2010-03-21 17:25:18 -07:00
19 changed files with 348 additions and 170 deletions

@@ -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 \

23
NEWS

@@ -1,3 +1,26 @@
ver 0.15.11 (2010/06/14)
* tags:
- ape: support album artist
* decoders:
- 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
- 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
ver 0.15.10 (2010/05/30)
* input:
- mms: fix memory leak in error handler
- mms: initialize the "eof" attribute
* decoders:
- mad: properly calculate ID3 size without libid3tag
ver 0.15.9 (2010/03/21)
* decoders:
- mad: fix crash when seeking at end of song

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.15.9, 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)
@@ -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
@@ -913,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

@@ -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,64 +130,86 @@ 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)
static AVInputFormat *
ffmpeg_probe(struct decoder *decoder, struct input_stream *is,
const char *uri)
{
assert(stream != NULL);
assert(uri != NULL);
enum {
BUFFER_SIZE = 16384,
PADDING = 16,
};
char *base = g_path_get_basename(uri);
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;
}
const char *suffix = strrchr(base, '.');
if (suffix != NULL && suffix[1] != 0)
g_strlcat(stream->url, suffix, sizeof(stream->url));
/* 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;
g_free(base);
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);
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, NULL, 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_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_stream(format_context);
mpd_ffmpeg_stream_close(stream);
return false;
}
@@ -209,11 +221,15 @@ ffmpeg_helper(const char *uri, struct input_stream *input,
if (!codec) {
g_warning("Unsupported audio codec\n");
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_stream(format_context);
mpd_ffmpeg_stream_close(stream);
return false;
}
@@ -227,7 +243,8 @@ ffmpeg_helper(const char *uri, struct input_stream *input,
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;
}
@@ -372,8 +389,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, decoder, input,
ffmpeg_decode_internal, &ctx);
g_free(uri);
}
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
@@ -401,12 +420,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);
@@ -450,7 +478,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;

@@ -425,7 +425,27 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
/* This code is enabled when libid3tag is disabled. Instead
of parsing the ID3 frame, it just skips it. */
mad_stream_skip(&data->stream, tagsize);
size_t count = data->stream.bufend - data->stream.this_frame;
if (tagsize <= count) {
mad_stream_skip(&data->stream, tagsize);
} else {
mad_stream_skip(&data->stream, count);
while (count < tagsize) {
size_t len = tagsize - count;
char ignored[1024];
if (len > sizeof(ignored))
len = sizeof(ignored);
len = decoder_read(data->decoder, data->input_stream,
ignored, len);
if (len == 0)
break;
else
count += len;
}
}
#endif
}
@@ -433,16 +453,16 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
/**
* This function emulates libid3tag when it is disabled. Instead of
* doing a real analyzation of the frame, it just checks whether the
* frame begins with the string "ID3". If so, it returns the full
* length.
* frame begins with the string "ID3". If so, it returns the length
* of the ID3 frame.
*/
static signed long
id3_tag_query(const void *p0, size_t length)
{
const char *p = p0;
return length > 3 && memcmp(p, "ID3", 3) == 0
? length
return length >= 10 && memcmp(p, "ID3", 3) == 0
? (p[8] << 7) + p[9] + 10
: 0;
}
#endif /* !HAVE_ID3TAG */

@@ -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;
}

@@ -19,6 +19,7 @@
#include "../decoder_api.h"
#include "config.h"
#include "tag_table.h"
#include <glib.h>
@@ -339,6 +340,22 @@ 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_ALBUM_ARTIST] = "album artist",
[TAG_ITEM_COMPOSER] = "writer",
[TAG_ITEM_PERFORMER] = "band",
};
static enum tag_type
mp4ff_tag_name_parse(const char *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 *
mp4_tag_dup(const char *file)
{
@@ -394,24 +411,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 = mp4ff_tag_name_parse(item);
if (type != TAG_NUM_OF_ITEM_TYPES)
tag_add_item(ret, type, value);
free(item);
free(value);

@@ -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)
{
@@ -226,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 */
@@ -241,7 +251,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 +275,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;

@@ -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;
}

@@ -23,7 +23,7 @@
struct client;
struct directory;
int
void
directory_print(struct client *client, const struct directory *directory);
#endif

@@ -49,10 +49,13 @@ input_mms_open(struct input_stream *is, const char *url)
m = g_new(struct input_mms, 1);
m->mms = mmsx_connect(NULL, NULL, url, 128 * 1024);
if (m->mms == NULL) {
g_free(m);
g_warning("mmsx_connect() failed");
return false;
}
m->eof = false;
/* XX is this correct? at least this selects the ffmpeg
decoder, which seems to work fine*/
is->mime = g_strdup("audio/x-ms-wma");

@@ -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
}

@@ -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;
}

@@ -28,7 +28,7 @@
* would put too much stress on the allocator.
*/
struct pcm_buffer {
char *buffer;
void *buffer;
size_t size;
};

@@ -24,6 +24,7 @@
#include "playlist_internal.h"
#include "player_control.h"
#include "idle.h"
#include <glib.h>
@@ -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);

@@ -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;
}

@@ -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.
*/

@@ -19,12 +19,47 @@
#include "tag_ape.h"
#include "tag.h"
#include "tag_table.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = {
[TAG_ITEM_ALBUM_ARTIST] = "album artist",
[TAG_ITEM_DATE] = "year"
};
static enum tag_type
tag_ape_name_parse(const char *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 *
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;
enum tag_type type = tag_ape_name_parse(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;
}
struct tag *
tag_ape_load(const char *file)
{
@@ -36,7 +71,6 @@ tag_ape_load(const char *file)
size_t tagLen;
size_t size;
unsigned long flags;
int i;
char *key;
struct {
@@ -48,26 +82,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;
@@ -127,17 +141,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;
}

43
src/tag_table.h Normal file

@@ -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 <glib.h>
/**
* 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