diff options
Diffstat (limited to 'src/inputPlugins')
-rw-r--r-- | src/inputPlugins/_flac_common.c | 8 | ||||
-rw-r--r-- | src/inputPlugins/_flac_common.h | 4 | ||||
-rw-r--r-- | src/inputPlugins/_ogg_common.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/aac_plugin.c | 359 | ||||
-rw-r--r-- | src/inputPlugins/audiofile_plugin.c | 57 | ||||
-rw-r--r-- | src/inputPlugins/flac_plugin.c | 20 | ||||
-rw-r--r-- | src/inputPlugins/mod_plugin.c | 3 | ||||
-rw-r--r-- | src/inputPlugins/mp3_plugin.c | 212 | ||||
-rw-r--r-- | src/inputPlugins/mp4_plugin.c | 21 | ||||
-rw-r--r-- | src/inputPlugins/mpc_plugin.c | 6 | ||||
-rw-r--r-- | src/inputPlugins/oggflac_plugin.c | 29 | ||||
-rw-r--r-- | src/inputPlugins/oggvorbis_plugin.c | 63 | ||||
-rw-r--r-- | src/inputPlugins/wavpack_plugin.c | 144 |
13 files changed, 509 insertions, 418 deletions
diff --git a/src/inputPlugins/_flac_common.c b/src/inputPlugins/_flac_common.c index 3401a8b4f..6890c7c50 100644 --- a/src/inputPlugins/_flac_common.c +++ b/src/inputPlugins/_flac_common.c @@ -26,12 +26,6 @@ #include "_flac_common.h" #include "../log.h" -#include "../tag.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../decode.h" -#include "../replayGain.h" -#include "../os_compat.h" #include <FLAC/format.h> #include <FLAC/metadata.h> @@ -180,7 +174,7 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata * block, void flac_error_common_cb(const char *plugin, const FLAC__StreamDecoderErrorStatus status, - FlacData * data) + mpd_unused FlacData * data) { if (dc_intr()) return; diff --git a/src/inputPlugins/_flac_common.h b/src/inputPlugins/_flac_common.h index 5c147a064..6fe5bd744 100644 --- a/src/inputPlugins/_flac_common.h +++ b/src/inputPlugins/_flac_common.h @@ -26,10 +26,6 @@ #if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC) -#include "../tag.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../decode.h" #include <FLAC/export.h> #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 # include <FLAC/seekable_stream_decoder.h> diff --git a/src/inputPlugins/_ogg_common.c b/src/inputPlugins/_ogg_common.c index d24b2b47b..a7525c2de 100644 --- a/src/inputPlugins/_ogg_common.c +++ b/src/inputPlugins/_ogg_common.c @@ -28,7 +28,6 @@ (defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7) #include "../utils.h" -#include "../os_compat.h" ogg_stream_type ogg_stream_type_detect(InputStream * inStream) { diff --git a/src/inputPlugins/aac_plugin.c b/src/inputPlugins/aac_plugin.c index 98329a4b3..512e73e53 100644 --- a/src/inputPlugins/aac_plugin.c +++ b/src/inputPlugins/aac_plugin.c @@ -23,66 +23,65 @@ #define AAC_MAX_CHANNELS 6 #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../os_compat.h" #include <faad.h> /* all code here is either based on or copied from FAAD2's frontend code */ typedef struct { InputStream *inStream; - long bytesIntoBuffer; - long bytesConsumed; - long fileOffset; + size_t bytesIntoBuffer; + size_t bytesConsumed; + off_t fileOffset; unsigned char *buffer; int atEof; } AacBuffer; +static void aac_buffer_shift(AacBuffer * b, size_t length) +{ + assert(length >= b->bytesConsumed); + assert(length <= b->bytesConsumed + b->bytesIntoBuffer); + + memmove(b->buffer, b->buffer + length, + b->bytesConsumed + b->bytesIntoBuffer - length); + + length -= b->bytesConsumed; + b->bytesConsumed = 0; + b->bytesIntoBuffer -= length; +} + static void fillAacBuffer(AacBuffer * b) { - if (b->bytesConsumed > 0) { - int bread; + size_t bread; - if (b->bytesIntoBuffer) { - memmove((void *)b->buffer, (void *)(b->buffer + - b->bytesConsumed), - b->bytesIntoBuffer); - } + if (b->bytesIntoBuffer >= FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS) + /* buffer already full */ + return; - if (!b->atEof) { - bread = readFromInputStream(b->inStream, - (void *)(b->buffer + - b-> - bytesIntoBuffer), - 1, b->bytesConsumed); - if (bread != b->bytesConsumed) - b->atEof = 1; - b->bytesIntoBuffer += bread; - } + aac_buffer_shift(b, b->bytesConsumed); - b->bytesConsumed = 0; + if (!b->atEof) { + size_t rest = FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS - + b->bytesIntoBuffer; - if (b->bytesIntoBuffer > 3) { - if (memcmp(b->buffer, "TAG", 3) == 0) - b->bytesIntoBuffer = 0; - } - if (b->bytesIntoBuffer > 11) { - if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0) { - b->bytesIntoBuffer = 0; - } - } - if (b->bytesIntoBuffer > 8) { - if (memcmp(b->buffer, "APETAGEX", 8) == 0) { - b->bytesIntoBuffer = 0; - } - } + bread = readFromInputStream(b->inStream, + (void *)(b->buffer + + b-> + bytesIntoBuffer), + 1, rest); + if (bread == 0 && inputStreamAtEOF(b->inStream)) + b->atEof = 1; + b->bytesIntoBuffer += bread; } + + if ((b->bytesIntoBuffer > 3 && memcmp(b->buffer, "TAG", 3) == 0) || + (b->bytesIntoBuffer > 11 && + memcmp(b->buffer, "LYRICSBEGIN", 11) == 0) || + (b->bytesIntoBuffer > 8 && memcmp(b->buffer, "APETAGEX", 8) == 0)) + b->bytesIntoBuffer = 0; } -static void advanceAacBuffer(AacBuffer * b, int bytes) +static void advanceAacBuffer(AacBuffer * b, size_t bytes) { b->fileOffset += bytes; b->bytesConsumed = bytes; @@ -94,36 +93,76 @@ static int adtsSampleRates[] = 16000, 12000, 11025, 8000, 7350, 0, 0, 0 }; -static int adtsParse(AacBuffer * b, float *length) +/** + * Check whether the buffer head is an AAC frame, and return the frame + * length. Returns 0 if it is not a frame. + */ +static size_t adts_check_frame(AacBuffer * b) +{ + if (b->bytesIntoBuffer <= 7) + return 0; + + /* check syncword */ + if (!((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0))) + return 0; + + return (((unsigned int)b->buffer[3] & 0x3) << 11) | + (((unsigned int)b->buffer[4]) << 3) | + (b->buffer[5] >> 5); +} + +/** + * Find the next AAC frame in the buffer. Returns 0 if no frame is + * found or if not enough data is available. + */ +static size_t adts_find_frame(AacBuffer * b) { - int frames, frameLength; - int tFrameLength = 0; + const unsigned char *p; + size_t frame_length; + + while ((p = memchr(b->buffer, 0xff, b->bytesIntoBuffer)) != NULL) { + /* discard data before 0xff */ + if (p > b->buffer) + aac_buffer_shift(b, p - b->buffer); + + if (b->bytesIntoBuffer <= 7) + /* not enough data yet */ + return 0; + + /* is it a frame? */ + frame_length = adts_check_frame(b); + if (frame_length > 0) + /* yes, it is */ + return frame_length; + + /* it's just some random 0xff byte; discard and and + continue searching */ + aac_buffer_shift(b, 1); + } + + /* nothing at all; discard the whole buffer */ + aac_buffer_shift(b, b->bytesIntoBuffer); + return 0; +} + +static void adtsParse(AacBuffer * b, float *length) +{ + unsigned int frames, frameLength; int sampleRate = 0; - float framesPerSec, bytesPerFrame; + float framesPerSec; /* Read all frames to ensure correct time and bitrate */ for (frames = 0;; frames++) { fillAacBuffer(b); - if (b->bytesIntoBuffer > 7) { - /* check syncword */ - if (!((b->buffer[0] == 0xFF) && - ((b->buffer[1] & 0xF6) == 0xF0))) { - break; - } - + frameLength = adts_find_frame(b); + if (frameLength > 0) { if (frames == 0) { sampleRate = adtsSampleRates[(b-> buffer[2] & 0x3c) >> 2]; } - frameLength = ((((unsigned int)b->buffer[3] & 0x3)) - << 11) | (((unsigned int)b->buffer[4]) - << 3) | (b->buffer[5] >> 5); - - tFrameLength += frameLength; - if (frameLength > b->bytesIntoBuffer) break; @@ -133,46 +172,34 @@ static int adtsParse(AacBuffer * b, float *length) } framesPerSec = (float)sampleRate / 1024.0; - if (frames != 0) { - bytesPerFrame = (float)tFrameLength / (float)(frames * 1000); - } else - bytesPerFrame = 0; if (framesPerSec != 0) *length = (float)frames / framesPerSec; - - return 1; } -static void initAacBuffer(InputStream * inStream, AacBuffer * b, float *length, - size_t * retFileread, size_t * retTagsize) +static void initAacBuffer(InputStream * inStream, AacBuffer * b) { - size_t fileread; - size_t bread; - size_t tagsize; - - if (length) - *length = -1; - memset(b, 0, sizeof(AacBuffer)); b->inStream = inStream; - fileread = inStream->size; - b->buffer = xmalloc(FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS); memset(b->buffer, 0, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS); +} - bread = readFromInputStream(inStream, b->buffer, 1, - FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS); - b->bytesIntoBuffer = bread; - b->bytesConsumed = 0; - b->fileOffset = 0; +static void aac_parse_header(AacBuffer * b, float *length) +{ + size_t fileread; + size_t tagsize; - if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS) - b->atEof = 1; + if (length) + *length = -1; + + fileread = b->inStream->size; + + fillAacBuffer(b); tagsize = 0; - if (!memcmp(b->buffer, "ID3", 3)) { + if (b->bytesIntoBuffer >= 10 && !memcmp(b->buffer, "ID3", 3)) { tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) | (b->buffer[8] << 7) | (b->buffer[9] << 0); @@ -181,28 +208,19 @@ static void initAacBuffer(InputStream * inStream, AacBuffer * b, float *length, fillAacBuffer(b); } - if (retFileread) - *retFileread = fileread; - if (retTagsize) - *retTagsize = tagsize; - if (length == NULL) return; - if ((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) { + if (b->bytesIntoBuffer >= 2 && + (b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) { adtsParse(b, length); seekInputStream(b->inStream, tagsize, SEEK_SET); - bread = readFromInputStream(b->inStream, b->buffer, 1, - FAAD_MIN_STREAMSIZE * - AAC_MAX_CHANNELS); - if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS) - b->atEof = 1; - else - b->atEof = 0; - b->bytesIntoBuffer = bread; + b->bytesIntoBuffer = 0; b->bytesConsumed = 0; b->fileOffset = tagsize; + + fillAacBuffer(b); } else if (memcmp(b->buffer, "ADIF", 4) == 0) { int bitRate; int skipSize = (b->buffer[4] & 0x80) ? 9 : 0; @@ -231,7 +249,6 @@ static float getAacFloatTotalTime(char *file) { AacBuffer b; float length; - size_t fileread, tagsize; faacDecHandle decoder; faacDecConfigurationPtr config; uint32_t sampleRate; @@ -242,7 +259,8 @@ static float getAacFloatTotalTime(char *file) if (openInputStream(&inStream, file) < 0) return -1; - initAacBuffer(&inStream, &b, &length, &fileread, &tagsize); + initAacBuffer(&inStream, &b); + aac_parse_header(&b, &length); if (length < 0) { decoder = faacDecOpen(); @@ -282,6 +300,132 @@ static int getAacTotalTime(char *file) return file_time; } +static int aac_stream_decode(InputStream *inStream) +{ + float file_time; + float totalTime = 0; + faacDecHandle decoder; + faacDecFrameInfo frameInfo; + faacDecConfigurationPtr config; + long bread; + uint32_t sampleRate; + unsigned char channels; + unsigned int sampleCount; + char *sampleBuffer; + size_t sampleBufferLen; + mpd_uint16 bitRate = 0; + AacBuffer b; + + initAacBuffer(inStream, &b); + aac_parse_header(&b, NULL); + + decoder = faacDecOpen(); + + config = faacDecGetCurrentConfiguration(decoder); + config->outputFormat = FAAD_FMT_16BIT; +#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX + config->downMatrix = 1; +#endif +#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR + config->dontUpSampleImplicitSBR = 0; +#endif + faacDecSetConfiguration(decoder, config); + + while (b.bytesIntoBuffer < FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS && + !b.atEof && !dc_intr()) { + fillAacBuffer(&b); + adts_find_frame(&b); + fillAacBuffer(&b); + } + +#ifdef HAVE_FAAD_BUFLEN_FUNCS + bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer, + &sampleRate, &channels); +#else + bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels); +#endif + if (bread < 0) { + ERROR("Error not a AAC stream.\n"); + faacDecClose(decoder); + if (b.buffer) + free(b.buffer); + return -1; + } + + dc.audio_format.bits = 16; + dc.total_time = totalTime; + + file_time = 0.0; + + advanceAacBuffer(&b, bread); + + while (1) { + fillAacBuffer(&b); + adts_find_frame(&b); + fillAacBuffer(&b); + + if (b.bytesIntoBuffer == 0) + break; + +#ifdef HAVE_FAAD_BUFLEN_FUNCS + sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer, + b.bytesIntoBuffer); +#else + sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer); +#endif + + if (frameInfo.error > 0) { + ERROR("error decoding AAC stream\n"); + ERROR("faad2 error: %s\n", + faacDecGetErrorMessage(frameInfo.error)); + break; + } +#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE + sampleRate = frameInfo.samplerate; +#endif + + dc.audio_format.channels = frameInfo.channels; + dc.audio_format.sampleRate = sampleRate; + + advanceAacBuffer(&b, frameInfo.bytesconsumed); + + sampleCount = (unsigned long)(frameInfo.samples); + + if (sampleCount > 0) { + bitRate = frameInfo.bytesconsumed * 8.0 * + frameInfo.channels * sampleRate / + frameInfo.samples / 1000 + 0.5; + file_time += + (float)(frameInfo.samples) / frameInfo.channels / + sampleRate; + } + + sampleBufferLen = sampleCount * 2; + + switch (ob_send(sampleBuffer, sampleBufferLen, + file_time, bitRate, NULL)) { + case DC_ACTION_NONE: break; + case DC_ACTION_SEEK: + /* + * this plugin doesn't support seek because nobody + * has bothered, yet... + */ + dc_action_seek_fail(DC_SEEK_ERROR); + break; + default: goto out; + } + } +out: + + faacDecClose(decoder); + if (b.buffer) + free(b.buffer); + + return 0; +} + + + static int aac_decode(char *path) { float file_time; @@ -292,7 +436,6 @@ static int aac_decode(char *path) long bread; uint32_t sampleRate; unsigned char channels; - int eof = 0; unsigned int sampleCount; char *sampleBuffer; size_t sampleBufferLen; @@ -309,7 +452,8 @@ static int aac_decode(char *path) if (openInputStream(&inStream, path) < 0) return -1; - initAacBuffer(&inStream, &b, NULL, NULL, NULL); + initAacBuffer(&inStream, &b); + aac_parse_header(&b, NULL); decoder = faacDecOpen(); @@ -346,13 +490,12 @@ static int aac_decode(char *path) advanceAacBuffer(&b, bread); - while (!eof) { + while (1) { fillAacBuffer(&b); - if (b.bytesIntoBuffer == 0) { - eof = 1; + if (b.bytesIntoBuffer == 0) break; - } + #ifdef HAVE_FAAD_BUFLEN_FUNCS sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer, b.bytesIntoBuffer); @@ -364,7 +507,6 @@ static int aac_decode(char *path) ERROR("error decoding AAC file: %s\n", path); ERROR("faad2 error: %s\n", faacDecGetErrorMessage(frameInfo.error)); - eof = 1; break; } #ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE @@ -399,9 +541,10 @@ static int aac_decode(char *path) */ dc_action_seek_fail(DC_SEEK_ERROR); break; - default: eof = 1; + default: goto out; } } +out: faacDecClose(decoder); if (b.buffer) @@ -435,10 +578,10 @@ InputPlugin aacPlugin = { NULL, NULL, NULL, - NULL, + aac_stream_decode, aac_decode, aacTagDup, - INPUT_PLUGIN_STREAM_FILE, + INPUT_PLUGIN_STREAM_FILE | INPUT_PLUGIN_STREAM_URL, aac_suffixes, aac_mimeTypes }; diff --git a/src/inputPlugins/audiofile_plugin.c b/src/inputPlugins/audiofile_plugin.c index 114a87786..fcebf562b 100644 --- a/src/inputPlugins/audiofile_plugin.c +++ b/src/inputPlugins/audiofile_plugin.c @@ -22,11 +22,7 @@ #ifdef HAVE_AUDIOFILE -#include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../os_compat.h" #include <audiofile.h> @@ -51,6 +47,8 @@ static int audiofile_decode(char *path) int bits; mpd_uint16 bitRate; struct stat st; + int ret, current = 0; + char chunk[CHUNK_SIZE]; if (stat(path, &st) < 0) { ERROR("failed to stat: %s\n", path); @@ -88,34 +86,29 @@ static int audiofile_decode(char *path) fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1); - { - int ret, eof = 0, current = 0; - char chunk[CHUNK_SIZE]; - - while (!eof) { - if (dc_seek()) { - dc_action_begin(); - current = dc.seek_where * - dc.audio_format.sampleRate; - afSeekFrame(af_fp, AF_DEFAULT_TRACK, current); - dc_action_end(); - } - - ret = - afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, - CHUNK_SIZE / fs); - if (ret <= 0) - eof = 1; - else { - current += ret; - ob_send(chunk, ret * fs, - (float)current / - (float)dc.audio_format.sampleRate, - bitRate, - NULL); - if (dc_intr()) - break; - } + while (1) { + if (dc_seek()) { + dc_action_begin(); + current = dc.seek_where * + dc.audio_format.sampleRate; + afSeekFrame(af_fp, AF_DEFAULT_TRACK, current); + dc_action_end(); + } + + ret = + afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, + CHUNK_SIZE / fs); + if (ret <= 0) + break; + else { + current += ret; + ob_send(chunk, ret * fs, + (float)current / + (float)dc.audio_format.sampleRate, + bitRate, + NULL); + if (dc_intr()) + break; } } afCloseFile(af_fp); diff --git a/src/inputPlugins/flac_plugin.c b/src/inputPlugins/flac_plugin.c index 4a4ac627c..de0648c90 100644 --- a/src/inputPlugins/flac_plugin.c +++ b/src/inputPlugins/flac_plugin.c @@ -22,16 +22,10 @@ #include "../utils.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../replayGain.h" -#include "../audio.h" -#include "../os_compat.h" /* this code was based on flac123, from flac-tools */ -static flac_read_status flacRead(const flac_decoder * flacDec, +static flac_read_status flacRead(mpd_unused const flac_decoder * flacDec, FLAC__byte buf[], flac_read_status_size_t *bytes, void *fdata) @@ -57,7 +51,7 @@ static flac_read_status flacRead(const flac_decoder * flacDec, return flac_read_status_continue; } -static flac_seek_status flacSeek(const flac_decoder * flacDec, +static flac_seek_status flacSeek(mpd_unused const flac_decoder * flacDec, FLAC__uint64 offset, void *fdata) { @@ -70,7 +64,7 @@ static flac_seek_status flacSeek(const flac_decoder * flacDec, return flac_seek_status_ok; } -static flac_tell_status flacTell(const flac_decoder * flacDec, +static flac_tell_status flacTell(mpd_unused const flac_decoder * flacDec, FLAC__uint64 * offset, void *fdata) { @@ -81,7 +75,7 @@ static flac_tell_status flacTell(const flac_decoder * flacDec, return flac_tell_status_ok; } -static flac_length_status flacLength(const flac_decoder * flacDec, +static flac_length_status flacLength(mpd_unused const flac_decoder * flacDec, FLAC__uint64 * length, void *fdata) { @@ -92,7 +86,7 @@ static flac_length_status flacLength(const flac_decoder * flacDec, return flac_length_status_ok; } -static FLAC__bool flacEOF(const flac_decoder * flacDec, void *fdata) +static FLAC__bool flacEOF(mpd_unused const flac_decoder * flacDec, void *fdata) { FlacData *data = (FlacData *) fdata; @@ -101,7 +95,7 @@ static FLAC__bool flacEOF(const flac_decoder * flacDec, void *fdata) return false; } -static void flacError(const flac_decoder *dec, +static void flacError(mpd_unused const flac_decoder *dec, FLAC__StreamDecoderErrorStatus status, void *fdata) { flac_error_common_cb("flac", status, (FlacData *) fdata); @@ -199,7 +193,7 @@ static void flacPrintErroredState(FLAC__StreamDecoderState state) } #endif /* FLAC_API_VERSION_CURRENT >= 7 */ -static void flacMetadata(const flac_decoder * dec, +static void flacMetadata(mpd_unused const flac_decoder * dec, const FLAC__StreamMetadata * block, void *vdata) { flac_metadata_common_cb(block, (FlacData *) vdata); diff --git a/src/inputPlugins/mod_plugin.c b/src/inputPlugins/mod_plugin.c index 9f9da6273..df938f0ed 100644 --- a/src/inputPlugins/mod_plugin.c +++ b/src/inputPlugins/mod_plugin.c @@ -21,10 +21,7 @@ #ifdef HAVE_MIKMOD #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../os_compat.h" #include <mikmod.h> diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index c36cab6f0..f1304f401 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -20,7 +20,6 @@ #ifdef HAVE_MAD -#include "../pcm_utils.h" #include <mad.h> #ifdef HAVE_ID3TAG @@ -29,23 +28,24 @@ #include "../log.h" #include "../utils.h" -#include "../replayGain.h" -#include "../tag.h" #include "../conf.h" -#include "../os_compat.h" - #define FRAMES_CUSHION 2000 #define READ_BUFFER_SIZE 40960 -#define DECODE_SKIP -3 -#define DECODE_BREAK -2 -#define DECODE_CONT -1 -#define DECODE_OK 0 +enum mp3_action { + DECODE_SKIP = -3, + DECODE_BREAK = -2, + DECODE_CONT = -1, + DECODE_OK = 0 +}; -#define MUTEFRAME_SKIP 1 -#define MUTEFRAME_SEEK 2 +enum muteframe { + MUTEFRAME_NONE, + MUTEFRAME_SKIP, + MUTEFRAME_SEEK +}; /* the number of samples of silence the decoder inserts at start */ #define DECODERDELAY 529 @@ -65,8 +65,8 @@ static unsigned long prng(unsigned long state) return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; } -static signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, - struct audio_dither *dither) +static mpd_sint16 audio_linear_dither(unsigned int bits, mad_fixed_t sample, + struct audio_dither *dither) { unsigned int scalebits; mad_fixed_t output, mask, rnd; @@ -107,7 +107,29 @@ static signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, dither->error[0] = sample - output; - return output >> scalebits; + return (mpd_sint16)(output >> scalebits); +} + +static unsigned dither_buffer(mpd_sint16 *dest0, const struct mad_synth *synth, + struct audio_dither *dither, + unsigned int start, unsigned int end, + unsigned int num_channels) +{ + mpd_sint16 *dest = dest0; + unsigned int i; + + for (i = start; i < end; ++i) { + *dest++ = audio_linear_dither(16, + synth->pcm.samples[0][i], + dither); + + if (num_channels == 2) + *dest++ = audio_linear_dither(16, + synth->pcm.samples[1][i], + dither); + } + + return dest - dest0; } /* end of stolen stuff from mpg321 */ @@ -123,7 +145,7 @@ static int mp3_plugin_init(void) /* decoder stuff is based on madlld */ -#define MP3_DATA_OUTPUT_BUFFER_SIZE 4096 +#define MP3_DATA_OUTPUT_BUFFER_SIZE 2048 typedef struct _mp3DecodeData { struct mad_stream stream; @@ -131,25 +153,22 @@ typedef struct _mp3DecodeData { struct mad_synth synth; mad_timer_t timer; unsigned char readBuffer[READ_BUFFER_SIZE]; - char outputBuffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; - char *outputPtr; - char *outputBufferEnd; + mpd_sint16 outputBuffer[MP3_DATA_OUTPUT_BUFFER_SIZE]; float totalTime; float elapsedTime; - int muteFrame; + enum muteframe muteFrame; long *frameOffset; mad_timer_t *times; - long highestFrame; - long maxFrames; - long currentFrame; - int dropFramesAtStart; - int dropFramesAtEnd; - int dropSamplesAtStart; - int dropSamplesAtEnd; + unsigned long highestFrame; + unsigned long maxFrames; + unsigned long currentFrame; + unsigned int dropFramesAtStart; + unsigned int dropFramesAtEnd; + unsigned int dropSamplesAtStart; + unsigned int dropSamplesAtEnd; int foundXing; int foundFirstFrame; int decodedFirstFrame; - int flush; unsigned long bitRate; InputStream *inStream; struct audio_dither dither; @@ -158,10 +177,7 @@ typedef struct _mp3DecodeData { static void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) { - data->outputPtr = data->outputBuffer; - data->outputBufferEnd = - data->outputBuffer + MP3_DATA_OUTPUT_BUFFER_SIZE; - data->muteFrame = 0; + data->muteFrame = MUTEFRAME_NONE; data->highestFrame = 0; data->maxFrames = 0; data->frameOffset = NULL; @@ -174,7 +190,6 @@ static void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) data->foundXing = 0; data->foundFirstFrame = 0; data->decodedFirstFrame = 0; - data->flush = 1; data->inStream = inStream; data->layer = 0; memset(&(data->dither), 0, sizeof(struct audio_dither)); @@ -357,8 +372,9 @@ fail: } #endif -static int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag, - ReplayGainInfo ** replayGainInfo) +static enum mp3_action +decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag, + ReplayGainInfo ** replayGainInfo) { enum mad_layer layer; @@ -400,7 +416,6 @@ static int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag, ERROR("unrecoverable frame level error " "(%s).\n", mad_stream_errorstr(&data->stream)); - data->flush = 0; return DECODE_BREAK; } } @@ -421,7 +436,8 @@ static int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag, return DECODE_OK; } -static int decodeNextFrame(mp3DecodeData * data) +static enum mp3_action +decodeNextFrame(mp3DecodeData * data) { if ((data->stream).buffer == NULL || (data->stream).error == MAD_ERROR_BUFLEN) { @@ -453,7 +469,6 @@ static int decodeNextFrame(mp3DecodeData * data) ERROR("unrecoverable frame level error " "(%s).\n", mad_stream_errorstr(&data->stream)); - data->flush = 0; return DECODE_BREAK; } } @@ -819,7 +834,7 @@ static float frame_time(mp3DecodeData * data, long j) static void mp3Read_seek(mp3DecodeData * data) { - long j = 0; + unsigned long j = 0; data->muteFrame = MUTEFRAME_SEEK; assert(pthread_equal(pthread_self(), dc.thread)); @@ -829,22 +844,20 @@ static void mp3Read_seek(mp3DecodeData * data) j++; if (j < data->highestFrame) { dc_action_begin(); - if (seekMp3InputBuffer(data, data->frameOffset[j]) < 0) { + if (seekMp3InputBuffer(data, data->frameOffset[j]) < 0) dc.seek_where = DC_SEEK_ERROR; - } else { - data->outputPtr = data->outputBuffer; + else data->currentFrame = j; - } - data->muteFrame = 0; + data->muteFrame = MUTEFRAME_NONE; dc_action_end(); } } -static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) +static enum mp3_action +mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) { - int samplesPerFrame; - int samplesLeft; - int i; + unsigned int pcm_length, max_samples; + unsigned int i; int ret; int skip; @@ -877,22 +890,21 @@ static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) switch (data->muteFrame) { case MUTEFRAME_SKIP: - data->muteFrame = 0; + data->muteFrame = MUTEFRAME_NONE; break; case MUTEFRAME_SEEK: if (dc.seek_where <= data->elapsedTime) { dc_action_begin(); assert(dc.action == DC_ACTION_SEEK); - data->outputPtr = data->outputBuffer; - data->muteFrame = 0; + data->muteFrame = MUTEFRAME_NONE; dc_action_end(); } break; - default: + case MUTEFRAME_NONE: mad_synth_frame(&data->synth, &data->frame); if (!data->foundFirstFrame) { - samplesPerFrame = (data->synth).pcm.length; + unsigned int samplesPerFrame = (data->synth).pcm.length; data->dropFramesAtStart = data->dropSamplesAtStart / samplesPerFrame; data->dropFramesAtEnd = data->dropSamplesAtEnd / samplesPerFrame; data->dropSamplesAtStart = data->dropSamplesAtStart % samplesPerFrame; @@ -924,60 +936,57 @@ static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) metadata_pipe_send(tag, data->elapsedTime); } - samplesLeft = (data->synth).pcm.length; + if (!data->decodedFirstFrame) { + i = data->dropSamplesAtStart; + data->decodedFirstFrame = 1; + } else + i = 0; + + pcm_length = data->synth.pcm.length; + if (data->dropSamplesAtEnd && + (data->currentFrame == data->maxFrames - data->dropFramesAtEnd)) { + if (data->dropSamplesAtEnd >= pcm_length) + pcm_length = 0; + else + pcm_length -= data->dropSamplesAtEnd; + } - for (i = 0; i < (data->synth).pcm.length; i++) { - mpd_sint16 *sample; + max_samples = sizeof(data->outputBuffer) / + (2 * MAD_NCHANNELS(&(data->frame).header)); - samplesLeft--; + while (i < pcm_length) { + enum dc_action action; + unsigned int num_samples = pcm_length - i; - if (!data->decodedFirstFrame && - (i < data->dropSamplesAtStart)) { - continue; - } else if (data->dropSamplesAtEnd && - (data->currentFrame == (data->maxFrames - data->dropFramesAtEnd)) && - (samplesLeft < data->dropSamplesAtEnd)) { - /* stop decoding, effectively dropping - * all remaining samples */ - return DECODE_BREAK; - } + if (num_samples > max_samples) + num_samples = max_samples; + i += num_samples; - sample = (mpd_sint16 *) data->outputPtr; - *sample = (mpd_sint16) audio_linear_dither(16, - (data->synth).pcm.samples[0][i], - &(data->dither)); - data->outputPtr += 2; - - if (MAD_NCHANNELS(&(data->frame).header) == 2) { - sample = (mpd_sint16 *) data->outputPtr; - *sample = (mpd_sint16) audio_linear_dither(16, - (data->synth).pcm.samples[1][i], - &(data->dither)); - data->outputPtr += 2; - } + num_samples = dither_buffer(data->outputBuffer, + &data->synth, &data->dither, + i - num_samples, i, + MAD_NCHANNELS( + &(data->frame).header)); - if (data->outputPtr >= data->outputBufferEnd) { - enum dc_action action = ob_send( - data->outputBuffer, - data->outputPtr - - data->outputBuffer, - data->elapsedTime, - data->bitRate / 1000, - replayGainInfo ? *replayGainInfo - : NULL); - - if (action == DC_ACTION_STOP) { - data->flush = 0; - return DECODE_BREAK; - } - data->outputPtr = data->outputBuffer; + action = ob_send(data->outputBuffer, + 2 * num_samples, + data->elapsedTime, + data->bitRate / 1000, + replayGainInfo ? *replayGainInfo : NULL); - if (action == DC_ACTION_SEEK) - break; - } + if (action == DC_ACTION_STOP) + return DECODE_BREAK; + + if (action == DC_ACTION_SEEK) + break; } - data->decodedFirstFrame = 1; + if (data->dropSamplesAtEnd && + (data->currentFrame == + (data->maxFrames - data->dropFramesAtEnd))) + /* stop decoding, effectively dropping + * all remaining samples */ + return DECODE_BREAK; if (dc_seek()) { if (data->inStream->seekable) @@ -997,7 +1006,7 @@ static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) break; else if (ret == DECODE_SKIP) skip = 1; - if (!data->muteFrame) { + if (data->muteFrame == MUTEFRAME_NONE) { while ((ret = decodeNextFrame(data)) == DECODE_CONT && !dc_intr() && dc_seek()) ; if (ret == DECODE_BREAK || dc_intr() || dc_seek()) @@ -1065,11 +1074,6 @@ static int mp3_decode(InputStream * inStream) metadata_pipe_send(tag, 0); while (mp3Read(&data, &replayGainInfo) != DECODE_BREAK) ; - /* send last little bit if not dc_intr() */ - if (!dc_intr() && data.outputPtr != data.outputBuffer && data.flush) { - ob_send(data.outputBuffer, data.outputPtr - data.outputBuffer, - data.elapsedTime, data.bitRate / 1000, replayGainInfo); - } if (replayGainInfo) freeReplayGainInfo(replayGainInfo); diff --git a/src/inputPlugins/mp4_plugin.c b/src/inputPlugins/mp4_plugin.c index bf200c534..8e3d02354 100644 --- a/src/inputPlugins/mp4_plugin.c +++ b/src/inputPlugins/mp4_plugin.c @@ -21,13 +21,7 @@ #ifdef HAVE_FAAD #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../decode.h" -#include "../os_compat.h" #include "../mp4ff/mp4ff.h" @@ -100,7 +94,6 @@ static int mp4_decode(InputStream * inStream) unsigned char channels; long sampleId; long numSamples; - int eof = 0; long dur; unsigned int sampleCount; char *sampleBuffer; @@ -183,7 +176,7 @@ static int mp4_decode(InputStream * inStream) seekTable = xmalloc(sizeof(float) * numSamples); - for (sampleId = 0; sampleId < numSamples && !eof; sampleId++) { + for (sampleId = 0; sampleId < numSamples; sampleId++) { if (!seeking && dc_seek()) { dc_action_begin(); assert(dc.action == DC_ACTION_SEEK); @@ -229,10 +222,9 @@ static int mp4_decode(InputStream * inStream) continue; if (mp4ff_read_sample(mp4fh, track, sampleId, &mp4Buffer, - &mp4BufferSize) == 0) { - eof = 1; - continue; - } + &mp4BufferSize) == 0) + break; + #ifdef HAVE_FAAD_BUFLEN_FUNCS sampleBuffer = faacDecDecode(decoder, &frameInfo, mp4Buffer, mp4BufferSize); @@ -245,7 +237,6 @@ static int mp4_decode(InputStream * inStream) if (frameInfo.error > 0) { ERROR("faad2 error: %s\n", faacDecGetErrorMessage(frameInfo.error)); - eof = 1; break; } @@ -276,10 +267,8 @@ static int mp4_decode(InputStream * inStream) ob_send(sampleBuffer, sampleBufferLen, file_time, bitRate, NULL); - if (dc_intr()) { - eof = 1; + if (dc_intr()) break; - } } free(seekTable); diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c index 116e471ff..ea27d1dbf 100644 --- a/src/inputPlugins/mpc_plugin.c +++ b/src/inputPlugins/mpc_plugin.c @@ -21,13 +21,7 @@ #ifdef HAVE_MPCDEC #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../replayGain.h" -#include "../os_compat.h" #include <mpcdec/mpcdec.h> diff --git a/src/inputPlugins/oggflac_plugin.c b/src/inputPlugins/oggflac_plugin.c index 6c5998afe..4b3bb0a6b 100644 --- a/src/inputPlugins/oggflac_plugin.c +++ b/src/inputPlugins/oggflac_plugin.c @@ -27,12 +27,6 @@ #include "../utils.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../replayGain.h" -#include "../audio.h" -#include "../os_compat.h" static void oggflac_cleanup(FlacData * data, OggFLAC__SeekableStreamDecoder * decoder) @@ -43,7 +37,7 @@ static void oggflac_cleanup(FlacData * data, OggFLAC__seekable_stream_decoder_delete(decoder); } -static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(const +static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, FLAC__byte buf[], @@ -68,7 +62,7 @@ static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(const return OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; } -static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(const +static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, FLAC__uint64 offset, @@ -83,7 +77,7 @@ static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(const return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; } -static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(const +static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, FLAC__uint64 * @@ -96,7 +90,7 @@ static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(const return OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; } -static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(const +static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, FLAC__uint64 * @@ -110,7 +104,7 @@ static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(const return OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; } -static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder, +static FLAC__bool of_EOF_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, void *fdata) { FlacData *data = (FlacData *) fdata; @@ -120,7 +114,7 @@ static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder, return false; } -static void of_error_cb(const OggFLAC__SeekableStreamDecoder * decoder, +static void of_error_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, FLAC__StreamDecoderErrorStatus status, void *fdata) { flac_error_common_cb("oggflac", status, (FlacData *) fdata); @@ -157,7 +151,7 @@ static void oggflacPrintErroredState(OggFLAC__SeekableStreamDecoderState state) } } -static FLAC__StreamDecoderWriteStatus oggflacWrite(const +static FLAC__StreamDecoderWriteStatus oggflacWrite(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, const FLAC__Frame * frame, @@ -214,7 +208,7 @@ static FLAC__StreamDecoderWriteStatus oggflacWrite(const } /* used by TagDup */ -static void of_metadata_dup_cb(const OggFLAC__SeekableStreamDecoder * decoder, +static void of_metadata_dup_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * decoder, const FLAC__StreamMetadata * block, void *vdata) { FlacData *data = (FlacData *) vdata; @@ -235,7 +229,7 @@ static void of_metadata_dup_cb(const OggFLAC__SeekableStreamDecoder * decoder, } /* used by decode */ -static void of_metadata_decode_cb(const OggFLAC__SeekableStreamDecoder * dec, +static void of_metadata_decode_cb(mpd_unused const OggFLAC__SeekableStreamDecoder * dec, const FLAC__StreamMetadata * block, void *vdata) { @@ -333,6 +327,11 @@ static MpdTag *oggflac_TagDup(char *file) static unsigned int oggflac_try_decode(InputStream * inStream) { + if (!inStream->seekable) + /* we cannot seek after the detection, so don't bother + checking */ + return 1; + return (ogg_stream_type_detect(inStream) == FLAC) ? 1 : 0; } diff --git a/src/inputPlugins/oggvorbis_plugin.c b/src/inputPlugins/oggvorbis_plugin.c index 70a0ce2d3..d14ae2bac 100644 --- a/src/inputPlugins/oggvorbis_plugin.c +++ b/src/inputPlugins/oggvorbis_plugin.c @@ -25,13 +25,7 @@ #include "_ogg_common.h" #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../inputStream.h" -#include "../outputBuffer.h" -#include "../replayGain.h" -#include "../os_compat.h" #ifndef HAVE_TREMOR #include <vorbis/vorbisfile.h> @@ -86,7 +80,7 @@ static int ogg_seek_cb(void *vdata, ogg_int64_t offset, int whence) } /* TODO: check Ogg libraries API and see if we can just not have this func */ -static int ogg_close_cb(void *vdata) +static int ogg_close_cb(mpd_unused void *vdata) { return 0; } @@ -246,32 +240,32 @@ static int oggvorbis_decode(InputStream * inStream) callbacks.close_func = ogg_close_cb; callbacks.tell_func = ogg_tell_cb; if ((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) { - if (!dc_intr()) { - switch (ret) { - case OV_EREAD: - errorStr = "read error"; - break; - case OV_ENOTVORBIS: - errorStr = "not vorbis stream"; - break; - case OV_EVERSION: - errorStr = "vorbis version mismatch"; - break; - case OV_EBADHEADER: - errorStr = "invalid vorbis header"; - break; - case OV_EFAULT: - errorStr = "internal logic error"; - break; - default: - errorStr = "unknown error"; - break; - } - ERROR("Error decoding Ogg Vorbis stream: %s\n", - errorStr); - return -1; + if (dc_intr()) + return 0; + + switch (ret) { + case OV_EREAD: + errorStr = "read error"; + break; + case OV_ENOTVORBIS: + errorStr = "not vorbis stream"; + break; + case OV_EVERSION: + errorStr = "vorbis version mismatch"; + break; + case OV_EBADHEADER: + errorStr = "invalid vorbis header"; + break; + case OV_EFAULT: + errorStr = "internal logic error"; + break; + default: + errorStr = "unknown error"; + break; } - return 0; + + ERROR("Error decoding Ogg Vorbis stream: %s\n", errorStr); + return -1; } dc.total_time = ov_time_total(&vf, -1); if (dc.total_time < 0) @@ -368,6 +362,11 @@ static MpdTag *oggvorbis_TagDup(char *file) static unsigned int oggvorbis_try_decode(InputStream * inStream) { + if (!inStream->seekable) + /* we cannot seek after the detection, so don't bother + checking */ + return 1; + return (ogg_stream_type_detect(inStream) == VORBIS) ? 1 : 0; } diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c index 2538be326..c7e024a41 100644 --- a/src/inputPlugins/wavpack_plugin.c +++ b/src/inputPlugins/wavpack_plugin.c @@ -23,11 +23,7 @@ #ifdef HAVE_WAVPACK #include "../utils.h" -#include "../audio.h" #include "../log.h" -#include "../pcm_utils.h" -#include "../outputBuffer.h" -#include "../os_compat.h" #include "../path.h" #include <wavpack/wavpack.h> @@ -113,7 +109,8 @@ static void format_samples_int(int Bps, void *buffer, uint32_t samcnt) /* * This function converts floating point sample data to 16 bit integer. */ -static void format_samples_float(int Bps, void *buffer, uint32_t samcnt) +static void format_samples_float(mpd_unused int Bps, void *buffer, + uint32_t samcnt) { int16_t *dst = (int16_t *)buffer; float *src = (float *)buffer; @@ -427,86 +424,80 @@ static unsigned int wavpack_trydecode(InputStream *is) return 1; } -/* - * Decodes a stream. - */ -static int wavpack_streamdecode(InputStream *is) +/* wvc being the "correction" file to supplement the original .wv */ +static int wavpack_open_wvc(InputStream *is_wvc) { - char error[ERRORLEN]; - WavpackContext *wpc; - InputStream is_wvc; - int open_flags = OPEN_2CH_MAX | OPEN_NORMALIZE /*| OPEN_STREAMING*/; - char *wvc_url = NULL; - int err; - InputStreamPlus isp, isp_wvc; - int canseek; - - /* Try to find wvc */ - /* wvc being the "correction" file to supplement the original .wv */ - do { - char tmp[MPD_PATH_MAX]; - const char *utf8url; - size_t len; - err = 1; + char wvc_url[MPD_PATH_MAX]; + size_t len; - /* This is the only reader of dc.current_song */ - if (!(utf8url = get_song_url(tmp, dc.current_song))) - break; + /* This is the only reader of dc.current_song */ + if (!get_song_url(wvc_url, dc.current_song)) + return 0; - if (!(len = strlen(utf8url))) - break; + len = strlen(wvc_url); + if ((len + 2) >= MPD_PATH_MAX) + return 0; - wvc_url = (char *)xmalloc(len + sizeof("c")); - memcpy(wvc_url, utf8url, len); - wvc_url[len] = 'c'; - wvc_url[len + 1] = '\0'; + /* convert the original ".wv" path to a ".wvc" path */ + assert(wvc_url[len - 3] == '.'); + assert(wvc_url[len - 2] == 'w' || wvc_url[len - 2] == 'w'); + assert(wvc_url[len - 1] == 'v' || wvc_url[len - 1] == 'V'); + assert(wvc_url[len] == '\0'); - if (openInputStream(&is_wvc, wvc_url)) - break; + wvc_url[len] = 'c'; + wvc_url[len + 1] = '\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 :/ - */ - break; - } - - /* FIXME: replace with future "peek" function */ - if (bufferInputStream(&is_wvc) >= 0) { - err = 0; - break; - } + if (openInputStream(is_wvc, wvc_url) < 0) { + /* lowercase 'c' didn't work, maybe uppercase... */ + wvc_url[len] = 'C'; + if (openInputStream(is_wvc, wvc_url) < 0) + return 0; + } - if (dc_intr()) - break; + /* + * 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 :/ + */ + break; - /* Save some CPU */ - my_usleep(1000); /* FIXME: remove */ + /* FIXME: replace with future "peek" function */ + if (bufferInputStream(is_wvc) >= 0) { + DEBUG("wavpack: got wvc file: %s\n", wvc_url); + return 1; /* success */ } - if (err) { - closeInputStream(&is_wvc); + + if (dc_intr()) break; - } + /* Save some CPU */ + my_usleep(1000); /* FIXME: remove */ + } - open_flags |= OPEN_WVC; + closeInputStream(is_wvc); + return 0; +} - } while (0); - canseek = can_seek(&isp); - if (wvc_url != NULL) { - if (err) { - free(wvc_url); - wvc_url = NULL; - } else { - initInputStreamPlus(&isp_wvc, &is_wvc); - } +/* + * Decodes a stream. + */ +static int wavpack_streamdecode(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(&is_wvc)) { + initInputStreamPlus(&isp_wvc, &is_wvc); + open_flags |= OPEN_WVC; } initInputStreamPlus(&isp, is); @@ -515,17 +506,16 @@ static int wavpack_streamdecode(InputStream *is) if (wpc == NULL) { ERROR("failed to open WavPack stream: %s\n", error); + if (open_flags & OPEN_WVC) + closeInputStream(&is_wvc); return -1; } - wavpack_decode(wpc, canseek, NULL); + wavpack_decode(wpc, can_seek(&isp), NULL); WavpackCloseFile(wpc); - if (wvc_url != NULL) { + if (open_flags & OPEN_WVC) closeInputStream(&is_wvc); - free(wvc_url); - } - closeInputStream(is); return 0; } |