This patch extends aphasemeter filter to display metadata for out-of-phase or mono sequences of stereo streams. Displays start, end and duration as for silencedetect filter.
From 763cd15c156be8ef7c577519e57bf14990adcf69 Mon Sep 17 00:00:00 2001 From: Romane Lafon <romane@nomalab.com> Date: Wed, 8 May 2019 17:59:29 +0200 Subject: [PATCH] avfilter/avf_aphasemeter: Add out of phase and mono detection
Signed-off-by: Romane Lafon <romane@nomalab.com> --- libavfilter/avf_aphasemeter.c | 108 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c index ed837059ea..e2c534d0c9 100644 --- a/libavfilter/avf_aphasemeter.c +++ b/libavfilter/avf_aphasemeter.c @@ -28,26 +28,40 @@ #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" +#include "libavutil/timestamp.h" #include "avfilter.h" #include "formats.h" #include "audio.h" #include "video.h" #include "internal.h" +#include "stdbool.h" +#include "float.h" typedef struct AudioPhaseMeterContext { const AVClass *class; AVFrame *out; int do_video; + int do_phasing_detection; int w, h; AVRational frame_rate; int contrast[4]; uint8_t *mpc_str; uint8_t mpc[4]; int draw_median_phase; + float tolerance; + float angle; + bool is_mono; + bool is_out_phase; + float mono_idx[2]; + float out_idx[2]; + double duration; + float phase; + bool start_presence; } AudioPhaseMeterContext; #define OFFSET(x) offsetof(AudioPhaseMeterContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +#define pi 3.14159265359 static const AVOption aphasemeter_options[] = { { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, @@ -59,6 +73,10 @@ static const AVOption aphasemeter_options[] = { { "bc", "set blue contrast", OFFSET(contrast[2]), AV_OPT_TYPE_INT, {.i64=1}, 0, 255, FLAGS }, { "mpc", "set median phase color", OFFSET(mpc_str), AV_OPT_TYPE_STRING, {.str = "none"}, 0, 0, FLAGS }, { "video", "set video output", OFFSET(do_video), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, + { "phasing", "set mono and out-of-phase detection output", OFFSET(do_phasing_detection), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + { "tolerance", "set phase tolerance", OFFSET(tolerance), AV_OPT_TYPE_FLOAT, {.i64 = 0}, 0, 1, FLAGS }, + { "angle", "set angle threshold for out-of-phase detection", OFFSET(angle), AV_OPT_TYPE_FLOAT, {.i64 = 175}, 0, 180, FLAGS }, + { "duration", "set minimum mono duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS }, { NULL } }; @@ -140,6 +158,27 @@ static inline int get_x(float phase, int w) return (phase + 1.) / 2. * (w - 1); } +static float get_index(AVFilterLink *inlink, AVFrame *in) +{ + char *index_str = av_ts2timestr(in->pts, &inlink->time_base); + return atof(index_str); +} + +static float get_duration(float index[2]) +{ + return index[1] - index[0]; +} + +static void set_meta(AVFrame *insamples, const char *key, float value) +{ + char buf[128]; + char str[128]; + + snprintf(str, sizeof(str), "%f", value); + snprintf(buf, sizeof(buf), "lavfi.aphasemeter.%s", key); + av_dict_set(&insamples->metadata, buf, str, 0); +} + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; @@ -154,6 +193,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out; uint8_t *dst; int i; + float tolerance = 1.0 - s->tolerance; + float angle = cos(s->angle/180.0*pi); if (s->do_video && (!s->out || s->out->width != outlink->w || s->out->height != outlink->h)) { @@ -193,7 +234,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) fphase += phase; } fphase /= in->nb_samples; - + s->phase = fphase; if (s->do_video) { if (s->draw_median_phase) { dst = out->data[0] + get_x(fphase, s->w) * 4; @@ -206,10 +247,54 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) metadata = &in->metadata; if (metadata) { - uint8_t value[128]; + set_meta(in, "phase", fphase); + } + + if (s->do_phasing_detection) { + if ((s->is_mono == false) && ((tolerance - fphase) < FLT_EPSILON)) { + s->is_mono = true; + s->start_presence = true; + s->mono_idx[0] = get_index(inlink, in); + } + if ((s->is_mono == true) && ((tolerance - fphase) < FLT_EPSILON) && (s->start_presence == true)) { + float mono_duration; + s->mono_idx[1] = get_index(inlink, in); + mono_duration = get_duration(s->mono_idx); + if (mono_duration >= s->duration) { + set_meta(in, "mono_start", s->mono_idx[0]); + av_log(s, AV_LOG_INFO, "mono_start: %f\n", s->mono_idx[0]); + s->start_presence = false; + } + } + if ((s->is_mono == true) && ((tolerance - fphase) > FLT_EPSILON)) { + float mono_duration; + s->mono_idx[1] = get_index(inlink, in); + mono_duration = get_duration(s->mono_idx); + if (mono_duration > s->duration) { + set_meta(in, "mono_end", s->mono_idx[1]); + set_meta(in, "mono_duration", mono_duration); + av_log(s, AV_LOG_INFO, "mono_end: %f | mono_duration: %f\n", s->mono_idx[1], mono_duration); + } + s->is_mono = false; + } - snprintf(value, sizeof(value), "%f", fphase); - av_dict_set(metadata, "lavfi.aphasemeter.phase", value, 0); + if ((s->is_out_phase == false) && (fphase <= angle)) { + s->out_idx[0] = get_index(inlink, in); + s->is_out_phase = true; + } + if ((s->is_out_phase == true) && (fphase > angle)) { + float out_phase_duration; + s->out_idx[1] = get_index(inlink, in); + out_phase_duration = get_duration(s->out_idx); + + set_meta(in, "out_phase_start", s->out_idx[0]); + av_log(s, AV_LOG_INFO, "out_phase_start: %f\n", s->out_idx[0]); + set_meta(in, "out_phase_end", s->out_idx[1]); + set_meta(in, "out_phase_duration", out_phase_duration); + av_log(s, AV_LOG_INFO, "out_phase_end: %f | out_phase_duration: %f\n", s->out_idx[1], out_phase_duration); + + s->is_out_phase = false; + } } if (s->do_video) { @@ -224,6 +309,21 @@ static av_cold void uninit(AVFilterContext *ctx) AudioPhaseMeterContext *s = ctx->priv; int i; + if (s->do_phasing_detection) { + float tolerance = 1.0 - s->tolerance; + float mono_duration; + AVFilterLink *inlink = ctx->inputs[0]; + + if ((s->is_mono == true) && (fabs(tolerance - s->phase) < FLT_EPSILON)) { + char *index_str = av_ts2timestr(inlink->current_pts, &inlink->time_base); + s->mono_idx[1] = atof(index_str); + mono_duration = get_duration(s->mono_idx); + if (mono_duration > s->duration) { + av_log(s, AV_LOG_INFO, "mono_end: %f | mono_duration: %f\n", s->mono_idx[1], mono_duration); + } + s->is_mono = false; + } + } av_frame_free(&s->out); for (i = 0; i < ctx->nb_outputs; i++) av_freep(&ctx->output_pads[i].name); -- 2.11.0
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".