7

I would like to compare a large number of videos to a good reference video in order to find videos with poor quality. I want to do this in a batch mode by calling a command line utility, I'm already using ffmpeg in this manner to grab video frames.

ffmpg will give me a PSNR value to compare the input and output videos if I transcode a video. I was under the impression I could use something like this to compare two separate videos but can't find a way to do it.

Would I be better grabbing a single frame from each video and comparing those somehow? PSNR may not be the best option for me?

I'm not looking for minor differences in quality but for major differences such a sync problems or large amounts of snow.

Any suggestions? Thanks in advance :-)

6 Answers 6

32

This is how you use the psnr filter in ffmpeg to compare two separate videos:

ffmpeg -i input_video.mp4 -i reference_video.mp4 -filter_complex "psnr" -f null /dev/null

On Windows replace /dev/null with NUL.

Documentation says that input_video will be passed unchanged to output_video, and the psnr value will be shown on the command line.

3
  • 7
    since you don't need the output that run's a lot faster if you send it to the null muxer: -f null -
    – tlum
    Commented Dec 31, 2016 at 8:43
  • @llogan @pewpew Just wondering if there maybe an issue that if the reference_video.mp4 and input_video.mp4 have different frames' number? like, reference_video.mp4 have 3477 frame and the input_video.mp4 have 3469 frames? Transcoder in mobile phone might drop some frames.
    – alwaysday1
    Commented Dec 16, 2020 at 11:47
  • 1
    @tli2020 The reference video could be VFR. The video created from re-encoding it with ffmpeg is CFR; created by dropping or duplicating frames to make constant frame rate.
    – llogan
    Commented Dec 16, 2020 at 18:20
10
.\..\ffmpeg -i [Input] -i [Output] -lavfi  psnr="stats_file=psnr.log" -f null -

I was looking at the ssim command (https://ffmpeg.org/ffmpeg-all.html#ssim) and decided to try it for the psnr command to see if I can get any useful results. It seems useful to me. The log file has an mse_avg value that I found was useful for detecting macroblocking in a video that I generated.

http://www.mathworks.com/help/vision/ref/psnr.html helped me to understand what mse and psnr means.

1
  • 2
    It works! A nice answer. By the way, there is a more accurate video quality metric 'VMAF' by Netflix, and it is open source!
    – shintaroid
    Commented May 28, 2017 at 4:27
6

ffmpeg has a psnr filter:

.. psnr             VV->V      Calculate the PSNR between two video streams.

see https://trac.ffmpeg.org/wiki/FilteringGuide for details

0
2

ffmpeg can compute PSNR & SSIM during the encoding but to compare 2 video I used AVISynth compare

2

Alternative command if you want to calculate the PSNR with FFmpeg

ffmpeg -i [Input1] -i [Input2] -lavfi psnr -f null -

ffmpeg -i [Input1] -i [Input2] -filter_complex psnr -f null -

Excepted output

ffmpeg version git-2019-11-22-27c6c92 Copyright (c) 2000-2019 the FFmpeg developers
...
[Parsed_psnr_0 @ 000001e47a2bee40] PSNR y:9.145728 u:22.375364 v:23.917491 average:10.819717 min:9.523630 max:14.456108

If you are using the JAVE2 library for java to process videos

function void calculatePSNR(String in1, String in2){
    FFMPEGExecutor ffmpeg = new DefaultFFMPEGLocator().createExecutor()
    ffmpeg.addArgument("-i");
    ffmpeg.addArgument(in1);
    ffmpeg.addArgument("-i");
    ffmpeg.addArgument(in2);
    ffmpeg.addArgument("-lavfi");
    ffmpeg.addArgument("psnr");
    ffmpeg.addArgument("-f");
    ffmpeg.addArgument("null");
    ffmpeg.addArgument("-");
    try {
       ffmpeg.execute();
    } catch (IOException e) {
       e.printStackTrace();
       ffmpeg.destroy();
    }
    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()));
        int lineNR = 0;

        String line;
        while((line = reader.readLine()) != null) {
            if (line.contains("PSNR")){
                System.out.println(line);    
            }
            lineNR++;
        }

    } catch (IOException e) {
        e.printStackTrace();
        ffmpeg.destroy();
    }
    ffmpeg.destroy();
}
1
  • 2
    When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: How do I write a good answer.
    – David Buck
    Commented Nov 27, 2019 at 2:14
1

I'm not sure how suitable it is, but I just did a trial by obtaining the psnr during transcoding of an input and output video, then using the psnr filter to compare the same input and output video. The psnr values differed in both cases though.

I got this for transcoding:

PSNR Mean Y:27.458 U:40.780 V:41.989 Avg:29.130 Global:28.996 kb/s:25.71

The documentation for the transcoder psnr just states: "Calculate PSNR of compressed frames."

and this for the filter:

PSNR average:24.30 min:23.09 max:30.50

For the filter, the documentation states: "The filter stores the accumulated MSE (mean squared error) of each frame, and at the end of the processing it is averaged across all frames equally, and the following formula is applied to obtain the PSNR:PSNR = 10*log10(MAX^2/MSE)"

I'll probably be choosing either the filter or transcoder to consistently calculate psnr across all the videos I need to compare though, so the absolute value won't matter to me.

Not the answer you're looking for? Browse other questions tagged or ask your own question.