af_lavfi: implement af-metadata property

Works like vf-metadata. Unfortunately requires some code duplication
(even though it's not much).

Fixes #2311.
This commit is contained in:
wm4 2015-09-11 23:04:02 +02:00
parent f095e86b61
commit 4e0e24c3c2
6 changed files with 63 additions and 10 deletions

View File

@ -19,6 +19,8 @@ Interface changes
::
--- mpv 0.11.0 ---
- add "af-metadata" property
--- mpv 0.10.0 ---
- add --video-aspect-method option
- add --playlist-pos option

View File

@ -1091,6 +1091,9 @@ Property list
An example of these kind of metadata are the cropping parameters
added by ``--vf=lavfi=cropdetect``.
``af-metadata/<filter-label>``
Equivalent to ``vf-metadata/<filter-label>``, but for audio filters.
``pause`` (RW)
Pause status. This is usually ``yes`` or ``no``. See ``--pause``.

View File

@ -695,6 +695,18 @@ void af_control_all(struct af_stream *s, int cmd, void *arg)
af->control(af, cmd, arg);
}
int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label)
{
char *label_str = bstrdup0(NULL, label);
struct af_instance *cur = af_find_by_label(s, label_str);
talloc_free(label_str);
if (cur) {
return cur->control ? cur->control(cur, cmd, arg) : CONTROL_NA;
} else {
return CONTROL_UNKNOWN;
}
}
// Used by filters to add a filtered frame to the output queue.
// Ownership of frame is transferred from caller to the filter chain.
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame)

View File

@ -127,6 +127,7 @@ enum af_control {
AF_CONTROL_GET_PAN_BALANCE,
AF_CONTROL_SET_PLAYBACK_SPEED,
AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE,
AF_CONTROL_GET_METADATA,
};
// Argument for AF_CONTROL_SET_PAN_LEVEL
@ -145,6 +146,7 @@ int af_remove_by_label(struct af_stream *s, char *label);
struct af_instance *af_find_by_label(struct af_stream *s, char *label);
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
void af_control_all(struct af_stream *s, int cmd, void *arg);
int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label);
void af_seek_reset(struct af_stream *s);
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame);

View File

@ -34,11 +34,14 @@
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include "config.h"
#include "audio/format.h"
#include "audio/fmt-conversion.h"
#include "af.h"
#include "common/av_common.h"
#include "common/tags.h"
#include "options/m_option.h"
@ -63,6 +66,8 @@ struct priv {
bool eof;
struct mp_tags *metadata;
// options
char *cfg_graph;
char **cfg_avopts;
@ -213,6 +218,12 @@ static int control(struct af_instance *af, int cmd, void *arg)
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
case AF_CONTROL_GET_METADATA:
if (p->metadata) {
*(struct mp_tags *)arg = *p->metadata;
return CONTROL_OK;
}
return CONTROL_NA;
case AF_CONTROL_RESET:
reset(af);
return AF_OK;
@ -220,6 +231,17 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_UNKNOWN;
}
static void get_metadata_from_av_frame(struct af_instance *af, AVFrame *frame)
{
#if HAVE_AVFRAME_METADATA
struct priv *p = af->priv;
if (!p->metadata)
p->metadata = talloc_zero(p, struct mp_tags);
mp_tags_copy_from_av_dictionary(p->metadata, av_frame_get_metadata(frame));
#endif
}
static int filter_frame(struct af_instance *af, struct mp_audio *data)
{
struct priv *p = af->priv;
@ -307,6 +329,7 @@ static int filter_out(struct af_instance *af)
af->delay = in_time - out_time;
}
get_metadata_from_av_frame(af, frame);
af_add_output_frame(af, out);
av_frame_free(&frame);
return 0;

View File

@ -1187,21 +1187,31 @@ static int mp_property_chapter_metadata(void *ctx, struct m_property *prop,
return tag_property(action, arg, mpctx->chapters[chapter].metadata);
}
static int mp_property_vf_metadata(void *ctx, struct m_property *prop,
int action, void *arg)
static int mp_property_filter_metadata(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
if (!(mpctx->d_video && mpctx->d_video->vfilter))
return M_PROPERTY_UNAVAILABLE;
struct vf_chain *vf = mpctx->d_video->vfilter;
const char *type = prop->priv;
if (action == M_PROPERTY_KEY_ACTION) {
struct m_property_action_arg *ka = arg;
bstr key;
char *rem;
m_property_split_path(ka->key, &key, &rem);
struct mp_tags vf_metadata = {0};
switch (vf_control_by_label(vf, VFCTRL_GET_METADATA, &vf_metadata, key)) {
struct mp_tags metadata = {0};
int res = CONTROL_UNKNOWN;
if (strcmp(type, "vf") == 0) {
if (!(mpctx->d_video && mpctx->d_video->vfilter))
return M_PROPERTY_UNAVAILABLE;
struct vf_chain *vf = mpctx->d_video->vfilter;
res = vf_control_by_label(vf, VFCTRL_GET_METADATA, &metadata, key);
} else if (strcmp(type, "af") == 0) {
if (!(mpctx->d_audio && mpctx->d_audio->afilter))
return M_PROPERTY_UNAVAILABLE;
struct af_stream *af = mpctx->d_audio->afilter;
res = af_control_by_label(af, AF_CONTROL_GET_METADATA, &metadata, key);
}
switch (res) {
case CONTROL_UNKNOWN:
return M_PROPERTY_UNKNOWN;
case CONTROL_NA: // empty
@ -1209,9 +1219,9 @@ static int mp_property_vf_metadata(void *ctx, struct m_property *prop,
if (strlen(rem)) {
struct m_property_action_arg next_ka = *ka;
next_ka.key = rem;
return tag_property(M_PROPERTY_KEY_ACTION, &next_ka, &vf_metadata);
return tag_property(M_PROPERTY_KEY_ACTION, &next_ka, &metadata);
} else {
return tag_property(ka->action, ka->arg, &vf_metadata);
return tag_property(ka->action, ka->arg, &metadata);
}
return M_PROPERTY_OK;
default:
@ -3379,7 +3389,8 @@ static const struct m_property mp_properties[] = {
{"metadata", mp_property_metadata},
{"filtered-metadata", mp_property_filtered_metadata},
{"chapter-metadata", mp_property_chapter_metadata},
{"vf-metadata", mp_property_vf_metadata},
{"vf-metadata", mp_property_filter_metadata, .priv = "vf"},
{"af-metadata", mp_property_filter_metadata, .priv = "af"},
{"pause", mp_property_pause},
{"core-idle", mp_property_core_idle},
{"eof-reached", mp_property_eof_reached},