2 * Copyright (c) 2012 Andrey Utkin
3 * Copyright (c) 2012 Stefano Sabatini
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Filter that changes number of samples on single output operation
27 #include "libavutil/audio_fifo.h"
28 #include "libavutil/avassert.h"
29 #include "libavutil/channel_layout.h"
30 #include "libavutil/opt.h"
38 int nb_out_samples
; ///< how many samples to output
39 AVAudioFifo
*fifo
; ///< samples are queued here
44 #define OFFSET(x) offsetof(ASNSContext, x)
45 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
47 static const AVOption asetnsamples_options
[] = {
48 { "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
},
49 { "n", "set the number of per-frame output samples", OFFSET(nb_out_samples
), AV_OPT_TYPE_INT
, {.i64
=1024}, 1, INT_MAX
, FLAGS
},
50 { "pad", "pad last frame with zeros", OFFSET(pad
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1, FLAGS
},
51 { "p", "pad last frame with zeros", OFFSET(pad
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1, FLAGS
},
55 AVFILTER_DEFINE_CLASS(asetnsamples
);
57 static av_cold
int init(AVFilterContext
*ctx
)
59 ASNSContext
*asns
= ctx
->priv
;
61 asns
->next_out_pts
= AV_NOPTS_VALUE
;
62 av_log(ctx
, AV_LOG_VERBOSE
, "nb_out_samples:%d pad:%d\n", asns
->nb_out_samples
, asns
->pad
);
67 static av_cold
void uninit(AVFilterContext
*ctx
)
69 ASNSContext
*asns
= ctx
->priv
;
70 av_audio_fifo_free(asns
->fifo
);
73 static int config_props_output(AVFilterLink
*outlink
)
75 ASNSContext
*asns
= outlink
->src
->priv
;
77 asns
->fifo
= av_audio_fifo_alloc(outlink
->format
, outlink
->channels
, asns
->nb_out_samples
);
79 return AVERROR(ENOMEM
);
80 outlink
->flags
|= FF_LINK_FLAG_REQUEST_LOOP
;
85 static int push_samples(AVFilterLink
*outlink
)
87 ASNSContext
*asns
= outlink
->src
->priv
;
88 AVFrame
*outsamples
= NULL
;
89 int ret
, nb_out_samples
, nb_pad_samples
;
92 nb_out_samples
= av_audio_fifo_size(asns
->fifo
) ? asns
->nb_out_samples
: 0;
93 nb_pad_samples
= nb_out_samples
- FFMIN(nb_out_samples
, av_audio_fifo_size(asns
->fifo
));
95 nb_out_samples
= FFMIN(asns
->nb_out_samples
, av_audio_fifo_size(asns
->fifo
));
102 outsamples
= ff_get_audio_buffer(outlink
, nb_out_samples
);
104 return AVERROR(ENOMEM
);
106 av_audio_fifo_read(asns
->fifo
,
107 (void **)outsamples
->extended_data
, nb_out_samples
);
110 av_samples_set_silence(outsamples
->extended_data
, nb_out_samples
- nb_pad_samples
,
111 nb_pad_samples
, outlink
->channels
,
113 outsamples
->nb_samples
= nb_out_samples
;
114 outsamples
->channel_layout
= outlink
->channel_layout
;
115 outsamples
->sample_rate
= outlink
->sample_rate
;
116 outsamples
->pts
= asns
->next_out_pts
;
118 if (asns
->next_out_pts
!= AV_NOPTS_VALUE
)
119 asns
->next_out_pts
+= av_rescale_q(nb_out_samples
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
121 ret
= ff_filter_frame(outlink
, outsamples
);
124 return nb_out_samples
;
127 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*insamples
)
129 AVFilterContext
*ctx
= inlink
->dst
;
130 ASNSContext
*asns
= ctx
->priv
;
131 AVFilterLink
*outlink
= ctx
->outputs
[0];
133 int nb_samples
= insamples
->nb_samples
;
135 if (av_audio_fifo_space(asns
->fifo
) < nb_samples
) {
136 av_log(ctx
, AV_LOG_DEBUG
, "No space for %d samples, stretching audio fifo\n", nb_samples
);
137 ret
= av_audio_fifo_realloc(asns
->fifo
, av_audio_fifo_size(asns
->fifo
) + nb_samples
);
139 av_log(ctx
, AV_LOG_ERROR
,
140 "Stretching audio fifo failed, discarded %d samples\n", nb_samples
);
144 av_audio_fifo_write(asns
->fifo
, (void **)insamples
->extended_data
, nb_samples
);
145 if (asns
->next_out_pts
== AV_NOPTS_VALUE
)
146 asns
->next_out_pts
= insamples
->pts
;
147 av_frame_free(&insamples
);
149 while (av_audio_fifo_size(asns
->fifo
) >= asns
->nb_out_samples
)
150 push_samples(outlink
);
154 static int request_frame(AVFilterLink
*outlink
)
156 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
159 ret
= ff_request_frame(inlink
);
160 if (ret
== AVERROR_EOF
) {
161 ret
= push_samples(outlink
);
162 return ret
< 0 ? ret
: ret
> 0 ? 0 : AVERROR_EOF
;
168 static const AVFilterPad asetnsamples_inputs
[] = {
171 .type
= AVMEDIA_TYPE_AUDIO
,
172 .filter_frame
= filter_frame
,
177 static const AVFilterPad asetnsamples_outputs
[] = {
180 .type
= AVMEDIA_TYPE_AUDIO
,
181 .request_frame
= request_frame
,
182 .config_props
= config_props_output
,
187 AVFilter ff_af_asetnsamples
= {
188 .name
= "asetnsamples",
189 .description
= NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
190 .priv_size
= sizeof(ASNSContext
),
191 .priv_class
= &asetnsamples_class
,
194 .inputs
= asetnsamples_inputs
,
195 .outputs
= asetnsamples_outputs
,