A quick PSNR/SSIM analyzer for Linux
by Emanuele Oriani

qpsnr stands for Quick PSNR (PSNR definition and SSIM definition).

Update 18 Jul 2020
The main sources of this project have been moved to github; this page won't be updated any longer.

Update 11 Feb 2015
Recompiled main 64 bit package with Ubuntu 14.04, now using libavformat54.

Update 16 Nov 2013
Released version 0.2.5, use now the following libraries: libavformat53, libswscale2. Fixed some bugs, introduced more options (thanks Paul Caron for helping with porting)

Update 27 Feb 2010
Fixed one bug related to image saving; version updated to 0.2.1.

Update 21 Feb 2010
Apparently Ubuntu people won't release updated libav* libraries until 10.10. This is a bit sad. Nevertheless, I've released them as well latest binaries. Just scroll below at known issues.

Update 20 Feb 2010
Finally got confirmed that libav*.so.* in Ubuntu 9.10 (and apparently even 10.04) are broken (ie. don't support finalized Theora format).

Update 18 Feb 2010
As seen as PSNR is good but another objective measure does exist, I've added to this tool even the ability to compute SSIM (invoke with -a ssim or -a avg_ssim to compute it)

About it
I wanted to compute PSNR of some movies, to perform test analysis on codecs; unluckily on Linux I could not find any native tool (eg. tools usable without emulation/wine). One way to compute PSNR is to use mplayer, extract all the frames you're interested into a temporary directory, then invoke some other processes to perform it and finally write it on a file.
This approach has many issues. The most important are that is slow, it requires a lot of disk space and involves fiddling around. This is not good. Another issue is that usually PSNR is computed between two sources, a reference and a derivative of the reference (usually the derivative is lossy compressed). Problem is that I would like to perform the PSNR of a reference video vs. multiple derivatives (like the derivatives compressed with same codec but different bitrate/settings) and the mplayer script approach doesn't really make it.

Then I decided to write (in C++ naturally) my own tool, relying on libavcodec to get the frames of video streams; once I wrote the base classes to handle video frames, I then moved on the next big thing to do: make it extremely quick!
Luckily I reused previously written threading (threads and thread pools) and synchronization (semaphores) classes.
As seen as those had been already tested it has been very straightforward to implement few bits and put the togheter.

In order to achieve quick performance and resposiveness I've developed the following architecture:

QPSNR diagram
Here a brief explanation:
  • A thread to read frames from Video Reference is created
  • Multiple threads to read frames from all the Video derivatives (Video 1, Video 2, ... Video n) are created
  • Analyzer threads (to compute the PSNR os SSIM) are created
Then what happens is the following:
  1. Video threads (green boxes) extract a frame
  2. Buffers containing the just extracted video frames are handed over to the analyzer threads
  3. While analyzer threads do process the buffers, Video threads execute step 1.
  4. When analyzer threads are done, go to step 2.
This way we don't use any tmpfile and we try to use each available core.

Other cool features are that you can get an average of the PSNR (for example each 25 frames) and you can compute the PSNR of other colorspaces, not only RGB.
To see all options just run it with -h (or --help) option.

  • Multi threaded (tries to use all available cores/CPUs)
  • Relies on libavcodec to decode video (dynamic library) so unless something there is broken (see known issues) you're good to go
  • Low memory usage (no temporary files needed)
  • Easily extendible
  • Compute PSNR or SSIM (SSIM as now is only computed in Y colorspace)

./qpsnr -s 1000 -m 500 -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR from frame 1001 to 1500 between
reference_video.avi and video1.avi video2.avi video3.avi
./qpsnr -m 500 -a avg_psnr --aopts fpa=25:colorspace=hsi -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR in HSI colorspace for the first 500 frames, printing the average of each 25 frames
./qpsnr -I -s 2000 --aopts colorspace=ycbcr -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR in YCbCr colorspace skipping the first 2000 frames, saving each frame as ppm image (careful, this will use a lot of disk space!).
./qpsnr -s 100 -m 500 -a avg_ssim -o blocksize=16:fpa=30 -r reference_video.avi video1.avi video2.avi video3.avi
will compute the SSIM with block size 16x16 from frame 101 to 501, printing the average each 30 frames, between
reference_video.avi and video1.avi video2.avi video3.avi

Download it (v 0.2.5)!

Ubuntu 14.04 amd64 qpsnr x86-64
To compile the sources install libavcodec-dev, libavformat-dev and libswscale-dev.
QPSNR It is released under the Gpl V3.
If you have any issue with this process, please do report them to me.
Please report any bug/issue to me!
(old sources/packages)

Known issues
  • No issues as of now.
Past issues - no more applicable
  • The current version of libavcodec installed in Ubuntu 9.10 is not able to properly decode Theora video streams! Ubuntu bug has already been reaised (a forum thread here). To fix this one has to use a more recent (ie. working) version of these libraries. Apparently this won't be fixed in Ubuntu 9.10/10.04 as well, so I've compiled for both i386 and x86-64 the latest version of ffmpeg libraries (those fully support Theora video streams).
    I'd recommend not to install those in system directories (mplayer for example doesn't really like them), but simply decompress in the same directory where you will run your software and then do the following: export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH so when you'll execute qpsnr from there you'll load the right libraries. Please bear in mind that other apps could not work, but in this case, just close and reopen a terminal; with this method nothing will be compromised.
Notes on SSIM
While the PSNR is computed on the whole image for each color channel, the SSIM is computed only for Y (as in TCbCr colorspace), only on macroblocks of the specified size; if for example you specify 8x8 size, the SSIM between 2 frames will be computed on 8x8 tiled blocks of the image then an average of each block's SSIM will be taken as final value.
Another example, with 640x480 image size and 16x16 SSIM macroblock size, we'll have 40 (640/16) * 30 (480/16) = 1200 macroblocks: the reported SSIM will be the average of the single value of each SSIM.

In case you want to tell me anything feel free to contct me at ema at fastwebnet dot it .