From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 19F6140B28 for ; Tue, 4 Apr 2023 23:12:23 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C584968B60B; Wed, 5 Apr 2023 02:12:20 +0300 (EEST) Received: from mail-ed1-f44.google.com (mail-ed1-f44.google.com [209.85.208.44]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6031468A829 for ; Wed, 5 Apr 2023 02:12:14 +0300 (EEST) Received: by mail-ed1-f44.google.com with SMTP id w9so136721257edc.3 for ; Tue, 04 Apr 2023 16:12:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680649933; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=RO0TelkN3lYvFQhia5a+8DlryQaCUgw76mtLQT5R6xc=; b=DQmg0huEH44Syr+cyqXvKu+mT7olhnqxOxeIGkqc3lrot2nRDrqQ06ZuTacBQkgGFv hQEMW1EYfcoc1CWMYUkxPez5Jm8lzo/VEPsQ0fralDJGnnMC5qZpoF8NXVaNPNsnV5sK rBfmvEekikzG253zmP5AQUGwhd36uB/iipsY4QAJaNjYFc6OH1BZnis+OE05kDOwTNeX 5acrvDPc0qleBxCJs3/k93qTLji+YzK6EUc/Q3kONlLDe7WhQspfDbW4h65IVUail1+D DpjzDN6YlEy5U1W75/5ACYbicwd8uAJxXiroYTNuNddmz+ANk2bvihVcvaw5eGBxV8ix fOpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680649933; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=RO0TelkN3lYvFQhia5a+8DlryQaCUgw76mtLQT5R6xc=; b=AS7iKANooJ5+k7qZUH5p4PIYg/ENf/oT0b+KyNhQIDVqanP798Vv84ztfsU8KN+r3L Hv/cjT6/I8YqNIRmchcdV9xhkc5xzV0y1oYATPHlLT2RjsqfEwsTHEuTlJpNjps638Cn j3d2XH2+8a6d0z9ko3SyZKB5UB+zYpwvKZObwp0W2BZsgepkRubuBSCD/WbuqmUfytm/ eAdGgN18R820Kx+SqBrM7/Q9m5rwPsVXmrtYOi6oRkMUgktwJ3JX6uWY7/i9kRSmEgvc asmL+SspJX+DJQWAmK/FDhW94D4KanI+8FO3mYI1XrvIK77IB9J9lMYQEg+gN+iIbb+y TdqQ== X-Gm-Message-State: AAQBX9fszoA4bnx+cVXplTCPvJOXwlE3wCAg3ZQedHb3eEzFOGepz/oA +MCAhNYdD2A/5oOvZClrOJVTMI1YoWqqqg== X-Google-Smtp-Source: AKy350YydQNmv5zya+jvhFvwJpn3KzClhADL+s/xQtkqJdwtx70J3WbPBeTVcjitcxVUOuH+I41aDg== X-Received: by 2002:a17:906:6894:b0:944:18ef:c970 with SMTP id n20-20020a170906689400b0094418efc970mr1200105ejr.32.1680649932595; Tue, 04 Apr 2023 16:12:12 -0700 (PDT) Received: from mariano (dynamic-adsl-62-10-98-143.clienti.tiscali.it. [62.10.98.143]) by smtp.gmail.com with ESMTPSA id qo26-20020a170907213a00b00930aa50372csm6486106ejb.43.2023.04.04.16.12.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Apr 2023 16:12:12 -0700 (PDT) Received: by mariano (Postfix, from userid 1000) id A0C12BFB73; Wed, 5 Apr 2023 01:12:10 +0200 (CEST) From: Stefano Sabatini To: FFmpeg development discussions and patches Date: Wed, 5 Apr 2023 01:12:10 +0200 Message-Id: <20230404231210.70359-1-stefasab@gmail.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] tools/normalize: port to python3, extend syntax X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Stefano Sabatini Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: Also add documentation and logging. --- tools/normalize.py | 106 +++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/tools/normalize.py b/tools/normalize.py index 7d87c5e154..e87f738c5f 100755 --- a/tools/normalize.py +++ b/tools/normalize.py @@ -1,33 +1,73 @@ -#!/usr/bin/env python2 - -import sys, subprocess - -if len(sys.argv) > 2: - ifile = sys.argv[1] - encopt = sys.argv[2:-1] - ofile = sys.argv[-1] -else: - print 'usage: %s [encode_options] ' % sys.argv[0] - sys.exit(1) - -analysis_cmd = 'ffprobe -v error -of compact=p=0:nk=1 ' -analysis_cmd += '-show_entries frame_tags=lavfi.r128.I -f lavfi ' -analysis_cmd += "amovie='%s',ebur128=metadata=1" % ifile -try: - probe_out = subprocess.check_output(analysis_cmd, shell=True) -except subprocess.CalledProcessError, e: - sys.exit(e.returncode) -loudness = ref = -23 -for line in probe_out.splitlines(): - sline = line.rstrip() - if sline: - loudness = sline -adjust = ref - float(loudness) -if abs(adjust) < 0.0001: - print 'No normalization needed for ' + ifile -else: - print "Adjust %s by %.1fdB" % (ifile, adjust) - norm_cmd = ['ffmpeg', '-i', ifile, '-af', 'volume=%fdB' % adjust] - norm_cmd += encopt + [ofile] - print ' => %s' % ' '.join(norm_cmd) - subprocess.call(norm_cmd) +#!/usr/bin/env python3 + +import argparse +import logging +import shlex +import subprocess + +HELP = ''' +Normalize audio input. + +The command uses ffprobe to analyze an input file with the ebur128 +filter, and finally run ffmpeg to normalize the input depending on the +computed adjustment. + +ffmpeg encoding arguments can be passed through the extra arguments +after options, for example as in: +normalize.py --input input.mp3 --output output.mp3 -- -loglevel debug -y +''' + +logging.basicConfig(format='normalize|%(levelname)s> %(message)s', level=logging.INFO) +log = logging.getLogger() + + +class Formatter( + argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter +): + pass + + +def normalize(): + parser = argparse.ArgumentParser(description=HELP, formatter_class=Formatter) + parser.add_argument('--input', '-i', required=True, help='specify input file') + parser.add_argument('--output', '-o', required=True, help='specify output file') + parser.add_argument('--dry-run', '-n', help='simulate commands', action='store_true') + parser.add_argument('encode_arguments', nargs='*', help='specify encode options used for the actual encoding') + + args = parser.parse_args() + + analysis_cmd = [ + 'ffprobe', '-v', 'error', '-of', 'compact=p=0:nk=1', + '-show_entries', 'frame_tags=lavfi.r128.I', '-f', 'lavfi', + f"amovie='{args.input}',ebur128=metadata=1" + ] + + def _run_command(cmd, dry_run=False): + log.info(f"Running command:\n$ {shlex.join(cmd)}") + if not dry_run: + result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE) + return result + + result = _run_command(analysis_cmd) + + loudness = ref = -23 + for line in result.stdout.splitlines(): + sline = line.rstrip() + if sline: + loudness = sline + + adjust = ref - float(loudness) + if abs(adjust) < 0.0001: + logging.info(f"No normalization needed for '{args.input}'") + return + + logging.info(f"Adjusting '{args.input}' by {adjust:.2f}dB...") + normalize_cmd = [ + 'ffmpeg', '-i', args.input, '-af', f'volume={adjust:.2f}dB', + ] + args.encode_arguments + [args.output] + + _run_command(normalize_cmd, args.dry_run) + + +if __name__ == '__main__': + normalize() -- 2.25.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".