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