mirror of
https://github.com/mpv-player/mpv
synced 2025-01-21 07:10:52 +00:00
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.
This commit is contained in:
parent
58880c00ee
commit
7e209185f1
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user