ffmpeg loudnorm 2pass in single line

13,385

Solution 1

There's no way to run a two-pass loudnorm filter automatically with just ffmpeg, but you can use the ffmpeg-normalize program to do it for you. I know you've mentioned it, but if you want to encode video at the same time – particularly with two passes – then you will however have to work with one intermediate file, that is:

  • First run: ffmpeg-normalize on the original video, copying the original video stream.
  • Second run: x264-encoding (multithreaded) of the normalized audio file or the original file's video streams.

What you want to achieve simply cannot be done by ffmpeg alone. You need to program your own solution, especially if you want to handle several files in parallel. This would certainly speed up the process, even if a single ffmpeg run is only using one thread.

As a starting point, there's also a simpler Ruby script in the FFmpeg repository. It performs two loudnorm passes, reading the statistics of the first run. You may be able to modify it to additionaly run the two-pass x264 encoding with multithreading, that is, run the first x264 pass in the first run, the second in the second run:

First pass:

ffmpeg -y -i $FILE -c:v libx264 -b:v 4000k -pass 1 -filter:a loudnorm=print_format=json -f mkv /dev/null

Read the JSON statistics from the loudnorm output (e.g., using Python's JSON parser, or any other tool like grep or awk), then run the second pass:

ffmpeg -i $FILE -c:v libx264 -b:v 4000k -pass 2 -filter:a loudnorm=linear=true:measured_I=$input_i:measured_LRA=$input_lra:measured_tp=$input_tp:measured_thresh=$input_thresh -c:a aac -b:a 256k $FILE.mkv

Where $input_i, $input_lra, $input_tp, $input_thresh are the values read from the first pass.

Solution 2

There is no need for another program. This actually CAN be done with ffmpeg alone. I actually created a bat file that will do this.

cls
echo off
ffmpeg -i %1 -filter_complex "[0:a]loudnorm=I=-16:TP=-1.5:LRA=11:print_format=summary" -f null x 2>%1.txt
@for /f "tokens=3" %%a in ('findstr /C:"Input Integrated" %1.txt') do (set II=%%a)
echo %II% is the Input Integrated
@for /f "tokens=4" %%a in ('findstr /C:"Input True Peak" %1.txt') do (set ITP=%%a)
echo %ITP% is the Input True Peak
@for /f "tokens=3" %%a in ('findstr /C:"Input LRA" %1.txt') do (set ILRA=%%a)
echo %ILRA% is the Input LRA
@for /f "tokens=3" %%a in ('findstr /C:"Input Threshold" %1.txt') do (set IT=%%a)
echo %IT% is the Input Threshold
@for /f "tokens=3" %%a in ('findstr /C:"Output Integrated" %1.txt') do (set OI=%%a)
echo %OI% is the Output Integrated
@for /f "tokens=4" %%a in ('findstr /C:"Output True Peak" %1.txt') do (set OTP=%%a)
echo %OTP% is the Output True Peak
@for /f "tokens=3" %%a in ('findstr /C:"Output LRA" %1.txt') do (set OLRA=%%a)
echo %OLRA% is the Output LRA
@for /f "tokens=3" %%a in ('findstr /C:"Output Threshold" %1.txt') do (set OT=%%a)
echo %OT% is the Output Threshold
@for /f "tokens=3" %%a in ('findstr /C:"Target Offset" %1.txt') do (set TO=%%a)
echo %TO% is the Target Offset


ffmpeg -i %1 -af loudnorm=linear=true:I=-16:LRA=11:tp=-1.5:measured_I=%II%:measured_LRA=%ILRA%:measured_tp=%ITP%:measured_thresh=%IT%:offset=%TO%:print_format=summary loudnorm.wav

What this does is it first analyzes the audio and saves the results to a text file. It then reads the results from the text file and stores them as variables for each required measurement field. All you have to do it adjust the I= and TP= to your liking in the file.

Share:
13,385

Related videos on Youtube

user1654164
Author by

user1654164

Updated on September 18, 2022

Comments

  • user1654164
    user1654164 over 1 year

    TL;DR an example of loudnorm 2pass in single line using ffpmpeg (ffmpeg-normalize is single thread/process and I can't combine other ffmpeg options to it)

    Not really much examples on loudnorm since it's relatively new to ffmpeg, I've been using ffmpeg for 10 or so years. I am new to loudnorm however

    I've read:

    http://k.ylo.ph/2016/04/04/loudnorm.html

    How can I normalize audio using ffmpeg?

    which are helpful. however I'm trying to consolidate multiple ffmpeg entries into 1. using ffmpeg-normalize (the python) library limits you to a single thread/process as well. which is slow

    for 2 pass of ffmpeg x264 you can simply do:

    ffmpeg -y -i $FILE -c:v libx264 -b:v 4000k -pass 1 -c:a aac -b:a 256k -f mkv /dev/null && \
    ffmpeg -i $FILE -c:v libx264 -b:v 4000k -pass 2 -c:a aac -b:a 256k $FILE.mkv
    

    doesn't seem to exist for loudnorm though. I don't see a way to do it at all with a single and 2 pass?

    currently I'm encoding video,then normalizing audio, and finally stripping metadata and chapter data from files if it exists (regardless if it exists or not)

    this creates 3 throw-away files (including the original)

    being able to do loudnorm in a single line would help me add other stuff to it also is it possible to do a 2pass of x264 and a 2pass of loudnorm simultaneously? as in have it process the two and then combine them in the second pass.

    If possible I'd like examples of these and not links to things. I can google links on my own and have for several weeks. Thanks

  • NineCattoRules
    NineCattoRules about 2 years
    Sorry but how could you decode JSON from first pass using Python? I tried with json.loads(pass1) but it doesn't work.
  • slhck
    slhck about 2 years
    @NineCattoRules You have to first filter out all irrelevant output. ffmpeg will print a lot of other things, so you need to grep for the correct line from loudnorm.
  • NineCattoRules
    NineCattoRules about 2 years
    How could I grep only loudnorm part? Could you please help me here ?