#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "audio.h"
int nb_out_samples; ///< how many samples to output
AVAudioFifo *fifo; ///< samples are queued here
int64_t next_out_pts;
- int req_fullfilled;
int pad;
} ASNSContext;
#define OFFSET(x) offsetof(ASNSContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption asetnsamples_options[] = {
-{ "pad", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
-{ "p", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
-{ "nb_out_samples", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.dbl=1024}, 1, INT_MAX },
-{ "n", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.dbl=1024}, 1, INT_MAX },
-{ NULL }
+ { "nb_out_samples", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "n", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "pad", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
+ { "p", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
+ { NULL }
};
AVFILTER_DEFINE_CLASS(asetnsamples);
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+static av_cold int init(AVFilterContext *ctx)
{
ASNSContext *asns = ctx->priv;
- int err;
-
- asns->class = &asetnsamples_class;
- av_opt_set_defaults(asns);
-
- if ((err = av_set_options_string(asns, args, "=", ":")) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
- return err;
- }
asns->next_out_pts = AV_NOPTS_VALUE;
- av_log(ctx, AV_LOG_INFO, "nb_out_samples:%d pad:%d\n", asns->nb_out_samples, asns->pad);
+ av_log(ctx, AV_LOG_VERBOSE, "nb_out_samples:%d pad:%d\n", asns->nb_out_samples, asns->pad);
return 0;
}
static int config_props_output(AVFilterLink *outlink)
{
ASNSContext *asns = outlink->src->priv;
- int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
- asns->fifo = av_audio_fifo_alloc(outlink->format, nb_channels, asns->nb_out_samples);
+ asns->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, asns->nb_out_samples);
if (!asns->fifo)
return AVERROR(ENOMEM);
static int push_samples(AVFilterLink *outlink)
{
ASNSContext *asns = outlink->src->priv;
- AVFilterBufferRef *outsamples = NULL;
- int nb_out_samples, nb_pad_samples;
+ AVFrame *outsamples = NULL;
+ int ret, nb_out_samples, nb_pad_samples;
if (asns->pad) {
nb_out_samples = av_audio_fifo_size(asns->fifo) ? asns->nb_out_samples : 0;
if (!nb_out_samples)
return 0;
- outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_out_samples);
- av_assert0(outsamples);
+ outsamples = ff_get_audio_buffer(outlink, nb_out_samples);
+ if (!outsamples)
+ return AVERROR(ENOMEM);
av_audio_fifo_read(asns->fifo,
(void **)outsamples->extended_data, nb_out_samples);
if (nb_pad_samples)
av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples,
- nb_pad_samples, av_get_channel_layout_nb_channels(outlink->channel_layout),
+ nb_pad_samples, outlink->channels,
outlink->format);
- outsamples->audio->nb_samples = nb_out_samples;
- outsamples->audio->channel_layout = outlink->channel_layout;
- outsamples->audio->sample_rate = outlink->sample_rate;
+ outsamples->nb_samples = nb_out_samples;
+ outsamples->channel_layout = outlink->channel_layout;
+ outsamples->sample_rate = outlink->sample_rate;
outsamples->pts = asns->next_out_pts;
if (asns->next_out_pts != AV_NOPTS_VALUE)
- asns->next_out_pts += nb_out_samples;
+ asns->next_out_pts += av_rescale_q(nb_out_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
- ff_filter_samples(outlink, outsamples);
- asns->req_fullfilled = 1;
+ ret = ff_filter_frame(outlink, outsamples);
+ if (ret < 0)
+ return ret;
return nb_out_samples;
}
-static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
{
AVFilterContext *ctx = inlink->dst;
ASNSContext *asns = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
int ret;
- int nb_samples = insamples->audio->nb_samples;
+ int nb_samples = insamples->nb_samples;
if (av_audio_fifo_space(asns->fifo) < nb_samples) {
av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples);
if (ret < 0) {
av_log(ctx, AV_LOG_ERROR,
"Stretching audio fifo failed, discarded %d samples\n", nb_samples);
- return;
+ return -1;
}
}
av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples);
if (asns->next_out_pts == AV_NOPTS_VALUE)
asns->next_out_pts = insamples->pts;
- avfilter_unref_buffer(insamples);
+ av_frame_free(&insamples);
- if (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
+ while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
push_samples(outlink);
+ return 0;
}
static int request_frame(AVFilterLink *outlink)
{
- ASNSContext *asns = outlink->src->priv;
AVFilterLink *inlink = outlink->src->inputs[0];
int ret;
- asns->req_fullfilled = 0;
- do {
- ret = ff_request_frame(inlink);
- } while (!asns->req_fullfilled && ret >= 0);
-
- if (ret == AVERROR_EOF)
- while (push_samples(outlink))
- ;
+ ret = ff_request_frame(inlink);
+ if (ret == AVERROR_EOF) {
+ ret = push_samples(outlink);
+ return ret < 0 ? ret : ret > 0 ? 0 : AVERROR_EOF;
+ }
return ret;
}
-AVFilter avfilter_af_asetnsamples = {
- .name = "asetnsamples",
- .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
- .priv_size = sizeof(ASNSContext),
- .init = init,
- .uninit = uninit,
-
- .inputs = (const AVFilterPad[]) {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_samples = filter_samples,
- .min_perms = AV_PERM_READ|AV_PERM_WRITE
- },
- { .name = NULL }
+static const AVFilterPad asetnsamples_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
},
+ { NULL }
+};
- .outputs = (const AVFilterPad[]) {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .request_frame = request_frame,
- .config_props = config_props_output,
- },
- { .name = NULL }
+static const AVFilterPad asetnsamples_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame,
+ .config_props = config_props_output,
},
+ { NULL }
+};
+
+AVFilter ff_af_asetnsamples = {
+ .name = "asetnsamples",
+ .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
+ .priv_size = sizeof(ASNSContext),
+ .priv_class = &asetnsamples_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = asetnsamples_inputs,
+ .outputs = asetnsamples_outputs,
};