decoder_api: automatically send stream tag
If an input stream provides tags (e.g. from an icecast server), send them in the decoder_data() and decoder_tag() methods. Removed the according code from the mp3 and oggvorbis plugins - decoders shouldn't have to care about stream tags. This patch also adds the missing decoder_tag() invocation to the mp3 plugin.
This commit is contained in:
parent
8bb2da063f
commit
ac96022c1d
@ -942,19 +942,6 @@ mp3_synth_and_send(struct mp3_data *data, ReplayGainInfo *replay_gain_info)
|
|||||||
return DECODE_COMMAND_STOP;
|
return DECODE_COMMAND_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->input_stream->meta_title) {
|
|
||||||
struct tag *tag = tag_new();
|
|
||||||
if (data->input_stream->meta_name) {
|
|
||||||
tag_add_item(tag, TAG_ITEM_NAME,
|
|
||||||
data->input_stream->meta_name);
|
|
||||||
}
|
|
||||||
tag_add_item(tag, TAG_ITEM_TITLE,
|
|
||||||
data->input_stream->meta_title);
|
|
||||||
free(data->input_stream->meta_title);
|
|
||||||
data->input_stream->meta_title = NULL;
|
|
||||||
tag_free(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data->decoded_first_frame) {
|
if (!data->decoded_first_frame) {
|
||||||
i = data->drop_start_samples;
|
i = data->drop_start_samples;
|
||||||
data->decoded_first_frame = true;
|
data->decoded_first_frame = true;
|
||||||
@ -1079,37 +1066,14 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
|
|||||||
|
|
||||||
mp3_audio_format(&data, &audio_format);
|
mp3_audio_format(&data, &audio_format);
|
||||||
|
|
||||||
if (input_stream->meta_title) {
|
|
||||||
if (tag)
|
|
||||||
tag_free(tag);
|
|
||||||
tag = tag_new();
|
|
||||||
tag_add_item(tag, TAG_ITEM_TITLE, input_stream->meta_title);
|
|
||||||
free(input_stream->meta_title);
|
|
||||||
input_stream->meta_title = NULL;
|
|
||||||
if (input_stream->meta_name) {
|
|
||||||
tag_add_item(tag, TAG_ITEM_NAME,
|
|
||||||
input_stream->meta_name);
|
|
||||||
}
|
|
||||||
tag_free(tag);
|
|
||||||
} else if (tag) {
|
|
||||||
if (input_stream->meta_name) {
|
|
||||||
tag_clear_items_by_type(tag, TAG_ITEM_NAME);
|
|
||||||
tag_add_item(tag, TAG_ITEM_NAME,
|
|
||||||
input_stream->meta_name);
|
|
||||||
}
|
|
||||||
tag_free(tag);
|
|
||||||
} else if (input_stream->meta_name) {
|
|
||||||
tag = tag_new();
|
|
||||||
if (input_stream->meta_name) {
|
|
||||||
tag_add_item(tag, TAG_ITEM_NAME,
|
|
||||||
input_stream->meta_name);
|
|
||||||
}
|
|
||||||
tag_free(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format,
|
decoder_initialized(decoder, &audio_format,
|
||||||
data.input_stream->seekable, data.total_time);
|
data.input_stream->seekable, data.total_time);
|
||||||
|
|
||||||
|
if (tag != NULL) {
|
||||||
|
decoder_tag(decoder, input_stream, tag);
|
||||||
|
tag_free(tag);
|
||||||
|
}
|
||||||
|
|
||||||
while (mp3_read(&data, &replay_gain_info)) ;
|
while (mp3_read(&data, &replay_gain_info)) ;
|
||||||
|
|
||||||
if (replay_gain_info)
|
if (replay_gain_info)
|
||||||
|
@ -181,23 +181,14 @@ static struct tag *oggCommentsParse(char **comments)
|
|||||||
|
|
||||||
static void putOggCommentsIntoOutputBuffer(struct decoder *decoder,
|
static void putOggCommentsIntoOutputBuffer(struct decoder *decoder,
|
||||||
struct input_stream *is,
|
struct input_stream *is,
|
||||||
char *streamName,
|
|
||||||
char **comments)
|
char **comments)
|
||||||
{
|
{
|
||||||
struct tag *tag;
|
struct tag *tag;
|
||||||
|
|
||||||
tag = oggCommentsParse(comments);
|
tag = oggCommentsParse(comments);
|
||||||
if (!tag && streamName) {
|
|
||||||
tag = tag_new();
|
|
||||||
}
|
|
||||||
if (!tag)
|
if (!tag)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (streamName) {
|
|
||||||
tag_clear_items_by_type(tag, TAG_ITEM_NAME);
|
|
||||||
tag_add_item(tag, TAG_ITEM_NAME, streamName);
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder_tag(decoder, is, tag);
|
decoder_tag(decoder, is, tag);
|
||||||
tag_free(tag);
|
tag_free(tag);
|
||||||
}
|
}
|
||||||
@ -288,7 +279,6 @@ oggvorbis_decode(struct decoder *decoder, struct input_stream *inStream)
|
|||||||
}
|
}
|
||||||
comments = ov_comment(&vf, -1)->user_comments;
|
comments = ov_comment(&vf, -1)->user_comments;
|
||||||
putOggCommentsIntoOutputBuffer(decoder, inStream,
|
putOggCommentsIntoOutputBuffer(decoder, inStream,
|
||||||
inStream->meta_name,
|
|
||||||
comments);
|
comments);
|
||||||
ogg_getReplayGainInfo(comments, &replayGainInfo);
|
ogg_getReplayGainInfo(comments, &replayGainInfo);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,33 @@ size_t decoder_read(struct decoder *decoder,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the tag items from the input stream (meta_name, meta_title) to
|
||||||
|
* a duplicate of the specified tag. The return value has to be freed
|
||||||
|
* with tag_free(). If this function returns NULL, then there are no
|
||||||
|
* tags provided by the stream.
|
||||||
|
*/
|
||||||
|
static struct tag *
|
||||||
|
tag_add_stream_tags(const struct tag *src_tag, const struct input_stream *is)
|
||||||
|
{
|
||||||
|
struct tag *tag;
|
||||||
|
|
||||||
|
assert(src_tag != NULL);
|
||||||
|
assert(is != NULL);
|
||||||
|
|
||||||
|
if ((is->meta_name == NULL || tag_has_type(src_tag, TAG_ITEM_NAME)) &&
|
||||||
|
(is->meta_title == NULL || tag_has_type(src_tag, TAG_ITEM_TITLE)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tag = tag_dup(src_tag);
|
||||||
|
if (is->meta_name != NULL && !tag_has_type(src_tag, TAG_ITEM_NAME))
|
||||||
|
tag_add_item(tag, TAG_ITEM_NAME, is->meta_name);
|
||||||
|
if (is->meta_title != NULL && !tag_has_type(src_tag, TAG_ITEM_TITLE))
|
||||||
|
tag_add_item(tag, TAG_ITEM_TITLE, is->meta_title);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All chunks are full of decoded data; wait for the player to free
|
* All chunks are full of decoded data; wait for the player to free
|
||||||
* one.
|
* one.
|
||||||
@ -148,6 +175,20 @@ decoder_data(struct decoder *decoder,
|
|||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
char *data;
|
char *data;
|
||||||
|
|
||||||
|
if (is != NULL && !decoder->stream_tag_sent) {
|
||||||
|
struct tag *tag1 = tag_new(), *tag2;
|
||||||
|
|
||||||
|
tag2 = tag_add_stream_tags(tag1, is);
|
||||||
|
tag_free(tag1);
|
||||||
|
|
||||||
|
if (tag2 != NULL) {
|
||||||
|
music_pipe_tag(tag2);
|
||||||
|
tag_free(tag2);
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder->stream_tag_sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) {
|
if (audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) {
|
||||||
data = _data;
|
data = _data;
|
||||||
} else {
|
} else {
|
||||||
@ -193,11 +234,21 @@ enum decoder_command
|
|||||||
decoder_tag(mpd_unused struct decoder *decoder, struct input_stream *is,
|
decoder_tag(mpd_unused struct decoder *decoder, struct input_stream *is,
|
||||||
const struct tag *tag)
|
const struct tag *tag)
|
||||||
{
|
{
|
||||||
|
struct tag *tag2 = is != NULL ? tag_add_stream_tags(tag, is) : NULL;
|
||||||
|
|
||||||
|
if (tag2 != NULL)
|
||||||
|
tag = tag2;
|
||||||
|
|
||||||
while (!music_pipe_tag(tag)) {
|
while (!music_pipe_tag(tag)) {
|
||||||
enum decoder_command cmd = need_chunks(is);
|
enum decoder_command cmd = need_chunks(is);
|
||||||
if (cmd != DECODE_COMMAND_NONE)
|
if (cmd != DECODE_COMMAND_NONE)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag2 != NULL)
|
||||||
|
tag_free(tag2);
|
||||||
|
|
||||||
|
decoder->stream_tag_sent = true;
|
||||||
|
|
||||||
return DECODE_COMMAND_NONE;
|
return DECODE_COMMAND_NONE;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@ struct decoder {
|
|||||||
struct pcm_convert_state conv_state;
|
struct pcm_convert_state conv_state;
|
||||||
|
|
||||||
bool seeking;
|
bool seeking;
|
||||||
|
|
||||||
|
/** has the tag from the input stream been sent yet? */
|
||||||
|
bool stream_tag_sent;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,6 +72,7 @@ static void decodeStart(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
decoder.seeking = false;
|
decoder.seeking = false;
|
||||||
|
decoder.stream_tag_sent = false;
|
||||||
|
|
||||||
dc.state = DECODE_STATE_START;
|
dc.state = DECODE_STATE_START;
|
||||||
dc.command = DECODE_COMMAND_NONE;
|
dc.command = DECODE_COMMAND_NONE;
|
||||||
|
Loading…
Reference in New Issue
Block a user