From 2a83ccdb8f71d224341ea5a6ddbc002693d887fb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 26 Aug 2008 08:27:05 +0200 Subject: added decoder_data() Moved all of the player-waiting code to decoder_data(), to make OutputBuffer more generic. --- src/decoder_api.c | 80 ++++++++++++++++++++++++++++++++++++ src/decoder_api.h | 15 +++++++ src/inputPlugins/_flac_common.h | 11 +++-- src/inputPlugins/aac_plugin.c | 6 +-- src/inputPlugins/audiofile_plugin.c | 14 +++---- src/inputPlugins/mod_plugin.c | 6 +-- src/inputPlugins/mp3_plugin.c | 31 +++++++------- src/inputPlugins/mp4_plugin.c | 6 +-- src/inputPlugins/mpc_plugin.c | 16 ++++---- src/inputPlugins/oggvorbis_plugin.c | 19 ++++----- src/inputPlugins/wavpack_plugin.c | 8 ++-- src/outputBuffer.c | 82 ++++++++----------------------------- src/outputBuffer.h | 19 ++++----- 13 files changed, 177 insertions(+), 136 deletions(-) (limited to 'src') diff --git a/src/decoder_api.c b/src/decoder_api.c index dfd1850b..681f593f 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -19,6 +19,8 @@ #include "decoder_api.h" +#include "utils.h" +#include "normalize.h" #include "playerData.h" #include "gcc.h" @@ -29,3 +31,81 @@ void decoder_initialized(mpd_unused struct decoder * decoder) dc.state = DECODE_STATE_DECODE; notify_signal(&pc.notify); } + +/** + * All chunks are full of decoded data; wait for the player to free + * one. + */ +static int need_chunks(InputStream * inStream, int seekable) +{ + if (dc.command == DECODE_COMMAND_STOP) + return OUTPUT_BUFFER_DC_STOP; + + if (dc.command == DECODE_COMMAND_SEEK) { + if (seekable) { + return OUTPUT_BUFFER_DC_SEEK; + } else { + dc.seekError = 1; + dc_command_finished(); + } + } + + if (!inStream || + bufferInputStream(inStream) <= 0) { + notify_wait(&dc.notify); + notify_signal(&pc.notify); + } + + return 0; +} + +int decoder_data(mpd_unused struct decoder *decoder, InputStream * inStream, + int seekable, + void *dataIn, size_t dataInLen, + float data_time, mpd_uint16 bitRate, + ReplayGainInfo * replayGainInfo) +{ + size_t nbytes; + char *data; + size_t datalen; + static char *convBuffer; + static size_t convBufferLen; + int ret; + + if (cmpAudioFormat(&(ob.audioFormat), &(dc.audioFormat)) == 0) { + data = dataIn; + datalen = dataInLen; + } else { + datalen = pcm_sizeOfConvBuffer(&(dc.audioFormat), dataInLen, + &(ob.audioFormat)); + if (datalen > convBufferLen) { + if (convBuffer != NULL) + free(convBuffer); + convBuffer = xmalloc(datalen); + convBufferLen = datalen; + } + data = convBuffer; + datalen = pcm_convertAudioFormat(&(dc.audioFormat), dataIn, + dataInLen, &(ob.audioFormat), + data, &(ob.convState)); + } + + if (replayGainInfo != NULL && (replayGainState != REPLAYGAIN_OFF)) + doReplayGain(replayGainInfo, data, datalen, &ob.audioFormat); + else if (normalizationEnabled) + normalizeData(data, datalen, &ob.audioFormat); + + while (datalen > 0) { + nbytes = ob_append(data, datalen, data_time, bitRate); + datalen -= nbytes; + data += nbytes; + + if (datalen > 0) { + ret = need_chunks(inStream, seekable); + if (ret != 0) + return ret; + } + } + + return 0; +} diff --git a/src/decoder_api.h b/src/decoder_api.h index c9ab3ebb..a56b7ef5 100644 --- a/src/decoder_api.h +++ b/src/decoder_api.h @@ -27,6 +27,8 @@ */ #include "inputPlugin.h" +#include "inputStream.h" +#include "replayGain.h" /** * Opaque handle which the decoder plugin passes to the functions in @@ -40,4 +42,17 @@ struct decoder; */ void decoder_initialized(struct decoder * decoder); +/** + * This function is called by the decoder plugin when it has + * successfully decoded block of input data. + * + * We send inStream for buffering the inputStream while waiting to + * send the next chunk + */ +int decoder_data(struct decoder *decoder, InputStream * inStream, + int seekable, + void *data, size_t datalen, + float data_time, mpd_uint16 bitRate, + ReplayGainInfo * replayGainInfo); + #endif diff --git a/src/inputPlugins/_flac_common.h b/src/inputPlugins/_flac_common.h index 2d59f4d9..9eb916b8 100644 --- a/src/inputPlugins/_flac_common.h +++ b/src/inputPlugins/_flac_common.h @@ -165,12 +165,11 @@ MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block, /* keep this inlined, this is just macro but prettier :) */ static inline int flacSendChunk(FlacData * data) { - if (ob_send(data->inStream, - 1, data->chunk, - data->chunk_length, data->time, - data->bitRate, - data->replayGainInfo) == - OUTPUT_BUFFER_DC_STOP) + if (decoder_data(data->decoder, data->inStream, + 1, data->chunk, + data->chunk_length, data->time, + data->bitRate, + data->replayGainInfo) == OUTPUT_BUFFER_DC_STOP) return -1; return 0; diff --git a/src/inputPlugins/aac_plugin.c b/src/inputPlugins/aac_plugin.c index d03826c8..c6bd9985 100644 --- a/src/inputPlugins/aac_plugin.c +++ b/src/inputPlugins/aac_plugin.c @@ -391,9 +391,9 @@ static int aac_decode(struct decoder * mpd_decoder, char *path) sampleBufferLen = sampleCount * 2; - ob_send(NULL, 0, sampleBuffer, - sampleBufferLen, file_time, - bitRate, NULL); + decoder_data(mpd_decoder, NULL, 0, sampleBuffer, + sampleBufferLen, file_time, + bitRate, NULL); if (dc.command == DECODE_COMMAND_SEEK) { dc.seekError = 1; dc_command_finished(); diff --git a/src/inputPlugins/audiofile_plugin.c b/src/inputPlugins/audiofile_plugin.c index faa58fe6..fc257263 100644 --- a/src/inputPlugins/audiofile_plugin.c +++ b/src/inputPlugins/audiofile_plugin.c @@ -106,13 +106,13 @@ static int audiofile_decode(struct decoder * decoder, char *path) eof = 1; else { current += ret; - ob_send(NULL, - 1, - chunk, ret * fs, - (float)current / - (float)dc.audioFormat. - sampleRate, bitRate, - NULL); + decoder_data(decoder, NULL, + 1, + chunk, ret * fs, + (float)current / + (float)dc.audioFormat. + sampleRate, bitRate, + NULL); if (dc.command == DECODE_COMMAND_STOP) break; } diff --git a/src/inputPlugins/mod_plugin.c b/src/inputPlugins/mod_plugin.c index c09803ee..792cb0c8 100644 --- a/src/inputPlugins/mod_plugin.c +++ b/src/inputPlugins/mod_plugin.c @@ -200,9 +200,9 @@ static int mod_decode(struct decoder * decoder, char *path) ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE); total_time += ret * secPerByte; - ob_send(NULL, 0, - (char *)data->audio_buffer, ret, - total_time, 0, NULL); + decoder_data(decoder, NULL, 0, + (char *)data->audio_buffer, ret, + total_time, 0, NULL); } ob_flush(); diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index f9189535..399491d0 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -812,7 +812,8 @@ static int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data, return 0; } -static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) +static int mp3Read(mp3DecodeData * data, struct decoder *decoder, + ReplayGainInfo ** replayGainInfo) { int samplesPerFrame; int samplesLeft; @@ -926,13 +927,13 @@ static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) } if (data->outputPtr >= data->outputBufferEnd) { - ret = ob_send(data->inStream, - data->inStream->seekable, - data->outputBuffer, - data->outputPtr - data->outputBuffer, - data->elapsedTime, - data->bitRate / 1000, - (replayGainInfo != NULL) ? *replayGainInfo : NULL); + ret = decoder_data(decoder, data->inStream, + data->inStream->seekable, + data->outputBuffer, + data->outputPtr - data->outputBuffer, + data->elapsedTime, + data->bitRate / 1000, + (replayGainInfo != NULL) ? *replayGainInfo : NULL); if (ret == OUTPUT_BUFFER_DC_STOP) { data->flush = 0; return DECODE_BREAK; @@ -1063,16 +1064,16 @@ static int mp3_decode(struct decoder * decoder, InputStream * inStream) decoder_initialized(decoder); - while (mp3Read(&data, &replayGainInfo) != DECODE_BREAK) ; + while (mp3Read(&data, decoder, &replayGainInfo) != DECODE_BREAK) ; /* send last little bit if not DECODE_COMMAND_STOP */ if (dc.command != DECODE_COMMAND_STOP && data.outputPtr != data.outputBuffer && data.flush) { - ob_send(NULL, - data.inStream->seekable, - data.outputBuffer, - data.outputPtr - data.outputBuffer, - data.elapsedTime, data.bitRate / 1000, - replayGainInfo); + decoder_data(decoder, NULL, + data.inStream->seekable, + data.outputBuffer, + data.outputPtr - data.outputBuffer, + data.elapsedTime, data.bitRate / 1000, + replayGainInfo); } if (replayGainInfo) diff --git a/src/inputPlugins/mp4_plugin.c b/src/inputPlugins/mp4_plugin.c index de658511..197d0062 100644 --- a/src/inputPlugins/mp4_plugin.c +++ b/src/inputPlugins/mp4_plugin.c @@ -270,9 +270,9 @@ static int mp4_decode(struct decoder * mpd_decoder, InputStream * inStream) sampleBuffer += offset * channels * 2; - ob_send(inStream, 1, sampleBuffer, - sampleBufferLen, file_time, - bitRate, NULL); + decoder_data(mpd_decoder, inStream, 1, sampleBuffer, + sampleBufferLen, file_time, + bitRate, NULL); if (dc.command == DECODE_COMMAND_STOP) { eof = 1; break; diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c index d4ee40f9..abdf44c6 100644 --- a/src/inputPlugins/mpc_plugin.c +++ b/src/inputPlugins/mpc_plugin.c @@ -215,11 +215,11 @@ static int mpc_decode(struct decoder * mpd_decoder, InputStream * inStream) bitRate = vbrUpdateBits * dc.audioFormat.sampleRate / 1152 / 1000; - ob_send(inStream, - inStream->seekable, - chunk, chunkpos, - total_time, - bitRate, replayGainInfo); + decoder_data(mpd_decoder, inStream, + inStream->seekable, + chunk, chunkpos, + total_time, + bitRate, replayGainInfo); chunkpos = 0; s16 = (mpd_sint16 *) chunk; @@ -237,9 +237,9 @@ static int mpc_decode(struct decoder * mpd_decoder, InputStream * inStream) bitRate = vbrUpdateBits * dc.audioFormat.sampleRate / 1152 / 1000; - ob_send(NULL, inStream->seekable, - chunk, chunkpos, total_time, bitRate, - replayGainInfo); + decoder_data(mpd_decoder, NULL, inStream->seekable, + chunk, chunkpos, total_time, bitRate, + replayGainInfo); } ob_flush(); diff --git a/src/inputPlugins/oggvorbis_plugin.c b/src/inputPlugins/oggvorbis_plugin.c index 0867de69..1333bc15 100644 --- a/src/inputPlugins/oggvorbis_plugin.c +++ b/src/inputPlugins/oggvorbis_plugin.c @@ -309,12 +309,11 @@ static int oggvorbis_decode(struct decoder * decoder, InputStream * inStream) if ((test = ov_bitrate_instant(&vf)) > 0) { bitRate = test / 1000; } - ob_send(inStream, - inStream->seekable, - chunk, chunkpos, - ov_pcm_tell(&vf) / - dc.audioFormat.sampleRate, - bitRate, replayGainInfo); + decoder_data(decoder, inStream, + inStream->seekable, + chunk, chunkpos, + ov_pcm_tell(&vf) / dc.audioFormat.sampleRate, + bitRate, replayGainInfo); chunkpos = 0; if (dc.command == DECODE_COMMAND_STOP) break; @@ -322,10 +321,10 @@ static int oggvorbis_decode(struct decoder * decoder, InputStream * inStream) } if (dc.command != DECODE_COMMAND_STOP && chunkpos > 0) { - ob_send(NULL, inStream->seekable, - chunk, chunkpos, - ov_time_tell(&vf), bitRate, - replayGainInfo); + decoder_data(decoder, NULL, inStream->seekable, + chunk, chunkpos, + ov_time_tell(&vf), bitRate, + replayGainInfo); } if (replayGainInfo) diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c index cd832fdc..e4134bb3 100644 --- a/src/inputPlugins/wavpack_plugin.c +++ b/src/inputPlugins/wavpack_plugin.c @@ -207,10 +207,10 @@ static void wavpack_decode(struct decoder * decoder, format_samples(Bps, chunk, samplesgot * dc.audioFormat.channels); - ob_send(NULL, 0, chunk, - samplesgot * outsamplesize, - file_time, bitrate, - replayGainInfo); + decoder_data(decoder, NULL, 0, chunk, + samplesgot * outsamplesize, + file_time, bitrate, + replayGainInfo); } } while (samplesgot == samplesreq); diff --git a/src/outputBuffer.c b/src/outputBuffer.c index ff8cf758..97a9e78b 100644 --- a/src/outputBuffer.c +++ b/src/outputBuffer.c @@ -17,10 +17,9 @@ */ #include "outputBuffer.h" +#include "playerData.h" #include "utils.h" -#include "normalize.h" -#include "playerData.h" void ob_init(unsigned int size) { @@ -148,16 +147,12 @@ ob_chunk * ob_get_chunk(const unsigned i) } /** - * Return the tail chunk which has room for additional data. If there - * is no room in the queue, this function blocks until the player - * thread has finished playing its current chunk. + * Return the tail chunk which has room for additional data. * - * @return the positive index of the new chunk; OUTPUT_BUFFER_DC_SEEK - * if another thread requested seeking; OUTPUT_BUFFER_DC_STOP if - * another thread requested stopping the decoder. + * @return the positive index of the new chunk; -1 if there is no + * room. */ -static int tailChunk(InputStream * inStream, - int seekable, float data_time, mpd_uint16 bitRate) +static int tailChunk(float data_time, mpd_uint16 bitRate) { unsigned int next; ob_chunk *chunk; @@ -167,26 +162,9 @@ static int tailChunk(InputStream * inStream, if (chunk->chunkSize == sizeof(chunk->data)) { /* this chunk is full; allocate a new chunk */ next = successor(ob.end); - while (ob.begin == next) { - /* all chunks are full of decoded data; wait - for the player to free one */ - - if (dc.command == DECODE_COMMAND_STOP) - return OUTPUT_BUFFER_DC_STOP; - - if (dc.command == DECODE_COMMAND_SEEK) { - if (seekable) { - return OUTPUT_BUFFER_DC_SEEK; - } else { - dc.seekError = 1; - dc_command_finished(); - } - } - if (!inStream || bufferInputStream(inStream) <= 0) { - notify_wait(&dc.notify); - notify_signal(&pc.notify); - } - } + if (ob.begin == next) + /* no chunks available */ + return -1; output_buffer_expand(next); chunk = ob_get_chunk(next); @@ -204,46 +182,17 @@ static int tailChunk(InputStream * inStream, return ob.end; } -int ob_send(InputStream * inStream, - int seekable, void *dataIn, - size_t dataInLen, float data_time, mpd_uint16 bitRate, - ReplayGainInfo * replayGainInfo) +size_t ob_append(const void *data0, size_t datalen, + float data_time, mpd_uint16 bitRate) { - size_t dataToSend; - char *data; - size_t datalen; - static char *convBuffer; - static size_t convBufferLen; + const unsigned char *data = data0; + size_t ret = 0, dataToSend; ob_chunk *chunk = NULL; - if (cmpAudioFormat(&(ob.audioFormat), &(dc.audioFormat)) == 0) { - data = dataIn; - datalen = dataInLen; - } else { - datalen = pcm_sizeOfConvBuffer(&(dc.audioFormat), dataInLen, - &(ob.audioFormat)); - if (datalen > convBufferLen) { - if (convBuffer != NULL) - free(convBuffer); - convBuffer = xmalloc(datalen); - convBufferLen = datalen; - } - data = convBuffer; - datalen = pcm_convertAudioFormat(&(dc.audioFormat), dataIn, - dataInLen, &(ob.audioFormat), - data, &(ob.convState)); - } - - if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF)) - doReplayGain(replayGainInfo, data, datalen, &ob.audioFormat); - else if (normalizationEnabled) - normalizeData(data, datalen, &ob.audioFormat); - while (datalen) { - int chunk_index = tailChunk(inStream, seekable, - data_time, bitRate); + int chunk_index = tailChunk(data_time, bitRate); if (chunk_index < 0) - return chunk_index; + return ret; chunk = ob_get_chunk(chunk_index); @@ -255,12 +204,13 @@ int ob_send(InputStream * inStream, chunk->chunkSize += dataToSend; datalen -= dataToSend; data += dataToSend; + ret += dataToSend; } if (chunk != NULL && chunk->chunkSize == sizeof(chunk->data)) ob_flush(); - return 0; + return ret; } void ob_skip(unsigned num) diff --git a/src/outputBuffer.h b/src/outputBuffer.h index da574f4b..ebbc0d22 100644 --- a/src/outputBuffer.h +++ b/src/outputBuffer.h @@ -20,9 +20,6 @@ #define OUTPUT_BUFFER_H #include "pcm_utils.h" -#include "mpd_types.h" -#include "inputStream.h" -#include "replayGain.h" #define OUTPUT_BUFFER_DC_STOP -1 #define OUTPUT_BUFFER_DC_SEEK -2 @@ -98,15 +95,15 @@ int ob_absolute(const unsigned relative); ob_chunk * ob_get_chunk(const unsigned i); -/* we send inStream for buffering the inputStream while waiting to - send the next chunk */ -int ob_send(InputStream * inStream, - int seekable, - void *data, - size_t datalen, - float data_time, - mpd_uint16 bitRate, ReplayGainInfo * replayGainInfo); +/** + * Append a data block to the buffer. + * + * @return the number of bytes actually written + */ +size_t ob_append(const void *data, size_t datalen, + float data_time, mpd_uint16 bitRate); void ob_skip(unsigned num); #endif + -- cgit v1.2.3