Requires a little bit of massaging for the key/value access to work correctly, it's not terribly intrusive all things considered.
Unified · Split
| @@ -0,0 +1 @@ | |||
| 1 | add `metadata` sub-property for `track-list` | ||
| @@ -3373,6 +3373,10 @@ Property list · 3372 unmodified lines | |||
| 3373 | Dolby Vision profile and level. May not be available if the container | 3373 | Dolby Vision profile and level. May not be available if the container |
| 3374 | does not provide this information. | 3374 | does not provide this information. |
| 3375 | 3375 | ||
| 3376 | ``track-list/N/metadata``, | ||
| 3377 | Works like the ``metadata`` property, but it accesses metadata that is | ||
| 3378 | set per track/stream instead of global values for the entire file. | ||
| 3379 | |||
| 3376 | When querying the property with the client API using ``MPV_FORMAT_NODE``, | 3380 | When querying the property with the client API using ``MPV_FORMAT_NODE``, |
| 3377 | or with Lua ``mp.get_property_native``, this will return a mpv_node with | 3381 | or with Lua ``mp.get_property_native``, this will return a mpv_node with |
| 3378 | the following contents: | 3382 | the following contents: |
| @@ -3426,6 +3430,8 @@ Property list · 47 unmodified lines | |||
| 3426 | "replaygain-album-gain" MPV_FORMAT_DOUBLE | 3430 | "replaygain-album-gain" MPV_FORMAT_DOUBLE |
| 3427 | "dolby-vision-profile" MPV_FORMAT_INT64 | 3431 | "dolby-vision-profile" MPV_FORMAT_INT64 |
| 3428 | "dolby-vision-level" MPV_FORMAT_INT64 | 3432 | "dolby-vision-level" MPV_FORMAT_INT64 |
| 3433 | "metadata" MPV_FORMAT_NODE_MAP | ||
| 3434 | (key and string value for each metadata entry) | ||
| 3429 | 3435 | ||
| 3430 | ``current-tracks/...`` | 3436 | ``current-tracks/...`` |
| 3431 | This gives access to currently selected tracks. It redirects to the correct | 3437 | This gives access to currently selected tracks. It redirects to the correct |
| @@ -220,6 +220,8 @@ struct m_sub_property { · 219 unmodified lines | |||
| 220 | .type = {.type = CONF_TYPE_BOOL}, .value = {.bool_ = (f)} | 220 | .type = {.type = CONF_TYPE_BOOL}, .value = {.bool_ = (f)} |
| 221 | #define SUB_PROP_PTS(f) \ | 221 | #define SUB_PROP_PTS(f) \ |
| 222 | .type = {.type = &m_option_type_time}, .value = {.double_ = (f)} | 222 | .type = {.type = &m_option_type_time}, .value = {.double_ = (f)} |
| 223 | #define SUB_PROP_KEYVALUE_LIST(l) \ | ||
| 224 | .type = {.type = &m_option_type_keyvalue_list}, .value = {.keyvalue_list = (l)} | ||
| 223 | 225 | ||
| 224 | int m_property_read_sub_validate(void *ctx, struct m_property *prop, | 226 | int m_property_read_sub_validate(void *ctx, struct m_property *prop, |
| 225 | int action, void *arg); | 227 | int action, void *arg); |
| @@ -2004,6 +2004,13 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) · 2003 unmodified lines | |||
| 2004 | struct replaygain_data rg = has_rg ? *track->stream->codec->replaygain_data | 2004 | struct replaygain_data rg = has_rg ? *track->stream->codec->replaygain_data |
| 2005 | : (struct replaygain_data){0}; | 2005 | : (struct replaygain_data){0}; |
| 2006 | 2006 | ||
| 2007 | struct mp_tags *tags = track->stream ? track->stream->tags : &(struct mp_tags){0}; | ||
| 2008 | char **tag_list = talloc_zero_array(NULL, char *, tags->num_keys * 2 + 1); | ||
| 2009 | for (int i = 0; i < tags->num_keys; i++) { | ||
| 2010 | tag_list[2 * i] = talloc_strdup(tag_list, tags->keys[i]); | ||
| 2011 | tag_list[2 * i + 1] = talloc_strdup(tag_list, tags->values[i]); | ||
| 2012 | } | ||
| 2013 | |||
| 2007 | double par = 0.0; | 2014 | double par = 0.0; |
| 2008 | if (p.par_h) | 2015 | if (p.par_h) |
| 2009 | par = p.par_w / (double) p.par_h; | 2016 | par = p.par_w / (double) p.par_h; |
| @@ -2087,10 +2094,37 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) · 77 unmodified lines | |||
| 2087 | .unavailable = !p.dovi}, | 2094 | .unavailable = !p.dovi}, |
| 2088 | {"dolby-vision-level", SUB_PROP_INT(p.dv_level), | 2095 | {"dolby-vision-level", SUB_PROP_INT(p.dv_level), |
| 2089 | .unavailable = !p.dovi}, | 2096 | .unavailable = !p.dovi}, |
| 2097 | {"metadata", SUB_PROP_KEYVALUE_LIST(tag_list), | ||
| 2098 | .unavailable = !tags->num_keys}, | ||
| 2090 | {0} | 2099 | {0} |
| 2091 | }; | 2100 | }; |
| 2092 | 2101 | ||
| 2093 | return m_property_read_sub(props, action, arg); | 2102 | int ret = 0; |
| 2103 | switch (action) { | ||
| 2104 | case M_PROPERTY_KEY_ACTION: ; | ||
| 2105 | struct m_property_action_arg *ka = arg; | ||
| 2106 | if (!strncmp(ka->key, "metadata/", 9)) { | ||
| 2107 | bstr key = {0}; | ||
| 2108 | char *rem = ""; | ||
| 2109 | m_property_split_path(ka->key, &key, &rem); | ||
| 2110 | ka->key = !rem[0] ? "metadata" : rem; | ||
| 2111 | if (rem[0]) { | ||
| 2112 | if (!tags || tags->num_keys == 0) { | ||
| 2113 | ret = M_PROPERTY_UNAVAILABLE; | ||
| 2114 | } else { | ||
| 2115 | ret = tag_property(action, (void *)ka, tags); | ||
| 2116 | } | ||
| 2117 | goto done; | ||
| 2118 | } | ||
| 2119 | } | ||
| 2120 | MP_FALLTHROUGH; | ||
| 2121 | default: | ||
| 2122 | ret = m_property_read_sub(props, action, arg); | ||
| 2123 | } | ||
| 2124 | |||
| 2125 | done: | ||
| 2126 | talloc_free(tag_list); | ||
| 2127 | return ret; | ||
| 2094 | } | 2128 | } |
| 2095 | 2129 | ||
| 2096 | static const char *track_type_name(struct track *t) | 2130 | static const char *track_type_name(struct track *t) |