diff options
author | Max Kellermann <max@duempel.org> | 2008-10-26 11:29:25 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-10-26 11:29:25 +0100 |
commit | e11355f47d545fe523b019481415b1347aecd4bd (patch) | |
tree | f178cd838be280d0517dc0e5910c36cb96a2a80e /src/inputPlugins/wavpack_plugin.c | |
parent | cbc71191f0ed75c5fafad5c387f009c2139a7bed (diff) | |
download | mpd-e11355f47d545fe523b019481415b1347aecd4bd.tar.gz mpd-e11355f47d545fe523b019481415b1347aecd4bd.tar.xz mpd-e11355f47d545fe523b019481415b1347aecd4bd.zip |
renamed src/inputPlugins/ to src/decoder/
These plugins are not input plugins, they are decoder plugins. No
CamelCase in the directory name.
Diffstat (limited to 'src/inputPlugins/wavpack_plugin.c')
-rw-r--r-- | src/inputPlugins/wavpack_plugin.c | 574 |
1 files changed, 0 insertions, 574 deletions
diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c deleted file mode 100644 index 14b7e5f69..000000000 --- a/src/inputPlugins/wavpack_plugin.c +++ /dev/null @@ -1,574 +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 - * - * WavPack support added by Laszlo Ashin <kodest@gmail.com> - * - * 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 "../utils.h" -#include "../log.h" -#include "../path.h" - -#include <wavpack/wavpack.h> - -/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */ -#define CHUNK_SIZE 1020 - -#define ERRORLEN 80 - -static struct { - const char *name; - int type; -} tagtypes[] = { - { "artist", TAG_ITEM_ARTIST }, - { "album", TAG_ITEM_ALBUM }, - { "title", TAG_ITEM_TITLE }, - { "track", TAG_ITEM_TRACK }, - { "name", TAG_ITEM_NAME }, - { "genre", TAG_ITEM_GENRE }, - { "date", TAG_ITEM_DATE }, - { "composer", TAG_ITEM_COMPOSER }, - { "performer", TAG_ITEM_PERFORMER }, - { "comment", TAG_ITEM_COMMENT }, - { "disc", TAG_ITEM_DISC }, - { NULL, 0 } -}; - -/* - * This function has been borrowed from the tiny player found on - * wavpack.com. Modifications were required because mpd only handles - * max 16 bit samples. - */ -static void format_samples_int(int Bps, void *buffer, uint32_t samcnt) -{ - int32_t temp; - uchar *dst = (uchar *)buffer; - int32_t *src = (int32_t *)buffer; - - switch (Bps) { - case 1: - while (samcnt--) - *dst++ = *src++; - break; - case 2: - while (samcnt--) { - temp = *src++; -#ifdef WORDS_BIGENDIAN - *dst++ = (uchar)(temp >> 8); - *dst++ = (uchar)(temp); -#else - *dst++ = (uchar)(temp); - *dst++ = (uchar)(temp >> 8); -#endif - } - break; - case 3: - /* downscale to 16 bits */ - while (samcnt--) { - temp = *src++; -#ifdef WORDS_BIGENDIAN - *dst++ = (uchar)(temp >> 16); - *dst++ = (uchar)(temp >> 8); -#else - *dst++ = (uchar)(temp >> 8); - *dst++ = (uchar)(temp >> 16); -#endif - } - break; - case 4: - /* downscale to 16 bits */ - while (samcnt--) { - temp = *src++; -#ifdef WORDS_BIGENDIAN - *dst++ = (uchar)(temp >> 24); - *dst++ = (uchar)(temp >> 16); - -#else - *dst++ = (uchar)(temp >> 16); - *dst++ = (uchar)(temp >> 24); -#endif - } - break; - } -} - -/* - * This function converts floating point sample data to 16 bit integer. - */ -static void format_samples_float(mpd_unused int Bps, void *buffer, - uint32_t samcnt) -{ - int16_t *dst = (int16_t *)buffer; - float *src = (float *)buffer; - - while (samcnt--) { - *dst++ = (int16_t)(*src++); - } -} - -/* - * This does the main decoding thing. - * Requires an already opened WavpackContext. - */ -static void wavpack_decode(struct decoder * decoder, - WavpackContext *wpc, int canseek, - ReplayGainInfo *replayGainInfo) -{ - struct audio_format audio_format; - void (*format_samples)(int Bps, void *buffer, uint32_t samcnt); - char chunk[CHUNK_SIZE]; - float file_time; - int samplesreq, samplesgot; - int allsamples; - int position, outsamplesize; - int Bps; - - audio_format.sample_rate = WavpackGetSampleRate(wpc); - audio_format.channels = WavpackGetReducedChannels(wpc); - audio_format.bits = WavpackGetBitsPerSample(wpc); - - if (audio_format.bits > 16) - audio_format.bits = 16; - - if ((WavpackGetMode(wpc) & MODE_FLOAT) == MODE_FLOAT) - format_samples = format_samples_float; - else - format_samples = format_samples_int; -/* - if ((WavpackGetMode(wpc) & MODE_WVC) == MODE_WVC) - ERROR("decoding WITH wvc!!!\n"); - else - ERROR("decoding without wvc\n"); -*/ - allsamples = WavpackGetNumSamples(wpc); - Bps = WavpackGetBytesPerSample(wpc); - - outsamplesize = Bps; - if (outsamplesize > 2) - outsamplesize = 2; - outsamplesize *= audio_format.channels; - - samplesreq = sizeof(chunk) / (4 * audio_format.channels); - - decoder_initialized(decoder, &audio_format, - (float)allsamples / audio_format.sample_rate); - - position = 0; - - do { - if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { - if (canseek) { - int where; - - decoder_clear(decoder); - - where = decoder_seek_where(decoder) * - audio_format.sample_rate; - if (WavpackSeekSample(wpc, where)) { - position = where; - decoder_command_finished(decoder); - } else - decoder_seek_error(decoder); - } else { - decoder_seek_error(decoder); - } - } - - if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) - break; - - samplesgot = WavpackUnpackSamples(wpc, - (int32_t *)chunk, samplesreq); - if (samplesgot > 0) { - int bitrate = (int)(WavpackGetInstantBitrate(wpc) / - 1000 + 0.5); - position += samplesgot; - file_time = (float)position / audio_format.sample_rate; - - format_samples(Bps, chunk, - samplesgot * audio_format.channels); - - decoder_data(decoder, NULL, 0, chunk, - samplesgot * outsamplesize, - file_time, bitrate, - replayGainInfo); - } - } while (samplesgot == samplesreq); - - decoder_flush(decoder); -} - -static char *wavpack_tag(WavpackContext *wpc, char *key) -{ - char *value = NULL; - int size; - - size = WavpackGetTagItem(wpc, key, NULL, 0); - if (size > 0) { - size++; - value = xmalloc(size); - if (!value) - return NULL; - WavpackGetTagItem(wpc, key, value, size); - } - - return value; -} - -static ReplayGainInfo *wavpack_replaygain(WavpackContext *wpc) -{ - static char replaygain_track_gain[] = "replaygain_track_gain"; - static char replaygain_album_gain[] = "replaygain_album_gain"; - static char replaygain_track_peak[] = "replaygain_track_peak"; - static char replaygain_album_peak[] = "replaygain_album_peak"; - ReplayGainInfo *replayGainInfo; - int found = 0; - char *value; - - replayGainInfo = newReplayGainInfo(); - - value = wavpack_tag(wpc, replaygain_track_gain); - if (value) { - replayGainInfo->trackGain = atof(value); - free(value); - found = 1; - } - - value = wavpack_tag(wpc, replaygain_album_gain); - if (value) { - replayGainInfo->albumGain = atof(value); - free(value); - found = 1; - } - - value = wavpack_tag(wpc, replaygain_track_peak); - if (value) { - replayGainInfo->trackPeak = atof(value); - free(value); - found = 1; - } - - value = wavpack_tag(wpc, replaygain_album_peak); - if (value) { - replayGainInfo->albumPeak = atof(value); - free(value); - found = 1; - } - - - if (found) - return replayGainInfo; - - freeReplayGainInfo(replayGainInfo); - - return NULL; -} - -/* - * Reads metainfo from the specified file. - */ -static struct tag *wavpack_tagdup(char *fname) -{ - WavpackContext *wpc; - struct tag *tag; - char error[ERRORLEN]; - char *s; - int ssize; - int i, j; - - wpc = WavpackOpenFileInput(fname, error, OPEN_TAGS, 0); - if (wpc == NULL) { - ERROR("failed to open WavPack file \"%s\": %s\n", fname, error); - return NULL; - } - - tag = tag_new(); - tag->time = - (float)WavpackGetNumSamples(wpc) / WavpackGetSampleRate(wpc); - - ssize = 0; - s = NULL; - - for (i = 0; tagtypes[i].name != NULL; ++i) { - j = WavpackGetTagItem(wpc, tagtypes[i].name, NULL, 0); - if (j > 0) { - ++j; - - if (s == NULL) { - s = xmalloc(j); - if (s == NULL) break; - ssize = j; - } else if (j > ssize) { - char *t = (char *)xrealloc(s, j); - if (t == NULL) break; - ssize = j; - s = t; - } - - WavpackGetTagItem(wpc, tagtypes[i].name, s, j); - tag_add_item(tag, tagtypes[i].type, s); - } - } - - if (s != NULL) - free(s); - - WavpackCloseFile(wpc); - - return tag; -} - -/* - * mpd InputStream <=> WavpackStreamReader wrapper callbacks - */ - -/* This struct is needed for per-stream last_byte storage. */ -typedef struct { - struct decoder *decoder; - InputStream *is; - /* Needed for push_back_byte() */ - int last_byte; -} InputStreamPlus; - -static int32_t read_bytes(void *id, void *data, int32_t bcount) -{ - InputStreamPlus *isp = (InputStreamPlus *)id; - uint8_t *buf = (uint8_t *)data; - int32_t i = 0; - - if (isp->last_byte != EOF) { - *buf++ = isp->last_byte; - isp->last_byte = EOF; - --bcount; - ++i; - } - return i + decoder_read(isp->decoder, isp->is, buf, bcount); -} - -static uint32_t get_pos(void *id) -{ - return ((InputStreamPlus *)id)->is->offset; -} - -static int set_pos_abs(void *id, uint32_t pos) -{ - return seekInputStream(((InputStreamPlus *)id)->is, pos, SEEK_SET); -} - -static int set_pos_rel(void *id, int32_t delta, int mode) -{ - return seekInputStream(((InputStreamPlus *)id)->is, delta, mode); -} - -static int push_back_byte(void *id, int c) -{ - ((InputStreamPlus *)id)->last_byte = c; - return 1; -} - -static uint32_t get_length(void *id) -{ - return ((InputStreamPlus *)id)->is->size; -} - -static int can_seek(void *id) -{ - return ((InputStreamPlus *)id)->is->seekable; -} - -static WavpackStreamReader mpd_is_reader = { - .read_bytes = read_bytes, - .get_pos = get_pos, - .set_pos_abs = set_pos_abs, - .set_pos_rel = set_pos_rel, - .push_back_byte = push_back_byte, - .get_length = get_length, - .can_seek = can_seek, - .write_bytes = NULL /* no need to write edited tags */ -}; - -static void -initInputStreamPlus(InputStreamPlus *isp, struct decoder *decoder, - InputStream *is) -{ - isp->decoder = decoder; - isp->is = is; - isp->last_byte = EOF; -} - -/* - * Tries to decode the specified stream, and gives true if managed to do it. - */ -static bool wavpack_trydecode(InputStream *is) -{ - char error[ERRORLEN]; - WavpackContext *wpc; - InputStreamPlus isp; - - initInputStreamPlus(&isp, NULL, is); - wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, NULL, error, - OPEN_STREAMING, 0); - if (wpc == NULL) - return false; - - WavpackCloseFile(wpc); - /* Seek it back in order to play from the first byte. */ - seekInputStream(is, 0, SEEK_SET); - - return true; -} - -static int wavpack_open_wvc(struct decoder *decoder, - InputStream *is_wvc) -{ - char tmp[MPD_PATH_MAX]; - const char *utf8url; - size_t len; - char *wvc_url = NULL; - int ret; - - /* - * As we use dc->utf8url, this function will be bad for - * single files. utf8url is not absolute file path :/ - */ - utf8url = decoder_get_url(decoder, tmp); - if (utf8url == NULL) - return 0; - - len = strlen(utf8url); - if (!len) - return 0; - - wvc_url = (char *)xmalloc(len + 2); /* +2: 'c' and EOS */ - if (wvc_url == NULL) - return 0; - - memcpy(wvc_url, utf8url, len); - wvc_url[len] = 'c'; - wvc_url[len + 1] = '\0'; - - ret = openInputStream(is_wvc, wvc_url); - free(wvc_url); - - if (ret) - return 0; - - /* - * And we try to buffer in order to get know - * about a possible 404 error. - */ - for (;;) { - if (inputStreamAtEOF(is_wvc)) { - /* - * EOF is reached even without - * a single byte is read... - * So, this is not good :/ - */ - closeInputStream(is_wvc); - return 0; - } - - if (bufferInputStream(is_wvc) >= 0) - return 1; - - if (decoder_get_command(decoder) != DECODE_COMMAND_NONE) { - closeInputStream(is_wvc); - return 0; - } - - /* Save some CPU */ - my_usleep(1000); - } -} - -/* - * Decodes a stream. - */ -static int wavpack_streamdecode(struct decoder * decoder, InputStream *is) -{ - char error[ERRORLEN]; - WavpackContext *wpc; - InputStream is_wvc; - int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE /*| OPEN_STREAMING*/; - InputStreamPlus isp, isp_wvc; - - if (wavpack_open_wvc(decoder, &is_wvc)) { - initInputStreamPlus(&isp_wvc, decoder, &is_wvc); - open_flags |= OPEN_WVC; - } - - initInputStreamPlus(&isp, decoder, is); - wpc = WavpackOpenFileInputEx(&mpd_is_reader, &isp, &isp_wvc, error, - open_flags, 15); - - if (wpc == NULL) { - ERROR("failed to open WavPack stream: %s\n", error); - return -1; - } - - wavpack_decode(decoder, wpc, can_seek(&isp), NULL); - - WavpackCloseFile(wpc); - if (open_flags & OPEN_WVC) - closeInputStream(&is_wvc); - closeInputStream(is); - - return 0; -} - -/* - * Decodes a file. - */ -static int wavpack_filedecode(struct decoder * decoder, char *fname) -{ - char error[ERRORLEN]; - WavpackContext *wpc; - ReplayGainInfo *replayGainInfo; - - wpc = WavpackOpenFileInput(fname, error, - OPEN_TAGS | OPEN_WVC | - OPEN_2CH_MAX | OPEN_NORMALIZE, 15); - if (wpc == NULL) { - ERROR("failed to open WavPack file \"%s\": %s\n", fname, error); - return -1; - } - - replayGainInfo = wavpack_replaygain(wpc); - - wavpack_decode(decoder, wpc, 1, replayGainInfo); - - if (replayGainInfo) - freeReplayGainInfo(replayGainInfo); - - WavpackCloseFile(wpc); - - return 0; -} - -static char const *wavpackSuffixes[] = { "wv", NULL }; -static char const *wavpackMimeTypes[] = { "audio/x-wavpack", NULL }; - -struct decoder_plugin wavpackPlugin = { - .name = "wavpack", - .try_decode = wavpack_trydecode, - .stream_decode = wavpack_streamdecode, - .file_decode = wavpack_filedecode, - .tag_dup = wavpack_tagdup, - .stream_types = INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL, - .suffixes = wavpackSuffixes, - .mime_types = wavpackMimeTypes -}; |