Merge branch 'v0.16.x'
Conflicts: NEWS configure.ac
This commit is contained in:
@@ -60,8 +60,10 @@ ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx)
|
||||
assert(remaining > 10);
|
||||
|
||||
char *buffer = g_malloc(remaining);
|
||||
if (fread(buffer, 1, remaining, fp) != remaining)
|
||||
if (fread(buffer, 1, remaining, fp) != remaining) {
|
||||
g_free(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read tags */
|
||||
unsigned n = GUINT32_FROM_LE(footer.count);
|
||||
|
11
src/conf.c
11
src/conf.c
@@ -372,6 +372,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
assert(*line != 0);
|
||||
g_propagate_prefixed_error(error_r, error,
|
||||
"line %i: ", count);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -383,6 +384,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
g_set_error(error_r, config_quark(), 0,
|
||||
"unrecognized parameter in config file at "
|
||||
"line %i: %s\n", count, name);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -392,6 +394,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
"config parameter \"%s\" is first defined "
|
||||
"on line %i and redefined on line %i\n",
|
||||
name, param->line, count);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -403,6 +406,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
if (*line != '{') {
|
||||
g_set_error(error_r, config_quark(), 0,
|
||||
"line %i: '{' expected", count);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -411,12 +415,15 @@ config_read_file(const char *file, GError **error_r)
|
||||
g_set_error(error_r, config_quark(), 0,
|
||||
"line %i: Unknown tokens after '{'",
|
||||
count);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
param = config_read_block(fp, &count, string, error_r);
|
||||
if (param == NULL)
|
||||
if (param == NULL) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* a string value */
|
||||
|
||||
@@ -433,6 +440,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -440,6 +448,7 @@ config_read_file(const char *file, GError **error_r)
|
||||
g_set_error(error_r, config_quark(), 0,
|
||||
"line %i: Unknown tokens after value",
|
||||
count);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -180,7 +180,7 @@ db_check(void)
|
||||
}
|
||||
|
||||
/* Check if we can write to the directory */
|
||||
if (access(dirPath, R_OK | W_OK)) {
|
||||
if (access(dirPath, X_OK | W_OK)) {
|
||||
g_warning("Can't create db file in \"%s\": %s",
|
||||
dirPath, strerror(errno));
|
||||
g_free(dirPath);
|
||||
|
@@ -138,6 +138,33 @@ mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input)
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* API compatibility wrapper for av_open_input_stream() and
|
||||
* avformat_open_input().
|
||||
*/
|
||||
static int
|
||||
mpd_ffmpeg_open_input(AVFormatContext **ic_ptr,
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
|
||||
AVIOContext *pb,
|
||||
#else
|
||||
ByteIOContext *pb,
|
||||
#endif
|
||||
const char *filename,
|
||||
AVInputFormat *fmt)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,1,3)
|
||||
AVFormatContext *context = avformat_alloc_context();
|
||||
if (context == NULL)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
context->pb = pb;
|
||||
*ic_ptr = context;
|
||||
return avformat_open_input(ic_ptr, filename, fmt, NULL);
|
||||
#else
|
||||
return av_open_input_stream(ic_ptr, pb, filename, fmt, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream)
|
||||
{
|
||||
@@ -317,9 +344,9 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
|
||||
}
|
||||
|
||||
//ffmpeg works with ours "fileops" helper
|
||||
AVFormatContext *format_context;
|
||||
if (av_open_input_stream(&format_context, stream->io, input->uri,
|
||||
input_format, NULL) != 0) {
|
||||
AVFormatContext *format_context = NULL;
|
||||
if (mpd_ffmpeg_open_input(&format_context, stream->io, input->uri,
|
||||
input_format) != 0) {
|
||||
g_warning("Open failed\n");
|
||||
mpd_ffmpeg_stream_close(stream);
|
||||
return;
|
||||
@@ -441,13 +468,26 @@ static const ffmpeg_tag_map ffmpeg_tag_maps[] = {
|
||||
};
|
||||
|
||||
static bool
|
||||
ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m,
|
||||
ffmpeg_copy_metadata(struct tag *tag,
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
|
||||
AVDictionary *m,
|
||||
#else
|
||||
AVMetadata *m,
|
||||
#endif
|
||||
const ffmpeg_tag_map tag_map)
|
||||
{
|
||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
|
||||
AVDictionaryEntry *mt = NULL;
|
||||
|
||||
while ((mt = av_dict_get(m, tag_map.name, mt, 0)) != NULL)
|
||||
tag_add_item(tag, tag_map.type, mt->value);
|
||||
#else
|
||||
AVMetadataTag *mt = NULL;
|
||||
|
||||
while ((mt = av_metadata_get(m, tag_map.name, mt, 0)) != NULL)
|
||||
tag_add_item(tag, tag_map.type, mt->value);
|
||||
#endif
|
||||
|
||||
return mt != NULL;
|
||||
}
|
||||
|
||||
@@ -463,9 +503,9 @@ ffmpeg_stream_tag(struct input_stream *is)
|
||||
if (stream == NULL)
|
||||
return NULL;
|
||||
|
||||
AVFormatContext *f;
|
||||
if (av_open_input_stream(&f, stream->io, is->uri,
|
||||
input_format, NULL) != 0) {
|
||||
AVFormatContext *f = NULL;
|
||||
if (mpd_ffmpeg_open_input(&f, stream->io, is->uri,
|
||||
input_format) != 0) {
|
||||
mpd_ffmpeg_stream_close(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -224,7 +224,8 @@ flac_tag_apply_metadata(struct tag *tag, const char *track,
|
||||
break;
|
||||
|
||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||
tag->time = flac_duration(&block->data.stream_info);
|
||||
if (block->data.stream_info.sample_rate > 0)
|
||||
tag->time = flac_duration(&block->data.stream_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#ifndef MPD_FLAC_METADATA_H
|
||||
#define MPD_FLAC_METADATA_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <FLAC/metadata.h>
|
||||
|
||||
@@ -29,6 +30,8 @@ struct replay_gain_info;
|
||||
static inline unsigned
|
||||
flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info)
|
||||
{
|
||||
assert(stream_info->sample_rate > 0);
|
||||
|
||||
return (stream_info->total_samples + stream_info->sample_rate - 1) /
|
||||
stream_info->sample_rate;
|
||||
}
|
||||
|
@@ -106,12 +106,14 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
|
||||
g_set_error(error, ao_output_quark(), 0,
|
||||
"\"%s\" is not a valid ao driver",
|
||||
value);
|
||||
g_free(ad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ai = ao_driver_info(ad->driver)) == NULL) {
|
||||
g_set_error(error, ao_output_quark(), 0,
|
||||
"problems getting driver info");
|
||||
g_free(ad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -129,6 +131,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
|
||||
g_set_error(error, ao_output_quark(), 0,
|
||||
"problems parsing options \"%s\"",
|
||||
options[i]);
|
||||
g_free(ad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -103,6 +103,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
|
||||
if (encoder_plugin == NULL) {
|
||||
g_set_error(error, httpd_output_quark(), 0,
|
||||
"No such encoder: %s", encoder_name);
|
||||
g_free(httpd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -79,23 +79,27 @@ recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
|
||||
if (encoder_plugin == NULL) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"No such encoder: %s", encoder_name);
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
recorder->path = config_get_block_string(param, "path", NULL);
|
||||
if (recorder->path == NULL) {
|
||||
g_set_error(error_r, recorder_output_quark(), 0,
|
||||
"'path' not configured");
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* initialize encoder */
|
||||
|
||||
recorder->encoder = encoder_init(encoder_plugin, param, error_r);
|
||||
if (recorder->encoder == NULL)
|
||||
return NULL;
|
||||
goto failure;
|
||||
|
||||
return recorder;
|
||||
|
||||
failure:
|
||||
g_free(recorder);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -152,7 +152,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
if (port == 0) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"shout port must be configured");
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
check_block_param("password");
|
||||
@@ -174,21 +174,21 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
"shout quality \"%s\" is not a number in the "
|
||||
"range -1 to 10, line %i",
|
||||
value, param->line);
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (config_get_block_string(param, "bitrate", NULL) != NULL) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"quality and bitrate are "
|
||||
"both defined");
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
} else {
|
||||
value = config_get_block_string(param, "bitrate", NULL);
|
||||
if (value == NULL) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"neither bitrate nor quality defined");
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
sd->bitrate = strtol(value, &test, 10);
|
||||
@@ -196,7 +196,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
if (*test != '\0' || sd->bitrate <= 0) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"bitrate must be a positive integer");
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,12 +206,12 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"couldn't find shout encoder plugin \"%s\"",
|
||||
encoding);
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
sd->encoder = encoder_init(encoder_plugin, param, error);
|
||||
if (sd->encoder == NULL)
|
||||
return NULL;
|
||||
goto failure;
|
||||
|
||||
if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0)
|
||||
shout_format = SHOUT_FORMAT_MP3;
|
||||
@@ -225,7 +225,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"you cannot stream \"%s\" to shoutcast, use mp3",
|
||||
encoding);
|
||||
return NULL;
|
||||
goto failure;
|
||||
} else if (0 == strcmp(value, "shoutcast"))
|
||||
protocol = SHOUT_PROTOCOL_ICY;
|
||||
else if (0 == strcmp(value, "icecast1"))
|
||||
@@ -237,7 +237,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
"shout protocol \"%s\" is not \"shoutcast\" or "
|
||||
"\"icecast1\"or \"icecast2\"",
|
||||
value);
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
} else {
|
||||
protocol = SHOUT_PROTOCOL_HTTP;
|
||||
@@ -256,7 +256,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(sd->shout_conn));
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* optional paramters */
|
||||
@@ -267,14 +267,14 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
if (value != NULL && shout_set_genre(sd->shout_conn, value)) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(sd->shout_conn));
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
value = config_get_block_string(param, "description", NULL);
|
||||
if (value != NULL && shout_set_description(sd->shout_conn, value)) {
|
||||
g_set_error(error, shout_output_quark(), 0,
|
||||
"%s", shout_get_error(sd->shout_conn));
|
||||
return NULL;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
value = config_get_block_string(param, "url", NULL);
|
||||
@@ -307,6 +307,10 @@ my_shout_init_driver(const struct audio_format *audio_format,
|
||||
}
|
||||
|
||||
return sd;
|
||||
|
||||
failure:
|
||||
free_shout_data(sd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@@ -579,8 +579,10 @@ sticker_load(const char *type, const char *uri)
|
||||
bool success;
|
||||
|
||||
success = sticker_list_values(sticker->table, type, uri);
|
||||
if (!success)
|
||||
if (!success) {
|
||||
sticker_free(sticker);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_hash_table_size(sticker->table) == 0) {
|
||||
/* don't return empty sticker objects */
|
||||
|
Reference in New Issue
Block a user