diff options
Diffstat (limited to 'src/decoder')
-rw-r--r-- | src/decoder/_flac_common.c | 5 | ||||
-rw-r--r-- | src/decoder/audiofile_plugin.c | 8 | ||||
-rw-r--r-- | src/decoder/faad_plugin.c | 6 | ||||
-rw-r--r-- | src/decoder/ffmpeg_plugin.c | 18 | ||||
-rw-r--r-- | src/decoder/flac_plugin.c | 14 | ||||
-rw-r--r-- | src/decoder/mad_plugin.c | 10 | ||||
-rw-r--r-- | src/decoder/mikmod_plugin.c | 4 | ||||
-rw-r--r-- | src/decoder/modplug_plugin.c | 6 | ||||
-rw-r--r-- | src/decoder/mp4ff_plugin.c | 6 | ||||
-rw-r--r-- | src/decoder/mpcdec_plugin.c | 4 | ||||
-rw-r--r-- | src/decoder/sidplay_plugin.cxx | 4 | ||||
-rw-r--r-- | src/decoder/sndfile_decoder_plugin.c | 244 | ||||
-rw-r--r-- | src/decoder/vorbis_plugin.c | 3 | ||||
-rw-r--r-- | src/decoder/wavpack_plugin.c | 6 |
14 files changed, 287 insertions, 51 deletions
diff --git a/src/decoder/_flac_common.c b/src/decoder/_flac_common.c index e096750f3..09f7269bd 100644 --- a/src/decoder/_flac_common.c +++ b/src/decoder/_flac_common.c @@ -201,9 +201,8 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata * block, switch (block->type) { case FLAC__METADATA_TYPE_STREAMINFO: - data->audio_format.bits = (int8_t)si->bits_per_sample; - data->audio_format.sample_rate = si->sample_rate; - data->audio_format.channels = (int8_t)si->channels; + audio_format_init(&data->audio_format, si->sample_rate, + si->bits_per_sample, si->channels); data->total_time = ((float)si->total_samples) / (si->sample_rate); break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: diff --git a/src/decoder/audiofile_plugin.c b/src/decoder/audiofile_plugin.c index f66d90dc1..b4959f6c2 100644 --- a/src/decoder/audiofile_plugin.c +++ b/src/decoder/audiofile_plugin.c @@ -136,11 +136,9 @@ audiofile_stream_decode(struct decoder *decoder, struct input_stream *is) afSetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bits); afGetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits); - audio_format.bits = (uint8_t)bits; - audio_format.sample_rate = - (unsigned int)afGetRate(af_fp, AF_DEFAULT_TRACK); - audio_format.channels = - (uint8_t)afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK); + + audio_format_init(&audio_format, afGetRate(af_fp, AF_DEFAULT_TRACK), + bits, afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK)); if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", diff --git a/src/decoder/faad_plugin.c b/src/decoder/faad_plugin.c index d0537dd5b..1b8b2b784 100644 --- a/src/decoder/faad_plugin.c +++ b/src/decoder/faad_plugin.c @@ -262,11 +262,7 @@ faad_decoder_init(faacDecHandle decoder, struct decoder_buffer *buffer, decoder_buffer_consume(buffer, nbytes); - *audio_format = (struct audio_format){ - .bits = 16, - .channels = channels, - .sample_rate = sample_rate, - }; + audio_format_init(audio_format, sample_rate, 16, channels); return true; } diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index abccdf977..e6646f649 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -267,6 +267,7 @@ ffmpeg_decode_internal(struct ffmpeg_context *ctx) struct audio_format audio_format; enum decoder_command cmd; int total_time; + uint8_t bits; total_time = 0; @@ -275,13 +276,13 @@ ffmpeg_decode_internal(struct ffmpeg_context *ctx) } #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(41<<8)+0) - audio_format.bits = (uint8_t) av_get_bits_per_sample_format(codec_context->sample_fmt); + bits = (uint8_t) av_get_bits_per_sample_format(codec_context->sample_fmt); #else /* XXX fixme 16-bit for older ffmpeg (13 Aug 2007) */ - audio_format.bits = (uint8_t) 16; + bits = (uint8_t) 16; #endif - audio_format.sample_rate = (unsigned int)codec_context->sample_rate; - audio_format.channels = codec_context->channels; + audio_format_init(&audio_format, codec_context->sample_rate, bits, + codec_context->channels); if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", @@ -342,8 +343,9 @@ static void ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m, enum tag_type type, const char *name) { - AVMetadataTag *mt = av_metadata_get(m, name, NULL, 0); - if (mt != NULL) + AVMetadataTag *mt = NULL; + + while ((mt = av_metadata_get(m, name, mt, 0)) != NULL) tag_add_item(tag, type, mt->value); } #endif @@ -351,13 +353,15 @@ ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m, static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx) { struct tag *tag = (struct tag *) ctx->tag; - const AVFormatContext *f = ctx->format_context; + AVFormatContext *f = ctx->format_context; tag->time = 0; if (f->duration != (int64_t)AV_NOPTS_VALUE) tag->time = f->duration / AV_TIME_BASE; #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) + av_metadata_conv(f, NULL, f->iformat->metadata_conv); + ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_TITLE, "title"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ARTIST, "author"); ffmpeg_copy_metadata(tag, f->metadata, TAG_ITEM_ALBUM, "album"); diff --git a/src/decoder/flac_plugin.c b/src/decoder/flac_plugin.c index 1d7a9f868..89a812f52 100644 --- a/src/decoder/flac_plugin.c +++ b/src/decoder/flac_plugin.c @@ -300,6 +300,8 @@ flac_cue_tag_load(const char *file) FLAC__uint64 track_time = 0; #ifdef HAVE_CUE /* libcue */ FLAC__StreamMetadata* vc = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + char* cs_filename; + FILE* cs_file; #endif /* libcue */ FLAC__StreamMetadata* si = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO); FLAC__StreamMetadata* cs = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET); @@ -328,6 +330,18 @@ flac_cue_tag_load(const char *file) } FLAC__metadata_object_delete(vc); } + + if (tag == NULL) { + cs_filename = g_strconcat(file, ".cue", NULL); + + cs_file = fopen(cs_filename, "rt"); + g_free(cs_filename); + + if (cs_file != NULL) { + tag = cue_tag_file(cs_file, tnum); + fclose(cs_file); + } + } #endif /* libcue */ if (tag == NULL) diff --git a/src/decoder/mad_plugin.c b/src/decoder/mad_plugin.c index 1ef7183fa..c5287564f 100644 --- a/src/decoder/mad_plugin.c +++ b/src/decoder/mad_plugin.c @@ -1170,13 +1170,6 @@ 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) { @@ -1192,7 +1185,8 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream) return; } - mp3_audio_format(&data, &audio_format); + audio_format_init(&audio_format, data.frame.header.samplerate, 24, + MAD_NCHANNELS(&data.frame.header)); decoder_initialized(decoder, &audio_format, data.input_stream->seekable, data.total_time); diff --git a/src/decoder/mikmod_plugin.c b/src/decoder/mikmod_plugin.c index 065c34319..e7b7bfb03 100644 --- a/src/decoder/mikmod_plugin.c +++ b/src/decoder/mikmod_plugin.c @@ -175,9 +175,7 @@ mod_decode(struct decoder *decoder, const char *path) return; } - audio_format.bits = 16; - audio_format.sample_rate = 44100; - audio_format.channels = 2; + audio_format_init(&audio_format, 44100, 16, 2); secPerByte = 1.0 / ((audio_format.bits * audio_format.channels / 8.0) * diff --git a/src/decoder/modplug_plugin.c b/src/decoder/modplug_plugin.c index f636f2fa6..6c375e6a0 100644 --- a/src/decoder/modplug_plugin.c +++ b/src/decoder/modplug_plugin.c @@ -121,9 +121,7 @@ mod_decode(struct decoder *decoder, struct input_stream *is) return; } - audio_format.bits = 16; - audio_format.sample_rate = 44100; - audio_format.channels = 2; + audio_format_init(&audio_format, 44100, 16, 2); sec_perbyte = 1.0 / ((audio_format.bits * audio_format.channels / 8.0) * @@ -186,7 +184,7 @@ static struct tag *mod_tagdup(const char *file) return NULL; } ret = tag_new(); - ret->time = 0; + ret->time = ModPlug_GetLength(f) / 1000; title = g_strdup(ModPlug_GetName(f)); if (title) diff --git a/src/decoder/mp4ff_plugin.c b/src/decoder/mp4ff_plugin.c index cf9382904..d2c63f983 100644 --- a/src/decoder/mp4ff_plugin.c +++ b/src/decoder/mp4ff_plugin.c @@ -131,11 +131,7 @@ mp4_faad_new(mp4ff_t *mp4fh, int *track_r, struct audio_format *audio_format) } *track_r = track; - *audio_format = (struct audio_format){ - .bits = 16, - .channels = channels, - .sample_rate = sample_rate, - }; + audio_format_init(audio_format, sample_rate, 16, channels); if (!audio_format_valid(audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", diff --git a/src/decoder/mpcdec_plugin.c b/src/decoder/mpcdec_plugin.c index 26349f93a..a684da104 100644 --- a/src/decoder/mpcdec_plugin.c +++ b/src/decoder/mpcdec_plugin.c @@ -193,9 +193,7 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is) mpc_demux_get_info(demux, &info); #endif - audio_format.bits = 24; - audio_format.channels = info.channels; - audio_format.sample_rate = info.sample_freq; + audio_format_init(&audio_format, info.sample_freq, 24, info.channels); if (!audio_format_valid(&audio_format)) { #ifndef MPC_IS_OLD_API diff --git a/src/decoder/sidplay_plugin.cxx b/src/decoder/sidplay_plugin.cxx index c62e6b4b6..54ab746e2 100644 --- a/src/decoder/sidplay_plugin.cxx +++ b/src/decoder/sidplay_plugin.cxx @@ -103,9 +103,7 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) /* initialize the MPD decoder */ struct audio_format audio_format; - audio_format.sample_rate = 48000; - audio_format.bits = 16; - audio_format.channels = 2; + audio_format_init(&audio_format, 48000, 16, 2); decoder_initialized(decoder, &audio_format, false, -1); diff --git a/src/decoder/sndfile_decoder_plugin.c b/src/decoder/sndfile_decoder_plugin.c new file mode 100644 index 000000000..4cc64459f --- /dev/null +++ b/src/decoder/sndfile_decoder_plugin.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "decoder_api.h" + +#include <sndfile.h> + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "sndfile" + +static sf_count_t +sndfile_vio_get_filelen(void *user_data) +{ + const struct input_stream *is = user_data; + + return is->size; +} + +static sf_count_t +sndfile_vio_seek(sf_count_t offset, int whence, void *user_data) +{ + struct input_stream *is = user_data; + bool success; + + success = input_stream_seek(is, offset, whence); + if (!success) + return -1; + + return is->offset; +} + +static sf_count_t +sndfile_vio_read(void *ptr, sf_count_t count, void *user_data) +{ + struct input_stream *is = user_data; + size_t nbytes; + + nbytes = input_stream_read(is, ptr, count); + if (nbytes == 0 && is->error != 0) + return -1; + + return nbytes; +} + +static sf_count_t +sndfile_vio_write(G_GNUC_UNUSED const void *ptr, + G_GNUC_UNUSED sf_count_t count, + G_GNUC_UNUSED void *user_data) +{ + /* no writing! */ + return -1; +} + +static sf_count_t +sndfile_vio_tell(void *user_data) +{ + const struct input_stream *is = user_data; + + return is->offset; +} + +/** + * This SF_VIRTUAL_IO implementation wraps MPD's #input_stream to a + * libsndfile stream. + */ +static SF_VIRTUAL_IO vio = { + .get_filelen = sndfile_vio_get_filelen, + .seek = sndfile_vio_seek, + .read = sndfile_vio_read, + .write = sndfile_vio_write, + .tell = sndfile_vio_tell, +}; + +/** + * Converts a frame number to a timestamp (in seconds). + */ +static float +frame_to_time(sf_count_t frame, const struct audio_format *audio_format) +{ + return (float)frame / (float)audio_format->sample_rate; +} + +/** + * Converts a timestamp (in seconds) to a frame number. + */ +static sf_count_t +time_to_frame(float t, const struct audio_format *audio_format) +{ + return (sf_count_t)(t * audio_format->sample_rate); +} + +static void +sndfile_stream_decode(struct decoder *decoder, struct input_stream *is) +{ + SNDFILE *sf; + SF_INFO info; + struct audio_format audio_format; + size_t frame_size; + sf_count_t read_frames, num_frames, position = 0; + int buffer[4096]; + enum decoder_command cmd; + + info.format = 0; + + sf = sf_open_virtual(&vio, SFM_READ, &info, is); + if (sf == NULL) { + g_warning("sf_open_virtual() failed"); + return; + } + + /* for now, always read 32 bit samples. Later, we could lower + MPD's CPU usage by reading 16 bit samples with + sf_readf_short() on low-quality source files. */ + audio_format_init(&audio_format, info.samplerate, 32, info.channels); + + if (!audio_format_valid(&audio_format)) { + g_warning("invalid audio format"); + return; + } + + decoder_initialized(decoder, &audio_format, info.seekable, + frame_to_time(info.frames, &audio_format)); + + frame_size = audio_format_frame_size(&audio_format); + read_frames = sizeof(buffer) / frame_size; + + do { + num_frames = sf_readf_int(sf, buffer, read_frames); + if (num_frames <= 0) + break; + + cmd = decoder_data(decoder, is, + buffer, num_frames * frame_size, + frame_to_time(position, &audio_format), + 0, NULL); + if (cmd == DECODE_COMMAND_SEEK) { + sf_count_t c = + time_to_frame(decoder_seek_where(decoder), + &audio_format); + c = sf_seek(sf, c, SEEK_SET); + if (c < 0) + decoder_seek_error(decoder); + else + decoder_command_finished(decoder); + cmd = DECODE_COMMAND_NONE; + } + } while (cmd == DECODE_COMMAND_NONE); + + sf_close(sf); +} + +static struct tag * +sndfile_tag_dup(const char *path_fs) +{ + SNDFILE *sf; + SF_INFO info; + struct tag *tag; + const char *p; + + info.format = 0; + + sf = sf_open(path_fs, SFM_READ, &info); + if (sf == NULL) + return NULL; + + if (!audio_valid_sample_rate(info.samplerate)) { + sf_close(sf); + g_warning("Invalid sample rate in %s\n", path_fs); + return NULL; + } + + tag = tag_new(); + tag->time = info.frames / info.samplerate; + + p = sf_get_string(sf, SF_STR_TITLE); + if (p != NULL) + tag_add_item(tag, TAG_ITEM_TITLE, p); + + p = sf_get_string(sf, SF_STR_ARTIST); + if (p != NULL) + tag_add_item(tag, TAG_ITEM_ARTIST, p); + + p = sf_get_string(sf, SF_STR_DATE); + if (p != NULL) + tag_add_item(tag, TAG_ITEM_DATE, p); + + sf_close(sf); + + return tag; +} + +static const char *const sndfile_suffixes[] = { + "wav", "aiff", "aif", /* Microsoft / SGI / Apple */ + "au", "snd", /* Sun / DEC / NeXT */ + "paf", /* Paris Audio File */ + "iff", "svx", /* Commodore Amiga IFF / SVX */ + "sf", /* IRCAM */ + "voc", /* Creative */ + "w64", /* Soundforge */ + "pvf", /* Portable Voice Format */ + "xi", /* Fasttracker */ + "htk", /* HMM Tool Kit */ + "caf", /* Apple */ + "sd2", /* Sound Designer II */ + + /* libsndfile also supports FLAC and Ogg Vorbis, but only by + linking with libFLAC and libvorbis - we can do better, we + have native plugins for these libraries */ + + NULL +}; + +static const char *const sndfile_mime_types[] = { + "audio/x-wav", + "audio/x-aiff", + + /* what are the MIME types of the other supported formats? */ + + NULL +}; + +const struct decoder_plugin sndfile_decoder_plugin = { + .name = "sndfile", + .stream_decode = sndfile_stream_decode, + .tag_dup = sndfile_tag_dup, + .suffixes = sndfile_suffixes, + .mime_types = sndfile_mime_types, +}; diff --git a/src/decoder/vorbis_plugin.c b/src/decoder/vorbis_plugin.c index d4f81e91f..bab1d57ec 100644 --- a/src/decoder/vorbis_plugin.c +++ b/src/decoder/vorbis_plugin.c @@ -324,8 +324,7 @@ vorbis_stream_decode(struct decoder *decoder, vorbis_info *vi = ov_info(&vf, -1); struct replay_gain_info *new_rgi; - audio_format.channels = vi->channels; - audio_format.sample_rate = vi->rate; + audio_format_init(&audio_format, vi->rate, 16, vi->channels); if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", diff --git a/src/decoder/wavpack_plugin.c b/src/decoder/wavpack_plugin.c index 821536fb5..f3d701144 100644 --- a/src/decoder/wavpack_plugin.c +++ b/src/decoder/wavpack_plugin.c @@ -145,9 +145,9 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, int bytes_per_sample, output_sample_size; int position; - audio_format.sample_rate = WavpackGetSampleRate(wpc); - audio_format.channels = WavpackGetReducedChannels(wpc); - audio_format.bits = WavpackGetBitsPerSample(wpc); + audio_format_init(&audio_format, WavpackGetSampleRate(wpc), + WavpackGetBitsPerSample(wpc), + WavpackGetReducedChannels(wpc)); /* round bitwidth to 8-bit units */ audio_format.bits = (audio_format.bits + 7) & (~7); |