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