Commit eaff52fa authored by Alexey Rusakov's avatar Alexey Rusakov

Merge commit 'release-0.15.5' into alt

parents 7fe0a63d 7df1a2c7
ver 0.15.5 (2009/10/18)
* input:
- curl: don't abort if a packet has only metadata
- curl: fixed endless loop during buffering
* tags:
- riff, aiff: fixed "limited range" gcc warning
* decoders:
- flac: fixed two memory leaks in the CUE tag loader
* decoder_thread: change the fallback decoder name to "mad"
* output_thread: check again if output is open on CANCEL
* update: fixed memory leak during container scan
ver 0.15.4 (2009/10/03)
* decoders:
- vorbis: revert "faster tag scanning with ov_test_callback()"
- faad: skip assertion failure on large ID3 tags
- ffmpeg: use the "artist" tag if "author" is not present
* output:
- osx: fix the OS X 10.6 build
ver 0.15.3 (2009/08/29) ver 0.15.3 (2009/08/29)
* decoders: * decoders:
- vorbis: faster tag scanning with ov_test_callback() - vorbis: faster tag scanning with ov_test_callback()
......
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(mpd, 0.15.3, musicpd-dev-team@lists.sourceforge.net) AC_INIT(mpd, 0.15.5, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2]) AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2])
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
......
...@@ -177,11 +177,11 @@ input { ...@@ -177,11 +177,11 @@ input {
#audio_output { #audio_output {
# type "alsa" # type "alsa"
# name "My ALSA Device" # name "My ALSA Device"
# device "hw:0,0" # optional ## device "hw:0,0" # optional
# format "44100:16:2" # optional ## format "44100:16:2" # optional
# mixer_device "default" # optional ## mixer_device "default" # optional
# mixer_control "PCM" # optional ## mixer_control "PCM" # optional
# mixer_index "0" # optional ## mixer_index "0" # optional
#} #}
# #
# An example of an OSS output: # An example of an OSS output:
...@@ -189,10 +189,10 @@ input { ...@@ -189,10 +189,10 @@ input {
#audio_output { #audio_output {
# type "oss" # type "oss"
# name "My OSS Device" # name "My OSS Device"
# device "/dev/dsp" # optional ## device "/dev/dsp" # optional
# format "44100:16:2" # optional ## format "44100:16:2" # optional
# mixer_device "/dev/mixer" # optional ## mixer_device "/dev/mixer" # optional
# mixer_control "PCM" # optional ## mixer_control "PCM" # optional
#} #}
# #
# An example of a shout output (for streaming to Icecast): # An example of a shout output (for streaming to Icecast):
...@@ -208,12 +208,12 @@ input { ...@@ -208,12 +208,12 @@ input {
# quality "5.0" # quality "5.0"
# bitrate "128" # bitrate "128"
# format "44100:16:1" # format "44100:16:1"
# protocol "icecast2" # optional ## protocol "icecast2" # optional
# user "source" # optional ## user "source" # optional
# description "My Stream Description" # optional ## description "My Stream Description" # optional
# genre "jazz" # optional ## genre "jazz" # optional
# public "no" # optional ## public "no" # optional
# timeout "2" # optional ## timeout "2" # optional
#} #}
# #
# An example of a httpd output (built-in HTTP streaming server): # An example of a httpd output (built-in HTTP streaming server):
...@@ -223,7 +223,7 @@ input { ...@@ -223,7 +223,7 @@ input {
# name "My HTTP Stream" # name "My HTTP Stream"
# encoder "vorbis" # optional, vorbis or lame # encoder "vorbis" # optional, vorbis or lame
# port "8000" # port "8000"
# quality "5.0" # do not define if bitrate is defined ## quality "5.0" # do not define if bitrate is defined
# bitrate "128" # do not define if quality is defined # bitrate "128" # do not define if quality is defined
# format "44100:16:1" # format "44100:16:1"
#} #}
...@@ -233,8 +233,8 @@ input { ...@@ -233,8 +233,8 @@ input {
#audio_output { #audio_output {
# type "pulse" # type "pulse"
# name "My Pulse Output" # name "My Pulse Output"
# server "remote_server" # optional ## server "remote_server" # optional
# sink "remote_server_sink" # optional ## sink "remote_server_sink" # optional
#} #}
# #
## Example "pipe" output: ## Example "pipe" output:
......
...@@ -1210,29 +1210,24 @@ OK ...@@ -1210,29 +1210,24 @@ OK
<term> <term>
<cmdsynopsis> <cmdsynopsis>
<command>update</command> <command>update</command>
<arg><replaceable>URI</replaceable></arg> <arg choice="opt"><replaceable>URI</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
</term> </term>
<listitem> <listitem>
<para> <para>
Updates the music database. Updates the music database: find new files, remove
deleted files, update modified files.
</para> </para>
<para> <para>
<varname>URI</varname> is a particular directory or <varname>URI</varname> is a particular directory or
song/file to update. song/file to update. If you do not specify it,
everything is updated.
</para> </para>
<para> <para>
Prints "updating_db: JOBID" where Prints "updating_db: JOBID" where
<varname>JOBID</varname> is the job id requested for <varname>JOBID</varname> is a positive number
your update, and is displayed in status, while the identifying the update job. You can read the current
requested update is happening. job id in the <command>status</command> response.
</para>
<para>
To update a number of paths/songs at once, use
command_list, it will be much more faster/efficient.
Also, if you use a command_list for updating, only one
<command>update</command> job id will be returned per
sequence of updates.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -84,6 +84,11 @@ aiff_seek_id3(FILE *file) ...@@ -84,6 +84,11 @@ aiff_seek_id3(FILE *file)
return 0; return 0;
size = GUINT32_FROM_BE(chunk.size); size = GUINT32_FROM_BE(chunk.size);
if (size > G_MAXINT32)
/* too dangerous, bail out: possible integer
underflow when casting to off_t */
return 0;
if (size % 2 != 0) if (size % 2 != 0)
/* pad byte */ /* pad byte */
++size; ++size;
...@@ -92,11 +97,6 @@ aiff_seek_id3(FILE *file) ...@@ -92,11 +97,6 @@ aiff_seek_id3(FILE *file)
/* found it! */ /* found it! */
return size; return size;
if ((off_t)size < 0)
/* integer underflow after cast to signed
type */
return 0;
ret = fseek(file, size, SEEK_CUR); ret = fseek(file, size, SEEK_CUR);
if (ret != 0) if (ret != 0)
return 0; return 0;
......
...@@ -162,6 +162,7 @@ faad_song_duration(struct decoder_buffer *buffer, struct input_stream *is) ...@@ -162,6 +162,7 @@ faad_song_duration(struct decoder_buffer *buffer, struct input_stream *is)
size_t tagsize; size_t tagsize;
const unsigned char *data; const unsigned char *data;
size_t length; size_t length;
bool success;
fileread = is->size >= 0 ? is->size : 0; fileread = is->size >= 0 ? is->size : 0;
...@@ -179,8 +180,11 @@ faad_song_duration(struct decoder_buffer *buffer, struct input_stream *is) ...@@ -179,8 +180,11 @@ faad_song_duration(struct decoder_buffer *buffer, struct input_stream *is)
tagsize += 10; tagsize += 10;
decoder_buffer_consume(buffer, tagsize); success = decoder_buffer_skip(buffer, tagsize) &&
decoder_buffer_fill(buffer); decoder_buffer_fill(buffer);
if (!success)
return -1;
data = decoder_buffer_read(buffer, &length); data = decoder_buffer_read(buffer, &length);
if (data == NULL) if (data == NULL)
return -1; return -1;
......
...@@ -338,13 +338,14 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) ...@@ -338,13 +338,14 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
} }
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
static void static bool
ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m, ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m,
enum tag_type type, const char *name) enum tag_type type, const char *name)
{ {
AVMetadataTag *mt = av_metadata_get(m, name, NULL, 0); AVMetadataTag *mt = av_metadata_get(m, name, NULL, 0);
if (mt != NULL) if (mt != NULL)
tag_add_item(tag, type, mt->value); tag_add_item(tag, type, mt->value);
return mt != NULL;
} }
#endif #endif
...@@ -359,7 +360,9 @@ static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx) ...@@ -359,7 +360,9 @@ static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx)
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_TITLE, "title"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_TITLE, "title");
ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ARTIST, "author"); if (!ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ARTIST, "author"))
ffmpeg_copy_metadata(tag, f->metadata,
TAG_ITEM_ARTIST, "artist");
ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ALBUM, "album"); 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_COMMENT, "comment");
ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_GENRE, "genre"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_GENRE, "genre");
......
...@@ -299,10 +299,10 @@ flac_cue_tag_load(const char *file) ...@@ -299,10 +299,10 @@ flac_cue_tag_load(const char *file)
unsigned int sample_rate = 0; unsigned int sample_rate = 0;
FLAC__uint64 track_time = 0; FLAC__uint64 track_time = 0;
#ifdef HAVE_CUE /* libcue */ #ifdef HAVE_CUE /* libcue */
FLAC__StreamMetadata* vc = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__StreamMetadata* vc;
#endif /* libcue */ #endif /* libcue */
FLAC__StreamMetadata* si = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO); FLAC__StreamMetadata* si = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
FLAC__StreamMetadata* cs = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET); FLAC__StreamMetadata* cs;
tnum = flac_vtrack_tnum(file); tnum = flac_vtrack_tnum(file);
char_tnum = g_strdup_printf("%u", tnum); char_tnum = g_strdup_printf("%u", tnum);
...@@ -326,6 +326,7 @@ flac_cue_tag_load(const char *file) ...@@ -326,6 +326,7 @@ flac_cue_tag_load(const char *file)
} }
} }
} }
FLAC__metadata_object_delete(vc); FLAC__metadata_object_delete(vc);
} }
#endif /* libcue */ #endif /* libcue */
......
...@@ -383,7 +383,7 @@ vorbis_tag_dup(const char *file) ...@@ -383,7 +383,7 @@ vorbis_tag_dup(const char *file)
return NULL; return NULL;
} }
if (ov_test_callbacks(fp, &vf, NULL, 0, OV_CALLBACKS_STREAMONLY) < 0) { if (ov_open(fp, &vf, NULL, 0) < 0) {
fclose(fp); fclose(fp);
return NULL; return NULL;
} }
......
...@@ -138,3 +138,29 @@ decoder_buffer_consume(struct decoder_buffer *buffer, size_t nbytes) ...@@ -138,3 +138,29 @@ decoder_buffer_consume(struct decoder_buffer *buffer, size_t nbytes)
assert(buffer->consumed <= buffer->length); assert(buffer->consumed <= buffer->length);
} }
bool
decoder_buffer_skip(struct decoder_buffer *buffer, size_t nbytes)
{
size_t length;
const void *data;
bool success;
/* this could probably be optimized by seeking */
while (true) {
data = decoder_buffer_read(buffer, &length);
if (data != NULL) {
if (length > nbytes)
length = nbytes;
decoder_buffer_consume(buffer, length);
nbytes -= length;
if (nbytes == 0)
return true;
}
success = decoder_buffer_fill(buffer);
if (!success)
return false;
}
}
...@@ -93,4 +93,14 @@ decoder_buffer_read(const struct decoder_buffer *buffer, size_t *length_r); ...@@ -93,4 +93,14 @@ decoder_buffer_read(const struct decoder_buffer *buffer, size_t *length_r);
void void
decoder_buffer_consume(struct decoder_buffer *buffer, size_t nbytes); decoder_buffer_consume(struct decoder_buffer *buffer, size_t nbytes);
/**
* Skips the specified number of bytes, discarding its data.
*
* @param buffer the decoder_buffer object
* @param nbytes the number of bytes to skip
* @return true on success, false on error
*/
bool
decoder_buffer_skip(struct decoder_buffer *buffer, size_t nbytes);
#endif #endif
...@@ -169,7 +169,7 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -169,7 +169,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
if (plugin == NULL) { if (plugin == NULL) {
/* we already know our mp3Plugin supports streams, no /* we already know our mp3Plugin supports streams, no
* need to check for stream{Types,DecodeFunc} */ * need to check for stream{Types,DecodeFunc} */
if ((plugin = decoder_plugin_from_name("mp3"))) { if ((plugin = decoder_plugin_from_name("mad"))) {
ret = decoder_stream_decode(plugin, &decoder, ret = decoder_stream_decode(plugin, &decoder,
&input_stream); &input_stream);
} }
......
...@@ -282,6 +282,42 @@ input_curl_select(struct input_curl *c) ...@@ -282,6 +282,42 @@ input_curl_select(struct input_curl *c)
return ret; return ret;
} }
static bool
fill_buffer(struct input_stream *is)
{
struct input_curl *c = is->data;
CURLMcode mcode = CURLM_CALL_MULTI_PERFORM;
while (!c->eof && g_queue_is_empty(c->buffers)) {
int running_handles;
bool bret;
if (mcode != CURLM_CALL_MULTI_PERFORM) {
/* if we're still here, there is no input yet
- wait for input */
int ret = input_curl_select(c);
if (ret <= 0)
/* no data yet or error */
return false;
}
mcode = curl_multi_perform(c->multi, &running_handles);
if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) {
g_warning("curl_multi_perform() failed: %s\n",
curl_multi_strerror(mcode));
c->eof = true;
is->ready = true;
return false;
}
bret = input_curl_multi_info_read(is);
if (!bret)
return false;
}
return !g_queue_is_empty(c->buffers);
}
/** /**
* Mark a part of the buffer object as consumed. * Mark a part of the buffer object as consumed.
*/ */
...@@ -381,7 +417,7 @@ static size_t ...@@ -381,7 +417,7 @@ static size_t
input_curl_read(struct input_stream *is, void *ptr, size_t size) input_curl_read(struct input_stream *is, void *ptr, size_t size)
{ {
struct input_curl *c = is->data; struct input_curl *c = is->data;
CURLMcode mcode = CURLM_CALL_MULTI_PERFORM; bool success;
GQueue *rewind_buffers; GQueue *rewind_buffers;
size_t nbytes = 0; size_t nbytes = 0;
char *dest = ptr; char *dest = ptr;
...@@ -407,54 +443,33 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size) ...@@ -407,54 +443,33 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size)
} }
#endif #endif
/* fill the buffer */ do {
/* fill the buffer */
while (!c->eof && g_queue_is_empty(c->buffers)) {
int running_handles;
bool bret;
if (mcode != CURLM_CALL_MULTI_PERFORM) {
/* if we're still here, there is no input yet
- wait for input */
int ret = input_curl_select(c);
if (ret <= 0)
/* no data yet or error */
return 0;
}
mcode = curl_multi_perform(c->multi, &running_handles);
if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) {
g_warning("curl_multi_perform() failed: %s\n",
curl_multi_strerror(mcode));
c->eof = true;
is->ready = true;
return 0;
}
bret = input_curl_multi_info_read(is); success = fill_buffer(is);
if (!bret) if (!success)
return 0; return 0;
}
/* send buffer contents */ /* send buffer contents */
if (c->rewind != NULL && if (c->rewind != NULL &&
(!g_queue_is_empty(c->rewind) || is->offset == 0)) (!g_queue_is_empty(c->rewind) || is->offset == 0))
/* at the beginning or already writing the rewind /* at the beginning or already writing the rewind
buffer list */ buffer list */
rewind_buffers = c->rewind; rewind_buffers = c->rewind;
else else
/* we don't need the rewind buffers anymore */ /* we don't need the rewind buffers anymore */
rewind_buffers = NULL; rewind_buffers = NULL;
while (size > 0 && !g_queue_is_empty(c->buffers)) { while (size > 0 && !g_queue_is_empty(c->buffers)) {
size_t copy = read_from_buffer(&c->icy_metadata, c->buffers, size_t copy = read_from_buffer(&c->icy_metadata, c->buffers,
dest + nbytes, size, dest + nbytes, size,
rewind_buffers); rewind_buffers);
nbytes += copy; nbytes += copy;
size -= copy; size -= copy;
} }
} while (nbytes == 0);
if (icy_defined(&c->icy_metadata)) if (icy_defined(&c->icy_metadata))
copy_icy_tag(c); copy_icy_tag(c);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <errno.h> #include <errno.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "jack" #define G_LOG_DOMAIN "input_mms"
struct input_mms { struct input_mms {
mmsx_t *mms; mmsx_t *mms;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <glib.h> #include <glib.h>
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
#include <CoreServices/CoreServices.h>
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "osx" #define G_LOG_DOMAIN "osx"
......
...@@ -257,7 +257,8 @@ static gpointer audio_output_task(gpointer arg) ...@@ -257,7 +257,8 @@ static gpointer audio_output_task(gpointer arg)
case AO_COMMAND_CANCEL: case AO_COMMAND_CANCEL:
ao->chunk = NULL; ao->chunk = NULL;
ao_plugin_cancel(ao->plugin, ao->data); if (ao->open)
ao_plugin_cancel(ao->plugin, ao->data);
ao_command_finished(ao); ao_command_finished(ao);
/* the player thread will now clear our music /* the player thread will now clear our music
......
...@@ -83,6 +83,11 @@ riff_seek_id3(FILE *file) ...@@ -83,6 +83,11 @@ riff_seek_id3(FILE *file)
return 0; return 0;
size = GUINT32_FROM_LE(chunk.size); size = GUINT32_FROM_LE(chunk.size);
if (size > G_MAXINT32)
/* too dangerous, bail out: possible integer
underflow when casting to off_t */
return 0;
if (size % 2 != 0) if (size % 2 != 0)
/* pad byte */ /* pad byte */
++size; ++size;
...@@ -91,11 +96,6 @@ riff_seek_id3(FILE *file) ...@@ -91,11 +96,6 @@ riff_seek_id3(FILE *file)
/* found it! */ /* found it! */
return size; return size;
if ((off_t)size < 0)
/* integer underflow after cast to signed
type */
return 0;
ret = fseek(file, size, SEEK_CUR); ret = fseek(file, size, SEEK_CUR);
if (ret != 0) if (ret != 0)
return 0; return 0;
......
...@@ -459,20 +459,20 @@ update_container_file( struct directory* directory, ...@@ -459,20 +459,20 @@ update_container_file( struct directory* directory,
while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL) while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL)
{ {
struct song* song = song_file_new(vtrack, contdir); struct song* song = song_file_new(vtrack, contdir);
if (song == NULL) char *child_path_fs;
return true;
// shouldn't be necessary but it's there.. // shouldn't be necessary but it's there..
song->mtime = st->st_mtime; song->mtime = st->st_mtime;
song->tag = plugin->tag_dup(map_directory_child_fs(contdir, vtrack)); child_path_fs = map_directory_child_fs(contdir, vtrack);
g_free(vtrack);
song->tag = plugin->tag_dup(child_path_fs);
g_free(child_path_fs);
songvec_add(&contdir->songs, song); songvec_add(&contdir->songs, song);
song = NULL;
modified = true; modified = true;
g_free(vtrack);
} }
g_free(pathname); g_free(pathname);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment