[x264-devel] [PATCH] PSNR averages

Loren Merritt lorenm at u.washington.edu
Sun Aug 8 05:59:57 CEST 2004


x264 takes the arithmetic mean of frame-wise PSNRs to produce an
overall PSNR. This is meaningless. (Extreme case: what do you do with a
frame with no error? (infinite PSNR))
This patch corrects it to calculate PSNR from the mean squared error.

I also replace "PSNR/Size" (which is similarly meaningless) with
"MSE*Size". This quantity is probably closer to what someone wants to
measure when they think of "PSNR/Size". It also tends to be relatively
constant for a given video over a wide range of QPs.)

--Loren Merritt
-------------- next part --------------
Index: core/common.h
===================================================================
--- core/common.h	(revision 18)
+++ core/common.h	(working copy)
@@ -324,9 +324,9 @@
         /* per slice info */
         int   i_slice_count[5];
         int   i_slice_size[5];
-        float f_psnr_y[5];
-        float f_psnr_u[5];
-        float f_psnr_v[5];
+        float f_mse_y[5];
+        float f_mse_u[5];
+        float f_mse_v[5];
         int   i_mb_count[5][18];
     } stat;
 
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c	(revision 18)
+++ encoder/encoder.c	(working copy)
@@ -60,7 +60,7 @@
  ****************************************************************************/
 
 
-static float x264_psnr( uint8_t *pix1, int i_pix_stride, uint8_t *pix2, int i_pix2_stride, int i_width, int i_height )
+static float x264_mse( uint8_t *pix1, int i_pix_stride, uint8_t *pix2, int i_pix2_stride, int i_width, int i_height )
 {
     int64_t i_sqe = 0;
 
@@ -78,13 +78,14 @@
         }
     }
 
-    if( i_sqe == 0 )
-    {
-        return -1.0;
-    }
-    return (float)(10.0 * log( (double)65025.0 * (double)i_height * (double)i_width / (double)i_sqe ) / log( 10.0 ));
+    return (double)i_sqe / ((double)65025.0 * (double)i_height * (double)i_width);
 }
 
+static float x264_psnr( float mse )
+{
+    return (float)(-10.0 * log( mse ) / log( 10.0 ));
+}
+
 #if DEBUG_DUMP_FRAME
 static void x264_frame_dump( x264_t *h, x264_frame_t *fr, char *name )
 {
@@ -409,9 +410,9 @@
     h->stat.i_slice_size[SLICE_TYPE_P] = 0;
     h->stat.i_slice_size[SLICE_TYPE_B] = 0;
 
-    h->stat.f_psnr_y[SLICE_TYPE_I] = 0.0; h->stat.f_psnr_u[SLICE_TYPE_I] = 0.0; h->stat.f_psnr_v[SLICE_TYPE_I] = 0.0;
-    h->stat.f_psnr_y[SLICE_TYPE_P] = 0.0; h->stat.f_psnr_u[SLICE_TYPE_P] = 0.0; h->stat.f_psnr_v[SLICE_TYPE_P] = 0.0;
-    h->stat.f_psnr_y[SLICE_TYPE_B] = 0.0; h->stat.f_psnr_u[SLICE_TYPE_B] = 0.0; h->stat.f_psnr_v[SLICE_TYPE_B] = 0.0;
+    h->stat.f_mse_y[SLICE_TYPE_I] = 0.0; h->stat.f_mse_u[SLICE_TYPE_I] = 0.0; h->stat.f_mse_v[SLICE_TYPE_I] = 0.0;
+    h->stat.f_mse_y[SLICE_TYPE_P] = 0.0; h->stat.f_mse_u[SLICE_TYPE_P] = 0.0; h->stat.f_mse_v[SLICE_TYPE_P] = 0.0;
+    h->stat.f_mse_y[SLICE_TYPE_B] = 0.0; h->stat.f_mse_u[SLICE_TYPE_B] = 0.0; h->stat.f_mse_v[SLICE_TYPE_B] = 0.0;
 
     for( i = 0; i < 17; i++ )
     {
@@ -799,14 +800,14 @@
                              x264_nal_t **pp_nal, int *pi_nal,
                              x264_picture_t *pic )
 {
-    x264_frame_t   *frame_psnr = h->fdec; /* just to kept the current decoded frame for psnr calculation */
+    x264_frame_t   *frame_psnr = h->fdec; /* just to keep the current decoded frame for psnr calculation */
     int     i_nal_type;
     int     i_nal_ref_idc;
     int     i_slice_type;
 
     int i;
 
-    float psnr_y, psnr_u, psnr_v;
+    float mse_y, mse_u, mse_v;
 
     int   i_global_qp;
 
@@ -1123,16 +1124,16 @@
 
     /* ---------------------- Compute/Print statistics --------------------- */
     /* PSNR */
-    psnr_y = x264_psnr( frame_psnr->plane[0], frame_psnr->i_stride[0], h->fenc->plane[0], h->fenc->i_stride[0], h->param.i_width, h->param.i_height );
-    psnr_u = x264_psnr( frame_psnr->plane[1], frame_psnr->i_stride[1], h->fenc->plane[1], h->fenc->i_stride[1], h->param.i_width/2, h->param.i_height/2);
-    psnr_v = x264_psnr( frame_psnr->plane[2], frame_psnr->i_stride[2], h->fenc->plane[2], h->fenc->i_stride[2], h->param.i_width/2, h->param.i_height/2);
+    mse_y = x264_mse( frame_psnr->plane[0], frame_psnr->i_stride[0], h->fenc->plane[0], h->fenc->i_stride[0], h->param.i_width, h->param.i_height );
+    mse_u = x264_mse( frame_psnr->plane[1], frame_psnr->i_stride[1], h->fenc->plane[1], h->fenc->i_stride[1], h->param.i_width/2, h->param.i_height/2);
+    mse_v = x264_mse( frame_psnr->plane[2], frame_psnr->i_stride[2], h->fenc->plane[2], h->fenc->i_stride[2], h->param.i_width/2, h->param.i_height/2);
 
     /* Slice stat */
     h->stat.i_slice_count[i_slice_type]++;
     h->stat.i_slice_size[i_slice_type] += bs_pos( &h->out.bs) / 8;
-    h->stat.f_psnr_y[i_slice_type] += psnr_y;
-    h->stat.f_psnr_u[i_slice_type] += psnr_u;
-    h->stat.f_psnr_v[i_slice_type] += psnr_v;
+    h->stat.f_mse_y[i_slice_type] += mse_y;
+    h->stat.f_mse_u[i_slice_type] += mse_u;
+    h->stat.f_mse_v[i_slice_type] += mse_v;
 
     for( i = 0; i < 17; i++ )
     {
@@ -1151,7 +1152,7 @@
              i_mb_count[P_L0] + i_mb_count[P_8x8],
              i_mb_count[P_SKIP],
              h->out.nal[h->out.i_nal-1].i_payload,
-             psnr_y, psnr_u, psnr_v );
+             x264_psnr(mse_y), x264_psnr(mse_u), x264_psnr(mse_v) );
 #ifdef DEBUG_MB_TYPE
     for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
     {
@@ -1213,34 +1214,35 @@
     if( h->stat.i_slice_count[SLICE_TYPE_I] > 0 )
     {
         const int i_count = h->stat.i_slice_count[SLICE_TYPE_I];
-        fprintf( stderr, "x264: slice I:%-4d Avg size:%-5d PSNR Y:%2.2f U:%2.2f V:%2.2f PSNR-Y/Size:%2.2f\n",
+        fprintf( stderr, "x264: slice I:%-4d Avg size:%-5d PSNR Y:%5.2f U:%5.2f V:%5.2f MSE-Y*Size:%5.3f\n",
                  i_count,
                  h->stat.i_slice_size[SLICE_TYPE_I] / i_count,
-                 h->stat.f_psnr_y[SLICE_TYPE_I] / i_count,
-                 h->stat.f_psnr_u[SLICE_TYPE_I] / i_count,
-                 h->stat.f_psnr_v[SLICE_TYPE_I] / i_count,
-                 1000*h->stat.f_psnr_y[SLICE_TYPE_I] / h->stat.i_slice_size[SLICE_TYPE_I] );
+                 x264_psnr(h->stat.f_mse_y[SLICE_TYPE_I] / i_count),
+                 x264_psnr(h->stat.f_mse_u[SLICE_TYPE_I] / i_count),
+                 x264_psnr(h->stat.f_mse_v[SLICE_TYPE_I] / i_count),
+                 (h->stat.f_mse_y[SLICE_TYPE_I] / i_count) * h->stat.i_slice_size[SLICE_TYPE_I] / i_count );
     }
     if( h->stat.i_slice_count[SLICE_TYPE_P] > 0 )
     {
         const int i_count = h->stat.i_slice_count[SLICE_TYPE_P];
-        fprintf( stderr, "x264: slice P:%-4d Avg size:%-5d PSNR Y:%2.2f U:%2.2f V:%2.2f PSNR-Y/Size:%2.2f\n",
-                i_count,
-                h->stat.i_slice_size[SLICE_TYPE_P] / i_count,
-                h->stat.f_psnr_y[SLICE_TYPE_P] / i_count,
-                h->stat.f_psnr_u[SLICE_TYPE_P] / i_count,
-                h->stat.f_psnr_v[SLICE_TYPE_P] / i_count,
-                1000.0*h->stat.f_psnr_y[SLICE_TYPE_P] / h->stat.i_slice_size[SLICE_TYPE_P] );
+        fprintf( stderr, "x264: slice P:%-4d Avg size:%-5d PSNR Y:%5.2f U:%5.2f V:%5.2f MSE-Y*Size:%5.3f\n",
+                 i_count,
+                 h->stat.i_slice_size[SLICE_TYPE_P] / i_count,
+                 x264_psnr(h->stat.f_mse_y[SLICE_TYPE_P] / i_count),
+                 x264_psnr(h->stat.f_mse_u[SLICE_TYPE_P] / i_count),
+                 x264_psnr(h->stat.f_mse_v[SLICE_TYPE_P] / i_count),
+                 (h->stat.f_mse_y[SLICE_TYPE_P] / i_count) * h->stat.i_slice_size[SLICE_TYPE_P] / i_count );
     }
     if( h->stat.i_slice_count[SLICE_TYPE_B] > 0 )
     {
-        fprintf( stderr, "x264: slice B:%-4d Avg size:%-5d PSNR Y:%2.2f U:%2.2f V:%2.2f PSNR-Y/Size:%2.2f\n",
-                h->stat.i_slice_count[SLICE_TYPE_B],
-                h->stat.i_slice_size[SLICE_TYPE_B] / h->stat.i_slice_count[SLICE_TYPE_B],
-                h->stat.f_psnr_y[SLICE_TYPE_B] / h->stat.i_slice_count[SLICE_TYPE_B],
-                h->stat.f_psnr_u[SLICE_TYPE_B] / h->stat.i_slice_count[SLICE_TYPE_B],
-                h->stat.f_psnr_v[SLICE_TYPE_B] / h->stat.i_slice_count[SLICE_TYPE_B],
-                1000*h->stat.f_psnr_y[SLICE_TYPE_B] / h->stat.i_slice_size[SLICE_TYPE_B] );
+        const int i_count = h->stat.i_slice_count[SLICE_TYPE_B];
+        fprintf( stderr, "x264: slice B:%-4d Avg size:%-5d PSNR Y:%5.2f U:%5.2f V:%5.2f MSE-Y*Size:%5.3f\n",
+                 h->stat.i_slice_count[SLICE_TYPE_B],
+                 h->stat.i_slice_size[SLICE_TYPE_B] / i_count,
+                 x264_psnr(h->stat.f_mse_y[SLICE_TYPE_B] / i_count),
+                 x264_psnr(h->stat.f_mse_u[SLICE_TYPE_B] / i_count),
+                 x264_psnr(h->stat.f_mse_v[SLICE_TYPE_B] / i_count), 
+                 (h->stat.f_mse_y[SLICE_TYPE_B] / i_count) * h->stat.i_slice_size[SLICE_TYPE_B] / i_count );
     }
 
     /* MB types used */
@@ -1267,10 +1269,10 @@
                             h->stat.i_slice_count[SLICE_TYPE_P] +
                             h->stat.i_slice_count[SLICE_TYPE_B];
 
-        fprintf( stderr, "x264: overall PSNR Y:%2.2f U:%2.2f V:%2.2f kb/s:%.1f fps:%.3f\n",
-                 (h->stat.f_psnr_y[SLICE_TYPE_I]+h->stat.f_psnr_y[SLICE_TYPE_P]+h->stat.f_psnr_y[SLICE_TYPE_B]) / i_count,
-                 (h->stat.f_psnr_u[SLICE_TYPE_I]+h->stat.f_psnr_u[SLICE_TYPE_P]+h->stat.f_psnr_u[SLICE_TYPE_B]) / i_count,
-                 (h->stat.f_psnr_v[SLICE_TYPE_I]+h->stat.f_psnr_v[SLICE_TYPE_P]+h->stat.f_psnr_v[SLICE_TYPE_B]) / i_count,
+        fprintf( stderr, "x264: overall PSNR Y:%5.2f U:%5.2f V:%5.2f kb/s:%.1f fps:%.3f\n",
+                 x264_psnr( (h->stat.f_mse_y[SLICE_TYPE_I]+h->stat.f_mse_y[SLICE_TYPE_P]+h->stat.f_mse_y[SLICE_TYPE_B]) / i_count ),
+                 x264_psnr( (h->stat.f_mse_u[SLICE_TYPE_I]+h->stat.f_mse_u[SLICE_TYPE_P]+h->stat.f_mse_u[SLICE_TYPE_B]) / i_count ),
+                 x264_psnr( (h->stat.f_mse_v[SLICE_TYPE_I]+h->stat.f_mse_v[SLICE_TYPE_P]+h->stat.f_mse_v[SLICE_TYPE_B]) / i_count ),
                  h->param.f_fps * 8*(h->stat.i_slice_size[SLICE_TYPE_I]+h->stat.i_slice_size[SLICE_TYPE_P]+h->stat.i_slice_size[SLICE_TYPE_B]) / i_count / 1024,
                  (double)1000000.0 * (double)i_count / (double)i_mtime_encode_frame );
     }


More information about the x264-devel mailing list