mirror of
https://github.com/mpv-player/mpv
synced 2024-11-07 01:47:00 +01:00
demux: refactor tag handling
Make the code somewhat reuseable, instead of bound to a single demuxer instance. The plan is to add support for per-chapter tags later.
This commit is contained in:
parent
1aae5981a7
commit
ba07000b88
@ -542,6 +542,7 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
|
|||||||
.filepos = -1,
|
.filepos = -1,
|
||||||
.opts = opts,
|
.opts = opts,
|
||||||
.filename = talloc_strdup(demuxer, stream->url),
|
.filename = talloc_strdup(demuxer, stream->url),
|
||||||
|
.metadata = talloc_zero(demuxer, struct mp_tags),
|
||||||
};
|
};
|
||||||
demuxer->params = params; // temporary during open()
|
demuxer->params = params; // temporary during open()
|
||||||
stream_seek(stream, stream->start_pos);
|
stream_seek(stream, stream->start_pos);
|
||||||
@ -684,6 +685,42 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mp_tags_set_str(struct mp_tags *tags, const char *key, const char *value)
|
||||||
|
{
|
||||||
|
mp_tags_set_bstr(tags, bstr0(key), bstr0(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_tags_set_bstr(struct mp_tags *tags, bstr key, bstr value)
|
||||||
|
{
|
||||||
|
for (int n = 0; n < tags->num_keys; n++) {
|
||||||
|
if (bstrcasecmp0(key, tags->keys[n]) == 0) {
|
||||||
|
talloc_free(tags->values[n]);
|
||||||
|
tags->values[n] = talloc_strndup(tags, value.start, value.len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP_RESIZE_ARRAY(tags, tags->keys, tags->num_keys + 1);
|
||||||
|
MP_RESIZE_ARRAY(tags, tags->values, tags->num_keys + 1);
|
||||||
|
tags->keys[tags->num_keys] = talloc_strndup(tags, key.start, key.len);
|
||||||
|
tags->values[tags->num_keys] = talloc_strndup(tags, value.start, value.len);
|
||||||
|
tags->num_keys++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mp_tags_get_str(struct mp_tags *tags, const char *key)
|
||||||
|
{
|
||||||
|
return mp_tags_get_bstr(tags, bstr0(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mp_tags_get_bstr(struct mp_tags *tags, bstr key)
|
||||||
|
{
|
||||||
|
for (int n = 0; n < tags->num_keys; n++) {
|
||||||
|
if (bstrcasecmp0(key, tags->keys[n]) == 0)
|
||||||
|
return tags->values[n];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int demux_info_add(demuxer_t *demuxer, const char *opt, const char *param)
|
int demux_info_add(demuxer_t *demuxer, const char *opt, const char *param)
|
||||||
{
|
{
|
||||||
return demux_info_add_bstr(demuxer, bstr0(opt), bstr0(param));
|
return demux_info_add_bstr(demuxer, bstr0(opt), bstr0(param));
|
||||||
@ -691,49 +728,34 @@ int demux_info_add(demuxer_t *demuxer, const char *opt, const char *param)
|
|||||||
|
|
||||||
int demux_info_add_bstr(demuxer_t *demuxer, struct bstr opt, struct bstr param)
|
int demux_info_add_bstr(demuxer_t *demuxer, struct bstr opt, struct bstr param)
|
||||||
{
|
{
|
||||||
char **info = demuxer->info;
|
char *oldval = mp_tags_get_bstr(demuxer->metadata, opt);
|
||||||
int n = 0;
|
if (oldval) {
|
||||||
|
if (bstrcmp0(param, oldval) == 0)
|
||||||
|
|
||||||
for (n = 0; info && info[2 * n] != NULL; n++) {
|
|
||||||
if (!bstrcasecmp(opt, bstr0(info[2*n]))) {
|
|
||||||
if (!bstrcmp(param, bstr0(info[2*n + 1]))) {
|
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, "Demuxer info %.*s set to unchanged value %.*s\n",
|
|
||||||
BSTR_P(opt), BSTR_P(param));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "Demuxer info %.*s changed to %.*s\n",
|
|
||||||
BSTR_P(opt), BSTR_P(param));
|
|
||||||
talloc_free(info[2*n + 1]);
|
|
||||||
info[2*n + 1] = talloc_strndup(demuxer->info, param.start, param.len);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "Demuxer info %.*s changed to %.*s\n",
|
||||||
|
BSTR_P(opt), BSTR_P(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
info = demuxer->info = talloc_realloc(demuxer, info, char *, 2 * (n + 2));
|
mp_tags_set_bstr(demuxer->metadata, opt, param);
|
||||||
info[2*n] = talloc_strndup(demuxer->info, opt.start, opt.len);
|
|
||||||
info[2*n + 1] = talloc_strndup(demuxer->info, param.start, param.len);
|
|
||||||
memset(&info[2 * (n + 1)], 0, 2 * sizeof(char *));
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int demux_info_print(demuxer_t *demuxer)
|
int demux_info_print(demuxer_t *demuxer)
|
||||||
{
|
{
|
||||||
char **info = demuxer->info;
|
struct mp_tags *info = demuxer->metadata;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "Clip info:\n");
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "Clip info:\n");
|
||||||
for (n = 0; info[2 * n] != NULL; n++) {
|
for (n = 0; n < info->num_keys; n++) {
|
||||||
mp_msg(MSGT_DEMUX, MSGL_INFO, " %s: %s\n", info[2 * n],
|
mp_msg(MSGT_DEMUX, MSGL_INFO, " %s: %s\n", info->keys[n],
|
||||||
info[2 * n + 1]);
|
info->values[n]);
|
||||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_NAME%d=%s\n", n,
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_NAME%d=%s\n", n,
|
||||||
info[2 * n]);
|
info->keys[n]);
|
||||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_VALUE%d=%s\n", n,
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_VALUE%d=%s\n", n,
|
||||||
info[2 * n + 1]);
|
info->values[n]);
|
||||||
}
|
}
|
||||||
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_N=%d\n", n);
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CLIP_INFO_N=%d\n", n);
|
||||||
|
|
||||||
@ -742,15 +764,7 @@ int demux_info_print(demuxer_t *demuxer)
|
|||||||
|
|
||||||
char *demux_info_get(demuxer_t *demuxer, const char *opt)
|
char *demux_info_get(demuxer_t *demuxer, const char *opt)
|
||||||
{
|
{
|
||||||
int i;
|
return mp_tags_get_str(demuxer->metadata, opt);
|
||||||
char **info = demuxer->info;
|
|
||||||
|
|
||||||
for (i = 0; info && info[2 * i] != NULL; i++) {
|
|
||||||
if (!strcasecmp(opt, info[2 * i]))
|
|
||||||
return info[2 * i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void demux_info_update(struct demuxer *demuxer)
|
void demux_info_update(struct demuxer *demuxer)
|
||||||
|
@ -111,6 +111,12 @@ typedef struct demuxer_desc {
|
|||||||
int (*control)(struct demuxer *demuxer, int cmd, void *arg);
|
int (*control)(struct demuxer *demuxer, int cmd, void *arg);
|
||||||
} demuxer_desc_t;
|
} demuxer_desc_t;
|
||||||
|
|
||||||
|
struct mp_tags {
|
||||||
|
char **keys;
|
||||||
|
char **values;
|
||||||
|
int num_keys;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct demux_chapter
|
typedef struct demux_chapter
|
||||||
{
|
{
|
||||||
int original_index;
|
int original_index;
|
||||||
@ -185,8 +191,9 @@ typedef struct demuxer {
|
|||||||
// If the file is a playlist file
|
// If the file is a playlist file
|
||||||
struct playlist *playlist;
|
struct playlist *playlist;
|
||||||
|
|
||||||
|
struct mp_tags *metadata;
|
||||||
|
|
||||||
void *priv; // demuxer-specific internal data
|
void *priv; // demuxer-specific internal data
|
||||||
char **info; // metadata
|
|
||||||
struct MPOpts *opts;
|
struct MPOpts *opts;
|
||||||
struct demuxer_params *params;
|
struct demuxer_params *params;
|
||||||
} demuxer_t;
|
} demuxer_t;
|
||||||
@ -282,4 +289,9 @@ double demux_packet_list_duration(struct demux_packet **pkts, int num_pkts);
|
|||||||
struct demux_packet *demux_packet_list_fill(struct demux_packet **pkts,
|
struct demux_packet *demux_packet_list_fill(struct demux_packet **pkts,
|
||||||
int num_pkts, int *current);
|
int num_pkts, int *current);
|
||||||
|
|
||||||
|
void mp_tags_set_str(struct mp_tags *tags, const char *key, const char *value);
|
||||||
|
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);
|
||||||
|
|
||||||
#endif /* MPLAYER_DEMUXER_H */
|
#endif /* MPLAYER_DEMUXER_H */
|
||||||
|
@ -636,39 +636,38 @@ static int mp_property_angle(m_option_t *prop, int action, void *arg,
|
|||||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Demuxer meta data
|
static int tag_property(m_option_t *prop, int action, void *arg,
|
||||||
static int mp_property_metadata(m_option_t *prop, int action, void *arg,
|
struct mp_tags *tags)
|
||||||
MPContext *mpctx)
|
|
||||||
{
|
{
|
||||||
struct demuxer *demuxer = mpctx->master_demuxer;
|
|
||||||
if (!demuxer)
|
|
||||||
return M_PROPERTY_UNAVAILABLE;
|
|
||||||
|
|
||||||
static const m_option_t key_type =
|
static const m_option_t key_type =
|
||||||
{
|
{
|
||||||
"metadata", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL
|
"tags", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case M_PROPERTY_GET: {
|
case M_PROPERTY_GET: {
|
||||||
char **slist = NULL;
|
char **slist = NULL;
|
||||||
m_option_copy(prop, &slist, &demuxer->info);
|
int num = 0;
|
||||||
|
for (int n = 0; n < tags->num_keys; n++) {
|
||||||
|
MP_TARRAY_APPEND(NULL, slist, num, tags->keys[n]);
|
||||||
|
MP_TARRAY_APPEND(NULL, slist, num, tags->values[n]);
|
||||||
|
}
|
||||||
|
MP_TARRAY_APPEND(NULL, slist, num, NULL);
|
||||||
*(char ***)arg = slist;
|
*(char ***)arg = slist;
|
||||||
return M_PROPERTY_OK;
|
return M_PROPERTY_OK;
|
||||||
}
|
}
|
||||||
case M_PROPERTY_PRINT: {
|
case M_PROPERTY_PRINT: {
|
||||||
char **list = demuxer->info;
|
|
||||||
char *res = NULL;
|
char *res = NULL;
|
||||||
for (int n = 0; list && list[n]; n += 2) {
|
for (int n = 0; n < tags->num_keys; n++) {
|
||||||
res = talloc_asprintf_append_buffer(res, "%s: %s\n",
|
res = talloc_asprintf_append_buffer(res, "%s: %s\n",
|
||||||
list[n], list[n + 1]);
|
tags->keys[n], tags->values[n]);
|
||||||
}
|
}
|
||||||
*(char **)arg = res;
|
*(char **)arg = res;
|
||||||
return res ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE;
|
return res ? M_PROPERTY_OK : M_PROPERTY_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
case M_PROPERTY_KEY_ACTION: {
|
case M_PROPERTY_KEY_ACTION: {
|
||||||
struct m_property_action_arg *ka = arg;
|
struct m_property_action_arg *ka = arg;
|
||||||
char *meta = demux_info_get(demuxer, ka->key);
|
char *meta = mp_tags_get_str(tags, ka->key);
|
||||||
if (!meta)
|
if (!meta)
|
||||||
return M_PROPERTY_UNKNOWN;
|
return M_PROPERTY_UNKNOWN;
|
||||||
switch (ka->action) {
|
switch (ka->action) {
|
||||||
@ -684,6 +683,17 @@ static int mp_property_metadata(m_option_t *prop, int action, void *arg,
|
|||||||
return M_PROPERTY_NOT_IMPLEMENTED;
|
return M_PROPERTY_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Demuxer meta data
|
||||||
|
static int mp_property_metadata(m_option_t *prop, int action, void *arg,
|
||||||
|
MPContext *mpctx)
|
||||||
|
{
|
||||||
|
struct demuxer *demuxer = mpctx->master_demuxer;
|
||||||
|
if (!demuxer)
|
||||||
|
return M_PROPERTY_UNAVAILABLE;
|
||||||
|
|
||||||
|
return tag_property(prop, action, arg, demuxer->metadata);
|
||||||
|
}
|
||||||
|
|
||||||
static int mp_property_pause(m_option_t *prop, int action, void *arg,
|
static int mp_property_pause(m_option_t *prop, int action, void *arg,
|
||||||
void *ctx)
|
void *ctx)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user