summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-03-13 00:29:17 +0100
committerwm4 <wm4@nowhere>2014-03-13 00:29:17 +0100
commit3bc78a84cd776387fbbfe120cdfaa5b56d329c61 (patch)
treeda28a0812d81442532ba76fcd66adddded19456b /audio
parent1a86322dcaed46cdae89c8a53ae3fbe8dbc85968 (diff)
downloadmpv-3bc78a84cd776387fbbfe120cdfaa5b56d329c61.tar.bz2
mpv-3bc78a84cd776387fbbfe120cdfaa5b56d329c61.tar.xz
af_lavfi: beat it into working with Libav
The main incompatibility was that Libav didn't have av_opt_set_int_list. But since that function is excessively ugly and idiotic (look how it handles types), I'm not missing it much. Use an aformat filter instead to handle the functionality that was indirectly provided by it. This is similar to how vf_lavfi works. The other incompatibility was channel handling. Libav consistently uses channel layouts only, why ffmpeg still requires messing with channel counts to some degree. Get rid of most channel count uses (and hope channel layouts are "exact" enough). Only in one case FFmpeg fails with a runtime check if we feed it AVFrames with channel count unset. Another issue were AVFrame accessor functions. FFmpeg introduced these for ABI compatibility with Libav. I refuse to use them, and it's not my problem if FFmpeg doesn't manage to provide a stable ABI for fields provided both by FFmpeg and Libav.
Diffstat (limited to 'audio')
-rw-r--r--audio/filter/af_lavfi.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c
index eaec556dc7..4049e54021 100644
--- a/audio/filter/af_lavfi.c
+++ b/audio/filter/af_lavfi.c
@@ -53,6 +53,14 @@
avfilter_graph_parse(graph, filters, &(inputs), &(outputs), log_ctx)
#endif
+// ":" is deprecated, but "|" doesn't work in earlier versions.
+#if (IS_LIBAV_FORK && LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(3, 7, 0)) || \
+ (!IS_LIBAV_FORK && LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(3, 50, 100))
+#define FMTSEP "|"
+#else
+#define FMTSEP ":"
+#endif
+
struct priv {
AVFilterGraph *graph;
AVFilterContext *in;
@@ -78,8 +86,7 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
{
void *tmp = talloc_new(NULL);
struct priv *p = af->priv;
- AVFilterContext *in = NULL, *out = NULL;
- int r;
+ AVFilterContext *in = NULL, *out = NULL, *f_format = NULL;
if (bstr0(p->cfg_graph).len == 0) {
MP_FATAL(af, "lavfi: no filter graph set\n");
@@ -104,12 +111,29 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
if (!outputs || !inputs)
goto error;
+ // Build list of acceptable output sample formats. libavfilter will insert
+ // conversion filters if needed.
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL,
+ AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ char *fmtstr = talloc_strdup(tmp, "");
+ for (int n = 0; sample_fmts[n] != AV_SAMPLE_FMT_NONE; n++) {
+ const char *name = av_get_sample_fmt_name(sample_fmts[n]);
+ if (name) {
+ const char *s = fmtstr[0] ? FMTSEP : "";
+ fmtstr = talloc_asprintf_append_buffer(fmtstr, "%s%s", s, name);
+ }
+ }
+
char *src_args = talloc_asprintf(tmp,
- "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d:"
+ "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:"
"channel_layout=0x%"PRIx64, config->rate,
av_get_sample_fmt_name(af_to_avformat(config->format)),
- config->channels.num, 1, config->rate,
- mp_chmap_to_lavc(&config->channels));
+ 1, config->rate, mp_chmap_to_lavc(&config->channels));
if (avfilter_graph_create_filter(&in, avfilter_get_by_name("abuffer"),
"src", src_args, NULL, graph) < 0)
@@ -119,27 +143,18 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
"out", NULL, NULL, graph) < 0)
goto error;
- static const enum AVSampleFormat sample_fmts[] = {
- AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
- AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL,
- AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
- AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
- AV_SAMPLE_FMT_NONE
- };
- r = av_opt_set_int_list(out, "sample_fmts", sample_fmts,
- AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
- if (r < 0)
+ if (avfilter_graph_create_filter(&f_format, avfilter_get_by_name("aformat"),
+ "format", fmtstr, NULL, graph) < 0)
goto error;
- r = av_opt_set_int(out, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN);
- if (r < 0)
+ if (avfilter_link(f_format, 0, out, 0) < 0)
goto error;
outputs->name = av_strdup("in");
outputs->filter_ctx = in;
inputs->name = av_strdup("out");
- inputs->filter_ctx = out;
+ inputs->filter_ctx = f_format;
if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0)
goto error;
@@ -191,8 +206,6 @@ static int control(struct af_instance *af, int cmd, void *arg)
struct mp_chmap out_cm;
mp_chmap_from_lavc(&out_cm, l_out->channel_layout);
- if (!out_cm.num || out_cm.num != l_out->channels)
- mp_chmap_from_channels(&out_cm, l_out->channels);
mp_audio_set_channels(out, &out_cm);
if (!mp_audio_config_valid(out))
@@ -223,9 +236,12 @@ static int filter(struct af_instance *af, struct mp_audio *data, int flags)
// Timebase is 1/sample_rate
frame->pts = p->samples_in;
- av_frame_set_channels(frame, l_in->channels);
- av_frame_set_channel_layout(frame, l_in->channel_layout);
- av_frame_set_sample_rate(frame, l_in->sample_rate);
+ frame->channel_layout = l_in->channel_layout;
+ frame->sample_rate = l_in->sample_rate;
+#if !IS_LIBAV_FORK
+ // FFmpeg being a stupid POS
+ frame->channels = l_in->channels;
+#endif
frame->extended_data = frame->data;
for (int n = 0; n < data->num_planes; n++)