447 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			447 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This file is part of FFmpeg.
 | |
|  *
 | |
|  * FFmpeg is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2.1 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * FFmpeg is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with FFmpeg; if not, write to the Free Software
 | |
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | |
|  */
 | |
| 
 | |
| #undef ftype
 | |
| #undef FABS
 | |
| #undef FMAX
 | |
| #undef SAMPLE_FORMAT
 | |
| #undef SQRT
 | |
| #undef ZERO
 | |
| #undef ONE
 | |
| #undef TMIN
 | |
| #if DEPTH == 32
 | |
| #define SAMPLE_FORMAT flt
 | |
| #define SQRT sqrtf
 | |
| #define FMAX fmaxf
 | |
| #define FABS fabsf
 | |
| #define ftype float
 | |
| #define ZERO 0.f
 | |
| #define ONE 1.f
 | |
| #define TMIN -FLT_MAX
 | |
| #else
 | |
| #define SAMPLE_FORMAT dbl
 | |
| #define SQRT sqrt
 | |
| #define FMAX fmax
 | |
| #define FABS fabs
 | |
| #define ftype double
 | |
| #define ZERO 0.0
 | |
| #define ONE 1.0
 | |
| #define TMIN -DBL_MAX
 | |
| #endif
 | |
| 
 | |
| #define fn3(a,b)   a##_##b
 | |
| #define fn2(a,b)   fn3(a,b)
 | |
| #define fn(a)      fn2(a, SAMPLE_FORMAT)
 | |
| 
 | |
| static void fn(flush)(ftype *dst, const ftype *src, int src_pos,
 | |
|                       int nb_channels, int count, int src_nb_samples,
 | |
|                       int *out_nb_samples)
 | |
| {
 | |
|     int oidx, out_count = count;
 | |
|     int sidx = src_pos;
 | |
| 
 | |
|     if (count <= 0)
 | |
|         return;
 | |
| 
 | |
|     oidx = *out_nb_samples + out_count - 1;
 | |
|     *out_nb_samples += out_count;
 | |
|     while (out_count-- > 0) {
 | |
|         const int spos = sidx * nb_channels;
 | |
|         const int opos = oidx * nb_channels;
 | |
| 
 | |
|         for (int ch = 0; ch < nb_channels; ch++)
 | |
|             dst[opos + ch] = src[spos + ch];
 | |
| 
 | |
|         oidx--;
 | |
|         sidx--;
 | |
|         if (sidx < 0)
 | |
|             sidx = src_nb_samples - 1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void fn(queue_sample)(AVFilterContext *ctx,
 | |
|                              const ftype *src,
 | |
|                              ftype *queue,
 | |
|                              int *queue_pos,
 | |
|                              int *queue_size,
 | |
|                              int *window_pos,
 | |
|                              int *window_size,
 | |
|                              const int nb_channels,
 | |
|                              const int nb_samples,
 | |
|                              const int window_nb_samples)
 | |
| {
 | |
|     const int pos = *queue_pos * nb_channels;
 | |
| 
 | |
|     for (int ch = 0; ch < nb_channels; ch++)
 | |
|         queue[pos + ch] = src[ch];
 | |
| 
 | |
|     (*queue_pos)++;
 | |
|     if (*queue_pos >= nb_samples)
 | |
|         *queue_pos = 0;
 | |
| 
 | |
|     if (*queue_size < nb_samples)
 | |
|         (*queue_size)++;
 | |
| 
 | |
|     if (*window_size < window_nb_samples)
 | |
|         (*window_size)++;
 | |
| 
 | |
|     (*window_pos)++;
 | |
|     if (*window_pos >= window_nb_samples)
 | |
|         *window_pos = 0;
 | |
| }
 | |
| 
 | |
| static ftype fn(compute_avg)(ftype *cache, ftype x, ftype px,
 | |
|                              int window_size, int *unused, int *unused2)
 | |
| {
 | |
|     ftype r;
 | |
| 
 | |
|     cache[0] += FABS(x);
 | |
|     cache[0] -= FABS(px);
 | |
|     cache[0] = r = FMAX(cache[0], ZERO);
 | |
| 
 | |
|     return r / window_size;
 | |
| }
 | |
| 
 | |
| #define PEAKS(empty_value,op,sample, psample)\
 | |
|     if (!empty && psample == ss[front]) {    \
 | |
|         ss[front] = empty_value;             \
 | |
|         if (back != front) {                 \
 | |
|             front--;                         \
 | |
|             if (front < 0)                   \
 | |
|                 front = n - 1;               \
 | |
|         }                                    \
 | |
|         empty = front == back;               \
 | |
|     }                                        \
 | |
|                                              \
 | |
|     if (!empty && sample op ss[front]) {     \
 | |
|         while (1) {                          \
 | |
|             ss[front] = empty_value;         \
 | |
|             if (back == front) {             \
 | |
|                 empty = 1;                   \
 | |
|                 break;                       \
 | |
|             }                                \
 | |
|             front--;                         \
 | |
|             if (front < 0)                   \
 | |
|                 front = n - 1;               \
 | |
|         }                                    \
 | |
|     }                                        \
 | |
|                                              \
 | |
|     while (!empty && sample op ss[back]) {   \
 | |
|         ss[back] = empty_value;              \
 | |
|         if (back == front) {                 \
 | |
|             empty = 1;                       \
 | |
|             break;                           \
 | |
|         }                                    \
 | |
|         back++;                              \
 | |
|         if (back >= n)                       \
 | |
|             back = 0;                        \
 | |
|     }                                        \
 | |
|                                              \
 | |
|     if (!empty) {                            \
 | |
|         back--;                              \
 | |
|         if (back < 0)                        \
 | |
|             back = n - 1;                    \
 | |
|     }
 | |
| 
 | |
| static ftype fn(compute_median)(ftype *ss, ftype x, ftype px,
 | |
|                                 int n, int *ffront, int *bback)
 | |
| {
 | |
|     ftype r, ax = FABS(x);
 | |
|     int front = *ffront;
 | |
|     int back = *bback;
 | |
|     int empty = front == back && ss[front] == -ONE;
 | |
|     int idx;
 | |
| 
 | |
|     PEAKS(-ONE, >, ax, FABS(px))
 | |
| 
 | |
|     ss[back] = ax;
 | |
|     idx = (back <= front) ? back + (front - back + 1) / 2 : back + (n + front - back + 1) / 2;
 | |
|     if (idx >= n)
 | |
|         idx -= n;
 | |
|     av_assert2(idx >= 0 && idx < n);
 | |
|     r = ss[idx];
 | |
| 
 | |
|     *ffront = front;
 | |
|     *bback = back;
 | |
| 
 | |
|     return r;
 | |
| }
 | |
| 
 | |
| static ftype fn(compute_peak)(ftype *ss, ftype x, ftype px,
 | |
|                               int n, int *ffront, int *bback)
 | |
| {
 | |
|     ftype r, ax = FABS(x);
 | |
|     int front = *ffront;
 | |
|     int back = *bback;
 | |
|     int empty = front == back && ss[front] == ZERO;
 | |
| 
 | |
|     PEAKS(ZERO, >=, ax, FABS(px))
 | |
| 
 | |
|     ss[back] = ax;
 | |
|     r = ss[front];
 | |
| 
 | |
|     *ffront = front;
 | |
|     *bback = back;
 | |
| 
 | |
|     return r;
 | |
| }
 | |
| 
 | |
| static ftype fn(compute_ptp)(ftype *ss, ftype x, ftype px,
 | |
|                              int n, int *ffront, int *bback)
 | |
| {
 | |
|     int front = *ffront;
 | |
|     int back = *bback;
 | |
|     int empty = front == back && ss[front] == TMIN;
 | |
|     ftype r, max, min;
 | |
| 
 | |
|     PEAKS(TMIN, >=, x, px)
 | |
| 
 | |
|     ss[back] = x;
 | |
|     max = ss[front];
 | |
|     min = x;
 | |
|     r = FABS(min) + FABS(max - min);
 | |
| 
 | |
|     *ffront = front;
 | |
|     *bback = back;
 | |
| 
 | |
|     return r;
 | |
| }
 | |
| 
 | |
| static ftype fn(compute_rms)(ftype *cache, ftype x, ftype px,
 | |
|                              int window_size, int *unused, int *unused2)
 | |
| {
 | |
|     ftype r;
 | |
| 
 | |
|     cache[0] += x * x;
 | |
|     cache[0] -= px * px;
 | |
|     cache[0] = r = FMAX(cache[0], ZERO);
 | |
| 
 | |
|     return SQRT(r / window_size);
 | |
| }
 | |
| 
 | |
| static ftype fn(compute_dev)(ftype *ss, ftype x, ftype px,
 | |
|                              int n, int *unused, int *unused2)
 | |
| {
 | |
|     ftype r;
 | |
| 
 | |
|     ss[0] += x;
 | |
|     ss[0] -= px;
 | |
| 
 | |
|     ss[1] += x * x;
 | |
|     ss[1] -= px * px;
 | |
|     ss[1] = FMAX(ss[1], ZERO);
 | |
| 
 | |
|     r = FMAX(ss[1] - ss[0] * ss[0] / n, ZERO) / n;
 | |
| 
 | |
|     return SQRT(r);
 | |
| }
 | |
| 
 | |
| static void fn(filter_start)(AVFilterContext *ctx,
 | |
|                              const ftype *src, ftype *dst,
 | |
|                              int *nb_out_samples,
 | |
|                              const int nb_channels)
 | |
| {
 | |
|     SilenceRemoveContext *s = ctx->priv;
 | |
|     const int start_periods = s->start_periods;
 | |
|     int out_nb_samples = *nb_out_samples;
 | |
|     const int start_window_nb_samples = s->start_window->nb_samples;
 | |
|     const int start_nb_samples = s->start_queuef->nb_samples;
 | |
|     const int start_wpos = s->start_window_pos * nb_channels;
 | |
|     const int start_pos = s->start_queue_pos * nb_channels;
 | |
|     ftype *startw = (ftype *)s->start_window->data[0];
 | |
|     ftype *start = (ftype *)s->start_queuef->data[0];
 | |
|     const ftype start_threshold = s->start_threshold;
 | |
|     const int start_mode = s->start_mode;
 | |
|     int start_thres = (start_mode == T_ANY) ? 0 : 1;
 | |
|     const int start_duration = s->start_duration;
 | |
|     ftype *start_cache = (ftype *)s->start_cache;
 | |
|     const int start_silence = s->start_silence;
 | |
|     int window_size = start_window_nb_samples;
 | |
|     const int cache_size = s->cache_size;
 | |
|     int *front = s->start_front;
 | |
|     int *back = s->start_back;
 | |
| 
 | |
|     fn(queue_sample)(ctx, src, start,
 | |
|                      &s->start_queue_pos,
 | |
|                      &s->start_queue_size,
 | |
|                      &s->start_window_pos,
 | |
|                      &s->start_window_size,
 | |
|                      nb_channels,
 | |
|                      start_nb_samples,
 | |
|                      start_window_nb_samples);
 | |
| 
 | |
|     if (s->start_found_periods < 0)
 | |
|         goto skip;
 | |
| 
 | |
|     if (s->detection != D_PEAK && s->detection != D_MEDIAN &&
 | |
|         s->detection != D_PTP)
 | |
|         window_size = s->start_window_size;
 | |
| 
 | |
|     for (int ch = 0; ch < nb_channels; ch++) {
 | |
|         ftype start_sample = start[start_pos + ch];
 | |
|         ftype start_ow = startw[start_wpos + ch];
 | |
|         ftype tstart;
 | |
| 
 | |
|         tstart = fn(s->compute)(start_cache + ch * cache_size,
 | |
|                                 start_sample,
 | |
|                                 start_ow,
 | |
|                                 window_size,
 | |
|                                 front + ch,
 | |
|                                 back + ch);
 | |
| 
 | |
|         startw[start_wpos + ch] = start_sample;
 | |
| 
 | |
|         if (start_mode == T_ANY) {
 | |
|             start_thres |= tstart > start_threshold;
 | |
|         } else {
 | |
|             start_thres &= tstart > start_threshold;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (s->start_found_periods >= 0) {
 | |
|         if (start_silence > 0) {
 | |
|             s->start_silence_count++;
 | |
|             if (s->start_silence_count > start_silence)
 | |
|                 s->start_silence_count = start_silence;
 | |
|         }
 | |
| 
 | |
|         s->start_sample_count += start_thres;
 | |
|     }
 | |
| 
 | |
|     if (s->start_sample_count > start_duration) {
 | |
|         s->start_found_periods++;
 | |
|         if (s->start_found_periods >= start_periods) {
 | |
|             if (!ctx->is_disabled)
 | |
|                 fn(flush)(dst, start, s->start_queue_pos, nb_channels,
 | |
|                           s->start_silence_count, start_nb_samples,
 | |
|                           &out_nb_samples);
 | |
|             s->start_silence_count = 0;
 | |
|             s->start_found_periods = -1;
 | |
|         }
 | |
| 
 | |
|         s->start_sample_count = 0;
 | |
|     }
 | |
| 
 | |
| skip:
 | |
|     if (s->start_found_periods < 0 || ctx->is_disabled) {
 | |
|         const int dst_pos = out_nb_samples * nb_channels;
 | |
|         for (int ch = 0; ch < nb_channels; ch++)
 | |
|             dst[dst_pos + ch] = start[start_pos + ch];
 | |
|         out_nb_samples++;
 | |
|     }
 | |
| 
 | |
|     *nb_out_samples = out_nb_samples;
 | |
| }
 | |
| 
 | |
| static void fn(filter_stop)(AVFilterContext *ctx,
 | |
|                             const ftype *src, ftype *dst,
 | |
|                             int *nb_out_samples,
 | |
|                             const int nb_channels)
 | |
| {
 | |
|     SilenceRemoveContext *s = ctx->priv;
 | |
|     const int stop_periods = s->stop_periods;
 | |
|     int out_nb_samples = *nb_out_samples;
 | |
|     const int stop_window_nb_samples = s->stop_window->nb_samples;
 | |
|     const int stop_nb_samples = s->stop_queuef->nb_samples;
 | |
|     const int stop_wpos = s->stop_window_pos * nb_channels;
 | |
|     const int stop_pos = s->stop_queue_pos * nb_channels;
 | |
|     ftype *stopw = (ftype *)s->stop_window->data[0];
 | |
|     const ftype stop_threshold = s->stop_threshold;
 | |
|     ftype *stop = (ftype *)s->stop_queuef->data[0];
 | |
|     const int stop_mode = s->stop_mode;
 | |
|     int stop_thres = (stop_mode == T_ANY) ? 0 : 1;
 | |
|     const int stop_duration = s->stop_duration;
 | |
|     ftype *stop_cache = (ftype *)s->stop_cache;
 | |
|     const int stop_silence = s->stop_silence;
 | |
|     int window_size = stop_window_nb_samples;
 | |
|     const int cache_size = s->cache_size;
 | |
|     const int restart = s->restart;
 | |
|     int *front = s->stop_front;
 | |
|     int *back = s->stop_back;
 | |
| 
 | |
|     fn(queue_sample)(ctx, src, stop,
 | |
|                      &s->stop_queue_pos,
 | |
|                      &s->stop_queue_size,
 | |
|                      &s->stop_window_pos,
 | |
|                      &s->stop_window_size,
 | |
|                      nb_channels,
 | |
|                      stop_nb_samples,
 | |
|                      stop_window_nb_samples);
 | |
| 
 | |
|     if (s->detection != D_PEAK && s->detection != D_MEDIAN &&
 | |
|         s->detection != D_PTP)
 | |
|         window_size = s->stop_window_size;
 | |
| 
 | |
|     for (int ch = 0; ch < nb_channels; ch++) {
 | |
|         ftype stop_sample = stop[stop_pos + ch];
 | |
|         ftype stop_ow = stopw[stop_wpos + ch];
 | |
|         ftype tstop;
 | |
| 
 | |
|         tstop = fn(s->compute)(stop_cache + ch * cache_size,
 | |
|                                stop_sample,
 | |
|                                stop_ow,
 | |
|                                window_size,
 | |
|                                front + ch,
 | |
|                                back + ch);
 | |
| 
 | |
|         stopw[stop_wpos + ch] = stop_sample;
 | |
| 
 | |
|         if (stop_mode == T_ANY) {
 | |
|             stop_thres |= tstop <= stop_threshold;
 | |
|         } else {
 | |
|             stop_thres &= tstop <= stop_threshold;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     s->found_nonsilence = FFMAX(s->found_nonsilence, !stop_thres);
 | |
|     if (restart && !stop_thres)
 | |
|         s->stop_found_periods = 0;
 | |
| 
 | |
|     if (s->stop_found_periods >= 0 || ctx->is_disabled) {
 | |
|         if (s->found_nonsilence) {
 | |
|             s->stop_sample_count += stop_thres;
 | |
|             s->stop_sample_count *= stop_thres;
 | |
|         }
 | |
|     } else if (s->stop_silence_count > 0) {
 | |
|         const int dst_pos = out_nb_samples * nb_channels;
 | |
|         for (int ch = 0; ch < nb_channels; ch++)
 | |
|             dst[dst_pos + ch] = stop[stop_pos + ch];
 | |
|         s->stop_silence_count--;
 | |
|         out_nb_samples++;
 | |
|     }
 | |
| 
 | |
|     if (s->stop_sample_count > stop_duration) {
 | |
|         s->stop_found_periods++;
 | |
|         if (s->stop_found_periods >= stop_periods) {
 | |
|             s->stop_found_periods = -1;
 | |
|             s->stop_silence_count = stop_silence;
 | |
|         }
 | |
| 
 | |
|         s->stop_sample_count = 0;
 | |
|     }
 | |
| 
 | |
|     if (s->stop_found_periods >= 0 || ctx->is_disabled) {
 | |
|         const int dst_pos = out_nb_samples * nb_channels;
 | |
|         for (int ch = 0; ch < nb_channels; ch++)
 | |
|             dst[dst_pos + ch] = stop[stop_pos + ch];
 | |
|         out_nb_samples++;
 | |
|     }
 | |
| 
 | |
|     *nb_out_samples = out_nb_samples;
 | |
| }
 |