Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*
2
* Copyright (c) 2012 Andrey Utkin
3
* Copyright (c) 2012 Stefano Sabatini
4
*
5
* This file is part of FFmpeg.
6
*
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.
11
*
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.
16
*
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
20
*/
21
22
/**
23
* @file
24
* Filter that changes number of samples on single output operation
25
*/
26
27
#include "libavutil/audio_fifo.h"
28
#include "libavutil/avassert.h"
29
#include "libavutil/channel_layout.h"
30
#include "libavutil/opt.h"
31
#include "avfilter.h"
32
#include "audio.h"
33
#include "internal.h"
34
#include "formats.h"
35
36
typedef struct {
37
const AVClass *class;
38
int nb_out_samples; ///< how many samples to output
39
AVAudioFifo *fifo; ///< samples are queued here
40
int64_t next_out_pts;
41
int pad;
42
} ASNSContext;
43
44
#define OFFSET(x) offsetof(ASNSContext, x)
45
#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
46
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_BOOL, {.i64=1}, 0, 1, FLAGS },
51
{ "p", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
52
{ NULL }
53
};
54
55
AVFILTER_DEFINE_CLASS(asetnsamples);
56
57
static av_cold int init(AVFilterContext *ctx)
58
{
59
ASNSContext *asns = ctx->priv;
60
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);
63
64
return 0;
65
}
66
67
static av_cold void uninit(AVFilterContext *ctx)
68
{
69
ASNSContext *asns = ctx->priv;
70
av_audio_fifo_free(asns->fifo);
71
}
72
73
static int config_props_output(AVFilterLink *outlink)
74
{
75
ASNSContext *asns = outlink->src->priv;
76
77
asns->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, asns->nb_out_samples);
78
if (!asns->fifo)
79
return AVERROR(ENOMEM);
80
81
return 0;
82
}
83
84
static int push_samples(AVFilterLink *outlink)
85
{
86
ASNSContext *asns = outlink->src->priv;
87
AVFrame *outsamples = NULL;
88
int ret, nb_out_samples, nb_pad_samples;
89
90
if (asns->pad) {
91
nb_out_samples = av_audio_fifo_size(asns->fifo) ? asns->nb_out_samples : 0;
92
nb_pad_samples = nb_out_samples - FFMIN(nb_out_samples, av_audio_fifo_size(asns->fifo));
93
} else {
94
nb_out_samples = FFMIN(asns->nb_out_samples, av_audio_fifo_size(asns->fifo));
95
nb_pad_samples = 0;
96
}
97
98
if (!nb_out_samples)
99
return 0;
100
101
outsamples = ff_get_audio_buffer(outlink, nb_out_samples);
102
if (!outsamples)
103
return AVERROR(ENOMEM);
104
105
av_audio_fifo_read(asns->fifo,
106
(void **)outsamples->extended_data, nb_out_samples);
107
108
if (nb_pad_samples)
109
av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples,
110
nb_pad_samples, outlink->channels,
111
outlink->format);
112
outsamples->nb_samples = nb_out_samples;
113
outsamples->channel_layout = outlink->channel_layout;
114
outsamples->sample_rate = outlink->sample_rate;
115
outsamples->pts = asns->next_out_pts;
116
117
if (asns->next_out_pts != AV_NOPTS_VALUE)
118
asns->next_out_pts += av_rescale_q(nb_out_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
119
120
ret = ff_filter_frame(outlink, outsamples);
121
if (ret < 0)
122
return ret;
123
return nb_out_samples;
124
}
125
126
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
127
{
128
AVFilterContext *ctx = inlink->dst;
129
ASNSContext *asns = ctx->priv;
130
AVFilterLink *outlink = ctx->outputs[0];
131
int ret;
132
int nb_samples = insamples->nb_samples;
133
134
if (av_audio_fifo_space(asns->fifo) < nb_samples) {
135
av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples);
136
ret = av_audio_fifo_realloc(asns->fifo, av_audio_fifo_size(asns->fifo) + nb_samples);
137
if (ret < 0) {
138
av_log(ctx, AV_LOG_ERROR,
139
"Stretching audio fifo failed, discarded %d samples\n", nb_samples);
140
return -1;
141
}
142
}
143
av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples);
144
if (asns->next_out_pts == AV_NOPTS_VALUE)
145
asns->next_out_pts = insamples->pts;
146
av_frame_free(&insamples);
147
148
while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
149
push_samples(outlink);
150
return 0;
151
}
152
153
static int request_frame(AVFilterLink *outlink)
154
{
155
AVFilterLink *inlink = outlink->src->inputs[0];
156
int ret;
157
158
ret = ff_request_frame(inlink);
159
if (ret == AVERROR_EOF) {
160
ret = push_samples(outlink);
161
return ret < 0 ? ret : ret > 0 ? 0 : AVERROR_EOF;
162
}
163
164
return ret;
165
}
166
167
static const AVFilterPad asetnsamples_inputs[] = {
168
{
169
.name = "default",
170
.type = AVMEDIA_TYPE_AUDIO,
171
.filter_frame = filter_frame,
172
},
173
{ NULL }
174
};
175
176
static const AVFilterPad asetnsamples_outputs[] = {
177
{
178
.name = "default",
179
.type = AVMEDIA_TYPE_AUDIO,
180
.request_frame = request_frame,
181
.config_props = config_props_output,
182
},
183
{ NULL }
184
};
185
186
AVFilter ff_af_asetnsamples = {
187
.name = "asetnsamples",
188
.description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
189
.priv_size = sizeof(ASNSContext),
190
.priv_class = &asetnsamples_class,
191
.init = init,
192
.uninit = uninit,
193
.inputs = asetnsamples_inputs,
194
.outputs = asetnsamples_outputs,
195
};
196
197