Comparing PSNR of two videos, possibly with ffmpeg?

31,718

Solution 1

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

Solution 2

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.

Solution 3

.\..\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.

Solution 4

ffmpeg has a psnr filter:

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

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

Solution 5

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();
}
Share:
31,718
UnixNerd
Author by

UnixNerd

Java and C++ developer who loves cats, old BMWs and bicycles.

Updated on September 25, 2020

Comments

  • UnixNerd
    UnixNerd almost 4 years

    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 :-)