- Added PSNR feature to libavcodec and ffmpeg. By now just Y PSNR until I'm
authorJuanjo <pulento@users.sourceforge.net>
Tue, 26 Feb 2002 22:14:27 +0000 (22:14 +0000)
committerJuanjo <pulento@users.sourceforge.net>
Tue, 26 Feb 2002 22:14:27 +0000 (22:14 +0000)
sure it works ok. Also it's slow, so use it only when you _really_ need to
measure quality.
- Fix libavcodec Makefile to enable profiling.

Originally committed as revision 314 to svn://svn.ffmpeg.org/ffmpeg/trunk

ffmpeg.c
libavcodec/Makefile
libavcodec/avcodec.h
libavcodec/dsputil.c
libavcodec/dsputil.h
libavcodec/i386/mpegvideo_mmx.c
libavcodec/mpegvideo.c

index 80b1127..5d5431c 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -98,6 +98,7 @@ static char *str_comment = NULL;
 static int do_benchmark = 0;
 static int do_hex_dump = 0;
 static int do_play = 0;
+static int do_psnr = 0;
 
 typedef struct AVOutputStream {
     int file_index;          /* file index */
@@ -958,6 +959,8 @@ static int av_encode(AVFormatContext **output_files,
                         frame_number = ist->frame_number;
                         sprintf(buf + strlen(buf), "frame=%5d q=%2d ",
                                 frame_number, enc->quality);
+                        if (do_psnr)
+                            sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y);
                         vid = 1;
                     }
                     /* compute min pts value */
@@ -1006,6 +1009,8 @@ static int av_encode(AVFormatContext **output_files,
                 frame_number = ist->frame_number;
                 sprintf(buf + strlen(buf), "frame=%5d q=%2d ",
                         frame_number, enc->quality);
+                if (do_psnr)
+                    sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y);
                 vid = 1;
             }
             /* compute min pts value */
@@ -1618,6 +1623,10 @@ void opt_output_file(const char *filename)
                 video_enc->flags |= CODEC_FLAG_QSCALE;
                 video_enc->quality = video_qscale;
             }
+            if (do_psnr)
+                video_enc->get_psnr = 1;
+            else
+                video_enc->get_psnr = 0;
             /* XXX: need to find a way to set codec parameters */
             if (oc->format == &ppm_format ||
                 oc->format == &ppmpipe_format) {
@@ -1960,6 +1969,7 @@ const OptionDef options[] = {
       "add timings for benchmarking" },
     { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, 
       "dump each input packet" },
+    { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, 
 
     { NULL, },
 };
index 4898e86..fe124a4 100644 (file)
@@ -16,6 +16,11 @@ OBJS+= ac3dec.o \
        libac3/imdct.o  libac3/parse.o
 endif
 
+ifeq ($(TARGET_GPROF),yes)
+CFLAGS+=-p
+LDFLAGS+=-p
+endif
+
 # i386 mmx specific stuff
 ifeq ($(TARGET_MMX),yes)
 OBJS += i386/fdct_mmx.o i386/cputest.o \
index cc374c1..d8abfde 100644 (file)
@@ -123,6 +123,12 @@ typedef struct AVCodecContext {
     /* with a Start Code (it should) H.263 does   */
     void (*rtp_callback)(void *data, int size, int packet_number); 
 
+    /* These are for PSNR calculation, if you set get_psnr to 1 */
+    /* after encoding you will have the PSNR on psnr_y/cb/cr    */
+    int get_psnr;
+    float psnr_y;
+    float psnr_cb;
+    float psnr_cr;
                  
     /* the following fields are ignored */
     void *opaque;   /* can be used to carry app specific stuff */
index 701cb99..09c4c23 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <stdlib.h>
 #include <stdio.h>
+#include <math.h>
 #include "avcodec.h"
 #include "dsputil.h"
 #include "simple_idct.h"
@@ -576,3 +577,37 @@ void dsputil_init(void)
     
     build_zigzag_end();
 }
+
+void get_psnr(UINT8 *orig_image[3], UINT8 *coded_image[3],
+              int orig_linesize[3], int coded_linesize,
+              AVCodecContext *avctx)
+{
+    int quad, diff, x, y;
+    UINT8 *orig, *coded;
+    UINT32 *sq = squareTbl + 256;
+    
+    quad = 0;
+    diff = 0;
+    
+    /* Luminance */
+    orig = orig_image[0];
+    coded = coded_image[0];
+    
+    for (y=0;y<avctx->height;y++) {
+        for (x=0;x<avctx->width;x++) {
+            diff = *(orig + x) - *(coded + x);
+            quad += sq[diff];
+        }
+        orig += orig_linesize[0];
+        coded += coded_linesize;
+    }
+   
+    avctx->psnr_y = (float) quad / (float) (avctx->width * avctx->height);
+    
+    if (avctx->psnr_y) {
+        avctx->psnr_y = (float) (255 * 255) / avctx->psnr_y;
+        avctx->psnr_y = 10 * (float) log10 (avctx->psnr_y); 
+    } else
+        avctx->psnr_y = 99.99;
+}
+
index bb57b09..ed264c8 100644 (file)
@@ -2,6 +2,7 @@
 #define DSPUTIL_H
 
 #include "common.h"
+#include "avcodec.h"
 
 /* dct code */
 typedef short DCTELEM;
@@ -138,4 +139,9 @@ void dsputil_init_alpha(void);
 
 #endif
 
+/* PSNR */
+void get_psnr(UINT8 *orig_image[3], UINT8 *coded_image[3],
+              int orig_linesize[3], int coded_linesize,
+              AVCodecContext *avctx);
+              
 #endif
index 017e3d4..f23bdd8 100644 (file)
@@ -96,14 +96,14 @@ static void dct_unquantize_h263_mmx(MpegEncContext *s,
                 block[0] = block[0] * s->c_dc_scale;
         }
         for(i=1; i<8; i++) {
-           level = block[i];
-               if (level) {
-                       if (level < 0) {
-                               level = level * qmul - qadd;
-                       } else {
-                               level = level * qmul + qadd;
-                       }
-                       block[i] = level;
+            level = block[i];
+            if (level) {
+               if (level < 0) {
+                    level = level * qmul - qadd;
+                } else {
+                    level = level * qmul + qadd;
+                }
+                block[i] = level;
             }
         }
         nCoeffs=64;
index 7c866b7..6c4e372 100644 (file)
@@ -522,6 +522,12 @@ int MPV_encode_picture(AVCodecContext *avctx,
     s->total_bits += (pbBufPtr(&s->pb) - s->pb.buf) * 8;
 
     avctx->quality = s->qscale;
+    if (avctx->get_psnr) {
+        /* At this point pict->data should have the original frame   */
+        /* an s->current_picture should have the coded/decoded frame */
+        get_psnr(pict->data, s->current_picture,
+                 pict->linesize, s->linesize, avctx);
+    }
     return pbBufPtr(&s->pb) - s->pb.buf;
 }