FFmpeg
af_rubberband.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <rubberband/rubberband-c.h>
20 
22 #include "libavutil/common.h"
23 #include "libavutil/opt.h"
24 
25 #include "audio.h"
26 #include "avfilter.h"
27 #include "filters.h"
28 #include "formats.h"
29 #include "internal.h"
30 
31 typedef struct RubberBandContext {
32  const AVClass *class;
33  RubberBandState rbs;
34 
35  double tempo, pitch;
38  int64_t nb_samples_out;
39  int64_t nb_samples_in;
40  int64_t first_pts;
43 
44 #define OFFSET(x) offsetof(RubberBandContext, x)
45 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
46 #define AT AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
47 
48 static const AVOption rubberband_options[] = {
49  { "tempo", "set tempo scale factor", OFFSET(tempo), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, AT },
50  { "pitch", "set pitch scale factor", OFFSET(pitch), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, AT },
51  { "transients", "set transients", OFFSET(transients), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "transients" },
52  { "crisp", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsCrisp}, 0, 0, A, "transients" },
53  { "mixed", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsMixed}, 0, 0, A, "transients" },
54  { "smooth", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsSmooth}, 0, 0, A, "transients" },
55  { "detector", "set detector", OFFSET(detector), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "detector" },
56  { "compound", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorCompound}, 0, 0, A, "detector" },
57  { "percussive", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorPercussive}, 0, 0, A, "detector" },
58  { "soft", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorSoft}, 0, 0, A, "detector" },
59  { "phase", "set phase", OFFSET(phase), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "phase" },
60  { "laminar", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPhaseLaminar}, 0, 0, A, "phase" },
61  { "independent", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPhaseIndependent}, 0, 0, A, "phase" },
62  { "window", "set window", OFFSET(window), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "window" },
63  { "standard", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowStandard}, 0, 0, A, "window" },
64  { "short", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowShort}, 0, 0, A, "window" },
65  { "long", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowLong}, 0, 0, A, "window" },
66  { "smoothing", "set smoothing", OFFSET(smoothing), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "smoothing" },
67  { "off", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionSmoothingOff}, 0, 0, A, "smoothing" },
68  { "on", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionSmoothingOn}, 0, 0, A, "smoothing" },
69  { "formant", "set formant", OFFSET(formant), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "formant" },
70  { "shifted", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionFormantShifted}, 0, 0, A, "formant" },
71  { "preserved", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionFormantPreserved}, 0, 0, A, "formant" },
72  { "pitchq", "set pitch quality", OFFSET(opitch), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "pitch" },
73  { "quality", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighQuality}, 0, 0, A, "pitch" },
74  { "speed", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighSpeed}, 0, 0, A, "pitch" },
75  { "consistency", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighConsistency}, 0, 0, A, "pitch" },
76  { "channels", "set channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "channels" },
77  { "apart", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionChannelsApart}, 0, 0, A, "channels" },
78  { "together", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionChannelsTogether}, 0, 0, A, "channels" },
79  { NULL },
80 };
81 
82 AVFILTER_DEFINE_CLASS(rubberband);
83 
85 {
86  RubberBandContext *s = ctx->priv;
87 
88  if (s->rbs)
89  rubberband_delete(s->rbs);
90 }
91 
93 {
96  static const enum AVSampleFormat sample_fmts[] = {
99  };
100  int ret;
101 
103  if (!layouts)
104  return AVERROR(ENOMEM);
106  if (ret < 0)
107  return ret;
108 
110  if (!formats)
111  return AVERROR(ENOMEM);
113  if (ret < 0)
114  return ret;
115 
117  if (!formats)
118  return AVERROR(ENOMEM);
120 }
121 
123 {
124  AVFilterContext *ctx = inlink->dst;
125  RubberBandContext *s = ctx->priv;
126  AVFilterLink *outlink = ctx->outputs[0];
127  AVFrame *out;
128  int ret = 0, nb_samples;
129 
130  if (s->first_pts == AV_NOPTS_VALUE)
131  s->first_pts = in->pts;
132 
133  rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, ff_outlink_get_status(inlink));
134  s->nb_samples_in += in->nb_samples;
135 
136  nb_samples = rubberband_available(s->rbs);
137  if (nb_samples > 0) {
138  out = ff_get_audio_buffer(outlink, nb_samples);
139  if (!out) {
140  av_frame_free(&in);
141  return AVERROR(ENOMEM);
142  }
143  out->pts = s->first_pts + av_rescale_q(s->nb_samples_out,
144  (AVRational){ 1, outlink->sample_rate },
145  outlink->time_base);
146  nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples);
147  out->nb_samples = nb_samples;
148  ret = ff_filter_frame(outlink, out);
149  s->nb_samples_out += nb_samples;
150  }
151 
152  av_frame_free(&in);
153  if (ff_inlink_queued_samples(inlink) >= s->nb_samples)
154  ff_filter_set_ready(ctx, 100);
155  return ret < 0 ? ret : nb_samples;
156 }
157 
159 {
160  AVFilterContext *ctx = inlink->dst;
161  RubberBandContext *s = ctx->priv;
162  int opts = s->transients|s->detector|s->phase|s->window|
163  s->smoothing|s->formant|s->opitch|s->channels|
164  RubberBandOptionProcessRealTime;
165 
166  if (s->rbs)
167  rubberband_delete(s->rbs);
168  s->rbs = rubberband_new(inlink->sample_rate, inlink->channels, opts, 1. / s->tempo, s->pitch);
169  if (!s->rbs)
170  return AVERROR(ENOMEM);
171 
172  s->nb_samples = rubberband_get_samples_required(s->rbs);
173  s->first_pts = AV_NOPTS_VALUE;
174 
175  return 0;
176 }
177 
179 {
180  AVFilterLink *inlink = ctx->inputs[0];
181  AVFilterLink *outlink = ctx->outputs[0];
182  RubberBandContext *s = ctx->priv;
183  AVFrame *in = NULL;
184  int ret;
185 
187 
188  ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in);
189  if (ret < 0)
190  return ret;
191  if (ret > 0) {
192  ret = filter_frame(inlink, in);
193  if (ret != 0)
194  return ret;
195  }
196 
199 
200  return FFERROR_NOT_READY;
201 }
202 
203 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
204  char *res, int res_len, int flags)
205 {
206  RubberBandContext *s = ctx->priv;
207  int ret;
208 
209  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
210  if (ret < 0)
211  return ret;
212 
213  rubberband_set_time_ratio(s->rbs, 1. / s->tempo);
214  rubberband_set_pitch_scale(s->rbs, s->pitch);
215  s->nb_samples = rubberband_get_samples_required(s->rbs);
216 
217  return 0;
218 }
219 
220 static const AVFilterPad rubberband_inputs[] = {
221  {
222  .name = "default",
223  .type = AVMEDIA_TYPE_AUDIO,
224  .config_props = config_input,
225  },
226  { NULL }
227 };
228 
229 static const AVFilterPad rubberband_outputs[] = {
230  {
231  .name = "default",
232  .type = AVMEDIA_TYPE_AUDIO,
233  },
234  { NULL }
235 };
236 
238  .name = "rubberband",
239  .description = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."),
240  .query_formats = query_formats,
241  .priv_size = sizeof(RubberBandContext),
242  .priv_class = &rubberband_class,
243  .uninit = uninit,
244  .activate = activate,
248 };
formats
formats
Definition: signature.h:48
ff_get_audio_buffer
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:86
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
AVFilterChannelLayouts
A list of supported channel layouts.
Definition: formats.h:86
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
out
FILE * out
Definition: movenc.c:54
RubberBandContext::nb_samples
int nb_samples
Definition: af_rubberband.c:41
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:978
sample_fmts
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:953
layouts
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
FFERROR_NOT_READY
return FFERROR_NOT_READY
Definition: filter_design.txt:204
ff_af_rubberband
const AVFilter ff_af_rubberband
Definition: af_rubberband.c:237
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_rubberband.c:122
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_rubberband.c:158
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:111
ff_all_channel_counts
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition: formats.c:429
RubberBandContext::transients
int transients
Definition: af_rubberband.c:36
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:303
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:396
AVOption
AVOption.
Definition: opt.h:248
rubberband_options
static const AVOption rubberband_options[]
Definition: af_rubberband.c:48
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:149
FF_FILTER_FORWARD_STATUS_BACK
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition: filters.h:199
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:317
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:65
formats.h
window
static SDL_Window * window
Definition: ffplay.c:366
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_rubberband.c:203
OFFSET
#define OFFSET(x)
Definition: af_rubberband.c:44
RubberBandContext
Definition: af_rubberband.c:31
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
rubberband_inputs
static const AVFilterPad rubberband_inputs[]
Definition: af_rubberband.c:220
av_cold
#define av_cold
Definition: attributes.h:90
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:580
activate
static int activate(AVFilterContext *ctx)
Definition: af_rubberband.c:178
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:227
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
filters.h
ctx
AVFormatContext * ctx
Definition: movenc.c:48
channels
channels
Definition: aptx.h:33
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
opts
AVDictionary * opts
Definition: movenc.c:50
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
ff_inlink_consume_samples
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
Definition: avfilter.c:1395
NULL
#define NULL
Definition: coverity.c:32
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
RubberBandContext::window
int window
Definition: af_rubberband.c:36
A
#define A
Definition: af_rubberband.c:45
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
RubberBandContext::opitch
int opitch
Definition: af_rubberband.c:37
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
RubberBandContext::smoothing
int smoothing
Definition: af_rubberband.c:37
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:842
RubberBandContext::channels
int channels
Definition: af_rubberband.c:37
RubberBandContext::pitch
double pitch
Definition: af_rubberband.c:35
FF_FILTER_FORWARD_WANTED
FF_FILTER_FORWARD_WANTED(outlink, inlink)
internal.h
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:369
common.h
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
RubberBandContext::rbs
RubberBandState rbs
Definition: af_rubberband.c:33
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
ff_inlink_queued_samples
int ff_inlink_queued_samples(AVFilterLink *link)
Definition: avfilter.c:1356
RubberBandContext::phase
int phase
Definition: af_rubberband.c:36
AVFilter
Filter definition.
Definition: avfilter.h:145
ret
ret
Definition: filter_design.txt:187
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: af_rubberband.c:92
ff_all_samplerates
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:414
channel_layout.h
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(rubberband)
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
rubberband_outputs
static const AVFilterPad rubberband_outputs[]
Definition: af_rubberband.c:229
avfilter.h
RubberBandContext::nb_samples_in
int64_t nb_samples_in
Definition: af_rubberband.c:39
ff_outlink_get_status
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
Definition: avfilter.c:1525
AVFilterContext
An instance of a filter.
Definition: avfilter.h:333
RubberBandContext::first_pts
int64_t first_pts
Definition: af_rubberband.c:40
audio.h
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_rubberband.c:84
RubberBandContext::nb_samples_out
int64_t nb_samples_out
Definition: af_rubberband.c:38
FF_FILTER_FORWARD_STATUS
FF_FILTER_FORWARD_STATUS(inlink, outlink)
RubberBandContext::formant
int formant
Definition: af_rubberband.c:37
RubberBandContext::tempo
double tempo
Definition: af_rubberband.c:35
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
ff_set_common_samplerates
int ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:568
AT
#define AT
Definition: af_rubberband.c:46
RubberBandContext::detector
int detector
Definition: af_rubberband.c:36
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
ff_filter_set_ready
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition: avfilter.c:186
ff_set_common_channel_layouts
int ff_set_common_channel_layouts(AVFilterContext *ctx, AVFilterChannelLayouts *channel_layouts)
A helper for query_formats() which sets all links to the same list of channel layouts/sample rates.
Definition: formats.c:561