diff mbox series

[FFmpeg-devel] apsnr and asisdr filter

Message ID CAPYw7P4ogr1M9yxqFBh7AK3XaWKjEZarfDuJHYqdXdAYZpGcfw@mail.gmail.com
State New
Headers show
Series [FFmpeg-devel] apsnr and asisdr filter | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Paul B Mahol Aug. 13, 2023, 3:14 a.m. UTC
Attached.

Comments

Paul B Mahol Aug. 13, 2023, 10:15 p.m. UTC | #1
Will apply soon.
Michael Niedermayer Aug. 14, 2023, 8:51 a.m. UTC | #2
On Sun, Aug 13, 2023 at 05:14:48AM +0200, Paul B Mahol wrote:
> Attached.

>  af_asdr.c |   44 ++++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> f0f248ba7e893a63a684b92a6d82ab246fc1995c  0003-avfilter-af_asdr-use-single-structure-for-sums.patch
> From ad9def7fad58a75450176413564543a16965d165 Mon Sep 17 00:00:00 2001
> From: Paul B Mahol <onemda@gmail.com>
> Date: Sun, 13 Aug 2023 05:03:00 +0200
> Subject: [PATCH 3/3] avfilter/af_asdr: use single structure for sums
> 
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  libavfilter/af_asdr.c | 44 +++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
[...]

>  doc/filters.texi         |    7 +++++
>  libavfilter/Makefile     |    1 
>  libavfilter/af_asdr.c    |   64 ++++++++++++++++++++++++++++++++++++++++++++++-
>  libavfilter/allfilters.c |    1 
>  4 files changed, 72 insertions(+), 1 deletion(-)
> 8ed085a8902fa86f0a99838bbd6c4b2645e187d6  0002-avfilter-add-asisdr-filter.patch
> From dfb20b0f4d08428a43b38185776baf6819fc4336 Mon Sep 17 00:00:00 2001
> From: Paul B Mahol <onemda@gmail.com>
> Date: Sun, 13 Aug 2023 04:19:08 +0200
> Subject: [PATCH 2/3] avfilter: add asisdr filter
> 
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  doc/filters.texi         |  7 +++++
>  libavfilter/Makefile     |  1 +
>  libavfilter/af_asdr.c    | 64 +++++++++++++++++++++++++++++++++++++++-
>  libavfilter/allfilters.c |  1 +
>  4 files changed, 72 insertions(+), 1 deletion(-)
[...]

>  doc/filters.texi         |    7 ++++
>  libavfilter/Makefile     |    1 
>  libavfilter/af_asdr.c    |   67 ++++++++++++++++++++++++++++++++++++++++++++---
>  libavfilter/allfilters.c |    1 
>  4 files changed, 73 insertions(+), 3 deletions(-)
> 85562ee579f2ffd79d14e0d2d3d7938865dcaae3  0001-avfilter-add-apsnr-filter.patch
> From 8b457c83855ccc292a53be2bd716bf445d37d7e0 Mon Sep 17 00:00:00 2001
> From: Paul B Mahol <onemda@gmail.com>
> Date: Sun, 13 Aug 2023 02:57:57 +0200
> Subject: [PATCH 1/3] avfilter: add apsnr filter

Missing tests, please add fate tests

Thank you
Michael Niedermayer Aug. 14, 2023, 8:56 a.m. UTC | #3
On Sun, Aug 13, 2023 at 05:14:48AM +0200, Paul B Mahol wrote:
> Attached.

>  af_asdr.c |   44 ++++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> f0f248ba7e893a63a684b92a6d82ab246fc1995c  0003-avfilter-af_asdr-use-single-structure-for-sums.patch
> From ad9def7fad58a75450176413564543a16965d165 Mon Sep 17 00:00:00 2001
> From: Paul B Mahol <onemda@gmail.com>
> Date: Sun, 13 Aug 2023 05:03:00 +0200
> Subject: [PATCH 3/3] avfilter/af_asdr: use single structure for sums
> 
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  libavfilter/af_asdr.c | 44 +++++++++++++++++++++++--------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> 
> diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c
> index 53069427bf..dbbb7e3419 100644
> --- a/libavfilter/af_asdr.c
> +++ b/libavfilter/af_asdr.c
> @@ -27,13 +27,18 @@
>  #include "filters.h"
>  #include "internal.h"
>  
> +typedef struct ChanStats {
> +    double u;
> +    double v;
> +    double uv;
> +} ChanStats;
> +
>  typedef struct AudioSDRContext {
>      int channels;
>      uint64_t nb_samples;
>      double max;
> -    double *sum_u;
> -    double *sum_v;
> -    double *sum_uv;
> +
> +    ChanStats *chs;
>  
>      AVFrame *cache[2];
>  
> @@ -52,6 +57,7 @@ static int sdr_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
>      const int nb_samples = u->nb_samples;                                     \
>                                                                                \
>      for (int ch = start; ch < end; ch++) {                                    \
> +        ChanStats *chs = &s->chs[ch];                                         \
>          const type *const us = (type *)u->extended_data[ch];                  \
>          const type *const vs = (type *)v->extended_data[ch];                  \
>          double sum_uv = 0.;                                                   \
> @@ -62,8 +68,8 @@ static int sdr_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
>              sum_uv += (us[n] - vs[n]) * (us[n] - vs[n]);                      \
>          }                                                                     \
>                                                                                \
> -        s->sum_uv[ch] += sum_uv;                                              \
> -        s->sum_u[ch]  += sum_u;                                               \
> +        chs->uv += sum_uv;                                                    \
> +        chs->u  += sum_u;                                                     \
>      }                                                                         \
>                                                                                \
>      return 0;                                                                 \
> @@ -84,6 +90,7 @@ static int sisdr_##name(AVFilterContext *ctx, void *arg,int jobnr,int nb_jobs)\
>      const int nb_samples = u->nb_samples;                                     \
>                                                                                \
>      for (int ch = start; ch < end; ch++) {                                    \
> +        ChanStats *chs = &s->chs[ch];                                         \
>          const type *const us = (type *)u->extended_data[ch];                  \
>          const type *const vs = (type *)v->extended_data[ch];                  \
>          double sum_uv = 0.;                                                   \
> @@ -96,9 +103,9 @@ static int sisdr_##name(AVFilterContext *ctx, void *arg,int jobnr,int nb_jobs)\
>              sum_uv += us[n] * vs[n];                                          \
>          }                                                                     \
>                                                                                \
> -        s->sum_uv[ch] += sum_uv;                                              \
> -        s->sum_u[ch]  += sum_u;                                               \
> -        s->sum_v[ch]  += sum_v;                                               \
> +        chs->uv += sum_uv;                                                    \
> +        chs->u  += sum_u;                                                     \
> +        chs->v  += sum_v;                                                     \
>      }                                                                         \
>                                                                                \
>      return 0;                                                                 \
> @@ -119,6 +126,7 @@ static int psnr_##name(AVFilterContext *ctx, void *arg, int jobnr,int nb_jobs)\
>      const int nb_samples = u->nb_samples;                                     \
>                                                                                \
>      for (int ch = start; ch < end; ch++) {                                    \
> +        ChanStats *chs = &s->chs[ch];                                         \
>          const type *const us = (type *)u->extended_data[ch];                  \
>          const type *const vs = (type *)v->extended_data[ch];                  \
>          double sum_uv = 0.;                                                   \
> @@ -126,7 +134,7 @@ static int psnr_##name(AVFilterContext *ctx, void *arg, int jobnr,int nb_jobs)\
>          for (int n = 0; n < nb_samples; n++)                                  \
>              sum_uv += (us[n] - vs[n]) * (us[n] - vs[n]);                      \
>                                                                                \
> -        s->sum_uv[ch] += sum_uv;                                              \
> +        chs->uv += sum_uv;                                                    \
>      }                                                                         \
>                                                                                \
>      return 0;                                                                 \
> @@ -204,10 +212,8 @@ static int config_output(AVFilterLink *outlink)
>          s->filter = inlink->format == AV_SAMPLE_FMT_FLTP ? psnr_fltp : psnr_dblp;
>      s->max = inlink->format == AV_SAMPLE_FMT_FLTP ? FLT_MAX : DBL_MAX;
>  
> -    s->sum_u  = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_u));
> -    s->sum_v  = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_v));
> -    s->sum_uv = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_uv));
> -    if (!s->sum_u || !s->sum_uv || !s->sum_v)
> +    s->chs  = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->chs));
> +    if (!s->chs)
>          return AVERROR(ENOMEM);
>  
>      return 0;
> @@ -219,17 +225,17 @@ static av_cold void uninit(AVFilterContext *ctx)
>  
>      if (!strcmp(ctx->filter->name, "asdr")) {
>          for (int ch = 0; ch < s->channels; ch++)
> -            av_log(ctx, AV_LOG_INFO, "SDR ch%d: %g dB\n", ch, 20. * log10(s->sum_u[ch] / s->sum_uv[ch]));
> +            av_log(ctx, AV_LOG_INFO, "SDR ch%d: %g dB\n", ch, 20. * log10(s->chs[ch].u / s->chs[ch].uv));
>      } else if (!strcmp(ctx->filter->name, "asisdr")) {
>          for (int ch = 0; ch < s->channels; ch++) {
> -            double scale = s->sum_uv[ch] / s->sum_v[ch];
> -            double sisdr = s->sum_u[ch] / (s->sum_u[ch] + scale*scale*s->sum_v[ch] - 2.0*scale*s->sum_uv[ch]);
> +            double scale = s->chs[ch].uv / s->chs[ch].v;
> +            double sisdr = s->chs[ch].u / fmax(0., s->chs[ch].u + scale*scale*s->chs[ch].v - 2.0*scale*s->chs[ch].uv);
>  
>              av_log(ctx, AV_LOG_INFO, "SI-SDR ch%d: %g dB\n", ch, 10. * log10(sisdr));
>          }
>      } else {
>          for (int ch = 0; ch < s->channels; ch++) {
> -            double psnr = s->sum_uv[ch] > 0.0 ? 2.0 * log(s->max) - log(s->nb_samples / s->sum_uv[ch]) : INFINITY;
> +            double psnr = s->chs[ch].uv > 0.0 ? 2.0 * log(s->max) - log(s->nb_samples / s->chs[ch].uv) : INFINITY;
>  
>              av_log(ctx, AV_LOG_INFO, "PSNR ch%d: %g dB\n", ch, psnr);
>          }
> @@ -238,9 +244,7 @@ static av_cold void uninit(AVFilterContext *ctx)
>      av_frame_free(&s->cache[0]);
>      av_frame_free(&s->cache[1]);
>  
> -    av_freep(&s->sum_u);
> -    av_freep(&s->sum_v);
> -    av_freep(&s->sum_uv);
> +    av_freep(&s->chs);
>  }
>  
>  static const AVFilterPad inputs[] = {
> -- 
> 2.39.1
> 

>  doc/filters.texi         |    7 +++++
>  libavfilter/Makefile     |    1 
>  libavfilter/af_asdr.c    |   64 ++++++++++++++++++++++++++++++++++++++++++++++-
>  libavfilter/allfilters.c |    1 
>  4 files changed, 72 insertions(+), 1 deletion(-)
> 8ed085a8902fa86f0a99838bbd6c4b2645e187d6  0002-avfilter-add-asisdr-filter.patch
> From dfb20b0f4d08428a43b38185776baf6819fc4336 Mon Sep 17 00:00:00 2001
> From: Paul B Mahol <onemda@gmail.com>
> Date: Sun, 13 Aug 2023 04:19:08 +0200
> Subject: [PATCH 2/3] avfilter: add asisdr filter
> 
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  doc/filters.texi         |  7 +++++
>  libavfilter/Makefile     |  1 +
>  libavfilter/af_asdr.c    | 64 +++++++++++++++++++++++++++++++++++++++-
>  libavfilter/allfilters.c |  1 +
>  4 files changed, 72 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 1025917c63..159764bcb6 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -3197,6 +3197,13 @@ audio, the data is treated as if all the planes were concatenated.
>  A list of Adler-32 checksums for each data plane.
>  @end table
>  
> +@section asisdr
> +Measure Audio Scaled-Invariant Signal-to-Distortion Ratio.
> +
> +This filter takes two audio streams for input, and outputs first
> +audio stream.
> +Results are in dB per channel at end of either input.
> +
>  @section asoftclip
>  Apply audio soft clipping.
>  
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 90c30e3388..ba07f4ab1e 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -103,6 +103,7 @@ OBJS-$(CONFIG_ASETRATE_FILTER)               += af_asetrate.o
>  OBJS-$(CONFIG_ASETTB_FILTER)                 += settb.o
>  OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o
>  OBJS-$(CONFIG_ASIDEDATA_FILTER)              += f_sidedata.o
> +OBJS-$(CONFIG_ASISDR_FILTER)                 += af_asdr.o
>  OBJS-$(CONFIG_ASOFTCLIP_FILTER)              += af_asoftclip.o
>  OBJS-$(CONFIG_ASPECTRALSTATS_FILTER)         += af_aspectralstats.o
>  OBJS-$(CONFIG_ASPLIT_FILTER)                 += split.o
> diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c
> index b0401804f6..53069427bf 100644
> --- a/libavfilter/af_asdr.c
> +++ b/libavfilter/af_asdr.c
> @@ -32,6 +32,7 @@ typedef struct AudioSDRContext {
>      uint64_t nb_samples;
>      double max;
>      double *sum_u;
> +    double *sum_v;
>      double *sum_uv;
>  
>      AVFrame *cache[2];
> @@ -71,6 +72,41 @@ static int sdr_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
>  SDR_FILTER(fltp, float)
>  SDR_FILTER(dblp, double)
>  
> +#define SISDR_FILTER(name, type)                                              \
> +static int sisdr_##name(AVFilterContext *ctx, void *arg,int jobnr,int nb_jobs)\
> +{                                                                             \
> +    AudioSDRContext *s = ctx->priv;                                           \
> +    AVFrame *u = s->cache[0];                                                 \
> +    AVFrame *v = s->cache[1];                                                 \
> +    const int channels = u->ch_layout.nb_channels;                            \
> +    const int start = (channels * jobnr) / nb_jobs;                           \
> +    const int end = (channels * (jobnr+1)) / nb_jobs;                         \
> +    const int nb_samples = u->nb_samples;                                     \
> +                                                                              \
> +    for (int ch = start; ch < end; ch++) {                                    \
> +        const type *const us = (type *)u->extended_data[ch];                  \
> +        const type *const vs = (type *)v->extended_data[ch];                  \
> +        double sum_uv = 0.;                                                   \
> +        double sum_u = 0.;                                                    \
> +        double sum_v = 0.;                                                    \
> +
\
> +        for (int n = 0; n < nb_samples; n++) {                                \
> +            sum_u  += us[n] * us[n];                                          \
> +            sum_v  += vs[n] * vs[n];                                          \
> +            sum_uv += us[n] * vs[n];                                          \
> +        }                                                                     \

These should be handled by DSP code which can be asm optimized

> +                                                                              \
> +        s->sum_uv[ch] += sum_uv;                                              \
> +        s->sum_u[ch]  += sum_u;                                               \
> +        s->sum_v[ch]  += sum_v;                                               \
> +    }                                                                         \
> +                                                                              \
> +    return 0;                                                                 \
> +}
> +
> +SISDR_FILTER(fltp, float)
> +SISDR_FILTER(dblp, double)
[...]
> @@ -67,6 +71,34 @@ static int sdr_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
>  SDR_FILTER(fltp, float)
>  SDR_FILTER(dblp, double)
>  
> +#define PSNR_FILTER(name, type)                                               \
> +static int psnr_##name(AVFilterContext *ctx, void *arg, int jobnr,int nb_jobs)\
> +{                                                                             \
> +    AudioSDRContext *s = ctx->priv;                                           \
> +    AVFrame *u = s->cache[0];                                                 \
> +    AVFrame *v = s->cache[1];                                                 \
> +    const int channels = u->ch_layout.nb_channels;                            \
> +    const int start = (channels * jobnr) / nb_jobs;                           \
> +    const int end = (channels * (jobnr+1)) / nb_jobs;                         \
> +    const int nb_samples = u->nb_samples;                                     \
> +                                                                              \
> +    for (int ch = start; ch < end; ch++) {                                    \
> +        const type *const us = (type *)u->extended_data[ch];                  \
> +        const type *const vs = (type *)v->extended_data[ch];                  \
> +        double sum_uv = 0.;                                                   \
> +                                                                              \
> +        for (int n = 0; n < nb_samples; n++)                                  \
> +            sum_uv += (us[n] - vs[n]) * (us[n] - vs[n]);                      \

These should be handled by DSP code which can be asm optimized


> +                                                                              \
> +        s->sum_uv[ch] += sum_uv;                                              \
> +    }                                                                         \
> +                                                                              \
> +    return 0;                                                                 \
> +}
> +
> +PSNR_FILTER(fltp, float)
> +PSNR_FILTER(dblp, double)
> +
>  static int activate(AVFilterContext *ctx)
>  {
>      AudioSDRContext *s = ctx->priv;

[...]

Thx
diff mbox series

Patch

From 8b457c83855ccc292a53be2bd716bf445d37d7e0 Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Sun, 13 Aug 2023 02:57:57 +0200
Subject: [PATCH 1/3] avfilter: add apsnr filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 doc/filters.texi         |  7 +++++
 libavfilter/Makefile     |  1 +
 libavfilter/af_asdr.c    | 67 ++++++++++++++++++++++++++++++++++++++--
 libavfilter/allfilters.c |  1 +
 4 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index e041adc40f..1025917c63 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2892,6 +2892,13 @@  Default value is 8.
 
 This filter supports the all above options as @ref{commands}.
 
+@section apsnr
+Measure Audio Peak Signal-to-Noise Ratio.
+
+This filter takes two audio streams for input, and outputs first
+audio stream.
+Results are in dB per channel at end of either input.
+
 @section apsyclip
 Apply Psychoacoustic clipper to input audio stream.
 
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index b26a85a7d2..90c30e3388 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -85,6 +85,7 @@  OBJS-$(CONFIG_APAD_FILTER)                   += af_apad.o
 OBJS-$(CONFIG_APERMS_FILTER)                 += f_perms.o
 OBJS-$(CONFIG_APHASER_FILTER)                += af_aphaser.o generate_wave_table.o
 OBJS-$(CONFIG_APHASESHIFT_FILTER)            += af_afreqshift.o
+OBJS-$(CONFIG_APSNR_FILTER)                  += af_asdr.o
 OBJS-$(CONFIG_APSYCLIP_FILTER)               += af_apsyclip.o
 OBJS-$(CONFIG_APULSATOR_FILTER)              += af_apulsator.o
 OBJS-$(CONFIG_AREALTIME_FILTER)              += f_realtime.o
diff --git a/libavfilter/af_asdr.c b/libavfilter/af_asdr.c
index 7d778b7f6b..b0401804f6 100644
--- a/libavfilter/af_asdr.c
+++ b/libavfilter/af_asdr.c
@@ -18,6 +18,8 @@ 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <float.h>
+
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 
@@ -27,6 +29,8 @@ 
 
 typedef struct AudioSDRContext {
     int channels;
+    uint64_t nb_samples;
+    double max;
     double *sum_u;
     double *sum_uv;
 
@@ -67,6 +71,34 @@  static int sdr_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
 SDR_FILTER(fltp, float)
 SDR_FILTER(dblp, double)
 
+#define PSNR_FILTER(name, type)                                               \
+static int psnr_##name(AVFilterContext *ctx, void *arg, int jobnr,int nb_jobs)\
+{                                                                             \
+    AudioSDRContext *s = ctx->priv;                                           \
+    AVFrame *u = s->cache[0];                                                 \
+    AVFrame *v = s->cache[1];                                                 \
+    const int channels = u->ch_layout.nb_channels;                            \
+    const int start = (channels * jobnr) / nb_jobs;                           \
+    const int end = (channels * (jobnr+1)) / nb_jobs;                         \
+    const int nb_samples = u->nb_samples;                                     \
+                                                                              \
+    for (int ch = start; ch < end; ch++) {                                    \
+        const type *const us = (type *)u->extended_data[ch];                  \
+        const type *const vs = (type *)v->extended_data[ch];                  \
+        double sum_uv = 0.;                                                   \
+                                                                              \
+        for (int n = 0; n < nb_samples; n++)                                  \
+            sum_uv += (us[n] - vs[n]) * (us[n] - vs[n]);                      \
+                                                                              \
+        s->sum_uv[ch] += sum_uv;                                              \
+    }                                                                         \
+                                                                              \
+    return 0;                                                                 \
+}
+
+PSNR_FILTER(fltp, float)
+PSNR_FILTER(dblp, double)
+
 static int activate(AVFilterContext *ctx)
 {
     AudioSDRContext *s = ctx->priv;
@@ -97,6 +129,7 @@  static int activate(AVFilterContext *ctx)
         out = s->cache[0];
         s->cache[0] = NULL;
 
+        s->nb_samples += available;
         return ff_filter_frame(outlink, out);
     }
 
@@ -126,7 +159,12 @@  static int config_output(AVFilterLink *outlink)
     AudioSDRContext *s = ctx->priv;
 
     s->channels = inlink->ch_layout.nb_channels;
-    s->filter = inlink->format == AV_SAMPLE_FMT_FLTP ? sdr_fltp : sdr_dblp;
+
+    if (!strcmp(ctx->filter->name, "asdr"))
+        s->filter = inlink->format == AV_SAMPLE_FMT_FLTP ? sdr_fltp : sdr_dblp;
+    else
+        s->filter = inlink->format == AV_SAMPLE_FMT_FLTP ? psnr_fltp : psnr_dblp;
+    s->max = inlink->format == AV_SAMPLE_FMT_FLTP ? FLT_MAX : DBL_MAX;
 
     s->sum_u  = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_u));
     s->sum_uv = av_calloc(outlink->ch_layout.nb_channels, sizeof(*s->sum_uv));
@@ -140,8 +178,16 @@  static av_cold void uninit(AVFilterContext *ctx)
 {
     AudioSDRContext *s = ctx->priv;
 
-    for (int ch = 0; ch < s->channels; ch++)
-        av_log(ctx, AV_LOG_INFO, "SDR ch%d: %g dB\n", ch, 20. * log10(s->sum_u[ch] / s->sum_uv[ch]));
+    if (!strcmp(ctx->filter->name, "asdr")) {
+        for (int ch = 0; ch < s->channels; ch++)
+            av_log(ctx, AV_LOG_INFO, "SDR ch%d: %g dB\n", ch, 20. * log10(s->sum_u[ch] / s->sum_uv[ch]));
+    } else {
+        for (int ch = 0; ch < s->channels; ch++) {
+            double psnr = s->sum_uv[ch] > 0.0 ? 2.0 * log(s->max) - log(s->nb_samples / s->sum_uv[ch]) : INFINITY;
+
+            av_log(ctx, AV_LOG_INFO, "PSNR ch%d: %g dB\n", ch, psnr);
+        }
+    }
 
     av_frame_free(&s->cache[0]);
     av_frame_free(&s->cache[1]);
@@ -183,3 +229,18 @@  const AVFilter ff_af_asdr = {
     FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP,
                       AV_SAMPLE_FMT_DBLP),
 };
+
+const AVFilter ff_af_apsnr = {
+    .name           = "apsnr",
+    .description    = NULL_IF_CONFIG_SMALL("Measure Audio Peak Signal-to-Noise Ratio."),
+    .priv_size      = sizeof(AudioSDRContext),
+    .activate       = activate,
+    .uninit         = uninit,
+    .flags          = AVFILTER_FLAG_METADATA_ONLY |
+                      AVFILTER_FLAG_SLICE_THREADS |
+                      AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
+    FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP,
+                      AV_SAMPLE_FMT_DBLP),
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 286e601799..949c5d4992 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -71,6 +71,7 @@  extern const AVFilter ff_af_apad;
 extern const AVFilter ff_af_aperms;
 extern const AVFilter ff_af_aphaser;
 extern const AVFilter ff_af_aphaseshift;
+extern const AVFilter ff_af_apsnr;
 extern const AVFilter ff_af_apsyclip;
 extern const AVFilter ff_af_apulsator;
 extern const AVFilter ff_af_arealtime;
-- 
2.39.1