/* * 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; }