int color_mode; ///< display color scheme
int scale;
float saturation; ///< color saturation multiplier
+ float rotation; ///< color rotation
int data;
int xpos; ///< x position (current column)
- FFTContext *fft; ///< Fast Fourier Transform context
+ FFTContext **fft; ///< Fast Fourier Transform context
int fft_bits; ///< number of bits (FFT window size = 1<<fft_bits)
FFTComplex **fft_data; ///< bins holder for each (displayed) channels
float *window_func_lut; ///< Window function LUT
float gain;
int hop_size;
float *combine_buffer; ///< color combining buffer (3 * h items)
+ float **color_buffer; ///< color buffer (3 * h * ch items)
AVAudioFifo *fifo;
int64_t pts;
int single_pic;
{ "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_SLIDES-1, FLAGS, "slide" },
{ "replace", "replace old columns with new", 0, AV_OPT_TYPE_CONST, {.i64=REPLACE}, 0, 0, FLAGS, "slide" },
{ "scroll", "scroll from right to left", 0, AV_OPT_TYPE_CONST, {.i64=SCROLL}, 0, 0, FLAGS, "slide" },
- { "rscroll", "scroll from left to right", 0, AV_OPT_TYPE_CONST, {.i64=RSCROLL}, 0, 0, FLAGS, "slide" },
{ "fullframe", "return full frames", 0, AV_OPT_TYPE_CONST, {.i64=FULLFRAME}, 0, 0, FLAGS, "slide" },
+ { "rscroll", "scroll from left to right", 0, AV_OPT_TYPE_CONST, {.i64=RSCROLL}, 0, 0, FLAGS, "slide" },
{ "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, COMBINED, NB_MODES-1, FLAGS, "mode" },
{ "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
{ "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
{ "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
{ "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
{ "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=SQRT}, LINEAR, NB_SCALES-1, FLAGS, "scale" },
+ { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
{ "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
{ "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
+ { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
{ "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
{ "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
- { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
- { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
{ "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
{ "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" },
{ "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" },
{ "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" },
{ "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" },
{ "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" },
+ { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" },
+ { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" },
+ { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" },
+ { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" },
{ "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
{ "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
{ "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
{ "data", "set data mode", OFFSET(data), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_DMODES-1, FLAGS, "data" },
{ "magnitude", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_MAGNITUDE}, 0, 0, FLAGS, "data" },
{ "phase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_PHASE}, 0, 0, FLAGS, "data" },
+ { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
{ NULL }
};
int i;
av_freep(&s->combine_buffer);
- av_fft_end(s->fft);
+ if (s->fft) {
+ for (i = 0; i < s->nb_display_channels; i++)
+ av_fft_end(s->fft[i]);
+ }
+ av_freep(&s->fft);
if (s->fft_data) {
for (i = 0; i < s->nb_display_channels; i++)
av_freep(&s->fft_data[i]);
}
av_freep(&s->fft_data);
+ if (s->color_buffer) {
+ for (i = 0; i < s->nb_display_channels; i++)
+ av_freep(&s->color_buffer[i]);
+ }
+ av_freep(&s->color_buffer);
av_freep(&s->window_func_lut);
if (s->magnitudes) {
for (i = 0; i < s->nb_display_channels; i++)
}
s->win_size = 1 << fft_bits;
+ if (!s->fft) {
+ s->fft = av_calloc(inlink->channels, sizeof(*s->fft));
+ if (!s->fft)
+ return AVERROR(ENOMEM);
+ }
+
/* (re-)configuration if the video output changed (or first init) */
if (fft_bits != s->fft_bits) {
AVFrame *outpicref;
- av_fft_end(s->fft);
- s->fft = av_fft_init(fft_bits, 0);
- if (!s->fft) {
- av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. "
- "The window size might be too high.\n");
- return AVERROR(EINVAL);
- }
s->fft_bits = fft_bits;
/* FFT buffers: x2 for each (display) channel buffer.
* Note: we use free and malloc instead of a realloc-like function to
* make sure the buffer is aligned in memory for the FFT functions. */
- for (i = 0; i < s->nb_display_channels; i++)
+ for (i = 0; i < s->nb_display_channels; i++) {
+ av_fft_end(s->fft[i]);
av_freep(&s->fft_data[i]);
+ }
av_freep(&s->fft_data);
+
s->nb_display_channels = inlink->channels;
+ for (i = 0; i < s->nb_display_channels; i++) {
+ s->fft[i] = av_fft_init(fft_bits, 0);
+ if (!s->fft[i]) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. "
+ "The window size might be too high.\n");
+ return AVERROR(EINVAL);
+ }
+ }
s->magnitudes = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes));
if (!s->magnitudes)
return AVERROR(ENOMEM);
}
- s->phases = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes));
+ s->phases = av_calloc(s->nb_display_channels, sizeof(*s->phases));
if (!s->phases)
return AVERROR(ENOMEM);
for (i = 0; i < s->nb_display_channels; i++) {
return AVERROR(ENOMEM);
}
+ av_freep(&s->color_buffer);
+ s->color_buffer = av_calloc(s->nb_display_channels, sizeof(*s->color_buffer));
+ if (!s->color_buffer)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < s->nb_display_channels; i++) {
+ s->color_buffer[i] = av_calloc(s->orientation == VERTICAL ? s->h * 3 : s->w * 3, sizeof(**s->color_buffer));
+ if (!s->color_buffer[i])
+ return AVERROR(ENOMEM);
+ }
+
s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data));
if (!s->fft_data)
return AVERROR(ENOMEM);
return 0;
}
-static void run_fft(ShowSpectrumContext *s, AVFrame *fin)
+static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
- int ch, n;
+ ShowSpectrumContext *s = ctx->priv;
+ const float *window_func_lut = s->window_func_lut;
+ AVFrame *fin = arg;
+ const int ch = jobnr;
+ int n;
/* fill FFT input with the number of samples available */
- for (ch = 0; ch < s->nb_display_channels; ch++) {
- const float *p = (float *)fin->extended_data[ch];
+ const float *p = (float *)fin->extended_data[ch];
- for (n = 0; n < s->win_size; n++) {
- s->fft_data[ch][n].re = p[n] * s->window_func_lut[n];
- s->fft_data[ch][n].im = 0;
- }
+ for (n = 0; n < s->win_size; n++) {
+ s->fft_data[ch][n].re = p[n] * window_func_lut[n];
+ s->fft_data[ch][n].im = 0;
}
/* run FFT on each samples set */
- for (ch = 0; ch < s->nb_display_channels; ch++) {
- av_fft_permute(s->fft, s->fft_data[ch]);
- av_fft_calc(s->fft, s->fft_data[ch]);
- }
+ av_fft_permute(s->fft[ch], s->fft_data[ch]);
+ av_fft_calc(s->fft[ch], s->fft_data[ch]);
+
+ return 0;
}
#define RE(y, ch) s->fft_data[ch][y].re
#define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch))
#define PHASE(y, ch) atan2(IM(y, ch), RE(y, ch))
-static void calc_magnitudes(ShowSpectrumContext *s)
+static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
+ ShowSpectrumContext *s = ctx->priv;
const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1);
- int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
+ int y, h = s->orientation == VERTICAL ? s->h : s->w;
const float f = s->gain * w;
+ const int ch = jobnr;
+ float *magnitudes = s->magnitudes[ch];
- for (ch = 0; ch < s->nb_display_channels; ch++) {
- float *magnitudes = s->magnitudes[ch];
+ for (y = 0; y < h; y++)
+ magnitudes[y] = MAGNITUDE(y, ch) * f;
- for (y = 0; y < h; y++)
- magnitudes[y] = MAGNITUDE(y, ch) * f;
- }
+ return 0;
}
-static void calc_phases(ShowSpectrumContext *s)
+static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
- int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
+ ShowSpectrumContext *s = ctx->priv;
+ const int h = s->orientation == VERTICAL ? s->h : s->w;
+ const int ch = jobnr;
+ float *phases = s->phases[ch];
+ int y;
- for (ch = 0; ch < s->nb_display_channels; ch++) {
- float *phases = s->phases[ch];
+ for (y = 0; y < h; y++)
+ phases[y] = (PHASE(y, ch) / M_PI + 1) / 2;
- for (y = 0; y < h; y++)
- phases[y] = (PHASE(y, ch) / M_PI + 1) / 2;
- }
+ return 0;
}
static void acalc_magnitudes(ShowSpectrumContext *s)
if (s->color_mode == CHANNEL) {
if (s->nb_display_channels > 1) {
- *uf *= 0.5 * sin((2 * M_PI * ch) / s->nb_display_channels);
- *vf *= 0.5 * cos((2 * M_PI * ch) / s->nb_display_channels);
+ *uf *= 0.5 * sin((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
+ *vf *= 0.5 * cos((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
} else {
- *uf = 0.0f;
- *vf = 0.0f;
+ *uf *= 0.5 * sin(M_PI * s->rotation);
+ *vf *= 0.5 * cos(M_PI * s->rotation + M_PI_2);
}
+ } else {
+ *uf += *uf * sin(M_PI * s->rotation);
+ *vf += *vf * cos(M_PI * s->rotation + M_PI_2);
}
+
*uf *= s->saturation;
*vf *= s->saturation;
}
+ color_table[cm][i].v * lerpfrac;
}
- out[0] += y * yf;
- out[1] += u * uf;
- out[2] += v * vf;
+ out[0] = y * yf;
+ out[1] = u * uf;
+ out[2] = v * vf;
} else {
- out[0] += a * yf;
- out[1] += a * uf;
- out[2] += a * vf;
+ out[0] = a * yf;
+ out[1] = a * uf;
+ out[2] = a * vf;
}
}
}
}
+static int plot_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ShowSpectrumContext *s = ctx->priv;
+ const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
+ const int ch = jobnr;
+ float *magnitudes = s->magnitudes[ch];
+ float *phases = s->phases[ch];
+ float yf, uf, vf;
+ int y;
+
+ /* decide color range */
+ color_range(s, ch, &yf, &uf, &vf);
+
+ /* draw the channel */
+ for (y = 0; y < h; y++) {
+ int row = (s->mode == COMBINED) ? y : ch * h + y;
+ float *out = &s->color_buffer[ch][3 * row];
+ float a;
+
+ switch (s->data) {
+ case D_MAGNITUDE:
+ /* get magnitude */
+ a = magnitudes[y];
+ break;
+ case D_PHASE:
+ /* get phase */
+ a = phases[y];
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ /* apply scale */
+ switch (s->scale) {
+ case LINEAR:
+ a = av_clipf(a, 0, 1);
+ break;
+ case SQRT:
+ a = av_clipf(sqrt(a), 0, 1);
+ break;
+ case CBRT:
+ a = av_clipf(cbrt(a), 0, 1);
+ break;
+ case FOURTHRT:
+ a = av_clipf(sqrt(sqrt(a)), 0, 1);
+ break;
+ case FIFTHRT:
+ a = av_clipf(pow(a, 0.20), 0, 1);
+ break;
+ case LOG:
+ a = 1 + log10(av_clipd(a, 1e-6, 1)) / 6; // zero = -120dBFS
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ pick_color(s, yf, uf, vf, a, out);
+ }
+
+ return 0;
+}
+
static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
{
- int ret;
AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = ctx->outputs[0];
ShowSpectrumContext *s = ctx->priv;
AVFrame *outpicref = s->outpicref;
- int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
-
- int ch, plane, x, y;
+ int ret, plane, x, y, z = s->orientation == VERTICAL ? s->h : s->w;
/* fill a new spectrum column */
/* initialize buffer for combining to black */
- clear_combine_buffer(s, s->orientation == VERTICAL ? s->h : s->w);
+ clear_combine_buffer(s, z);
- for (ch = 0; ch < s->nb_display_channels; ch++) {
- float *magnitudes = s->magnitudes[ch];
- float *phases = s->phases[ch];
- float yf, uf, vf;
-
- /* decide color range */
- color_range(s, ch, &yf, &uf, &vf);
-
- /* draw the channel */
- for (y = 0; y < h; y++) {
- int row = (s->mode == COMBINED) ? y : ch * h + y;
- float *out = &s->combine_buffer[3 * row];
- float a;
-
- switch (s->data) {
- case D_MAGNITUDE:
- /* get magnitude */
- a = magnitudes[y];
- break;
- case D_PHASE:
- /* get phase */
- a = phases[y];
- break;
- default:
- av_assert0(0);
- }
+ ctx->internal->execute(ctx, plot_channel, NULL, NULL, s->nb_display_channels);
- /* apply scale */
- switch (s->scale) {
- case LINEAR:
- a = av_clipf(a, 0, 1);
- break;
- case SQRT:
- a = av_clipf(sqrt(a), 0, 1);
- break;
- case CBRT:
- a = av_clipf(cbrt(a), 0, 1);
- break;
- case FOURTHRT:
- a = av_clipf(sqrt(sqrt(a)), 0, 1);
- break;
- case FIFTHRT:
- a = av_clipf(pow(a, 0.20), 0, 1);
- break;
- case LOG:
- a = 1 + log10(av_clipd(a, 1e-6, 1)) / 6; // zero = -120dBFS
- break;
- default:
- av_assert0(0);
- }
-
- pick_color(s, yf, uf, vf, a, out);
+ for (y = 0; y < z * 3; y++) {
+ for (x = 0; x < s->nb_display_channels; x++) {
+ s->combine_buffer[y] += s->color_buffer[x][y];
}
}
av_assert0(fin->nb_samples == s->win_size);
- run_fft(s, fin);
+ ctx->internal->execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
+
if (s->data == D_MAGNITUDE)
- calc_magnitudes(s);
+ ctx->internal->execute(ctx, calc_channel_magnitudes, NULL, NULL, s->nb_display_channels);
+
if (s->data == D_PHASE)
- calc_phases(s);
+ ctx->internal->execute(ctx, calc_channel_phases, NULL, NULL, s->nb_display_channels);
ret = plot_spectrum_column(inlink, fin);
av_frame_free(&fin);
.inputs = showspectrum_inputs,
.outputs = showspectrum_outputs,
.priv_class = &showspectrum_class,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
};
#endif // CONFIG_SHOWSPECTRUM_FILTER
{ "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
{ "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
{ "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=LOG}, 0, NB_SCALES-1, FLAGS, "scale" },
+ { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
{ "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
{ "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
+ { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
{ "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
{ "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
- { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
- { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
{ "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
{ "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" },
{ "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" },
{ "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" },
{ "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" },
{ "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" },
+ { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" },
+ { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" },
+ { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" },
+ { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" },
{ "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
{ "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
{ "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
{ "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
{ "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
+ { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
{ NULL }
};
static int showspectrumpic_request_frame(AVFilterLink *outlink)
{
- ShowSpectrumContext *s = outlink->src->priv;
- AVFilterLink *inlink = outlink->src->inputs[0];
+ AVFilterContext *ctx = outlink->src;
+ ShowSpectrumContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
int ret;
ret = ff_request_frame(inlink);
}
}
- run_fft(s, fin);
+ ctx->internal->execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
acalc_magnitudes(s);
consumed += spf;
for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) {
float yf, uf, vf;
int channel = (multi) ? s->nb_display_channels - ch - 1 : chn;
+ float lout[3];
color_range(s, channel, &yf, &uf, &vf);
- pick_color(s, yf, uf, vf, y / (float)h, out);
+ pick_color(s, yf, uf, vf, y / (float)h, lout);
+ out[0] += lout[0];
+ out[1] += lout[1];
+ out[2] += lout[2];
}
memset(s->outpicref->data[0]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0] + s->w + s->start_x + 20, av_clip_uint8(out[0]), 10);
memset(s->outpicref->data[1]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[1] + s->w + s->start_x + 20, av_clip_uint8(out[1]), 10);
memset(s->outpicref->data[2]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[2] + s->w + s->start_x + 20, av_clip_uint8(out[2]), 10);
}
+
+ for (y = 0; ch == 0 && y < h; y += h / 10) {
+ float value = 120.0 * log10(1. - y / (float)h);
+ char *text;
+
+ if (value < -120)
+ break;
+ text = av_asprintf("%.0f dB", value);
+ if (!text)
+ continue;
+ drawtext(s->outpicref, s->w + s->start_x + 35, s->start_y + y - 5, text, 0);
+ }
}
}
.inputs = showspectrumpic_inputs,
.outputs = showspectrumpic_outputs,
.priv_class = &showspectrumpic_class,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
};
#endif // CONFIG_SHOWSPECTRUMPIC_FILTER