| @@ -21,7 +21,7 @@ · 20 unmodified lines |
| 21 | #include <float.h> | 21 | #include <float.h> |
| 22 | #include <math.h> | 22 | #include <math.h> |
| 23 | | 23 | |
| 24 | #include "libavcodec/avfft.h" | 24 | #include "libavutil/tx.h" |
| 25 | #include "libavutil/audio_fifo.h" | 25 | #include "libavutil/audio_fifo.h" |
| 26 | #include "libavutil/avassert.h" | 26 | #include "libavutil/avassert.h" |
| 27 | #include "libavutil/channel_layout.h" | 27 | #include "libavutil/channel_layout.h" |
| @@ -38,15 +38,14 @@ typedef struct ShowSpatialContext { · 10 unmodified lines |
| 38 | const AVClass *class; | 38 | const AVClass *class; |
| 39 | int w, h; | 39 | int w, h; |
| 40 | AVRational frame_rate; | 40 | AVRational frame_rate; |
| 41 | FFTContext *fft[2]; ///< Fast Fourier Transform context | 41 | AVTXContext *fft[2]; ///< Fast Fourier Transform context |
| 42 | FFTContext *ifft[2]; ///< Inverse Fast Fourier Transform context | 42 | AVComplexFloat *fft_data[2]; ///< bins holder for each (displayed) channels |
| 43 | int fft_bits; ///< number of bits (FFT window size = 1<<fft_bits) | 43 | AVComplexFloat *fft_tdata[2]; ///< bins holder for each (displayed) channels |
| 44 | FFTComplex *fft_data[2]; ///< bins holder for each (displayed) channels | | |
| 45 | float *window_func_lut; ///< Window function LUT | 44 | float *window_func_lut; ///< Window function LUT |
| | 45 | av_tx_fn tx_fn[2]; |
| 46 | int win_func; | 46 | int win_func; |
| 47 | int win_size; | 47 | int win_size; |
| 48 | int buf_size; | 48 | int buf_size; |
| 49 | float overlap; | | |
| 50 | int consumed; | 49 | int consumed; |
| 51 | int hop_size; | 50 | int hop_size; |
| 52 | AVAudioFifo *fifo; | 51 | AVAudioFifo *fifo; |
| @@ -61,7 +60,6 @@ static const AVOption showspatial_options[] = { · 8 unmodified lines |
| 61 | { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "512x512"}, 0, 0, FLAGS }, | 60 | { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "512x512"}, 0, 0, FLAGS }, |
| 62 | { "win_size", "set window size", OFFSET(win_size), AV_OPT_TYPE_INT, {.i64 = 4096}, 1024, 65536, FLAGS }, | 61 | { "win_size", "set window size", OFFSET(win_size), AV_OPT_TYPE_INT, {.i64 = 4096}, 1024, 65536, FLAGS }, |
| 63 | WIN_FUNC_OPTION("win_func", OFFSET(win_func), FLAGS, WFUNC_HANNING), | 62 | WIN_FUNC_OPTION("win_func", OFFSET(win_func), FLAGS, WFUNC_HANNING), |
| 64 | { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, | | |
| 65 | { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, | 63 | { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, |
| 66 | { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, | 64 | { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, |
| 67 | { NULL } | 65 | { NULL } |
| @@ -72,14 +70,13 @@ AVFILTER_DEFINE_CLASS(showspatial); · 4 unmodified lines |
| 72 | static av_cold void uninit(AVFilterContext *ctx) | 70 | static av_cold void uninit(AVFilterContext *ctx) |
| 73 | { | 71 | { |
| 74 | ShowSpatialContext *s = ctx->priv; | 72 | ShowSpatialContext *s = ctx->priv; |
| 75 | int i; | | |
| 76 | | 73 | |
| 77 | for (i = 0; i < 2; i++) | 74 | for (int i = 0; i < 2; i++) |
| 78 | av_fft_end(s->fft[i]); | 75 | av_tx_uninit(&s->fft[i]); |
| 79 | for (i = 0; i < 2; i++) | 76 | for (int i = 0; i < 2; i++) { |
| 80 | av_fft_end(s->ifft[i]); | | |
| 81 | for (i = 0; i < 2; i++) | | |
| 82 | av_freep(&s->fft_data[i]); | 77 | av_freep(&s->fft_data[i]); |
| | 78 | av_freep(&s->fft_tdata[i]); |
| | 79 | } |
| 83 | av_freep(&s->window_func_lut); | 80 | av_freep(&s->window_func_lut); |
| 84 | av_audio_fifo_free(s->fifo); | 81 | av_audio_fifo_free(s->fifo); |
| 85 | } | 82 | } |
| @@ -120,12 +117,11 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 34 unmodified lines |
| 120 | const float *p = (float *)fin->extended_data[ch]; | 117 | const float *p = (float *)fin->extended_data[ch]; |
| 121 | | 118 | |
| 122 | for (int n = 0; n < fin->nb_samples; n++) { | 119 | for (int n = 0; n < fin->nb_samples; n++) { |
| 123 | s->fft_data[ch][n].re = p[n] * window_func_lut[n]; | 120 | s->fft_tdata[ch][n].re = p[n] * window_func_lut[n]; |
| 124 | s->fft_data[ch][n].im = 0; | 121 | s->fft_tdata[ch][n].im = 0.f; |
| 125 | } | 122 | } |
| 126 | | 123 | |
| 127 | av_fft_permute(s->fft[ch], s->fft_data[ch]); | 124 | s->tx_fn[ch](s->fft[ch], s->fft_data[ch], s->fft_tdata[ch], sizeof(float)); |
| 128 | av_fft_calc(s->fft[ch], s->fft_data[ch]); | | |
| 129 | | 125 | |
| 130 | return 0; | 126 | return 0; |
| 131 | } | 127 | } |
| @@ -135,38 +131,41 @@ static int config_output(AVFilterLink *outlink) · 3 unmodified lines |
| 135 | AVFilterContext *ctx = outlink->src; | 131 | AVFilterContext *ctx = outlink->src; |
| 136 | AVFilterLink *inlink = ctx->inputs[0]; | 132 | AVFilterLink *inlink = ctx->inputs[0]; |
| 137 | ShowSpatialContext *s = ctx->priv; | 133 | ShowSpatialContext *s = ctx->priv; |
| 138 | int i, fft_bits; | | |
| 139 | float overlap; | 134 | float overlap; |
| | 135 | int ret; |
| 140 | | 136 | |
| 141 | outlink->w = s->w; | 137 | outlink->w = s->w; |
| 142 | outlink->h = s->h; | 138 | outlink->h = s->h; |
| 143 | outlink->sample_aspect_ratio = (AVRational){1,1}; | 139 | outlink->sample_aspect_ratio = (AVRational){1,1}; |
| 144 | | 140 | |
| 145 | s->buf_size = 1 << av_log2(s->win_size); | 141 | outlink->frame_rate = s->frame_rate; |
| 146 | s->win_size = s->buf_size; | 142 | outlink->time_base = av_inv_q(outlink->frame_rate); |
| 147 | fft_bits = av_log2(s->win_size); | | |
| 148 | | 143 | |
| 149 | /* (re-)configuration if the video output changed (or first init) */ | 144 | /* (re-)configuration if the video output changed (or first init) */ |
| 150 | if (fft_bits != s->fft_bits) { | 145 | if (s->win_size != s->buf_size) { |
| 151 | s->fft_bits = fft_bits; | 146 | s->buf_size = s->win_size; |
| 152 | | 147 | |
| 153 | /* FFT buffers: x2 for each channel buffer. | 148 | /* FFT buffers: x2 for each channel buffer. |
| 154 | * Note: we use free and malloc instead of a realloc-like function to | 149 | * Note: we use free and malloc instead of a realloc-like function to |
| 155 | * make sure the buffer is aligned in memory for the FFT functions. */ | 150 | * make sure the buffer is aligned in memory for the FFT functions. */ |
| 156 | for (i = 0; i < 2; i++) { | 151 | for (int i = 0; i < 2; i++) { |
| 157 | av_fft_end(s->fft[i]); | 152 | av_tx_uninit(&s->fft[i]); |
| 158 | av_freep(&s->fft_data[i]); | 153 | av_freep(&s->fft_data[i]); |
| | 154 | av_freep(&s->fft_tdata[i]); |
| 159 | } | 155 | } |
| 160 | for (i = 0; i < 2; i++) { | 156 | for (int i = 0; i < 2; i++) { |
| 161 | s->fft[i] = av_fft_init(fft_bits, 0); | 157 | float scale = 1.f; |
| 162 | if (!s->fft[i]) { | 158 | ret = av_tx_init(&s->fft[i], &s->tx_fn[i], AV_TX_FLOAT_FFT, |
| 163 | av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. " | 159 | 0, s->win_size, &scale, 0); |
| 164 | "The window size might be too high.\n"); | 160 | if (ret < 0) |
| 165 | return AVERROR(EINVAL); | 161 | return ret; |
| 166 | } | | |
| 167 | } | 162 | } |
| 168 | | 163 | |
| 169 | for (i = 0; i < 2; i++) { | 164 | for (int i = 0; i < 2; i++) { |
| | 165 | s->fft_tdata[i] = av_calloc(s->buf_size, sizeof(**s->fft_tdata)); |
| | 166 | if (!s->fft_tdata[i]) |
| | 167 | return AVERROR(ENOMEM); |
| | 168 | |
| 170 | s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data)); | 169 | s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data)); |
| 171 | if (!s->fft_data[i]) | 170 | if (!s->fft_data[i]) |
| 172 | return AVERROR(ENOMEM); | 171 | return AVERROR(ENOMEM); |
| @@ -179,19 +178,10 @@ static int config_output(AVFilterLink *outlink) · 6 unmodified lines |
| 179 | if (!s->window_func_lut) | 178 | if (!s->window_func_lut) |
| 180 | return AVERROR(ENOMEM); | 179 | return AVERROR(ENOMEM); |
| 181 | generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap); | 180 | generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap); |
| 182 | if (s->overlap == 1) | | |
| 183 | s->overlap = overlap; | | |
| 184 | | 181 | |
| 185 | s->hop_size = (1.f - s->overlap) * s->win_size; | 182 | s->hop_size = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); |
| 186 | if (s->hop_size < 1) { | | |
| 187 | av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap); | | |
| 188 | return AVERROR(EINVAL); | | |
| 189 | } | | |
| 190 | } | 183 | } |
| 191 | | 184 | |
| 192 | outlink->frame_rate = s->frame_rate; | | |
| 193 | outlink->time_base = av_inv_q(outlink->frame_rate); | | |
| 194 | | | |
| 195 | av_audio_fifo_free(s->fifo); | 185 | av_audio_fifo_free(s->fifo); |
| 196 | s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->win_size); | 186 | s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, s->win_size); |
| 197 | if (!s->fifo) | 187 | if (!s->fifo) |
| @@ -220,6 +210,7 @@ static int draw_spatial(AVFilterLink *inlink, AVFrame *insamples) · 22 unmodified lines |
| 220 | int h = s->h - 2; | 210 | int h = s->h - 2; |
| 221 | int w = s->w - 2; | 211 | int w = s->w - 2; |
| 222 | int z = s->win_size / 2; | 212 | int z = s->win_size / 2; |
| | 213 | int64_t pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base); |
| 223 | | 214 | |
| 224 | outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); | 215 | outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
| 225 | if (!outpicref) | 216 | if (!outpicref) |
| @@ -255,7 +246,7 @@ static int draw_spatial(AVFilterLink *inlink, AVFrame *insamples) · 29 unmodified lines |
| 255 | draw_dot(outpicref->data[2] + outpicref->linesize[2] * y + x, outpicref->linesize[2], cr); | 246 | draw_dot(outpicref->data[2] + outpicref->linesize[2] * y + x, outpicref->linesize[2], cr); |
| 256 | } | 247 | } |
| 257 | | 248 | |
| 258 | outpicref->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base); | 249 | outpicref->pts = pts; |
| 259 | outpicref->duration = 1; | 250 | outpicref->duration = 1; |
| 260 | | 251 | |
| 261 | return ff_filter_frame(outlink, outpicref); | 252 | return ff_filter_frame(outlink, outpicref); |