ffmpeg/libavfilter/silenceremove_template.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;
}