mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-08 13:22:53 +02:00
avfilter/sine: support expression in the number of output samples
This commit is contained in:
parent
db18b3d6e6
commit
a388ca359d
@ -2857,7 +2857,26 @@ Specify the sample rate, default is 44100.
|
||||
Specify the duration of the generated audio stream.
|
||||
|
||||
@item samples_per_frame
|
||||
Set the number of samples per output frame, default is 1024.
|
||||
Set the number of samples per output frame.
|
||||
|
||||
The expression can contain the following constants:
|
||||
|
||||
@table @option
|
||||
@item n
|
||||
The (sequential) number of the output audio frame, starting from 0.
|
||||
|
||||
@item pts
|
||||
The PTS (Presentation TimeStamp) of the output audio frame,
|
||||
expressed in @var{TB} units.
|
||||
|
||||
@item t
|
||||
The PTS of the output audio frame, expressed in seconds.
|
||||
|
||||
@item TB
|
||||
The timebase of the output audio frames.
|
||||
@end table
|
||||
|
||||
Default is @code{1024}.
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
@ -2878,6 +2897,12 @@ sine=f=220:b=4:d=5
|
||||
sine=frequency=220:beep_factor=4:duration=5
|
||||
@end example
|
||||
|
||||
@item
|
||||
Generate a 1 kHz sine wave following @code{1602,1601,1602,1601,1602} NTSC
|
||||
pattern:
|
||||
@example
|
||||
sine=1000:samples_per_frame='st(0,mod(n,5)); 1602-not(not(eq(ld(0),1)+eq(ld(0),3)))'
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@c man end AUDIO SOURCES
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/eval.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "audio.h"
|
||||
#include "avfilter.h"
|
||||
@ -31,7 +32,8 @@ typedef struct {
|
||||
const AVClass *class;
|
||||
double frequency;
|
||||
double beep_factor;
|
||||
int samples_per_frame;
|
||||
char *samples_per_frame;
|
||||
AVExpr *samples_per_frame_expr;
|
||||
int sample_rate;
|
||||
int64_t duration;
|
||||
int16_t *sin;
|
||||
@ -61,6 +63,9 @@ typedef struct {
|
||||
#define OPT_DUR(name, field, def, min, max, descr, ...) \
|
||||
OPT_GENERIC(name, field, def, min, max, descr, DURATION, str, __VA_ARGS__)
|
||||
|
||||
#define OPT_STR(name, field, def, min, max, descr, ...) \
|
||||
OPT_GENERIC(name, field, def, min, max, descr, STRING, str, __VA_ARGS__)
|
||||
|
||||
static const AVOption sine_options[] = {
|
||||
OPT_DBL("frequency", frequency, 440, 0, DBL_MAX, "set the sine frequency"),
|
||||
OPT_DBL("f", frequency, 440, 0, DBL_MAX, "set the sine frequency"),
|
||||
@ -70,7 +75,7 @@ static const AVOption sine_options[] = {
|
||||
OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate"),
|
||||
OPT_DUR("duration", duration, 0, 0, INT64_MAX, "set the audio duration"),
|
||||
OPT_DUR("d", duration, 0, 0, INT64_MAX, "set the audio duration"),
|
||||
OPT_INT("samples_per_frame", samples_per_frame, 1024, 0, INT_MAX, "set the number of samples per frame"),
|
||||
OPT_STR("samples_per_frame", samples_per_frame, "1024", 0, 0, "set the number of samples per frame"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@ -120,8 +125,25 @@ static void make_sin_table(int16_t *sin)
|
||||
sin[i + 2 * half_pi] = -sin[i];
|
||||
}
|
||||
|
||||
static const char *const var_names[] = {
|
||||
"n",
|
||||
"pts",
|
||||
"t",
|
||||
"TB",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum {
|
||||
VAR_N,
|
||||
VAR_PTS,
|
||||
VAR_T,
|
||||
VAR_TB,
|
||||
VAR_VARS_NB
|
||||
};
|
||||
|
||||
static av_cold int init(AVFilterContext *ctx)
|
||||
{
|
||||
int ret;
|
||||
SineContext *sine = ctx->priv;
|
||||
|
||||
if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD)))
|
||||
@ -136,6 +158,12 @@ static av_cold int init(AVFilterContext *ctx)
|
||||
sine->sample_rate + 0.5;
|
||||
}
|
||||
|
||||
ret = av_expr_parse(&sine->samples_per_frame_expr,
|
||||
sine->samples_per_frame, var_names,
|
||||
NULL, NULL, NULL, NULL, 0, sine);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -143,6 +171,8 @@ static av_cold void uninit(AVFilterContext *ctx)
|
||||
{
|
||||
SineContext *sine = ctx->priv;
|
||||
|
||||
av_expr_free(sine->samples_per_frame_expr);
|
||||
sine->samples_per_frame_expr = NULL;
|
||||
av_freep(&sine->sin);
|
||||
}
|
||||
|
||||
@ -188,9 +218,21 @@ static int request_frame(AVFilterLink *outlink)
|
||||
{
|
||||
SineContext *sine = outlink->src->priv;
|
||||
AVFrame *frame;
|
||||
int i, nb_samples = sine->samples_per_frame;
|
||||
double values[VAR_VARS_NB] = {
|
||||
[VAR_N] = outlink->frame_count,
|
||||
[VAR_PTS] = sine->pts,
|
||||
[VAR_T] = sine->pts * av_q2d(outlink->time_base),
|
||||
[VAR_TB] = av_q2d(outlink->time_base),
|
||||
};
|
||||
int i, nb_samples = lrint(av_expr_eval(sine->samples_per_frame_expr, values, sine));
|
||||
int16_t *samples;
|
||||
|
||||
if (nb_samples <= 0) {
|
||||
av_log(sine, AV_LOG_WARNING, "nb samples expression evaluated to %d, "
|
||||
"defaulting to 1024\n", nb_samples);
|
||||
nb_samples = 1024;
|
||||
}
|
||||
|
||||
if (sine->duration) {
|
||||
nb_samples = FFMIN(nb_samples, sine->duration - sine->pts);
|
||||
av_assert1(nb_samples >= 0);
|
||||
|
Loading…
Reference in New Issue
Block a user