added decoder_data()

Moved all of the player-waiting code to decoder_data(), to make
OutputBuffer more generic.
This commit is contained in:
Max Kellermann 2008-08-26 08:27:05 +02:00
parent 8814c0c898
commit 2a83ccdb8f
13 changed files with 177 additions and 136 deletions

View File

@ -19,6 +19,8 @@
#include "decoder_api.h" #include "decoder_api.h"
#include "utils.h"
#include "normalize.h"
#include "playerData.h" #include "playerData.h"
#include "gcc.h" #include "gcc.h"
@ -29,3 +31,81 @@ void decoder_initialized(mpd_unused struct decoder * decoder)
dc.state = DECODE_STATE_DECODE; dc.state = DECODE_STATE_DECODE;
notify_signal(&pc.notify); 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;
}

View File

@ -27,6 +27,8 @@
*/ */
#include "inputPlugin.h" #include "inputPlugin.h"
#include "inputStream.h"
#include "replayGain.h"
/** /**
* Opaque handle which the decoder plugin passes to the functions in * Opaque handle which the decoder plugin passes to the functions in
@ -40,4 +42,17 @@ struct decoder;
*/ */
void decoder_initialized(struct decoder * 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 #endif

View File

@ -165,12 +165,11 @@ MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
/* keep this inlined, this is just macro but prettier :) */ /* keep this inlined, this is just macro but prettier :) */
static inline int flacSendChunk(FlacData * data) static inline int flacSendChunk(FlacData * data)
{ {
if (ob_send(data->inStream, if (decoder_data(data->decoder, data->inStream,
1, data->chunk, 1, data->chunk,
data->chunk_length, data->time, data->chunk_length, data->time,
data->bitRate, data->bitRate,
data->replayGainInfo) == data->replayGainInfo) == OUTPUT_BUFFER_DC_STOP)
OUTPUT_BUFFER_DC_STOP)
return -1; return -1;
return 0; return 0;

View File

@ -391,9 +391,9 @@ static int aac_decode(struct decoder * mpd_decoder, char *path)
sampleBufferLen = sampleCount * 2; sampleBufferLen = sampleCount * 2;
ob_send(NULL, 0, sampleBuffer, decoder_data(mpd_decoder, NULL, 0, sampleBuffer,
sampleBufferLen, file_time, sampleBufferLen, file_time,
bitRate, NULL); bitRate, NULL);
if (dc.command == DECODE_COMMAND_SEEK) { if (dc.command == DECODE_COMMAND_SEEK) {
dc.seekError = 1; dc.seekError = 1;
dc_command_finished(); dc_command_finished();

View File

@ -106,13 +106,13 @@ static int audiofile_decode(struct decoder * decoder, char *path)
eof = 1; eof = 1;
else { else {
current += ret; current += ret;
ob_send(NULL, decoder_data(decoder, NULL,
1, 1,
chunk, ret * fs, chunk, ret * fs,
(float)current / (float)current /
(float)dc.audioFormat. (float)dc.audioFormat.
sampleRate, bitRate, sampleRate, bitRate,
NULL); NULL);
if (dc.command == DECODE_COMMAND_STOP) if (dc.command == DECODE_COMMAND_STOP)
break; break;
} }

View File

@ -200,9 +200,9 @@ static int mod_decode(struct decoder * decoder, char *path)
ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE); ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE);
total_time += ret * secPerByte; total_time += ret * secPerByte;
ob_send(NULL, 0, decoder_data(decoder, NULL, 0,
(char *)data->audio_buffer, ret, (char *)data->audio_buffer, ret,
total_time, 0, NULL); total_time, 0, NULL);
} }
ob_flush(); ob_flush();

View File

@ -812,7 +812,8 @@ static int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
return 0; return 0;
} }
static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo) static int mp3Read(mp3DecodeData * data, struct decoder *decoder,
ReplayGainInfo ** replayGainInfo)
{ {
int samplesPerFrame; int samplesPerFrame;
int samplesLeft; int samplesLeft;
@ -926,13 +927,13 @@ static int mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo)
} }
if (data->outputPtr >= data->outputBufferEnd) { if (data->outputPtr >= data->outputBufferEnd) {
ret = ob_send(data->inStream, ret = decoder_data(decoder, data->inStream,
data->inStream->seekable, data->inStream->seekable,
data->outputBuffer, data->outputBuffer,
data->outputPtr - data->outputBuffer, data->outputPtr - data->outputBuffer,
data->elapsedTime, data->elapsedTime,
data->bitRate / 1000, data->bitRate / 1000,
(replayGainInfo != NULL) ? *replayGainInfo : NULL); (replayGainInfo != NULL) ? *replayGainInfo : NULL);
if (ret == OUTPUT_BUFFER_DC_STOP) { if (ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0; data->flush = 0;
return DECODE_BREAK; return DECODE_BREAK;
@ -1063,16 +1064,16 @@ static int mp3_decode(struct decoder * decoder, InputStream * inStream)
decoder_initialized(decoder); 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 */ /* send last little bit if not DECODE_COMMAND_STOP */
if (dc.command != DECODE_COMMAND_STOP && if (dc.command != DECODE_COMMAND_STOP &&
data.outputPtr != data.outputBuffer && data.flush) { data.outputPtr != data.outputBuffer && data.flush) {
ob_send(NULL, decoder_data(decoder, NULL,
data.inStream->seekable, data.inStream->seekable,
data.outputBuffer, data.outputBuffer,
data.outputPtr - data.outputBuffer, data.outputPtr - data.outputBuffer,
data.elapsedTime, data.bitRate / 1000, data.elapsedTime, data.bitRate / 1000,
replayGainInfo); replayGainInfo);
} }
if (replayGainInfo) if (replayGainInfo)

View File

@ -270,9 +270,9 @@ static int mp4_decode(struct decoder * mpd_decoder, InputStream * inStream)
sampleBuffer += offset * channels * 2; sampleBuffer += offset * channels * 2;
ob_send(inStream, 1, sampleBuffer, decoder_data(mpd_decoder, inStream, 1, sampleBuffer,
sampleBufferLen, file_time, sampleBufferLen, file_time,
bitRate, NULL); bitRate, NULL);
if (dc.command == DECODE_COMMAND_STOP) { if (dc.command == DECODE_COMMAND_STOP) {
eof = 1; eof = 1;
break; break;

View File

@ -215,11 +215,11 @@ static int mpc_decode(struct decoder * mpd_decoder, InputStream * inStream)
bitRate = vbrUpdateBits * bitRate = vbrUpdateBits *
dc.audioFormat.sampleRate / 1152 / 1000; dc.audioFormat.sampleRate / 1152 / 1000;
ob_send(inStream, decoder_data(mpd_decoder, inStream,
inStream->seekable, inStream->seekable,
chunk, chunkpos, chunk, chunkpos,
total_time, total_time,
bitRate, replayGainInfo); bitRate, replayGainInfo);
chunkpos = 0; chunkpos = 0;
s16 = (mpd_sint16 *) chunk; s16 = (mpd_sint16 *) chunk;
@ -237,9 +237,9 @@ static int mpc_decode(struct decoder * mpd_decoder, InputStream * inStream)
bitRate = bitRate =
vbrUpdateBits * dc.audioFormat.sampleRate / 1152 / 1000; vbrUpdateBits * dc.audioFormat.sampleRate / 1152 / 1000;
ob_send(NULL, inStream->seekable, decoder_data(mpd_decoder, NULL, inStream->seekable,
chunk, chunkpos, total_time, bitRate, chunk, chunkpos, total_time, bitRate,
replayGainInfo); replayGainInfo);
} }
ob_flush(); ob_flush();

View File

@ -309,12 +309,11 @@ static int oggvorbis_decode(struct decoder * decoder, InputStream * inStream)
if ((test = ov_bitrate_instant(&vf)) > 0) { if ((test = ov_bitrate_instant(&vf)) > 0) {
bitRate = test / 1000; bitRate = test / 1000;
} }
ob_send(inStream, decoder_data(decoder, inStream,
inStream->seekable, inStream->seekable,
chunk, chunkpos, chunk, chunkpos,
ov_pcm_tell(&vf) / ov_pcm_tell(&vf) / dc.audioFormat.sampleRate,
dc.audioFormat.sampleRate, bitRate, replayGainInfo);
bitRate, replayGainInfo);
chunkpos = 0; chunkpos = 0;
if (dc.command == DECODE_COMMAND_STOP) if (dc.command == DECODE_COMMAND_STOP)
break; break;
@ -322,10 +321,10 @@ static int oggvorbis_decode(struct decoder * decoder, InputStream * inStream)
} }
if (dc.command != DECODE_COMMAND_STOP && chunkpos > 0) { if (dc.command != DECODE_COMMAND_STOP && chunkpos > 0) {
ob_send(NULL, inStream->seekable, decoder_data(decoder, NULL, inStream->seekable,
chunk, chunkpos, chunk, chunkpos,
ov_time_tell(&vf), bitRate, ov_time_tell(&vf), bitRate,
replayGainInfo); replayGainInfo);
} }
if (replayGainInfo) if (replayGainInfo)

View File

@ -207,10 +207,10 @@ static void wavpack_decode(struct decoder * decoder,
format_samples(Bps, chunk, format_samples(Bps, chunk,
samplesgot * dc.audioFormat.channels); samplesgot * dc.audioFormat.channels);
ob_send(NULL, 0, chunk, decoder_data(decoder, NULL, 0, chunk,
samplesgot * outsamplesize, samplesgot * outsamplesize,
file_time, bitrate, file_time, bitrate,
replayGainInfo); replayGainInfo);
} }
} while (samplesgot == samplesreq); } while (samplesgot == samplesreq);

View File

@ -17,10 +17,9 @@
*/ */
#include "outputBuffer.h" #include "outputBuffer.h"
#include "playerData.h"
#include "utils.h" #include "utils.h"
#include "normalize.h"
#include "playerData.h"
void ob_init(unsigned int size) 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 * Return the tail chunk which has room for additional data.
* is no room in the queue, this function blocks until the player
* thread has finished playing its current chunk.
* *
* @return the positive index of the new chunk; OUTPUT_BUFFER_DC_SEEK * @return the positive index of the new chunk; -1 if there is no
* if another thread requested seeking; OUTPUT_BUFFER_DC_STOP if * room.
* another thread requested stopping the decoder.
*/ */
static int tailChunk(InputStream * inStream, static int tailChunk(float data_time, mpd_uint16 bitRate)
int seekable, float data_time, mpd_uint16 bitRate)
{ {
unsigned int next; unsigned int next;
ob_chunk *chunk; ob_chunk *chunk;
@ -167,26 +162,9 @@ static int tailChunk(InputStream * inStream,
if (chunk->chunkSize == sizeof(chunk->data)) { if (chunk->chunkSize == sizeof(chunk->data)) {
/* this chunk is full; allocate a new chunk */ /* this chunk is full; allocate a new chunk */
next = successor(ob.end); next = successor(ob.end);
while (ob.begin == next) { if (ob.begin == next)
/* all chunks are full of decoded data; wait /* no chunks available */
for the player to free one */ return -1;
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);
}
}
output_buffer_expand(next); output_buffer_expand(next);
chunk = ob_get_chunk(next); chunk = ob_get_chunk(next);
@ -204,46 +182,17 @@ static int tailChunk(InputStream * inStream,
return ob.end; return ob.end;
} }
int ob_send(InputStream * inStream, size_t ob_append(const void *data0, size_t datalen,
int seekable, void *dataIn, float data_time, mpd_uint16 bitRate)
size_t dataInLen, float data_time, mpd_uint16 bitRate,
ReplayGainInfo * replayGainInfo)
{ {
size_t dataToSend; const unsigned char *data = data0;
char *data; size_t ret = 0, dataToSend;
size_t datalen;
static char *convBuffer;
static size_t convBufferLen;
ob_chunk *chunk = NULL; 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) { while (datalen) {
int chunk_index = tailChunk(inStream, seekable, int chunk_index = tailChunk(data_time, bitRate);
data_time, bitRate);
if (chunk_index < 0) if (chunk_index < 0)
return chunk_index; return ret;
chunk = ob_get_chunk(chunk_index); chunk = ob_get_chunk(chunk_index);
@ -255,12 +204,13 @@ int ob_send(InputStream * inStream,
chunk->chunkSize += dataToSend; chunk->chunkSize += dataToSend;
datalen -= dataToSend; datalen -= dataToSend;
data += dataToSend; data += dataToSend;
ret += dataToSend;
} }
if (chunk != NULL && chunk->chunkSize == sizeof(chunk->data)) if (chunk != NULL && chunk->chunkSize == sizeof(chunk->data))
ob_flush(); ob_flush();
return 0; return ret;
} }
void ob_skip(unsigned num) void ob_skip(unsigned num)

View File

@ -20,9 +20,6 @@
#define OUTPUT_BUFFER_H #define OUTPUT_BUFFER_H
#include "pcm_utils.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_STOP -1
#define OUTPUT_BUFFER_DC_SEEK -2 #define OUTPUT_BUFFER_DC_SEEK -2
@ -98,15 +95,15 @@ int ob_absolute(const unsigned relative);
ob_chunk * ob_get_chunk(const unsigned i); ob_chunk * ob_get_chunk(const unsigned i);
/* we send inStream for buffering the inputStream while waiting to /**
send the next chunk */ * Append a data block to the buffer.
int ob_send(InputStream * inStream, *
int seekable, * @return the number of bytes actually written
void *data, */
size_t datalen, size_t ob_append(const void *data, size_t datalen,
float data_time, float data_time, mpd_uint16 bitRate);
mpd_uint16 bitRate, ReplayGainInfo * replayGainInfo);
void ob_skip(unsigned num); void ob_skip(unsigned num);
#endif #endif