PR #22677 opened by anders-mjoll URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22677 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22677.patch
Add file option to write the loudness report to a file instead of outputting it to the logs. >From 1c89d2c7d6281eb46be41b611d31d80447c9799a Mon Sep 17 00:00:00 2001 From: Anders Rein <[email protected]> Date: Wed, 1 Apr 2026 10:47:33 +0200 Subject: [PATCH] lavfi/af_loudnorm: add file option Add file option to write the loudness report to a file instead of outputting it to the logs. --- doc/filters.texi | 6 ++++ libavfilter/af_loudnorm.c | 60 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 35d2165f47..dc4bfa3e89 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -5914,6 +5914,12 @@ Options are true or false. Default is false. @item print_format Set print format for stats. Options are summary, json, or none. Default value is none. + +@item file +If specified, report output is written to the named file. Instead of plain +filename any writable url can be specified. Filename ``-'' is a shorthand +for standard output. If @code{file} option is not set, output is written to +the log with AV_LOG_INFO loglevel. @end table @section lowpass diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index 432b9710a5..55de743061 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -20,8 +20,10 @@ /* http://k.ylo.ph/2016/04/04/loudnorm.html */ +#include "libavutil/log.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavformat/avio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" @@ -95,6 +97,9 @@ typedef struct LoudNormContext { FFEBUR128State *r128_in; FFEBUR128State *r128_out; + + char *file_str; + AVIOContext *report_avio_context; } LoudNormContext; #define OFFSET(x) offsetof(LoudNormContext, x) @@ -121,6 +126,7 @@ static const AVOption loudnorm_options[] = { { "none", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NONE}, 0, 0, FLAGS, .unit = "print_format" }, { "json", 0, 0, AV_OPT_TYPE_CONST, {.i64 = JSON}, 0, 0, FLAGS, .unit = "print_format" }, { "summary", 0, 0, AV_OPT_TYPE_CONST, {.i64 = SUMMARY}, 0, 0, FLAGS, .unit = "print_format" }, + { "file", "set file to print report to", OFFSET(file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, { NULL } }; @@ -800,6 +806,8 @@ static int config_input(AVFilterLink *inlink) static av_cold int init(AVFilterContext *ctx) { + int ret = 0; + LoudNormContext *s = ctx->priv; s->frame_type = FIRST_FRAME; @@ -816,14 +824,51 @@ static av_cold int init(AVFilterContext *ctx) } } + if (s->file_str != NULL) { + if (strcmp(s->file_str, "-") == 0) { + ret = avio_open(&s->report_avio_context, "pipe:1", AVIO_FLAG_WRITE); + } else { + ret = avio_open(&s->report_avio_context, s->file_str, AVIO_FLAG_WRITE); + } + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Could not open %s: %s\n", + s->file_str, av_err2str(ret)); + return ret; + } + } + return 0; } +static void write_report(AVFilterContext *ctx, const char *msg, ...) +{ + LoudNormContext *s = ctx->priv; + va_list argument_list; + int ret = 0; + + va_start(argument_list, msg); + if (msg) { + if (s->report_avio_context) { + ret = avio_vprintf(s->report_avio_context, msg, argument_list); + if (s->file_str) { + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to write loudness report to %s\n", s->file_str); + } else { + av_log(ctx, AV_LOG_INFO, "Wrote loudness report to %s\n", s->file_str); + } + } + } else { + av_vlog(ctx, AV_LOG_INFO, msg, argument_list); + } + } + va_end(argument_list); +} + static av_cold void uninit(AVFilterContext *ctx) { LoudNormContext *s = ctx->priv; double i_in, i_out, lra_in, lra_out, thresh_in, thresh_out, tp_in, tp_out; - int c; + int c, ret; if (!s->r128_in || !s->r128_out) goto end; @@ -853,7 +898,7 @@ static av_cold void uninit(AVFilterContext *ctx) break; case JSON: - av_log(ctx, AV_LOG_INFO, + write_report(ctx, "\n{\n" "\t\"input_i\" : \"%.2f\",\n" "\t\"input_tp\" : \"%.2f\",\n" @@ -880,7 +925,7 @@ static av_cold void uninit(AVFilterContext *ctx) break; case SUMMARY: - av_log(ctx, AV_LOG_INFO, + write_report(ctx, "\n" "Input Integrated: %+6.1f LUFS\n" "Input True Peak: %+6.1f dBTP\n" @@ -907,8 +952,15 @@ static av_cold void uninit(AVFilterContext *ctx) ); break; } - end: + if (s->report_avio_context != NULL) { + ret = avio_close(s->report_avio_context); + if (ret < 0) { + av_log(ctx, AV_LOG_WARNING, "Failed to close avio context for loudness report\n"); + } + s->report_avio_context = NULL; + } + if (s->r128_in) ff_ebur128_destroy(&s->r128_in); if (s->r128_out) -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
