From c5edb53797fb15b4753688b1a653bdfda53f25aa Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 16 Feb 2009 19:30:45 +0100 Subject: renamed decoder plugin "mp3" to "mad" A decoder plugin should be named after the library which is used. --- src/Makefile.am | 2 +- src/decoder/mad_plugin.c | 1218 ++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/mp3_plugin.c | 1218 ---------------------------------------------- src/decoder_list.c | 4 +- 4 files changed, 1221 insertions(+), 1221 deletions(-) create mode 100644 src/decoder/mad_plugin.c delete mode 100644 src/decoder/mp3_plugin.c diff --git a/src/Makefile.am b/src/Makefile.am index 1db8e1fe5..f3d9e40cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -267,7 +267,7 @@ endif # decoder plugins if HAVE_MAD -mpd_SOURCES += decoder/mp3_plugin.c +mpd_SOURCES += decoder/mad_plugin.c endif if HAVE_MPCDEC diff --git a/src/decoder/mad_plugin.c b/src/decoder/mad_plugin.c new file mode 100644 index 000000000..71d72bd12 --- /dev/null +++ b/src/decoder/mad_plugin.c @@ -0,0 +1,1218 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../decoder_api.h" +#include "../conf.h" +#include "config.h" +#include "tag_id3.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ID3TAG +#include +#endif + +#define FRAMES_CUSHION 2000 + +#define READ_BUFFER_SIZE 40960 + +enum mp3_action { + DECODE_SKIP = -3, + DECODE_BREAK = -2, + DECODE_CONT = -1, + DECODE_OK = 0 +}; + +enum muteframe { + MUTEFRAME_NONE, + MUTEFRAME_SKIP, + MUTEFRAME_SEEK +}; + +/* the number of samples of silence the decoder inserts at start */ +#define DECODERDELAY 529 + +#define DEFAULT_GAPLESS_MP3_PLAYBACK true + +static bool gapless_playback; + +static inline int32_t +mad_fixed_to_24_sample(mad_fixed_t sample) +{ + enum { + bits = 24, + MIN = -MAD_F_ONE, + MAX = MAD_F_ONE - 1 + }; + + /* round */ + sample = sample + (1L << (MAD_F_FRACBITS - bits)); + + /* clip */ + if (sample > MAX) + sample = MAX; + else if (sample < MIN) + sample = MIN; + + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - bits); +} + +static void +mad_fixed_to_24_buffer(int32_t *dest, const struct mad_synth *synth, + unsigned int start, unsigned int end, + unsigned int num_channels) +{ + unsigned int i, c; + + for (i = start; i < end; ++i) { + for (c = 0; c < num_channels; ++c) + *dest++ = mad_fixed_to_24_sample(synth->pcm.samples[c][i]); + } +} + +static bool +mp3_plugin_init(G_GNUC_UNUSED const struct config_param *param) +{ + gapless_playback = config_get_bool(CONF_GAPLESS_MP3_PLAYBACK, + DEFAULT_GAPLESS_MP3_PLAYBACK); + return true; +} + +#define MP3_DATA_OUTPUT_BUFFER_SIZE 2048 + +struct mp3_data { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + mad_timer_t timer; + unsigned char input_buffer[READ_BUFFER_SIZE]; + int32_t output_buffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; + float total_time; + float elapsed_time; + float seek_where; + enum muteframe mute_frame; + long *frame_offsets; + mad_timer_t *times; + unsigned long highest_frame; + unsigned long max_frames; + unsigned long current_frame; + unsigned int drop_start_frames; + unsigned int drop_end_frames; + unsigned int drop_start_samples; + unsigned int drop_end_samples; + bool found_xing; + bool found_first_frame; + bool decoded_first_frame; + unsigned long bit_rate; + struct decoder *decoder; + struct input_stream *input_stream; + enum mad_layer layer; +}; + +static void +mp3_data_init(struct mp3_data *data, struct decoder *decoder, + struct input_stream *input_stream) +{ + data->mute_frame = MUTEFRAME_NONE; + data->highest_frame = 0; + data->max_frames = 0; + data->frame_offsets = NULL; + data->times = NULL; + data->current_frame = 0; + data->drop_start_frames = 0; + data->drop_end_frames = 0; + data->drop_start_samples = 0; + data->drop_end_samples = 0; + data->found_xing = false; + data->found_first_frame = false; + data->decoded_first_frame = false; + data->decoder = decoder; + data->input_stream = input_stream; + data->layer = 0; + + mad_stream_init(&data->stream); + mad_stream_options(&data->stream, MAD_OPTION_IGNORECRC); + mad_frame_init(&data->frame); + mad_synth_init(&data->synth); + mad_timer_reset(&data->timer); +} + +static bool mp3_seek(struct mp3_data *data, long offset) +{ + if (!input_stream_seek(data->input_stream, offset, SEEK_SET)) + return false; + + mad_stream_buffer(&data->stream, data->input_buffer, 0); + (data->stream).error = 0; + + return true; +} + +static bool +mp3_fill_buffer(struct mp3_data *data) +{ + size_t remaining, length; + unsigned char *dest; + + if (data->stream.next_frame != NULL) { + remaining = data->stream.bufend - data->stream.next_frame; + memmove(data->input_buffer, data->stream.next_frame, + remaining); + dest = (data->input_buffer) + remaining; + length = READ_BUFFER_SIZE - remaining; + } else { + remaining = 0; + length = READ_BUFFER_SIZE; + dest = data->input_buffer; + } + + /* we've exhausted the read buffer, so give up!, these potential + * mp3 frames are way too big, and thus unlikely to be mp3 frames */ + if (length == 0) + return false; + + length = decoder_read(data->decoder, data->input_stream, dest, length); + if (length == 0) + return false; + + mad_stream_buffer(&data->stream, data->input_buffer, + length + remaining); + (data->stream).error = 0; + + return true; +} + +#ifdef HAVE_ID3TAG +/* Parse mp3 RVA2 frame. Shamelessly stolen from madplay. */ +static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gain_info) +{ + struct id3_frame const * frame; + + id3_latin1_t const *id; + id3_byte_t const *data; + id3_length_t length; + int found; + + enum { + CHANNEL_OTHER = 0x00, + CHANNEL_MASTER_VOLUME = 0x01, + CHANNEL_FRONT_RIGHT = 0x02, + CHANNEL_FRONT_LEFT = 0x03, + CHANNEL_BACK_RIGHT = 0x04, + CHANNEL_BACK_LEFT = 0x05, + CHANNEL_FRONT_CENTRE = 0x06, + CHANNEL_BACK_CENTRE = 0x07, + CHANNEL_SUBWOOFER = 0x08 + }; + + found = 0; + + /* relative volume adjustment information */ + + frame = id3_tag_findframe(tag, "RVA2", 0); + if (!frame) return 0; + + id = id3_field_getlatin1(id3_frame_field(frame, 0)); + data = id3_field_getbinarydata(id3_frame_field(frame, 1), + &length); + + if (!id || !data) return 0; + + /* + * "The 'identification' string is used to identify the + * situation and/or device where this adjustment should apply. + * The following is then repeated for every channel + * + * Type of channel $xx + * Volume adjustment $xx xx + * Bits representing peak $xx + * Peak volume $xx (xx ...)" + */ + + while (length >= 4) { + unsigned int peak_bytes; + + peak_bytes = (data[3] + 7) / 8; + if (4 + peak_bytes > length) + break; + + if (data[0] == CHANNEL_MASTER_VOLUME) { + signed int voladj_fixed; + double voladj_float; + + /* + * "The volume adjustment is encoded as a fixed + * point decibel value, 16 bit signed integer + * representing (adjustment*512), giving +/- 64 + * dB with a precision of 0.001953125 dB." + */ + + voladj_fixed = (data[1] << 8) | (data[2] << 0); + voladj_fixed |= -(voladj_fixed & 0x8000); + + voladj_float = (double) voladj_fixed / 512; + + replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = voladj_float; + replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = voladj_float; + + g_debug("parseRVA2: Relative Volume " + "%+.1f dB adjustment (%s)\n", + voladj_float, id); + + found = 1; + break; + } + + data += 4 + peak_bytes; + length -= 4 + peak_bytes; + } + + return found; +} +#endif + +#ifdef HAVE_ID3TAG +static struct replay_gain_info * +parse_id3_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(); + + 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 (strcasecmp(key, "replaygain_track_gain") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = atof(value); + found = true; + } else if (strcasecmp(key, "replaygain_album_gain") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = atof(value); + found = true; + } else if (strcasecmp(key, "replaygain_track_peak") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = atof(value); + found = true; + } else if (strcasecmp(key, "replaygain_album_peak") == 0) { + replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = atof(value); + found = true; + } + + free(key); + free(value); + } + + if (!found) { + /* fall back on RVA2 if no replaygain tags found */ + found = parse_rva2(tag, replay_gain_info); + } + + if (found) + return replay_gain_info; + replay_gain_info_free(replay_gain_info); + return NULL; +} +#endif + +#ifdef HAVE_ID3TAG +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 id3_tag *id3_tag = NULL; + id3_length_t count; + id3_byte_t const *id3_data; + id3_byte_t *allocated = NULL; + + count = data->stream.bufend - data->stream.this_frame; + + if (tagsize <= count) { + id3_data = data->stream.this_frame; + mad_stream_skip(&(data->stream), tagsize); + } else { + allocated = g_malloc(tagsize); + memcpy(allocated, data->stream.this_frame, count); + mad_stream_skip(&(data->stream), count); + + while (count < tagsize) { + size_t len; + + len = decoder_read(data->decoder, data->input_stream, + allocated + count, tagsize - count); + if (len == 0) + break; + else + count += len; + } + + if (count != tagsize) { + g_debug("mp3_decode: error parsing ID3 tag\n"); + g_free(allocated); + return; + } + + id3_data = allocated; + } + + id3_tag = id3_tag_parse(id3_data, tagsize); + if (id3_tag == NULL) { + g_free(allocated); + return; + } + + if (mpd_tag) { + struct tag *tmp_tag = tag_id3_import(id3_tag); + if (tmp_tag != NULL) { + if (*mpd_tag != NULL) + tag_free(*mpd_tag); + *mpd_tag = tmp_tag; + } + } + + 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; + } + } + + id3_tag_delete(id3_tag); + + g_free(allocated); +} +#endif + +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) +{ + enum mad_layer layer; + + if ((data->stream).buffer == NULL + || (data->stream).error == MAD_ERROR_BUFLEN) { + if (!mp3_fill_buffer(data)) + return DECODE_BREAK; + } + if (mad_header_decode(&data->frame.header, &data->stream)) { +#ifdef HAVE_ID3TAG + if ((data->stream).error == MAD_ERROR_LOSTSYNC && + (data->stream).this_frame) { + signed long tagsize = id3_tag_query((data->stream). + this_frame, + (data->stream). + bufend - + (data->stream). + this_frame); + + if (tagsize > 0) { + if (tag && !(*tag)) { + mp3_parse_id3(data, (size_t)tagsize, + tag, replay_gain_info_r); + } else { + mad_stream_skip(&(data->stream), + tagsize); + } + return DECODE_CONT; + } + } +#endif + if (MAD_RECOVERABLE((data->stream).error)) { + return DECODE_SKIP; + } else { + if ((data->stream).error == MAD_ERROR_BUFLEN) + return DECODE_CONT; + else { + g_warning("unrecoverable frame level error " + "(%s).\n", + mad_stream_errorstr(&data->stream)); + return DECODE_BREAK; + } + } + } + + layer = data->frame.header.layer; + if (!data->layer) { + if (layer != MAD_LAYER_II && layer != MAD_LAYER_III) { + /* Only layer 2 and 3 have been tested to work */ + return DECODE_SKIP; + } + data->layer = layer; + } else if (layer != data->layer) { + /* Don't decode frames with a different layer than the first */ + return DECODE_SKIP; + } + + return DECODE_OK; +} + +static enum mp3_action +decodeNextFrame(struct mp3_data *data) +{ + if ((data->stream).buffer == NULL + || (data->stream).error == MAD_ERROR_BUFLEN) { + if (!mp3_fill_buffer(data)) + return DECODE_BREAK; + } + if (mad_frame_decode(&data->frame, &data->stream)) { +#ifdef HAVE_ID3TAG + if ((data->stream).error == MAD_ERROR_LOSTSYNC) { + signed long tagsize = id3_tag_query((data->stream). + this_frame, + (data->stream). + bufend - + (data->stream). + this_frame); + if (tagsize > 0) { + mad_stream_skip(&(data->stream), tagsize); + return DECODE_CONT; + } + } +#endif + if (MAD_RECOVERABLE((data->stream).error)) { + return DECODE_SKIP; + } else { + if ((data->stream).error == MAD_ERROR_BUFLEN) + return DECODE_CONT; + else { + g_warning("unrecoverable frame level error " + "(%s).\n", + mad_stream_errorstr(&data->stream)); + return DECODE_BREAK; + } + } + } + + return DECODE_OK; +} + +/* xing stuff stolen from alsaplayer, and heavily modified by jat */ +#define XI_MAGIC (('X' << 8) | 'i') +#define NG_MAGIC (('n' << 8) | 'g') +#define IN_MAGIC (('I' << 8) | 'n') +#define FO_MAGIC (('f' << 8) | 'o') + +enum xing_magic { + XING_MAGIC_XING, /* VBR */ + XING_MAGIC_INFO /* CBR */ +}; + +struct xing { + long flags; /* valid fields (see below) */ + unsigned long frames; /* total number of frames */ + unsigned long bytes; /* total number of bytes */ + unsigned char toc[100]; /* 100-point seek table */ + long scale; /* VBR quality */ + enum xing_magic magic; /* header magic */ +}; + +enum { + XING_FRAMES = 0x00000001L, + XING_BYTES = 0x00000002L, + XING_TOC = 0x00000004L, + XING_SCALE = 0x00000008L +}; + +struct version { + unsigned major; + unsigned minor; +}; + +struct lame { + char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */ + struct version version; /* struct containing just the version */ + float peak; /* replaygain peak */ + float track_gain; /* replaygain track gain */ + float album_gain; /* replaygain album gain */ + int encoder_delay; /* # of added samples at start of mp3 */ + int encoder_padding; /* # of added samples at end of mp3 */ + int crc; /* CRC of the first 190 bytes of this frame */ +}; + +static bool +parse_xing(struct xing *xing, struct mad_bitptr *ptr, int *oldbitlen) +{ + unsigned long bits; + int bitlen; + int bitsleft; + int i; + + bitlen = *oldbitlen; + + if (bitlen < 16) + return false; + + bits = mad_bit_read(ptr, 16); + bitlen -= 16; + + if (bits == XI_MAGIC) { + if (bitlen < 16) + return false; + + if (mad_bit_read(ptr, 16) != NG_MAGIC) + return false; + + bitlen -= 16; + xing->magic = XING_MAGIC_XING; + } else if (bits == IN_MAGIC) { + if (bitlen < 16) + return false; + + if (mad_bit_read(ptr, 16) != FO_MAGIC) + return false; + + bitlen -= 16; + xing->magic = XING_MAGIC_INFO; + } + else if (bits == NG_MAGIC) xing->magic = XING_MAGIC_XING; + else if (bits == FO_MAGIC) xing->magic = XING_MAGIC_INFO; + else + return false; + + if (bitlen < 32) + return false; + xing->flags = mad_bit_read(ptr, 32); + bitlen -= 32; + + if (xing->flags & XING_FRAMES) { + if (bitlen < 32) + return false; + xing->frames = mad_bit_read(ptr, 32); + bitlen -= 32; + } + + if (xing->flags & XING_BYTES) { + if (bitlen < 32) + return false; + xing->bytes = mad_bit_read(ptr, 32); + bitlen -= 32; + } + + if (xing->flags & XING_TOC) { + if (bitlen < 800) + return false; + for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(ptr, 8); + bitlen -= 800; + } + + if (xing->flags & XING_SCALE) { + if (bitlen < 32) + return false; + xing->scale = mad_bit_read(ptr, 32); + bitlen -= 32; + } + + /* Make sure we consume no less than 120 bytes (960 bits) in hopes that + * the LAME tag is found there, and not right after the Xing header */ + bitsleft = 960 - ((*oldbitlen) - bitlen); + if (bitsleft < 0) + return false; + else if (bitsleft > 0) { + mad_bit_read(ptr, bitsleft); + bitlen -= bitsleft; + } + + *oldbitlen = bitlen; + + return true; +} + +static bool +parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) +{ + int adj = 0; + int name; + int orig; + int sign; + int gain; + int i; + + /* Unlike the xing header, the lame tag has a fixed length. Fail if + * not all 36 bytes (288 bits) are there. */ + if (*bitlen < 288) + return false; + + for (i = 0; i < 9; i++) + lame->encoder[i] = (char)mad_bit_read(ptr, 8); + lame->encoder[9] = '\0'; + + *bitlen -= 72; + + /* This is technically incorrect, since the encoder might not be lame. + * But there's no other way to determine if this is a lame tag, and we + * wouldn't want to go reading a tag that's not there. */ + if (!g_str_has_prefix(lame->encoder, "LAME")) + return false; + + if (sscanf(lame->encoder+4, "%u.%u", + &lame->version.major, &lame->version.minor) != 2) + return false; + + g_debug("detected LAME version %i.%i (\"%s\")\n", + lame->version.major, lame->version.minor, lame->encoder); + + /* The reference volume was changed from the 83dB used in the + * ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older + * versions, since everyone else uses 89dB instead of 83dB. + * Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so + * it's impossible to make the proper adjustment for 3.95. + * Fortunately, 3.95 was only out for about a day before 3.95.1 was + * released. -- tmz */ + if (lame->version.major < 3 || + (lame->version.major == 3 && lame->version.minor < 95)) + adj = 6; + + mad_bit_read(ptr, 16); + + lame->peak = mad_f_todouble(mad_bit_read(ptr, 32) << 5); /* peak */ + g_debug("LAME peak found: %f\n", lame->peak); + + lame->track_gain = 0; + name = mad_bit_read(ptr, 3); /* gain name */ + orig = mad_bit_read(ptr, 3); /* gain originator */ + sign = mad_bit_read(ptr, 1); /* sign bit */ + gain = mad_bit_read(ptr, 9); /* gain*10 */ + if (gain && name == 1 && orig != 0) { + lame->track_gain = ((sign ? -gain : gain) / 10.0) + adj; + g_debug("LAME track gain found: %f\n", lame->track_gain); + } + + /* tmz reports that this isn't currently written by any version of lame + * (as of 3.97). Since we have no way of testing it, don't use it. + * Wouldn't want to go blowing someone's ears just because we read it + * wrong. :P -- jat */ + lame->album_gain = 0; +#if 0 + name = mad_bit_read(ptr, 3); /* gain name */ + orig = mad_bit_read(ptr, 3); /* gain originator */ + sign = mad_bit_read(ptr, 1); /* sign bit */ + gain = mad_bit_read(ptr, 9); /* gain*10 */ + if (gain && name == 2 && orig != 0) { + lame->album_gain = ((sign ? -gain : gain) / 10.0) + adj; + g_debug("LAME album gain found: %f\n", lame->track_gain); + } +#else + mad_bit_read(ptr, 16); +#endif + + mad_bit_read(ptr, 16); + + lame->encoder_delay = mad_bit_read(ptr, 12); + lame->encoder_padding = mad_bit_read(ptr, 12); + + g_debug("encoder delay is %i, encoder padding is %i\n", + lame->encoder_delay, lame->encoder_padding); + + mad_bit_read(ptr, 80); + + lame->crc = mad_bit_read(ptr, 16); + + *bitlen -= 216; + + return true; +} + +static inline float +mp3_frame_duration(const struct mad_frame *frame) +{ + return mad_timer_count(frame->header.duration, + MAD_UNITS_MILLISECONDS) / 1000.0; +} + +static off_t +mp3_this_frame_offset(const struct mp3_data *data) +{ + off_t offset = data->input_stream->offset; + + if (data->stream.this_frame != NULL) + offset -= data->stream.bufend - data->stream.this_frame; + else + offset -= data->stream.bufend - data->stream.buffer; + + return offset; +} + +static off_t +mp3_rest_including_this_frame(const struct mp3_data *data) +{ + return data->input_stream->size - mp3_this_frame_offset(data); +} + +/** + * Attempt to calulcate the length of the song from filesize + */ +static void +mp3_filesize_to_song_length(struct mp3_data *data) +{ + off_t rest = mp3_rest_including_this_frame(data); + + if (rest > 0) { + float frame_duration = mp3_frame_duration(&data->frame); + + data->total_time = (rest * 8.0) / (data->frame).header.bitrate; + data->max_frames = data->total_time / frame_duration + + FRAMES_CUSHION; + } else { + data->max_frames = FRAMES_CUSHION; + data->total_time = 0; + } +} + +static bool +mp3_decode_first_frame(struct mp3_data *data, struct tag **tag, + struct replay_gain_info **replay_gain_info_r) +{ + struct xing xing; + struct lame lame; + struct mad_bitptr ptr; + int bitlen; + enum mp3_action ret; + + /* stfu gcc */ + memset(&xing, 0, sizeof(struct xing)); + xing.flags = 0; + + while (true) { + do { + ret = decode_next_frame_header(data, tag, + replay_gain_info_r); + } while (ret == DECODE_CONT); + if (ret == DECODE_BREAK) + return false; + if (ret == DECODE_SKIP) continue; + + do { + ret = decodeNextFrame(data); + } while (ret == DECODE_CONT); + if (ret == DECODE_BREAK) + return false; + if (ret == DECODE_OK) break; + } + + ptr = data->stream.anc_ptr; + bitlen = data->stream.anc_bitlen; + + mp3_filesize_to_song_length(data); + + /* + * if an xing tag exists, use that! + */ + if (parse_xing(&xing, &ptr, &bitlen)) { + data->found_xing = true; + data->mute_frame = MUTEFRAME_SKIP; + + if ((xing.flags & XING_FRAMES) && xing.frames) { + mad_timer_t duration = data->frame.header.duration; + mad_timer_multiply(&duration, xing.frames); + data->total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000; + data->max_frames = xing.frames; + } + + if (parse_lame(&lame, &ptr, &bitlen)) { + if (gapless_playback && + data->input_stream->seekable) { + data->drop_start_samples = lame.encoder_delay + + DECODERDELAY; + data->drop_end_samples = lame.encoder_padding; + } + + /* Album gain isn't currently used. See comment in + * parse_lame() for details. -- jat */ + if (replay_gain_info_r && !*replay_gain_info_r && + 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; + } + } + } + + if (!data->max_frames) + return false; + + if (data->max_frames > 8 * 1024 * 1024) { + g_warning("mp3 file header indicates too many frames: %lu\n", + data->max_frames); + return false; + } + + data->frame_offsets = g_malloc(sizeof(long) * data->max_frames); + data->times = g_malloc(sizeof(mad_timer_t) * data->max_frames); + + return true; +} + +static void mp3_data_finish(struct mp3_data *data) +{ + mad_synth_finish(&data->synth); + mad_frame_finish(&data->frame); + mad_stream_finish(&data->stream); + + g_free(data->frame_offsets); + g_free(data->times); +} + +/* this is primarily used for getting total time for tags */ +static int mp3_total_file_time(const char *file) +{ + 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)) + 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) +{ + mp3_data_init(data, decoder, is); + *tag = NULL; + if (!mp3_decode_first_frame(data, tag, replay_gain_info_r)) { + mp3_data_finish(data); + if (tag && *tag) + tag_free(*tag); + return false; + } + + return true; +} + +static long +mp3_time_to_frame(const struct mp3_data *data, double t) +{ + unsigned long i; + + for (i = 0; i < data->highest_frame; ++i) { + double frame_time = + mad_timer_count(data->times[i], + MAD_UNITS_MILLISECONDS) / 1000.; + if (frame_time >= t) + break; + } + + return i; +} + +static void +mp3_update_timer_next_frame(struct mp3_data *data) +{ + if (data->current_frame >= data->highest_frame) { + /* record this frame's properties in + data->frame_offsets (for seeking) and + data->times */ + data->bit_rate = (data->frame).header.bitrate; + + if (data->current_frame >= data->max_frames) + /* cap data->current_frame */ + data->current_frame = data->max_frames - 1; + else + data->highest_frame++; + + data->frame_offsets[data->current_frame] = + mp3_this_frame_offset(data); + + mad_timer_add(&data->timer, (data->frame).header.duration); + data->times[data->current_frame] = data->timer; + } else + /* get the new timer value from data->times */ + data->timer = data->times[data->current_frame]; + + data->current_frame++; + data->elapsed_time = + mad_timer_count(data->timer, MAD_UNITS_MILLISECONDS) / 1000.0; +} + +/** + * 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) +{ + unsigned max_samples; + + max_samples = sizeof(data->output_buffer) / + sizeof(data->output_buffer[0]) / + MAD_NCHANNELS(&(data->frame).header); + + while (i < pcm_length) { + enum decoder_command cmd; + unsigned int num_samples = pcm_length - i; + if (num_samples > max_samples) + num_samples = max_samples; + + i += num_samples; + + mad_fixed_to_24_buffer(data->output_buffer, + &data->synth, + i - num_samples, i, + MAD_NCHANNELS(&(data->frame).header)); + num_samples *= MAD_NCHANNELS(&(data->frame).header); + + 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); + if (cmd != DECODE_COMMAND_NONE) + return cmd; + } + + return DECODE_COMMAND_NONE; +} + +/** + * 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) +{ + unsigned i, pcm_length; + enum decoder_command cmd; + + mad_synth_frame(&data->synth, &data->frame); + + if (!data->found_first_frame) { + unsigned int samples_per_frame = data->synth.pcm.length; + data->drop_start_frames = data->drop_start_samples / samples_per_frame; + data->drop_end_frames = data->drop_end_samples / samples_per_frame; + data->drop_start_samples = data->drop_start_samples % samples_per_frame; + data->drop_end_samples = data->drop_end_samples % samples_per_frame; + data->found_first_frame = true; + } + + if (data->drop_start_frames > 0) { + data->drop_start_frames--; + return DECODE_COMMAND_NONE; + } else if ((data->drop_end_frames > 0) && + (data->current_frame == (data->max_frames + 1 - data->drop_end_frames))) { + /* stop decoding, effectively dropping all remaining + frames */ + return DECODE_COMMAND_STOP; + } + + if (!data->decoded_first_frame) { + i = data->drop_start_samples; + data->decoded_first_frame = true; + } else + i = 0; + + pcm_length = data->synth.pcm.length; + if (data->drop_end_samples && + (data->current_frame == data->max_frames - data->drop_end_frames)) { + if (data->drop_end_samples >= pcm_length) + pcm_length = 0; + else + pcm_length -= data->drop_end_samples; + } + + cmd = mp3_send_pcm(data, i, pcm_length, replay_gain_info); + if (cmd != DECODE_COMMAND_NONE) + return cmd; + + if (data->drop_end_samples && + (data->current_frame == data->max_frames - data->drop_end_frames)) + /* stop decoding, effectively dropping + * all remaining samples */ + return DECODE_COMMAND_STOP; + + return DECODE_COMMAND_NONE; +} + +static bool +mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r) +{ + struct decoder *decoder = data->decoder; + enum mp3_action ret; + enum decoder_command cmd; + + mp3_update_timer_next_frame(data); + + switch (data->mute_frame) { + case MUTEFRAME_SKIP: + data->mute_frame = MUTEFRAME_NONE; + break; + case MUTEFRAME_SEEK: + if (data->elapsed_time >= data->seek_where) + 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); + if (cmd == DECODE_COMMAND_SEEK) { + unsigned long j; + + assert(data->input_stream->seekable); + + j = mp3_time_to_frame(data, + decoder_seek_where(decoder)); + if (j < data->highest_frame) { + if (mp3_seek(data, data->frame_offsets[j])) { + data->current_frame = j; + decoder_command_finished(decoder); + } else + decoder_seek_error(decoder); + } else { + data->seek_where = decoder_seek_where(decoder); + data->mute_frame = MUTEFRAME_SEEK; + decoder_command_finished(decoder); + } + } else if (cmd != DECODE_COMMAND_NONE) + return false; + } + + while (true) { + bool skip = false; + + do { + struct tag *tag = NULL; + + ret = decode_next_frame_header(data, &tag, + replay_gain_info_r); + + if (tag != NULL) { + decoder_tag(decoder, data->input_stream, tag); + tag_free(tag); + } + } while (ret == DECODE_CONT); + if (ret == DECODE_BREAK) + return false; + else if (ret == DECODE_SKIP) + skip = true; + + if (data->mute_frame == MUTEFRAME_NONE) { + do { + ret = decodeNextFrame(data); + } while (ret == DECODE_CONT); + if (ret == DECODE_BREAK) + return false; + } + + if (!skip && ret == DECODE_OK) + break; + } + + 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; + 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 (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); + + decoder_initialized(decoder, &audio_format, + data.input_stream->seekable, data.total_time); + + if (tag != NULL) { + decoder_tag(decoder, input_stream, tag); + tag_free(tag); + } + + while (mp3_read(&data, &replay_gain_info)) ; + + if (replay_gain_info) + replay_gain_info_free(replay_gain_info); + + if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK && + data.mute_frame == MUTEFRAME_SEEK) + decoder_command_finished(decoder); + + mp3_data_finish(&data); +} + +static struct tag *mp3_tag_dup(const char *file) +{ + struct tag *tag; + int total_time; + + total_time = mp3_total_file_time(file); + if (total_time < 0) { + g_debug("mp3_tag_dup: Failed to get total song time from: %s\n", + file); + return NULL; + } + + tag = tag_new(); + tag->time = total_time; + return tag; +} + +static const char *const mp3_suffixes[] = { "mp3", "mp2", NULL }; +static const char *const mp3_mime_types[] = { "audio/mpeg", NULL }; + +const struct decoder_plugin mad_decoder_plugin = { + .name = "mad", + .init = mp3_plugin_init, + .stream_decode = mp3_decode, + .tag_dup = mp3_tag_dup, + .suffixes = mp3_suffixes, + .mime_types = mp3_mime_types +}; diff --git a/src/decoder/mp3_plugin.c b/src/decoder/mp3_plugin.c deleted file mode 100644 index 9956435c9..000000000 --- a/src/decoder/mp3_plugin.c +++ /dev/null @@ -1,1218 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "../decoder_api.h" -#include "../conf.h" -#include "config.h" -#include "tag_id3.h" - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_ID3TAG -#include -#endif - -#define FRAMES_CUSHION 2000 - -#define READ_BUFFER_SIZE 40960 - -enum mp3_action { - DECODE_SKIP = -3, - DECODE_BREAK = -2, - DECODE_CONT = -1, - DECODE_OK = 0 -}; - -enum muteframe { - MUTEFRAME_NONE, - MUTEFRAME_SKIP, - MUTEFRAME_SEEK -}; - -/* the number of samples of silence the decoder inserts at start */ -#define DECODERDELAY 529 - -#define DEFAULT_GAPLESS_MP3_PLAYBACK true - -static bool gapless_playback; - -static inline int32_t -mad_fixed_to_24_sample(mad_fixed_t sample) -{ - enum { - bits = 24, - MIN = -MAD_F_ONE, - MAX = MAD_F_ONE - 1 - }; - - /* round */ - sample = sample + (1L << (MAD_F_FRACBITS - bits)); - - /* clip */ - if (sample > MAX) - sample = MAX; - else if (sample < MIN) - sample = MIN; - - /* quantize */ - return sample >> (MAD_F_FRACBITS + 1 - bits); -} - -static void -mad_fixed_to_24_buffer(int32_t *dest, const struct mad_synth *synth, - unsigned int start, unsigned int end, - unsigned int num_channels) -{ - unsigned int i, c; - - for (i = start; i < end; ++i) { - for (c = 0; c < num_channels; ++c) - *dest++ = mad_fixed_to_24_sample(synth->pcm.samples[c][i]); - } -} - -static bool -mp3_plugin_init(G_GNUC_UNUSED const struct config_param *param) -{ - gapless_playback = config_get_bool(CONF_GAPLESS_MP3_PLAYBACK, - DEFAULT_GAPLESS_MP3_PLAYBACK); - return true; -} - -#define MP3_DATA_OUTPUT_BUFFER_SIZE 2048 - -struct mp3_data { - struct mad_stream stream; - struct mad_frame frame; - struct mad_synth synth; - mad_timer_t timer; - unsigned char input_buffer[READ_BUFFER_SIZE]; - int32_t output_buffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; - float total_time; - float elapsed_time; - float seek_where; - enum muteframe mute_frame; - long *frame_offsets; - mad_timer_t *times; - unsigned long highest_frame; - unsigned long max_frames; - unsigned long current_frame; - unsigned int drop_start_frames; - unsigned int drop_end_frames; - unsigned int drop_start_samples; - unsigned int drop_end_samples; - bool found_xing; - bool found_first_frame; - bool decoded_first_frame; - unsigned long bit_rate; - struct decoder *decoder; - struct input_stream *input_stream; - enum mad_layer layer; -}; - -static void -mp3_data_init(struct mp3_data *data, struct decoder *decoder, - struct input_stream *input_stream) -{ - data->mute_frame = MUTEFRAME_NONE; - data->highest_frame = 0; - data->max_frames = 0; - data->frame_offsets = NULL; - data->times = NULL; - data->current_frame = 0; - data->drop_start_frames = 0; - data->drop_end_frames = 0; - data->drop_start_samples = 0; - data->drop_end_samples = 0; - data->found_xing = false; - data->found_first_frame = false; - data->decoded_first_frame = false; - data->decoder = decoder; - data->input_stream = input_stream; - data->layer = 0; - - mad_stream_init(&data->stream); - mad_stream_options(&data->stream, MAD_OPTION_IGNORECRC); - mad_frame_init(&data->frame); - mad_synth_init(&data->synth); - mad_timer_reset(&data->timer); -} - -static bool mp3_seek(struct mp3_data *data, long offset) -{ - if (!input_stream_seek(data->input_stream, offset, SEEK_SET)) - return false; - - mad_stream_buffer(&data->stream, data->input_buffer, 0); - (data->stream).error = 0; - - return true; -} - -static bool -mp3_fill_buffer(struct mp3_data *data) -{ - size_t remaining, length; - unsigned char *dest; - - if (data->stream.next_frame != NULL) { - remaining = data->stream.bufend - data->stream.next_frame; - memmove(data->input_buffer, data->stream.next_frame, - remaining); - dest = (data->input_buffer) + remaining; - length = READ_BUFFER_SIZE - remaining; - } else { - remaining = 0; - length = READ_BUFFER_SIZE; - dest = data->input_buffer; - } - - /* we've exhausted the read buffer, so give up!, these potential - * mp3 frames are way too big, and thus unlikely to be mp3 frames */ - if (length == 0) - return false; - - length = decoder_read(data->decoder, data->input_stream, dest, length); - if (length == 0) - return false; - - mad_stream_buffer(&data->stream, data->input_buffer, - length + remaining); - (data->stream).error = 0; - - return true; -} - -#ifdef HAVE_ID3TAG -/* Parse mp3 RVA2 frame. Shamelessly stolen from madplay. */ -static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gain_info) -{ - struct id3_frame const * frame; - - id3_latin1_t const *id; - id3_byte_t const *data; - id3_length_t length; - int found; - - enum { - CHANNEL_OTHER = 0x00, - CHANNEL_MASTER_VOLUME = 0x01, - CHANNEL_FRONT_RIGHT = 0x02, - CHANNEL_FRONT_LEFT = 0x03, - CHANNEL_BACK_RIGHT = 0x04, - CHANNEL_BACK_LEFT = 0x05, - CHANNEL_FRONT_CENTRE = 0x06, - CHANNEL_BACK_CENTRE = 0x07, - CHANNEL_SUBWOOFER = 0x08 - }; - - found = 0; - - /* relative volume adjustment information */ - - frame = id3_tag_findframe(tag, "RVA2", 0); - if (!frame) return 0; - - id = id3_field_getlatin1(id3_frame_field(frame, 0)); - data = id3_field_getbinarydata(id3_frame_field(frame, 1), - &length); - - if (!id || !data) return 0; - - /* - * "The 'identification' string is used to identify the - * situation and/or device where this adjustment should apply. - * The following is then repeated for every channel - * - * Type of channel $xx - * Volume adjustment $xx xx - * Bits representing peak $xx - * Peak volume $xx (xx ...)" - */ - - while (length >= 4) { - unsigned int peak_bytes; - - peak_bytes = (data[3] + 7) / 8; - if (4 + peak_bytes > length) - break; - - if (data[0] == CHANNEL_MASTER_VOLUME) { - signed int voladj_fixed; - double voladj_float; - - /* - * "The volume adjustment is encoded as a fixed - * point decibel value, 16 bit signed integer - * representing (adjustment*512), giving +/- 64 - * dB with a precision of 0.001953125 dB." - */ - - voladj_fixed = (data[1] << 8) | (data[2] << 0); - voladj_fixed |= -(voladj_fixed & 0x8000); - - voladj_float = (double) voladj_fixed / 512; - - replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = voladj_float; - replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = voladj_float; - - g_debug("parseRVA2: Relative Volume " - "%+.1f dB adjustment (%s)\n", - voladj_float, id); - - found = 1; - break; - } - - data += 4 + peak_bytes; - length -= 4 + peak_bytes; - } - - return found; -} -#endif - -#ifdef HAVE_ID3TAG -static struct replay_gain_info * -parse_id3_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(); - - 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 (strcasecmp(key, "replaygain_track_gain") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = atof(value); - found = true; - } else if (strcasecmp(key, "replaygain_album_gain") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_ALBUM].gain = atof(value); - found = true; - } else if (strcasecmp(key, "replaygain_track_peak") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = atof(value); - found = true; - } else if (strcasecmp(key, "replaygain_album_peak") == 0) { - replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = atof(value); - found = true; - } - - free(key); - free(value); - } - - if (!found) { - /* fall back on RVA2 if no replaygain tags found */ - found = parse_rva2(tag, replay_gain_info); - } - - if (found) - return replay_gain_info; - replay_gain_info_free(replay_gain_info); - return NULL; -} -#endif - -#ifdef HAVE_ID3TAG -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 id3_tag *id3_tag = NULL; - id3_length_t count; - id3_byte_t const *id3_data; - id3_byte_t *allocated = NULL; - - count = data->stream.bufend - data->stream.this_frame; - - if (tagsize <= count) { - id3_data = data->stream.this_frame; - mad_stream_skip(&(data->stream), tagsize); - } else { - allocated = g_malloc(tagsize); - memcpy(allocated, data->stream.this_frame, count); - mad_stream_skip(&(data->stream), count); - - while (count < tagsize) { - size_t len; - - len = decoder_read(data->decoder, data->input_stream, - allocated + count, tagsize - count); - if (len == 0) - break; - else - count += len; - } - - if (count != tagsize) { - g_debug("mp3_decode: error parsing ID3 tag\n"); - g_free(allocated); - return; - } - - id3_data = allocated; - } - - id3_tag = id3_tag_parse(id3_data, tagsize); - if (id3_tag == NULL) { - g_free(allocated); - return; - } - - if (mpd_tag) { - struct tag *tmp_tag = tag_id3_import(id3_tag); - if (tmp_tag != NULL) { - if (*mpd_tag != NULL) - tag_free(*mpd_tag); - *mpd_tag = tmp_tag; - } - } - - 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; - } - } - - id3_tag_delete(id3_tag); - - g_free(allocated); -} -#endif - -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) -{ - enum mad_layer layer; - - if ((data->stream).buffer == NULL - || (data->stream).error == MAD_ERROR_BUFLEN) { - if (!mp3_fill_buffer(data)) - return DECODE_BREAK; - } - if (mad_header_decode(&data->frame.header, &data->stream)) { -#ifdef HAVE_ID3TAG - if ((data->stream).error == MAD_ERROR_LOSTSYNC && - (data->stream).this_frame) { - signed long tagsize = id3_tag_query((data->stream). - this_frame, - (data->stream). - bufend - - (data->stream). - this_frame); - - if (tagsize > 0) { - if (tag && !(*tag)) { - mp3_parse_id3(data, (size_t)tagsize, - tag, replay_gain_info_r); - } else { - mad_stream_skip(&(data->stream), - tagsize); - } - return DECODE_CONT; - } - } -#endif - if (MAD_RECOVERABLE((data->stream).error)) { - return DECODE_SKIP; - } else { - if ((data->stream).error == MAD_ERROR_BUFLEN) - return DECODE_CONT; - else { - g_warning("unrecoverable frame level error " - "(%s).\n", - mad_stream_errorstr(&data->stream)); - return DECODE_BREAK; - } - } - } - - layer = data->frame.header.layer; - if (!data->layer) { - if (layer != MAD_LAYER_II && layer != MAD_LAYER_III) { - /* Only layer 2 and 3 have been tested to work */ - return DECODE_SKIP; - } - data->layer = layer; - } else if (layer != data->layer) { - /* Don't decode frames with a different layer than the first */ - return DECODE_SKIP; - } - - return DECODE_OK; -} - -static enum mp3_action -decodeNextFrame(struct mp3_data *data) -{ - if ((data->stream).buffer == NULL - || (data->stream).error == MAD_ERROR_BUFLEN) { - if (!mp3_fill_buffer(data)) - return DECODE_BREAK; - } - if (mad_frame_decode(&data->frame, &data->stream)) { -#ifdef HAVE_ID3TAG - if ((data->stream).error == MAD_ERROR_LOSTSYNC) { - signed long tagsize = id3_tag_query((data->stream). - this_frame, - (data->stream). - bufend - - (data->stream). - this_frame); - if (tagsize > 0) { - mad_stream_skip(&(data->stream), tagsize); - return DECODE_CONT; - } - } -#endif - if (MAD_RECOVERABLE((data->stream).error)) { - return DECODE_SKIP; - } else { - if ((data->stream).error == MAD_ERROR_BUFLEN) - return DECODE_CONT; - else { - g_warning("unrecoverable frame level error " - "(%s).\n", - mad_stream_errorstr(&data->stream)); - return DECODE_BREAK; - } - } - } - - return DECODE_OK; -} - -/* xing stuff stolen from alsaplayer, and heavily modified by jat */ -#define XI_MAGIC (('X' << 8) | 'i') -#define NG_MAGIC (('n' << 8) | 'g') -#define IN_MAGIC (('I' << 8) | 'n') -#define FO_MAGIC (('f' << 8) | 'o') - -enum xing_magic { - XING_MAGIC_XING, /* VBR */ - XING_MAGIC_INFO /* CBR */ -}; - -struct xing { - long flags; /* valid fields (see below) */ - unsigned long frames; /* total number of frames */ - unsigned long bytes; /* total number of bytes */ - unsigned char toc[100]; /* 100-point seek table */ - long scale; /* VBR quality */ - enum xing_magic magic; /* header magic */ -}; - -enum { - XING_FRAMES = 0x00000001L, - XING_BYTES = 0x00000002L, - XING_TOC = 0x00000004L, - XING_SCALE = 0x00000008L -}; - -struct version { - unsigned major; - unsigned minor; -}; - -struct lame { - char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */ - struct version version; /* struct containing just the version */ - float peak; /* replaygain peak */ - float track_gain; /* replaygain track gain */ - float album_gain; /* replaygain album gain */ - int encoder_delay; /* # of added samples at start of mp3 */ - int encoder_padding; /* # of added samples at end of mp3 */ - int crc; /* CRC of the first 190 bytes of this frame */ -}; - -static bool -parse_xing(struct xing *xing, struct mad_bitptr *ptr, int *oldbitlen) -{ - unsigned long bits; - int bitlen; - int bitsleft; - int i; - - bitlen = *oldbitlen; - - if (bitlen < 16) - return false; - - bits = mad_bit_read(ptr, 16); - bitlen -= 16; - - if (bits == XI_MAGIC) { - if (bitlen < 16) - return false; - - if (mad_bit_read(ptr, 16) != NG_MAGIC) - return false; - - bitlen -= 16; - xing->magic = XING_MAGIC_XING; - } else if (bits == IN_MAGIC) { - if (bitlen < 16) - return false; - - if (mad_bit_read(ptr, 16) != FO_MAGIC) - return false; - - bitlen -= 16; - xing->magic = XING_MAGIC_INFO; - } - else if (bits == NG_MAGIC) xing->magic = XING_MAGIC_XING; - else if (bits == FO_MAGIC) xing->magic = XING_MAGIC_INFO; - else - return false; - - if (bitlen < 32) - return false; - xing->flags = mad_bit_read(ptr, 32); - bitlen -= 32; - - if (xing->flags & XING_FRAMES) { - if (bitlen < 32) - return false; - xing->frames = mad_bit_read(ptr, 32); - bitlen -= 32; - } - - if (xing->flags & XING_BYTES) { - if (bitlen < 32) - return false; - xing->bytes = mad_bit_read(ptr, 32); - bitlen -= 32; - } - - if (xing->flags & XING_TOC) { - if (bitlen < 800) - return false; - for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(ptr, 8); - bitlen -= 800; - } - - if (xing->flags & XING_SCALE) { - if (bitlen < 32) - return false; - xing->scale = mad_bit_read(ptr, 32); - bitlen -= 32; - } - - /* Make sure we consume no less than 120 bytes (960 bits) in hopes that - * the LAME tag is found there, and not right after the Xing header */ - bitsleft = 960 - ((*oldbitlen) - bitlen); - if (bitsleft < 0) - return false; - else if (bitsleft > 0) { - mad_bit_read(ptr, bitsleft); - bitlen -= bitsleft; - } - - *oldbitlen = bitlen; - - return true; -} - -static bool -parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) -{ - int adj = 0; - int name; - int orig; - int sign; - int gain; - int i; - - /* Unlike the xing header, the lame tag has a fixed length. Fail if - * not all 36 bytes (288 bits) are there. */ - if (*bitlen < 288) - return false; - - for (i = 0; i < 9; i++) - lame->encoder[i] = (char)mad_bit_read(ptr, 8); - lame->encoder[9] = '\0'; - - *bitlen -= 72; - - /* This is technically incorrect, since the encoder might not be lame. - * But there's no other way to determine if this is a lame tag, and we - * wouldn't want to go reading a tag that's not there. */ - if (!g_str_has_prefix(lame->encoder, "LAME")) - return false; - - if (sscanf(lame->encoder+4, "%u.%u", - &lame->version.major, &lame->version.minor) != 2) - return false; - - g_debug("detected LAME version %i.%i (\"%s\")\n", - lame->version.major, lame->version.minor, lame->encoder); - - /* The reference volume was changed from the 83dB used in the - * ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older - * versions, since everyone else uses 89dB instead of 83dB. - * Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so - * it's impossible to make the proper adjustment for 3.95. - * Fortunately, 3.95 was only out for about a day before 3.95.1 was - * released. -- tmz */ - if (lame->version.major < 3 || - (lame->version.major == 3 && lame->version.minor < 95)) - adj = 6; - - mad_bit_read(ptr, 16); - - lame->peak = mad_f_todouble(mad_bit_read(ptr, 32) << 5); /* peak */ - g_debug("LAME peak found: %f\n", lame->peak); - - lame->track_gain = 0; - name = mad_bit_read(ptr, 3); /* gain name */ - orig = mad_bit_read(ptr, 3); /* gain originator */ - sign = mad_bit_read(ptr, 1); /* sign bit */ - gain = mad_bit_read(ptr, 9); /* gain*10 */ - if (gain && name == 1 && orig != 0) { - lame->track_gain = ((sign ? -gain : gain) / 10.0) + adj; - g_debug("LAME track gain found: %f\n", lame->track_gain); - } - - /* tmz reports that this isn't currently written by any version of lame - * (as of 3.97). Since we have no way of testing it, don't use it. - * Wouldn't want to go blowing someone's ears just because we read it - * wrong. :P -- jat */ - lame->album_gain = 0; -#if 0 - name = mad_bit_read(ptr, 3); /* gain name */ - orig = mad_bit_read(ptr, 3); /* gain originator */ - sign = mad_bit_read(ptr, 1); /* sign bit */ - gain = mad_bit_read(ptr, 9); /* gain*10 */ - if (gain && name == 2 && orig != 0) { - lame->album_gain = ((sign ? -gain : gain) / 10.0) + adj; - g_debug("LAME album gain found: %f\n", lame->track_gain); - } -#else - mad_bit_read(ptr, 16); -#endif - - mad_bit_read(ptr, 16); - - lame->encoder_delay = mad_bit_read(ptr, 12); - lame->encoder_padding = mad_bit_read(ptr, 12); - - g_debug("encoder delay is %i, encoder padding is %i\n", - lame->encoder_delay, lame->encoder_padding); - - mad_bit_read(ptr, 80); - - lame->crc = mad_bit_read(ptr, 16); - - *bitlen -= 216; - - return true; -} - -static inline float -mp3_frame_duration(const struct mad_frame *frame) -{ - return mad_timer_count(frame->header.duration, - MAD_UNITS_MILLISECONDS) / 1000.0; -} - -static off_t -mp3_this_frame_offset(const struct mp3_data *data) -{ - off_t offset = data->input_stream->offset; - - if (data->stream.this_frame != NULL) - offset -= data->stream.bufend - data->stream.this_frame; - else - offset -= data->stream.bufend - data->stream.buffer; - - return offset; -} - -static off_t -mp3_rest_including_this_frame(const struct mp3_data *data) -{ - return data->input_stream->size - mp3_this_frame_offset(data); -} - -/** - * Attempt to calulcate the length of the song from filesize - */ -static void -mp3_filesize_to_song_length(struct mp3_data *data) -{ - off_t rest = mp3_rest_including_this_frame(data); - - if (rest > 0) { - float frame_duration = mp3_frame_duration(&data->frame); - - data->total_time = (rest * 8.0) / (data->frame).header.bitrate; - data->max_frames = data->total_time / frame_duration + - FRAMES_CUSHION; - } else { - data->max_frames = FRAMES_CUSHION; - data->total_time = 0; - } -} - -static bool -mp3_decode_first_frame(struct mp3_data *data, struct tag **tag, - struct replay_gain_info **replay_gain_info_r) -{ - struct xing xing; - struct lame lame; - struct mad_bitptr ptr; - int bitlen; - enum mp3_action ret; - - /* stfu gcc */ - memset(&xing, 0, sizeof(struct xing)); - xing.flags = 0; - - while (true) { - do { - ret = decode_next_frame_header(data, tag, - replay_gain_info_r); - } while (ret == DECODE_CONT); - if (ret == DECODE_BREAK) - return false; - if (ret == DECODE_SKIP) continue; - - do { - ret = decodeNextFrame(data); - } while (ret == DECODE_CONT); - if (ret == DECODE_BREAK) - return false; - if (ret == DECODE_OK) break; - } - - ptr = data->stream.anc_ptr; - bitlen = data->stream.anc_bitlen; - - mp3_filesize_to_song_length(data); - - /* - * if an xing tag exists, use that! - */ - if (parse_xing(&xing, &ptr, &bitlen)) { - data->found_xing = true; - data->mute_frame = MUTEFRAME_SKIP; - - if ((xing.flags & XING_FRAMES) && xing.frames) { - mad_timer_t duration = data->frame.header.duration; - mad_timer_multiply(&duration, xing.frames); - data->total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000; - data->max_frames = xing.frames; - } - - if (parse_lame(&lame, &ptr, &bitlen)) { - if (gapless_playback && - data->input_stream->seekable) { - data->drop_start_samples = lame.encoder_delay + - DECODERDELAY; - data->drop_end_samples = lame.encoder_padding; - } - - /* Album gain isn't currently used. See comment in - * parse_lame() for details. -- jat */ - if (replay_gain_info_r && !*replay_gain_info_r && - 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; - } - } - } - - if (!data->max_frames) - return false; - - if (data->max_frames > 8 * 1024 * 1024) { - g_warning("mp3 file header indicates too many frames: %lu\n", - data->max_frames); - return false; - } - - data->frame_offsets = g_malloc(sizeof(long) * data->max_frames); - data->times = g_malloc(sizeof(mad_timer_t) * data->max_frames); - - return true; -} - -static void mp3_data_finish(struct mp3_data *data) -{ - mad_synth_finish(&data->synth); - mad_frame_finish(&data->frame); - mad_stream_finish(&data->stream); - - g_free(data->frame_offsets); - g_free(data->times); -} - -/* this is primarily used for getting total time for tags */ -static int mp3_total_file_time(const char *file) -{ - 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)) - 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) -{ - mp3_data_init(data, decoder, is); - *tag = NULL; - if (!mp3_decode_first_frame(data, tag, replay_gain_info_r)) { - mp3_data_finish(data); - if (tag && *tag) - tag_free(*tag); - return false; - } - - return true; -} - -static long -mp3_time_to_frame(const struct mp3_data *data, double t) -{ - unsigned long i; - - for (i = 0; i < data->highest_frame; ++i) { - double frame_time = - mad_timer_count(data->times[i], - MAD_UNITS_MILLISECONDS) / 1000.; - if (frame_time >= t) - break; - } - - return i; -} - -static void -mp3_update_timer_next_frame(struct mp3_data *data) -{ - if (data->current_frame >= data->highest_frame) { - /* record this frame's properties in - data->frame_offsets (for seeking) and - data->times */ - data->bit_rate = (data->frame).header.bitrate; - - if (data->current_frame >= data->max_frames) - /* cap data->current_frame */ - data->current_frame = data->max_frames - 1; - else - data->highest_frame++; - - data->frame_offsets[data->current_frame] = - mp3_this_frame_offset(data); - - mad_timer_add(&data->timer, (data->frame).header.duration); - data->times[data->current_frame] = data->timer; - } else - /* get the new timer value from data->times */ - data->timer = data->times[data->current_frame]; - - data->current_frame++; - data->elapsed_time = - mad_timer_count(data->timer, MAD_UNITS_MILLISECONDS) / 1000.0; -} - -/** - * 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) -{ - unsigned max_samples; - - max_samples = sizeof(data->output_buffer) / - sizeof(data->output_buffer[0]) / - MAD_NCHANNELS(&(data->frame).header); - - while (i < pcm_length) { - enum decoder_command cmd; - unsigned int num_samples = pcm_length - i; - if (num_samples > max_samples) - num_samples = max_samples; - - i += num_samples; - - mad_fixed_to_24_buffer(data->output_buffer, - &data->synth, - i - num_samples, i, - MAD_NCHANNELS(&(data->frame).header)); - num_samples *= MAD_NCHANNELS(&(data->frame).header); - - 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); - if (cmd != DECODE_COMMAND_NONE) - return cmd; - } - - return DECODE_COMMAND_NONE; -} - -/** - * 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) -{ - unsigned i, pcm_length; - enum decoder_command cmd; - - mad_synth_frame(&data->synth, &data->frame); - - if (!data->found_first_frame) { - unsigned int samples_per_frame = data->synth.pcm.length; - data->drop_start_frames = data->drop_start_samples / samples_per_frame; - data->drop_end_frames = data->drop_end_samples / samples_per_frame; - data->drop_start_samples = data->drop_start_samples % samples_per_frame; - data->drop_end_samples = data->drop_end_samples % samples_per_frame; - data->found_first_frame = true; - } - - if (data->drop_start_frames > 0) { - data->drop_start_frames--; - return DECODE_COMMAND_NONE; - } else if ((data->drop_end_frames > 0) && - (data->current_frame == (data->max_frames + 1 - data->drop_end_frames))) { - /* stop decoding, effectively dropping all remaining - frames */ - return DECODE_COMMAND_STOP; - } - - if (!data->decoded_first_frame) { - i = data->drop_start_samples; - data->decoded_first_frame = true; - } else - i = 0; - - pcm_length = data->synth.pcm.length; - if (data->drop_end_samples && - (data->current_frame == data->max_frames - data->drop_end_frames)) { - if (data->drop_end_samples >= pcm_length) - pcm_length = 0; - else - pcm_length -= data->drop_end_samples; - } - - cmd = mp3_send_pcm(data, i, pcm_length, replay_gain_info); - if (cmd != DECODE_COMMAND_NONE) - return cmd; - - if (data->drop_end_samples && - (data->current_frame == data->max_frames - data->drop_end_frames)) - /* stop decoding, effectively dropping - * all remaining samples */ - return DECODE_COMMAND_STOP; - - return DECODE_COMMAND_NONE; -} - -static bool -mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r) -{ - struct decoder *decoder = data->decoder; - enum mp3_action ret; - enum decoder_command cmd; - - mp3_update_timer_next_frame(data); - - switch (data->mute_frame) { - case MUTEFRAME_SKIP: - data->mute_frame = MUTEFRAME_NONE; - break; - case MUTEFRAME_SEEK: - if (data->elapsed_time >= data->seek_where) - 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); - if (cmd == DECODE_COMMAND_SEEK) { - unsigned long j; - - assert(data->input_stream->seekable); - - j = mp3_time_to_frame(data, - decoder_seek_where(decoder)); - if (j < data->highest_frame) { - if (mp3_seek(data, data->frame_offsets[j])) { - data->current_frame = j; - decoder_command_finished(decoder); - } else - decoder_seek_error(decoder); - } else { - data->seek_where = decoder_seek_where(decoder); - data->mute_frame = MUTEFRAME_SEEK; - decoder_command_finished(decoder); - } - } else if (cmd != DECODE_COMMAND_NONE) - return false; - } - - while (true) { - bool skip = false; - - do { - struct tag *tag = NULL; - - ret = decode_next_frame_header(data, &tag, - replay_gain_info_r); - - if (tag != NULL) { - decoder_tag(decoder, data->input_stream, tag); - tag_free(tag); - } - } while (ret == DECODE_CONT); - if (ret == DECODE_BREAK) - return false; - else if (ret == DECODE_SKIP) - skip = true; - - if (data->mute_frame == MUTEFRAME_NONE) { - do { - ret = decodeNextFrame(data); - } while (ret == DECODE_CONT); - if (ret == DECODE_BREAK) - return false; - } - - if (!skip && ret == DECODE_OK) - break; - } - - 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; - 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 (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); - - decoder_initialized(decoder, &audio_format, - data.input_stream->seekable, data.total_time); - - if (tag != NULL) { - decoder_tag(decoder, input_stream, tag); - tag_free(tag); - } - - while (mp3_read(&data, &replay_gain_info)) ; - - if (replay_gain_info) - replay_gain_info_free(replay_gain_info); - - if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK && - data.mute_frame == MUTEFRAME_SEEK) - decoder_command_finished(decoder); - - mp3_data_finish(&data); -} - -static struct tag *mp3_tag_dup(const char *file) -{ - struct tag *tag; - int total_time; - - total_time = mp3_total_file_time(file); - if (total_time < 0) { - g_debug("mp3_tag_dup: Failed to get total song time from: %s\n", - file); - return NULL; - } - - tag = tag_new(); - tag->time = total_time; - return tag; -} - -static const char *const mp3_suffixes[] = { "mp3", "mp2", NULL }; -static const char *const mp3_mime_types[] = { "audio/mpeg", NULL }; - -const struct decoder_plugin mp3Plugin = { - .name = "mp3", - .init = mp3_plugin_init, - .stream_decode = mp3_decode, - .tag_dup = mp3_tag_dup, - .suffixes = mp3_suffixes, - .mime_types = mp3_mime_types -}; diff --git a/src/decoder_list.c b/src/decoder_list.c index 34dc779c5..b6093a9bc 100644 --- a/src/decoder_list.c +++ b/src/decoder_list.c @@ -26,7 +26,7 @@ #include -extern const struct decoder_plugin mp3Plugin; +extern const struct decoder_plugin mad_decoder_plugin; extern const struct decoder_plugin vorbis_decoder_plugin; extern const struct decoder_plugin flac_decoder_plugin; extern const struct decoder_plugin oggflac_decoder_plugin; @@ -44,7 +44,7 @@ extern const struct decoder_plugin ffmpeg_plugin; static const struct decoder_plugin *const decoder_plugins[] = { #ifdef HAVE_MAD - &mp3Plugin, + &mad_decoder_plugin, #endif #ifdef HAVE_OGGVORBIS &vorbis_decoder_plugin, -- cgit v1.2.3