From 7e209185f1fa804dda4474de7246a4d85418315e Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 5 Jul 2014 16:45:56 +0200 Subject: demux, stream: change metadata notification (Again.) This time, we simply make it event-based, as it should be. This is done for both demuxer metadata and stream metadata. For some ogg-over-icy streams, 2 updates are reported on stream start. This is because libavformat reports an update right on start, while including the same info in the "static" metadata. I don't know if that's a bug or a feature. --- common/tags.c | 6 ++++++ common/tags.h | 1 + demux/demux.c | 33 ++++++++++++--------------------- demux/demux.h | 10 +++++++++- demux/demux_lavf.c | 1 + stream/cache.c | 23 +++++++++-------------- stream/stream_lavf.c | 46 +++++++++++++++++++--------------------------- 7 files changed, 57 insertions(+), 63 deletions(-) diff --git a/common/tags.c b/common/tags.c index f709cf0d5a..03765272df 100644 --- a/common/tags.c +++ b/common/tags.c @@ -61,6 +61,12 @@ void mp_tags_clear(struct mp_tags *tags) talloc_free_children(tags); } +void mp_tags_merge(struct mp_tags *tags, struct mp_tags *src) +{ + for (int n = 0; n < src->num_keys; n++) + mp_tags_set_str(tags, src->keys[n], src->values[n]); +} + void mp_tags_copy_from_av_dictionary(struct mp_tags *tags, struct AVDictionary *av_dict) { diff --git a/common/tags.h b/common/tags.h index 3bc0e6984b..4b7bcfa791 100644 --- a/common/tags.h +++ b/common/tags.h @@ -14,6 +14,7 @@ void mp_tags_set_bstr(struct mp_tags *tags, bstr key, bstr value); char *mp_tags_get_str(struct mp_tags *tags, const char *key); char *mp_tags_get_bstr(struct mp_tags *tags, bstr key); void mp_tags_clear(struct mp_tags *tags); +void mp_tags_merge(struct mp_tags *tags, struct mp_tags *src); struct AVDictionary; void mp_tags_copy_from_av_dictionary(struct mp_tags *tags, struct AVDictionary *av_dict); diff --git a/demux/demux.c b/demux/demux.c index 92a68d260e..b13225e642 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -651,31 +651,22 @@ char *demux_info_get(demuxer_t *demuxer, const char *opt) bool demux_info_update(struct demuxer *demuxer) { - struct mp_tags *tags = demuxer->metadata; + bool r = false; // Take care of stream metadata as well - char **meta; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_METADATA, &meta) > 0) { - for (int n = 0; meta[n + 0]; n += 2) - mp_tags_set_str(tags, meta[n + 0], meta[n + 1]); - talloc_free(meta); + struct mp_tags *s_meta = NULL; + if (stream_control(demuxer->stream, STREAM_CTRL_GET_METADATA, &s_meta) > 0) { + talloc_free(demuxer->stream_metadata); + demuxer->stream_metadata = talloc_steal(demuxer, s_meta); + demuxer->events |= DEMUX_EVENT_METADATA; } - // Check for metadata changes the hard way. - char *data = talloc_strdup(demuxer, ""); - for (int n = 0; n < tags->num_keys; n++) { - data = talloc_asprintf_append_buffer(data, "%s=%s\n", tags->keys[n], - tags->values[n]); - } - if (!demuxer->previous_metadata || - strcmp(demuxer->previous_metadata, data) != 0) - { - talloc_free(demuxer->previous_metadata); - demuxer->previous_metadata = data; + if (demuxer->events & DEMUX_EVENT_METADATA) { + demuxer->events &= ~DEMUX_EVENT_METADATA; + if (demuxer->stream_metadata) + mp_tags_merge(demuxer->metadata, demuxer->stream_metadata); demux_info_print(demuxer); - return true; - } else { - talloc_free(data); - return false; + r = true; } + return r; } int demux_control(demuxer_t *demuxer, int cmd, void *arg) diff --git a/demux/demux.h b/demux/demux.h index df1762eb08..3929e23c94 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -87,6 +87,10 @@ enum demux_check { DEMUX_CHECK_NORMAL, // normal, safe detection }; +enum demux_event { + DEMUX_EVENT_METADATA = (1 << 0), +}; + #define MAX_SH_STREAMS 256 struct demuxer; @@ -181,6 +185,9 @@ typedef struct demuxer { bool ts_resets_possible; bool warned_queue_overflow; + // Bitmask of DEMUX_EVENT_* + int events; + struct sh_stream **streams; int num_streams; bool stream_autoselect; @@ -203,7 +210,8 @@ typedef struct demuxer { struct playlist *playlist; struct mp_tags *metadata; - char *previous_metadata; + + struct mp_tags *stream_metadata; void *priv; // demuxer-specific internal data struct MPOpts *opts; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index f10c23a753..76a7d50471 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -616,6 +616,7 @@ static void update_metadata(demuxer_t *demuxer, AVPacket *pkt) mp_tags_clear(demuxer->metadata); mp_tags_copy_from_av_dictionary(demuxer->metadata, dict); av_dict_free(&dict); + demuxer->events |= DEMUX_EVENT_METADATA; } } #endif diff --git a/stream/cache.c b/stream/cache.c index db050734f9..3523f04704 100644 --- a/stream/cache.c +++ b/stream/cache.c @@ -56,6 +56,7 @@ #include "osdep/threads.h" #include "common/msg.h" +#include "common/tags.h" #include "options/options.h" #include "stream.h" @@ -115,7 +116,7 @@ struct priv { unsigned int stream_num_chapters; int stream_cache_idle; int stream_cache_fill; - char **stream_metadata; + struct mp_tags *stream_metadata; char *disc_name; }; @@ -372,7 +373,7 @@ static void update_cached_controls(struct priv *s) unsigned int ui; int64_t i64; double d; - char **m; + struct mp_tags *tags; char *t; s->stream_time_length = 0; if (stream_control(s->stream, STREAM_CTRL_GET_TIME_LENGTH, &d) == STREAM_OK) @@ -386,9 +387,9 @@ static void update_cached_controls(struct priv *s) s->stream_num_chapters = 0; if (stream_control(s->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &ui) == STREAM_OK) s->stream_num_chapters = ui; - if (stream_control(s->stream, STREAM_CTRL_GET_METADATA, &m) == STREAM_OK) { + if (stream_control(s->stream, STREAM_CTRL_GET_METADATA, &tags) == STREAM_OK) { talloc_free(s->stream_metadata); - s->stream_metadata = talloc_steal(s, m); + s->stream_metadata = talloc_steal(s, tags); } if (stream_control(s->stream, STREAM_CTRL_GET_DISC_NAME, &t) == STREAM_OK) { @@ -450,16 +451,10 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg) return STREAM_UNSUPPORTED; } case STREAM_CTRL_GET_METADATA: { - if (s->stream_metadata && s->stream_metadata[0]) { - char **m = talloc_new(NULL); - int num_m = 0; - for (int n = 0; s->stream_metadata[n]; n++) { - char *t = talloc_strdup(m, s->stream_metadata[n]); - MP_TARRAY_APPEND(NULL, m, num_m, t); - } - MP_TARRAY_APPEND(NULL, m, num_m, NULL); - MP_TARRAY_APPEND(NULL, m, num_m, NULL); - *(char ***)arg = m; + if (s->stream_metadata) { + ta_set_parent(s->stream_metadata, NULL); + *(struct mp_tags **)arg = s->stream_metadata; + s->stream_metadata = NULL; return STREAM_OK; } return STREAM_UNSUPPORTED; diff --git a/stream/stream_lavf.c b/stream/stream_lavf.c index 82aa4ab820..925be8acd1 100644 --- a/stream/stream_lavf.c +++ b/stream/stream_lavf.c @@ -24,6 +24,7 @@ #include "options/options.h" #include "options/path.h" #include "common/msg.h" +#include "common/tags.h" #include "stream.h" #include "options/m_option.h" @@ -33,7 +34,7 @@ #include "talloc.h" static int open_f(stream_t *stream); -static char **read_icy(stream_t *stream); +static struct mp_tags *read_icy(stream_t *stream); static int fill_buffer(stream_t *s, char *buffer, int max_len) { @@ -102,8 +103,8 @@ static int control(stream_t *s, int cmd, void *arg) return 1; break; case STREAM_CTRL_GET_METADATA: { - *(char ***)arg = read_icy(s); - if (!*(char ***)arg) + *(struct mp_tags **)arg = read_icy(s); + if (!*(struct mp_tags **)arg) break; return 1; } @@ -247,17 +248,7 @@ out: return res; } -static void append_meta(char ***info, int *num_info, bstr name, bstr val) -{ - if (name.len && val.len) { - char *cname = talloc_asprintf(*info, "icy-%.*s", BSTR_P(name)); - char *cval = talloc_asprintf(*info, "%.*s", BSTR_P(val)); - MP_TARRAY_APPEND(NULL, *info, *num_info, cname); - MP_TARRAY_APPEND(NULL, *info, *num_info, cval); - } -} - -static char **read_icy(stream_t *s) +static struct mp_tags *read_icy(stream_t *s) { AVIOContext *avio = s->priv; @@ -274,37 +265,38 @@ static char **read_icy(stream_t *s) &icy_packet) < 0) icy_packet = NULL; - char **res = NULL; + // Send a metadata update only 1. on start, and 2. on a new metadata packet. + // To detect new packages, set the icy_metadata_packet to "-" once we've + // read it (a bit hacky, but works). + struct mp_tags *res = NULL; if ((!icy_header || !icy_header[0]) && (!icy_packet || !icy_packet[0])) goto done; - res = talloc_new(NULL); - int num_res = 0; + bstr packet = bstr0(icy_packet); + if (bstr_equals0(packet, "-")) + goto done; + + res = talloc_zero(NULL, struct mp_tags); + bstr header = bstr0(icy_header); while (header.len) { bstr line = bstr_strip_linebreaks(bstr_getline(header, &header)); bstr name, val; - if (bstr_split_tok(line, ": ", &name, &val)) { - bstr_eatstart0(&name, "icy-"); - append_meta(&res, &num_res, name, val); - } + if (bstr_split_tok(line, ": ", &name, &val)) + mp_tags_set_bstr(res, name, val); } - bstr packet = bstr0(icy_packet); bstr head = bstr0("StreamTitle='"); int i = bstr_find(packet, head); if (i >= 0) { packet = bstr_cut(packet, i + head.len); int end = bstrchr(packet, '\''); packet = bstr_splice(packet, 0, end); - append_meta(&res, &num_res, bstr0("title"), packet); + mp_tags_set_bstr(res, bstr0("icy-title"), packet); } - if (res) { - MP_TARRAY_APPEND(NULL, res, num_res, NULL); - MP_TARRAY_APPEND(NULL, res, num_res, NULL); - } + av_opt_set(avio, "icy_metadata_packet", "-", AV_OPT_SEARCH_CHILDREN); done: av_free(icy_header); -- cgit v1.2.3