aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoder/mad_decoder_plugin.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/decoder/mad_decoder_plugin.c (renamed from src/decoder/mad_plugin.c)198
1 files changed, 114 insertions, 84 deletions
diff --git a/src/decoder/mad_plugin.c b/src/decoder/mad_decoder_plugin.c
index 7cc78a0d2..57221d878 100644
--- a/src/decoder/mad_plugin.c
+++ b/src/decoder/mad_decoder_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * 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
@@ -17,10 +17,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "../decoder_api.h"
-#include "../conf.h"
#include "config.h"
+#include "decoder_api.h"
+#include "conf.h"
#include "tag_id3.h"
+#include "audio_check.h"
#include <assert.h>
#include <unistd.h>
@@ -125,6 +126,7 @@ struct mp3_data {
unsigned int drop_end_frames;
unsigned int drop_start_samples;
unsigned int drop_end_samples;
+ bool found_replay_gain;
bool found_xing;
bool found_first_frame;
bool decoded_first_frame;
@@ -148,6 +150,7 @@ mp3_data_init(struct mp3_data *data, struct decoder *decoder,
data->drop_end_frames = 0;
data->drop_start_samples = 0;
data->drop_end_samples = 0;
+ data->found_replay_gain = false;
data->found_xing = false;
data->found_first_frame = false;
data->decoded_first_frame = false;
@@ -164,7 +167,7 @@ mp3_data_init(struct mp3_data *data, struct decoder *decoder,
static bool mp3_seek(struct mp3_data *data, long offset)
{
- if (!input_stream_seek(data->input_stream, offset, SEEK_SET))
+ if (!input_stream_seek(data->input_stream, offset, SEEK_SET, NULL))
return false;
mad_stream_buffer(&data->stream, data->input_buffer, 0);
@@ -297,17 +300,17 @@ static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gai
#endif
#ifdef HAVE_ID3TAG
-static struct replay_gain_info *
-parse_id3_replay_gain_info(struct id3_tag *tag)
+static bool
+parse_id3_replay_gain_info(struct replay_gain_info *replay_gain_info,
+ struct id3_tag *tag)
{
int i;
char *key;
char *value;
struct id3_frame *frame;
bool found = false;
- struct replay_gain_info *replay_gain_info;
- replay_gain_info = replay_gain_info_new();
+ replay_gain_info_init(replay_gain_info);
for (i = 0; (frame = id3_tag_findframe(tag, "TXXX", i)); i++) {
if (frame->nfields < 3)
@@ -338,21 +341,55 @@ parse_id3_replay_gain_info(struct id3_tag *tag)
free(value);
}
- if (!found) {
+ return found ||
/* fall back on RVA2 if no replaygain tags found */
- found = parse_rva2(tag, replay_gain_info);
+ parse_rva2(tag, replay_gain_info);
+}
+#endif
+
+#ifdef HAVE_ID3TAG
+static bool
+parse_id3_mixramp(char **mixramp_start, char **mixramp_end,
+ struct id3_tag *tag)
+{
+ int i;
+ char *key;
+ char *value;
+ struct id3_frame *frame;
+ bool found = false;
+
+ *mixramp_start = NULL;
+ *mixramp_end = NULL;
+
+ for (i = 0; (frame = id3_tag_findframe(tag, "TXXX", i)); i++) {
+ if (frame->nfields < 3)
+ continue;
+
+ key = (char *)
+ id3_ucs4_latin1duplicate(id3_field_getstring
+ (&frame->fields[1]));
+ value = (char *)
+ id3_ucs4_latin1duplicate(id3_field_getstring
+ (&frame->fields[2]));
+
+ if (g_ascii_strcasecmp(key, "mixramp_start") == 0) {
+ *mixramp_start = strdup(value);
+ found = true;
+ } else if (g_ascii_strcasecmp(key, "mixramp_end") == 0) {
+ *mixramp_end = strdup(value);
+ found = true;
+ }
+
+ free(key);
+ free(value);
}
- if (found)
- return replay_gain_info;
- replay_gain_info_free(replay_gain_info);
- return NULL;
+ return found;
}
#endif
static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
- struct tag **mpd_tag,
- struct replay_gain_info **replay_gain_info_r)
+ struct tag **mpd_tag)
{
#ifdef HAVE_ID3TAG
struct id3_tag *id3_tag = NULL;
@@ -405,13 +442,17 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
}
}
- if (replay_gain_info_r) {
- struct replay_gain_info *tmp_rgi =
- parse_id3_replay_gain_info(id3_tag);
- if (tmp_rgi != NULL) {
- if (*replay_gain_info_r)
- replay_gain_info_free(*replay_gain_info_r);
- *replay_gain_info_r = tmp_rgi;
+ if (data->decoder != NULL) {
+ struct replay_gain_info rgi;
+ char *mixramp_start;
+ char *mixramp_end;
+ if (parse_id3_replay_gain_info(&rgi, id3_tag)) {
+ decoder_replay_gain(data->decoder, &rgi);
+ data->found_replay_gain = true;
+ }
+ if (parse_id3_mixramp(&mixramp_start, &mixramp_end, id3_tag)) {
+ g_debug("setting mixramp_tags");
+ decoder_mixramp(data->decoder, mixramp_start, mixramp_end);
}
}
@@ -420,7 +461,6 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
g_free(allocated);
#else /* !HAVE_ID3TAG */
(void)mpd_tag;
- (void)replay_gain_info_r;
/* This code is enabled when libid3tag is disabled. Instead
of parsing the ID3 frame, it just skips it. */
@@ -448,8 +488,7 @@ id3_tag_query(const void *p0, size_t length)
#endif /* !HAVE_ID3TAG */
static enum mp3_action
-decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag,
- G_GNUC_UNUSED struct replay_gain_info **replay_gain_info_r)
+decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag)
{
enum mad_layer layer;
@@ -471,7 +510,7 @@ decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag,
if (tagsize > 0) {
if (tag && !(*tag)) {
mp3_parse_id3(data, (size_t)tagsize,
- tag, replay_gain_info_r);
+ tag);
} else {
mad_stream_skip(&(data->stream),
tagsize);
@@ -779,10 +818,10 @@ mp3_frame_duration(const struct mad_frame *frame)
MAD_UNITS_MILLISECONDS) / 1000.0;
}
-static off_t
+static goffset
mp3_this_frame_offset(const struct mp3_data *data)
{
- off_t offset = data->input_stream->offset;
+ goffset offset = data->input_stream->offset;
if (data->stream.this_frame != NULL)
offset -= data->stream.bufend - data->stream.this_frame;
@@ -792,7 +831,7 @@ mp3_this_frame_offset(const struct mp3_data *data)
return offset;
}
-static off_t
+static goffset
mp3_rest_including_this_frame(const struct mp3_data *data)
{
return data->input_stream->size - mp3_this_frame_offset(data);
@@ -804,7 +843,7 @@ mp3_rest_including_this_frame(const struct mp3_data *data)
static void
mp3_filesize_to_song_length(struct mp3_data *data)
{
- off_t rest = mp3_rest_including_this_frame(data);
+ goffset rest = mp3_rest_including_this_frame(data);
if (rest > 0) {
float frame_duration = mp3_frame_duration(&data->frame);
@@ -819,8 +858,7 @@ mp3_filesize_to_song_length(struct mp3_data *data)
}
static bool
-mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
- struct replay_gain_info **replay_gain_info_r)
+mp3_decode_first_frame(struct mp3_data *data, struct tag **tag)
{
struct xing xing;
struct lame lame;
@@ -834,8 +872,7 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
while (true) {
do {
- ret = decode_next_frame_header(data, tag,
- replay_gain_info_r);
+ ret = decode_next_frame_header(data, tag);
} while (ret == DECODE_CONT);
if (ret == DECODE_BREAK)
return false;
@@ -878,14 +915,17 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
/* Album gain isn't currently used. See comment in
* parse_lame() for details. -- jat */
- if (replay_gain_info_r && !*replay_gain_info_r &&
+ if (data->decoder != NULL &&
+ !data->found_replay_gain &&
lame.track_gain) {
- *replay_gain_info_r = replay_gain_info_new();
- (*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
- (*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
+ struct replay_gain_info rgi;
+ replay_gain_info_init(&rgi);
+ rgi.tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
+ rgi.tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
+ decoder_replay_gain(data->decoder, &rgi);
}
}
- }
+ }
if (!data->max_frames)
return false;
@@ -913,33 +953,29 @@ static void mp3_data_finish(struct mp3_data *data)
}
/* this is primarily used for getting total time for tags */
-static int mp3_total_file_time(const char *file)
+static int
+mad_decoder_total_file_time(struct input_stream *is)
{
- struct input_stream input_stream;
struct mp3_data data;
int ret;
- if (!input_stream_open(&input_stream, file))
- return -1;
- mp3_data_init(&data, NULL, &input_stream);
- if (!mp3_decode_first_frame(&data, NULL, NULL))
+ mp3_data_init(&data, NULL, is);
+ if (!mp3_decode_first_frame(&data, NULL))
ret = -1;
else
ret = data.total_time + 0.5;
mp3_data_finish(&data);
- input_stream_close(&input_stream);
return ret;
}
static bool
mp3_open(struct input_stream *is, struct mp3_data *data,
- struct decoder *decoder, struct tag **tag,
- struct replay_gain_info **replay_gain_info_r)
+ struct decoder *decoder, struct tag **tag)
{
mp3_data_init(data, decoder, is);
*tag = NULL;
- if (!mp3_decode_first_frame(data, tag, replay_gain_info_r)) {
+ if (!mp3_decode_first_frame(data, tag)) {
mp3_data_finish(data);
if (tag && *tag)
tag_free(*tag);
@@ -998,8 +1034,7 @@ mp3_update_timer_next_frame(struct mp3_data *data)
* Sends the synthesized current frame via decoder_data().
*/
static enum decoder_command
-mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
- struct replay_gain_info *replay_gain_info)
+mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length)
{
unsigned max_samples;
@@ -1024,9 +1059,7 @@ mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
cmd = decoder_data(data->decoder, data->input_stream,
data->output_buffer,
sizeof(data->output_buffer[0]) * num_samples,
- data->elapsed_time,
- data->bit_rate / 1000,
- replay_gain_info);
+ data->bit_rate / 1000);
if (cmd != DECODE_COMMAND_NONE)
return cmd;
}
@@ -1038,8 +1071,7 @@ mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
* Synthesize the current frame and send it via decoder_data().
*/
static enum decoder_command
-mp3_synth_and_send(struct mp3_data *data,
- struct replay_gain_info *replay_gain_info)
+mp3_synth_and_send(struct mp3_data *data)
{
unsigned i, pcm_length;
enum decoder_command cmd;
@@ -1080,7 +1112,7 @@ mp3_synth_and_send(struct mp3_data *data,
pcm_length -= data->drop_end_samples;
}
- cmd = mp3_send_pcm(data, i, pcm_length, replay_gain_info);
+ cmd = mp3_send_pcm(data, i, pcm_length);
if (cmd != DECODE_COMMAND_NONE)
return cmd;
@@ -1094,7 +1126,7 @@ mp3_synth_and_send(struct mp3_data *data,
}
static bool
-mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
+mp3_read(struct mp3_data *data)
{
struct decoder *decoder = data->decoder;
enum mp3_action ret;
@@ -1111,9 +1143,7 @@ mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
data->mute_frame = MUTEFRAME_NONE;
break;
case MUTEFRAME_NONE:
- cmd = mp3_synth_and_send(data,
- replay_gain_info_r != NULL
- ? *replay_gain_info_r : NULL);
+ cmd = mp3_synth_and_send(data);
if (cmd == DECODE_COMMAND_SEEK) {
unsigned long j;
@@ -1142,8 +1172,7 @@ mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
do {
struct tag *tag = NULL;
- ret = decode_next_frame_header(data, &tag,
- replay_gain_info_r);
+ ret = decode_next_frame_header(data, &tag);
if (tag != NULL) {
decoder_tag(decoder, data->input_stream, tag);
@@ -1170,29 +1199,34 @@ mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
return ret != DECODE_BREAK;
}
-static void mp3_audio_format(struct mp3_data *data, struct audio_format *af)
-{
- af->bits = 24;
- af->sample_rate = (data->frame).header.samplerate;
- af->channels = MAD_NCHANNELS(&(data->frame).header);
-}
-
static void
mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
{
struct mp3_data data;
+ GError *error = NULL;
struct tag *tag = NULL;
- struct replay_gain_info *replay_gain_info = NULL;
struct audio_format audio_format;
- if (!mp3_open(input_stream, &data, decoder, &tag, &replay_gain_info)) {
+ if (!mp3_open(input_stream, &data, decoder, &tag)) {
if (decoder_get_command(decoder) == DECODE_COMMAND_NONE)
g_warning
("Input does not appear to be a mp3 bit stream.\n");
return;
}
- mp3_audio_format(&data, &audio_format);
+ if (!audio_format_init_checked(&audio_format,
+ data.frame.header.samplerate,
+ SAMPLE_FORMAT_S24_P32,
+ MAD_NCHANNELS(&data.frame.header),
+ &error)) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+
+ if (tag != NULL)
+ tag_free(tag);
+ mp3_data_finish(&data);
+ return;
+ }
decoder_initialized(decoder, &audio_format,
data.input_stream->seekable, data.total_time);
@@ -1202,24 +1236,20 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
tag_free(tag);
}
- while (mp3_read(&data, &replay_gain_info)) ;
-
- if (replay_gain_info)
- replay_gain_info_free(replay_gain_info);
+ while (mp3_read(&data)) ;
mp3_data_finish(&data);
}
-static struct tag *mp3_tag_dup(const char *file)
+static struct tag *
+mad_decoder_stream_tag(struct input_stream *is)
{
struct tag *tag;
int total_time;
- total_time = mp3_total_file_time(file);
- if (total_time < 0) {
- g_debug("Failed to get total song time from: %s", file);
+ total_time = mad_decoder_total_file_time(is);
+ if (total_time < 0)
return NULL;
- }
tag = tag_new();
tag->time = total_time;
@@ -1233,7 +1263,7 @@ const struct decoder_plugin mad_decoder_plugin = {
.name = "mad",
.init = mp3_plugin_init,
.stream_decode = mp3_decode,
- .tag_dup = mp3_tag_dup,
+ .stream_tag = mad_decoder_stream_tag,
.suffixes = mp3_suffixes,
.mime_types = mp3_mime_types
};