#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
+#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
typedef struct ResampleContext {
AVAudioResampleContext *avr;
+ AVDictionary *options;
int64_t next_pts;
- /* set by filter_samples() to signal an output frame to request_frame() */
+ /* set by filter_frame() to signal an output frame to request_frame() */
int got_output;
} ResampleContext;
+static av_cold int init(AVFilterContext *ctx, const char *args)
+{
+ ResampleContext *s = ctx->priv;
+
+ if (args) {
+ int ret = av_dict_parse_string(&s->options, args, "=", ":", 0);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "error setting option string: %s\n", args);
+ return ret;
+ }
+
+ /* do not allow the user to override basic format options */
+ av_dict_set(&s->options, "in_channel_layout", NULL, 0);
+ av_dict_set(&s->options, "out_channel_layout", NULL, 0);
+ av_dict_set(&s->options, "in_sample_fmt", NULL, 0);
+ av_dict_set(&s->options, "out_sample_fmt", NULL, 0);
+ av_dict_set(&s->options, "in_sample_rate", NULL, 0);
+ av_dict_set(&s->options, "out_sample_rate", NULL, 0);
+ }
+
+ return 0;
+}
+
static av_cold void uninit(AVFilterContext *ctx)
{
ResampleContext *s = ctx->priv;
avresample_close(s->avr);
avresample_free(&s->avr);
}
+ av_dict_free(&s->options);
}
static int query_formats(AVFilterContext *ctx)
if (!(s->avr = avresample_alloc_context()))
return AVERROR(ENOMEM);
+ if (s->options) {
+ AVDictionaryEntry *e = NULL;
+ while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX)))
+ av_log(ctx, AV_LOG_VERBOSE, "lavr option: %s=%s\n", e->key, e->value);
+
+ av_opt_set_dict(s->avr, &s->options);
+ }
+
av_opt_set_int(s->avr, "in_channel_layout", inlink ->channel_layout, 0);
av_opt_set_int(s->avr, "out_channel_layout", outlink->channel_layout, 0);
av_opt_set_int(s->avr, "in_sample_fmt", inlink ->format, 0);
}
buf->pts = s->next_pts;
- return ff_filter_samples(outlink, buf);
+ return ff_filter_frame(outlink, buf);
}
return ret;
}
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
{
AVFilterContext *ctx = inlink->dst;
ResampleContext *s = ctx->priv;
s->next_pts = buf_out->pts + buf_out->audio->nb_samples;
- ret = ff_filter_samples(outlink, buf_out);
+ ret = ff_filter_frame(outlink, buf_out);
s->got_output = 1;
}
avfilter_unref_buffer(buf);
} else {
buf->format = outlink->format;
- ret = ff_filter_samples(outlink, buf);
+ ret = ff_filter_frame(outlink, buf);
s->got_output = 1;
}
return ret;
}
+static const AVFilterPad avfilter_af_resample_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .min_perms = AV_PERM_READ
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_af_resample_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame
+ },
+ { NULL }
+};
+
AVFilter avfilter_af_resample = {
.name = "resample",
.description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."),
.priv_size = sizeof(ResampleContext),
+ .init = init,
.uninit = uninit,
.query_formats = query_formats,
- .inputs = (const AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_samples = filter_samples,
- .min_perms = AV_PERM_READ },
- { .name = NULL}},
- .outputs = (const AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .config_props = config_output,
- .request_frame = request_frame },
- { .name = NULL}},
+ .inputs = avfilter_af_resample_inputs,
+ .outputs = avfilter_af_resample_outputs,
};