]> git.sesse.net Git - mlt/commitdiff
add vqm transition
authorDan Dennedy <dan@dennedy.org>
Mon, 6 Feb 2012 18:55:32 +0000 (10:55 -0800)
committerDan Dennedy <dan@dennedy.org>
Thu, 9 Feb 2012 05:05:07 +0000 (21:05 -0800)
src/modules/qimage/Makefile
src/modules/qimage/factory.c
src/modules/qimage/transition_vqm.cpp [new file with mode: 0644]

index 7368dddb0888ab4147bdc6c17c9f995420aefd70..72e977f8e62f5ffd89a81913dfcbc719369ddf36 100644 (file)
@@ -8,7 +8,9 @@ include config.mak
 TARGET = ../libmltqimage$(LIBSUF)
 
 OBJS = factory.o producer_qimage.o producer_kdenlivetitle.o
-CPPOBJS = qimage_wrapper.o kdenlivetitle_wrapper.o
+CPPOBJS = qimage_wrapper.o \
+       kdenlivetitle_wrapper.o \
+       transition_vqm.o
 
 CXXFLAGS += $(CFLAGS) $(QTCXXFLAGS) $(EXIFCXXFLAGS) -Wno-deprecated
 
index cb4fae7413b413274d2a43b19d9b3292f2fe5262..1c1e6366cbe3a1c1458da4c20b14360917c4ae46 100644 (file)
@@ -24,6 +24,7 @@
 
 extern mlt_producer producer_qimage_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
 extern mlt_producer producer_kdenlivetitle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
+extern mlt_transition transition_vqm_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg );
 
 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
 {
@@ -36,6 +37,7 @@ MLT_REPOSITORY
 {
        MLT_REGISTER( producer_type, "qimage", producer_qimage_init );
        MLT_REGISTER( producer_type, "kdenlivetitle", producer_kdenlivetitle_init );
+       MLT_REGISTER( transition_type, "vqm", transition_vqm_init );
        MLT_REGISTER_METADATA( producer_type, "qimage", metadata, "producer_qimage.yml" );
        MLT_REGISTER_METADATA( producer_type, "kdenlivetitle", metadata, "producer_kdenlivetitle.yml" );
 }
diff --git a/src/modules/qimage/transition_vqm.cpp b/src/modules/qimage/transition_vqm.cpp
new file mode 100644 (file)
index 0000000..a75a60a
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * transition_vqm.c -- video quality measurement
+ * Copyright (c) 2012 Dan Dennedy <dan@dennedy.org>
+ * Core psnr and ssim routines based on code from
+ *   qsnr (C) 2010 E. Oriani, ema <AT> fastwebnet <DOT> it
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <framework/mlt.h>
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+static double calc_psnr( const uint8_t *a, const uint8_t *b, int size, int bpp )
+{
+       double mse = 0.0;
+       int n = size + 1;
+
+       while ( --n )
+       {
+               int diff = *a - *b;
+               mse += diff * diff;
+               a += bpp;
+               b += bpp;
+       }
+
+       return 10.0 * log10( 255.0 * 255.0 / ( mse == 0 ? 1e-10 : mse/size ) );
+}
+
+static double calc_ssim( const uint8_t *a, const uint8_t *b, int width, int height, int window_size, int bpp )
+{
+       int     windows_x = width / window_size;
+       int windows_y = height / window_size;
+       double  avg = 0.0;
+
+       if ( !windows_x || !windows_y )
+               return 0.0;
+
+       // for each window
+       for ( int y = 0; y < windows_y; ++y )
+               for ( int x = 0; x < windows_x; ++x )
+               {
+                       int     base_offset = x * window_size + y * window_size * width;
+                       double  ref_acc = 0.0,
+                                       ref_acc_2 = 0.0,
+                                       cmp_acc = 0.0,
+                                       cmp_acc_2 = 0.0,
+                                       ref_cmp_acc = 0.0;
+
+                       // accumulate the pixel values for this window
+                       for ( int j = 0; j < window_size; ++j )
+                               for ( int i = 0; i < window_size; ++i )
+                               {
+                                       uint8_t c_a = a[bpp * (base_offset + j * width + i)];
+                                       uint8_t c_b = b[bpp * (base_offset + j * width + i)];
+                                       ref_acc += c_a;
+                                       ref_acc_2 += c_a * c_a;
+                                       cmp_acc += c_b;
+                                       cmp_acc_2 += c_b * c_b;
+                                       ref_cmp_acc += c_a * c_b;
+                               }
+
+                       // compute the SSIM for this window
+                       // http://en.wikipedia.org/wiki/SSIM
+                       // http://en.wikipedia.org/wiki/Variance
+                       // http://en.wikipedia.org/wiki/Covariance
+                       double n_samples = window_size * window_size,
+                                       ref_avg = ref_acc / n_samples,
+                                       ref_var = ref_acc_2 / n_samples - ref_avg * ref_avg,
+                                       cmp_avg = cmp_acc / n_samples,
+                                       cmp_var = cmp_acc_2 / n_samples - cmp_avg * cmp_avg,
+                                       ref_cmp_cov = ref_cmp_acc / n_samples - ref_avg * cmp_avg,
+                                       c1 = 6.5025, // (0.01*255.0)^2
+                                       c2 = 58.5225, // (0.03*255)^2
+                                       ssim_num = (2.0 * ref_avg * cmp_avg + c1) * (2.0 * ref_cmp_cov + c2),
+                                       ssim_den = (ref_avg * ref_avg + cmp_avg * cmp_avg + c1) * (ref_var + cmp_var + c2);
+
+                       // accumulate the SSIM
+                       avg += ssim_num / ssim_den;
+               }
+
+       // return the average SSIM
+       return avg / windows_x / windows_y;
+}
+
+static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+{
+       mlt_frame b_frame = mlt_frame_pop_frame( a_frame );
+       mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) );
+       uint8_t *b_image;
+       int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" );
+       double psnr[3], ssim[3];
+
+       *format = mlt_image_yuv422;
+       mlt_frame_get_image( b_frame, &b_image, format, width, height, writable );
+       mlt_frame_get_image( a_frame, image, format, width, height, writable );
+
+       psnr[0] = calc_psnr( *image, b_image, *width * *height, 2 );
+       psnr[1] = calc_psnr( *image + 1, b_image + 1, *width * *height / 2, 4 );
+       psnr[2] = calc_psnr( *image + 3, b_image + 3, *width * *height / 2, 4 );
+       ssim[0] = calc_ssim( *image, b_image, *width, *height, window_size, 2 );
+       ssim[1] = calc_ssim( *image + 1, b_image + 1, *width / 2, *height, window_size, 4 );
+       ssim[2] = calc_ssim( *image + 3, b_image + 3, *width / 2, *height, window_size, 4 );
+       printf( "%05d %05.2f %05.2f %05.2f %5.3f %5.3f %5.3f\n",
+                       mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2],
+                       ssim[0], ssim[1], ssim[2] );
+
+       window_size = mlt_image_format_size( *format, *width, *height, NULL ) / 2;
+       memcpy( *image + window_size, b_image + window_size, window_size );
+
+       return 0;
+}
+
+static mlt_frame process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
+{
+       mlt_frame_push_service( a_frame, transition );
+       mlt_frame_push_frame( a_frame, b_frame );
+       mlt_frame_push_get_image( a_frame, get_image );
+
+       return a_frame;
+}
+
+extern "C" {
+
+mlt_transition transition_vqm_init( mlt_profile profile, mlt_service_type type, const char *id, void *arg )
+{
+       mlt_transition transition = mlt_transition_new();
+
+       if ( transition )
+       {
+               mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
+
+               transition->process = process;
+               mlt_properties_set_int( properties, "_transition_type", 1 ); // video only
+               mlt_properties_set_int( properties, "window_size", 8 );
+               printf( "frame psnr[Y] psnr[Cb] psnr[Cr] ssim[Y] ssim[Cb] ssim[Cr]\n" );
+       }
+
+       return transition;
+}
+
+} // extern "C"