decoder_api: added function decoder_replay_gain()

This function replaces the replay_gain_info parameter for
decoder_data().  This allows the decoder to announce replay gain
changes, instead of having to pass the same object over and over.
This commit is contained in:
Max Kellermann 2010-01-03 22:44:23 +01:00
parent e58b4f773f
commit cd8f92c928
23 changed files with 113 additions and 96 deletions

View File

@ -44,7 +44,6 @@ flac_data_init(struct flac_data *data, struct decoder * decoder,
data->position = 0;
data->decoder = decoder;
data->input_stream = input_stream;
data->replay_gain_info = NULL;
data->tag = NULL;
}
@ -53,9 +52,6 @@ flac_data_deinit(struct flac_data *data)
{
pcm_buffer_deinit(&data->buffer);
if (data->replay_gain_info != NULL)
replay_gain_info_free(data->replay_gain_info);
if (data->tag != NULL)
tag_free(data->tag);
}
@ -111,6 +107,8 @@ flac_data_get_audio_format(struct flac_data *data,
void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
struct flac_data *data)
{
struct replay_gain_info *rgi;
switch (block->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
data->stream_info = block->data.stream_info;
@ -118,9 +116,11 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
if (data->replay_gain_info)
replay_gain_info_free(data->replay_gain_info);
data->replay_gain_info = flac_parse_replay_gain(block);
rgi = flac_parse_replay_gain(block);
if (rgi != NULL) {
decoder_replay_gain(data->decoder, rgi);
replay_gain_info_free(rgi);
}
if (data->tag != NULL)
flac_vorbis_comments_to_tag(data->tag, NULL,
@ -177,8 +177,7 @@ flac_common_write(struct flac_data *data, const FLAC__Frame * frame,
cmd = decoder_data(data->decoder, data->input_stream,
buffer, buffer_size,
bit_rate,
data->replay_gain_info);
bit_rate);
data->next_frame += frame->header.blocksize;
switch (cmd) {
case DECODE_COMMAND_NONE:

View File

@ -72,7 +72,6 @@ struct flac_data {
FLAC__uint64 position;
struct decoder *decoder;
struct input_stream *input_stream;
struct replay_gain_info *replay_gain_info;
struct tag *tag;
};

View File

@ -206,7 +206,7 @@ audiofile_stream_decode(struct decoder *decoder, struct input_stream *is)
cmd = decoder_data(decoder, NULL,
chunk, ret * fs,
bit_rate, NULL);
bit_rate);
if (cmd == DECODE_COMMAND_SEEK) {
AFframecount frame = decoder_seek_where(decoder) *

View File

@ -479,7 +479,7 @@ faad_stream_decode(struct decoder *mpd_decoder, struct input_stream *is)
cmd = decoder_data(mpd_decoder, is, decoded,
(size_t)frame_info.samples * 2,
bit_rate, NULL);
bit_rate);
} while (cmd != DECODE_COMMAND_STOP);
/* cleanup */

View File

@ -270,7 +270,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
cmd = decoder_data(decoder, is,
aligned_buffer, audio_size,
codec_context->bit_rate / 1000, NULL);
codec_context->bit_rate / 1000);
}
return cmd;
}

View File

@ -204,7 +204,7 @@ fluidsynth_file_decode(struct decoder *decoder, const char *path_fs)
break;
cmd = decoder_data(decoder, NULL, buffer, sizeof(buffer),
0, NULL);
0);
} while (cmd == DECODE_COMMAND_NONE);
/* clean up */

View File

@ -126,6 +126,7 @@ struct mp3_data {
unsigned int drop_end_frames;
unsigned int drop_start_samples;
unsigned int drop_end_samples;
bool found_replay_gain;
bool found_xing;
bool found_first_frame;
bool decoded_first_frame;
@ -149,6 +150,7 @@ mp3_data_init(struct mp3_data *data, struct decoder *decoder,
data->drop_end_frames = 0;
data->drop_start_samples = 0;
data->drop_end_samples = 0;
data->found_replay_gain = false;
data->found_xing = false;
data->found_first_frame = false;
data->decoded_first_frame = false;
@ -352,8 +354,7 @@ parse_id3_replay_gain_info(struct id3_tag *tag)
#endif
static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
struct tag **mpd_tag,
struct replay_gain_info **replay_gain_info_r)
struct tag **mpd_tag)
{
#ifdef HAVE_ID3TAG
struct id3_tag *id3_tag = NULL;
@ -406,13 +407,13 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
}
}
if (replay_gain_info_r) {
if (data->decoder != NULL) {
struct replay_gain_info *tmp_rgi =
parse_id3_replay_gain_info(id3_tag);
if (tmp_rgi != NULL) {
if (*replay_gain_info_r)
replay_gain_info_free(*replay_gain_info_r);
*replay_gain_info_r = tmp_rgi;
decoder_replay_gain(data->decoder, tmp_rgi);
replay_gain_info_free(tmp_rgi);
data->found_replay_gain = true;
}
}
@ -449,8 +450,7 @@ id3_tag_query(const void *p0, size_t length)
#endif /* !HAVE_ID3TAG */
static enum mp3_action
decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag,
G_GNUC_UNUSED struct replay_gain_info **replay_gain_info_r)
decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag)
{
enum mad_layer layer;
@ -472,7 +472,7 @@ decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag,
if (tagsize > 0) {
if (tag && !(*tag)) {
mp3_parse_id3(data, (size_t)tagsize,
tag, replay_gain_info_r);
tag);
} else {
mad_stream_skip(&(data->stream),
tagsize);
@ -820,8 +820,7 @@ mp3_filesize_to_song_length(struct mp3_data *data)
}
static bool
mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
struct replay_gain_info **replay_gain_info_r)
mp3_decode_first_frame(struct mp3_data *data, struct tag **tag)
{
struct xing xing;
struct lame lame;
@ -835,8 +834,7 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
while (true) {
do {
ret = decode_next_frame_header(data, tag,
replay_gain_info_r);
ret = decode_next_frame_header(data, tag);
} while (ret == DECODE_CONT);
if (ret == DECODE_BREAK)
return false;
@ -879,11 +877,15 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag,
/* Album gain isn't currently used. See comment in
* parse_lame() for details. -- jat */
if (replay_gain_info_r && !*replay_gain_info_r &&
if (data->decoder != NULL &&
!data->found_replay_gain &&
lame.track_gain) {
*replay_gain_info_r = replay_gain_info_new();
(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
(*replay_gain_info_r)->tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
struct replay_gain_info *rgi
= replay_gain_info_new();
rgi->tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
rgi->tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
decoder_replay_gain(data->decoder, rgi);
replay_gain_info_free(rgi);
}
}
}
@ -921,7 +923,7 @@ mad_decoder_total_file_time(struct input_stream *is)
int ret;
mp3_data_init(&data, NULL, is);
if (!mp3_decode_first_frame(&data, NULL, NULL))
if (!mp3_decode_first_frame(&data, NULL))
ret = -1;
else
ret = data.total_time + 0.5;
@ -932,12 +934,11 @@ mad_decoder_total_file_time(struct input_stream *is)
static bool
mp3_open(struct input_stream *is, struct mp3_data *data,
struct decoder *decoder, struct tag **tag,
struct replay_gain_info **replay_gain_info_r)
struct decoder *decoder, struct tag **tag)
{
mp3_data_init(data, decoder, is);
*tag = NULL;
if (!mp3_decode_first_frame(data, tag, replay_gain_info_r)) {
if (!mp3_decode_first_frame(data, tag)) {
mp3_data_finish(data);
if (tag && *tag)
tag_free(*tag);
@ -996,8 +997,7 @@ mp3_update_timer_next_frame(struct mp3_data *data)
* Sends the synthesized current frame via decoder_data().
*/
static enum decoder_command
mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
struct replay_gain_info *replay_gain_info)
mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length)
{
unsigned max_samples;
@ -1022,8 +1022,7 @@ mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
cmd = decoder_data(data->decoder, data->input_stream,
data->output_buffer,
sizeof(data->output_buffer[0]) * num_samples,
data->bit_rate / 1000,
replay_gain_info);
data->bit_rate / 1000);
if (cmd != DECODE_COMMAND_NONE)
return cmd;
}
@ -1035,8 +1034,7 @@ mp3_send_pcm(struct mp3_data *data, unsigned i, unsigned pcm_length,
* Synthesize the current frame and send it via decoder_data().
*/
static enum decoder_command
mp3_synth_and_send(struct mp3_data *data,
struct replay_gain_info *replay_gain_info)
mp3_synth_and_send(struct mp3_data *data)
{
unsigned i, pcm_length;
enum decoder_command cmd;
@ -1077,7 +1075,7 @@ mp3_synth_and_send(struct mp3_data *data,
pcm_length -= data->drop_end_samples;
}
cmd = mp3_send_pcm(data, i, pcm_length, replay_gain_info);
cmd = mp3_send_pcm(data, i, pcm_length);
if (cmd != DECODE_COMMAND_NONE)
return cmd;
@ -1091,7 +1089,7 @@ mp3_synth_and_send(struct mp3_data *data,
}
static bool
mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
mp3_read(struct mp3_data *data)
{
struct decoder *decoder = data->decoder;
enum mp3_action ret;
@ -1108,9 +1106,7 @@ mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
data->mute_frame = MUTEFRAME_NONE;
break;
case MUTEFRAME_NONE:
cmd = mp3_synth_and_send(data,
replay_gain_info_r != NULL
? *replay_gain_info_r : NULL);
cmd = mp3_synth_and_send(data);
if (cmd == DECODE_COMMAND_SEEK) {
unsigned long j;
@ -1139,8 +1135,7 @@ mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r)
do {
struct tag *tag = NULL;
ret = decode_next_frame_header(data, &tag,
replay_gain_info_r);
ret = decode_next_frame_header(data, &tag);
if (tag != NULL) {
decoder_tag(decoder, data->input_stream, tag);
@ -1173,10 +1168,9 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
struct mp3_data data;
GError *error = NULL;
struct tag *tag = NULL;
struct replay_gain_info *replay_gain_info = NULL;
struct audio_format audio_format;
if (!mp3_open(input_stream, &data, decoder, &tag, &replay_gain_info)) {
if (!mp3_open(input_stream, &data, decoder, &tag)) {
if (decoder_get_command(decoder) == DECODE_COMMAND_NONE)
g_warning
("Input does not appear to be a mp3 bit stream.\n");
@ -1193,8 +1187,6 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
if (tag != NULL)
tag_free(tag);
if (replay_gain_info != NULL)
replay_gain_info_free(replay_gain_info);
mp3_data_finish(&data);
return;
}
@ -1207,10 +1199,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
tag_free(tag);
}
while (mp3_read(&data, &replay_gain_info)) ;
if (replay_gain_info)
replay_gain_info_free(replay_gain_info);
while (mp3_read(&data)) ;
if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK &&
data.mute_frame == MUTEFRAME_SEEK)

View File

@ -169,8 +169,7 @@ mikmod_decoder_file_decode(struct decoder *decoder, const char *path_fs)
Player_Start(handle);
while (cmd == DECODE_COMMAND_NONE && Player_Active()) {
ret = VC_WriteBytes(buffer, sizeof(buffer));
cmd = decoder_data(decoder, NULL, buffer, ret,
0, NULL);
cmd = decoder_data(decoder, NULL, buffer, ret, 0);
}
Player_Stop();

View File

@ -134,7 +134,7 @@ mod_decode(struct decoder *decoder, struct input_stream *is)
cmd = decoder_data(decoder, NULL,
audio_buffer, ret,
0, NULL);
0);
if (cmd == DECODE_COMMAND_SEEK) {
float where = decoder_seek_where(decoder);

View File

@ -328,7 +328,7 @@ mp4_decode(struct decoder *mpd_decoder, struct input_stream *input_stream)
cmd = decoder_data(mpd_decoder, input_stream,
sample_buffer, sample_buffer_length,
bit_rate, NULL);
bit_rate);
}
g_free(seek_table);

View File

@ -210,6 +210,8 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = info.peak_album / 32767.0;
replay_gain_info->tuples[REPLAY_GAIN_TRACK].gain = info.gain_title * 0.01;
replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = info.peak_title / 32767.0;
decoder_replay_gain(mpd_decoder, replay_gain_info);
replay_gain_info_free(replay_gain_info);
decoder_initialized(mpd_decoder, &audio_format,
is->seekable,
@ -264,11 +266,9 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
cmd = decoder_data(mpd_decoder, is,
chunk, ret * sizeof(chunk[0]),
bit_rate, replay_gain_info);
bit_rate);
} while (cmd != DECODE_COMMAND_STOP);
replay_gain_info_free(replay_gain_info);
#ifndef MPC_IS_OLD_API
mpc_demux_exit(demux);
#endif

View File

@ -146,8 +146,7 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
/* send to MPD */
cmd = decoder_data(decoder, NULL, buffer, nbytes,
0, NULL);
cmd = decoder_data(decoder, NULL, buffer, nbytes, 0);
/* seeking not yet implemented */
} while (cmd == DECODE_COMMAND_NONE);

View File

@ -298,8 +298,7 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs)
decoder_timestamp(decoder, (double)player.time() / timebase);
cmd = decoder_data(decoder, NULL, buffer, nbytes,
0, NULL);
cmd = decoder_data(decoder, NULL, buffer, nbytes, 0);
if(cmd==DECODE_COMMAND_SEEK) {
unsigned data_time = player.time();

View File

@ -155,7 +155,7 @@ sndfile_stream_decode(struct decoder *decoder, struct input_stream *is)
cmd = decoder_data(decoder, is,
buffer, num_frames * frame_size,
0, NULL);
0);
if (cmd == DECODE_COMMAND_SEEK) {
sf_count_t c =
time_to_frame(decoder_seek_where(decoder),

11
src/decoder/vorbis_plugin.c Executable file → Normal file
View File

@ -277,7 +277,6 @@ vorbis_stream_decode(struct decoder *decoder,
char chunk[OGG_CHUNK_SIZE];
long bitRate = 0;
long test;
struct replay_gain_info *replay_gain_info = NULL;
const vorbis_info *vi;
enum decoder_command cmd = DECODE_COMMAND_NONE;
@ -364,9 +363,8 @@ vorbis_stream_decode(struct decoder *decoder,
vorbis_send_comments(decoder, input_stream, comments);
new_rgi = vorbis_comments_to_replay_gain(comments);
if (new_rgi != NULL) {
if (replay_gain_info != NULL)
replay_gain_info_free(replay_gain_info);
replay_gain_info = new_rgi;
decoder_replay_gain(decoder, new_rgi);
replay_gain_info_free(new_rgi);
}
prev_section = current_section;
@ -377,12 +375,9 @@ vorbis_stream_decode(struct decoder *decoder,
cmd = decoder_data(decoder, input_stream,
chunk, ret,
bitRate, replay_gain_info);
bitRate);
} while (cmd != DECODE_COMMAND_STOP);
if (replay_gain_info)
replay_gain_info_free(replay_gain_info);
ov_clear(&vf);
}

View File

@ -155,8 +155,7 @@ wavpack_bits_to_sample_format(bool is_float, int bytes_per_sample)
* Requires an already opened WavpackContext.
*/
static void
wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek,
struct replay_gain_info *replay_gain_info)
wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
{
GError *error = NULL;
bool is_float;
@ -233,8 +232,7 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek,
decoder_data(
decoder, NULL, chunk,
samples_got * output_sample_size,
bitrate,
replay_gain_info
bitrate
);
}
} while (samples_got > 0);
@ -544,7 +542,7 @@ wavpack_streamdecode(struct decoder * decoder, struct input_stream *is)
return;
}
wavpack_decode(decoder, wpc, can_seek, NULL);
wavpack_decode(decoder, wpc, can_seek);
WavpackCloseFile(wpc);
if (open_flags & OPEN_WVC) {
@ -575,13 +573,13 @@ wavpack_filedecode(struct decoder *decoder, const char *fname)
}
replay_gain_info = wavpack_replaygain(wpc);
wavpack_decode(decoder, wpc, true, replay_gain_info);
if (replay_gain_info) {
if (replay_gain_info != NULL) {
decoder_replay_gain(decoder, replay_gain_info);
replay_gain_info_free(replay_gain_info);
}
wavpack_decode(decoder, wpc, true);
WavpackCloseFile(wpc);
}

View File

@ -91,8 +91,7 @@ wildmidi_file_decode(struct decoder *decoder, const char *path_fs)
if (len <= 0)
break;
cmd = decoder_data(decoder, NULL, buffer, len,
0, NULL);
cmd = decoder_data(decoder, NULL, buffer, len, 0);
if (cmd == DECODE_COMMAND_SEEK) {
unsigned long seek_where = WILDMIDI_SAMPLE_RATE *

View File

@ -266,8 +266,7 @@ enum decoder_command
decoder_data(struct decoder *decoder,
struct input_stream *is,
const void *_data, size_t length,
uint16_t kbit_rate,
struct replay_gain_info *replay_gain_info)
uint16_t kbit_rate)
{
struct decoder_control *dc = decoder->dc;
const char *data = _data;
@ -354,7 +353,8 @@ decoder_data(struct decoder *decoder,
/* apply replay gain or normalization */
if (replay_gain_mode != REPLAY_GAIN_OFF)
replay_gain_apply(replay_gain_info, dest, nbytes,
replay_gain_apply(decoder->replay_gain,
dest, nbytes,
&dc->out_audio_format);
/* expand the music pipe chunk */
@ -418,3 +418,17 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
return cmd;
}
void
decoder_replay_gain(struct decoder *decoder,
const struct replay_gain_info *replay_gain_info)
{
assert(decoder != NULL);
if (decoder->replay_gain != NULL)
replay_gain_info_free(decoder->replay_gain);
decoder->replay_gain = replay_gain_info != NULL
? replay_gain_info_dup(replay_gain_info)
: NULL;
}

View File

@ -138,8 +138,7 @@ decoder_timestamp(struct decoder *decoder, double t);
enum decoder_command
decoder_data(struct decoder *decoder, struct input_stream *is,
const void *data, size_t length,
uint16_t kbit_rate,
struct replay_gain_info *replay_gain_info);
uint16_t kbit_rate);
/**
* This function is called by the decoder plugin when it has
@ -156,4 +155,15 @@ enum decoder_command
decoder_tag(struct decoder *decoder, struct input_stream *is,
const struct tag *tag);
/**
* Set replay gain values for the following chunks.
*
* @param decoder the decoder object
* @param rgi the replay_gain_info object; may be NULL to invalidate
* the previous replay gain values
*/
void
decoder_replay_gain(struct decoder *decoder,
const struct replay_gain_info *replay_gain_info);
#endif

View File

@ -52,6 +52,8 @@ struct decoder {
/** the chunk currently being written to */
struct music_chunk *chunk;
struct replay_gain_info *replay_gain;
};
/**

View File

@ -31,6 +31,7 @@
#include "mapper.h"
#include "path.h"
#include "uri.h"
#include "replay_gain.h"
#include <glib.h>
@ -302,6 +303,7 @@ decoder_run_song(struct decoder_control *dc,
{
struct decoder decoder = {
.dc = dc,
.replay_gain = NULL,
};
int ret;
@ -329,6 +331,9 @@ decoder_run_song(struct decoder_control *dc,
pcm_convert_deinit(&decoder.conv_state);
/* flush the last chunk */
if (decoder.replay_gain != NULL)
replay_gain_info_free(decoder.replay_gain);
if (decoder.chunk != NULL)
decoder_flush_chunk(&decoder);

View File

@ -106,8 +106,7 @@ enum decoder_command
decoder_data(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED struct input_stream *is,
const void *data, size_t datalen,
G_GNUC_UNUSED uint16_t bit_rate,
G_GNUC_UNUSED struct replay_gain_info *replay_gain_info)
G_GNUC_UNUSED uint16_t bit_rate)
{
write(1, data, datalen);
return DECODE_COMMAND_NONE;
@ -121,6 +120,12 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder,
return DECODE_COMMAND_NONE;
}
void
decoder_replay_gain(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED const struct replay_gain_info *replay_gain_info)
{
}
static void
print_tag(const struct tag *tag)
{

View File

@ -127,8 +127,7 @@ enum decoder_command
decoder_data(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED struct input_stream *is,
const void *data, size_t datalen,
G_GNUC_UNUSED uint16_t kbit_rate,
G_GNUC_UNUSED struct replay_gain_info *replay_gain_info)
G_GNUC_UNUSED uint16_t kbit_rate)
{
write(1, data, datalen);
return DECODE_COMMAND_NONE;
@ -142,6 +141,12 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder,
return DECODE_COMMAND_NONE;
}
void
decoder_replay_gain(G_GNUC_UNUSED struct decoder *decoder,
G_GNUC_UNUSED const struct replay_gain_info *replay_gain_info)
{
}
int main(int argc, char **argv)
{
GError *error = NULL;