ffmpeg loudnorm 2pass in single line
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.
Related videos on Youtube
user1654164
Updated on September 18, 2022Comments
-
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 about 2 yearsSorry but how could you decode JSON from first pass using Python? I tried with
json.loads(pass1)
but it doesn't work. -
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 about 2 yearsHow could I grep only loudnorm part? Could you please help me here ?