]> git.sesse.net Git - mlt/commitdiff
Add support for more image formats to vid.stab
authorBrian Matherly <pez4brian@yahoo.com>
Sat, 18 Jan 2014 04:21:10 +0000 (22:21 -0600)
committerBrian Matherly <pez4brian@yahoo.com>
Sat, 18 Jan 2014 04:21:49 +0000 (22:21 -0600)
src/framework/mlt_frame.h
src/modules/core/filter_imageconvert.c
src/modules/vid.stab/Makefile
src/modules/vid.stab/common.c [new file with mode: 0644]
src/modules/vid.stab/common.h
src/modules/vid.stab/filter_deshake.cpp
src/modules/vid.stab/filter_vidstab.cpp

index ae45e7be2ba3ff38bdfe4ef649bca62ca67a4df3..9d0060236c5cb755c1d3f4a231bb56707599732c 100644 (file)
@@ -157,4 +157,13 @@ extern void mlt_frame_write_ppm( mlt_frame frame );
   u = ((-152*r - 300*g + 450*b) >> 10) + 128;\
   v = ((450*r - 377*g - 73*b) >> 10) + 128;
 
+/** This macro scales YUV up into the full gamut of the RGB color space. */
+#define YUV2RGB_601_SCALED( y, u, v, r, g, b ) \
+  r = ((1192 * ( y - 16 ) + 1634 * ( v - 128 ) ) >> 10 ); \
+  g = ((1192 * ( y - 16 ) - 832 * ( v - 128 ) - 401 * ( u - 128 ) ) >> 10 ); \
+  b = ((1192 * ( y - 16 ) + 2066 * ( u - 128 ) ) >> 10 ); \
+  r = r < 0 ? 0 : r > 255 ? 255 : r; \
+  g = g < 0 ? 0 : g > 255 ? 255 : g; \
+  b = b < 0 ? 0 : b > 255 ? 255 : b;
+
 #endif
index 33c938802ce8762a91d1d840e24c09982cdcf8b8..20b13288194504464d38c6da780dd9948c54d1ac 100644 (file)
   u = u > 240 ? 240 : u;\
   v = v > 240 ? 240 : v
 
-/** This macro scales YUV up into the full gamut of the RGB color space. */
-#define YUV2RGB_601_SCALED( y, u, v, r, g, b ) \
-  r = ((1192 * ( y - 16 ) + 1634 * ( v - 128 ) ) >> 10 ); \
-  g = ((1192 * ( y - 16 ) - 832 * ( v - 128 ) - 401 * ( u - 128 ) ) >> 10 ); \
-  b = ((1192 * ( y - 16 ) + 2066 * ( u - 128 ) ) >> 10 ); \
-  r = r < 0 ? 0 : r > 255 ? 255 : r; \
-  g = g < 0 ? 0 : g > 255 ? 255 : g; \
-  b = b < 0 ? 0 : b > 255 ? 255 : b;
-
 /** This macro converts a YUV value to the RGB color space. */
 #define YUV2RGB_601_UNSCALED( y, u, v, r, g, b ) \
   r = ((1024 * y + 1404 * ( v - 128 ) ) >> 10 ); \
index f9991b2319b5ca5ee45cb88ed169f2157f2ee7d5..7f829f84e5de5ff6c4dba937e8b982f2d5976e37 100644 (file)
@@ -6,7 +6,8 @@ include ../../../config.mak
 
 TARGET = ../libmltvidstab$(LIBSUF)
 
-OBJS = factory.o
+OBJS = factory.o \
+       common.o
 
 CPPOBJS = filter_deshake.o
 CPPOBJS += filter_vidstab.o
diff --git a/src/modules/vid.stab/common.c b/src/modules/vid.stab/common.c
new file mode 100644 (file)
index 0000000..13acc67
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * common.c
+ * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
+ *
+ * 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 2 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, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <framework/mlt.h>
+#include <vid.stab/libvidstab.h>
+#include "common.h"
+
+mlt_image_format validate_format( mlt_image_format format )
+{
+       switch( format )
+       {
+       case mlt_image_rgb24a:
+       case mlt_image_rgb24:
+               return mlt_image_rgb24;
+       case mlt_image_yuv420p:
+               return mlt_image_yuv420p;
+       default:
+       case mlt_image_none:
+       case mlt_image_yuv422:
+       case mlt_image_opengl:
+       case mlt_image_glsl:
+       case mlt_image_glsl_texture:
+               return mlt_image_yuv422;
+       }
+}
+
+VSPixelFormat mltimage_to_vsimage( mlt_image_format mlt_format, int width, int height, uint8_t* mlt_img, uint8_t** vs_img )
+{
+       switch( mlt_format )
+       {
+       case mlt_image_rgb24:
+               // Convert RGB24 to YUV444 because it is the only planar
+               // format with comparable bit depth.
+               {
+                       *vs_img = mlt_pool_alloc( width * height * 3 );
+                       int y, u, v, r, g, b;
+                       int total = width * height + 1;
+                       uint8_t* yp = *vs_img;
+                       uint8_t* up = yp + ( width * height );
+                       uint8_t* vp = up + ( width * height );
+
+                       while( --total )
+                       {
+                               r = *mlt_img++;
+                               g = *mlt_img++;
+                               b = *mlt_img++;
+                               RGB2YUV_601_SCALED(r, g, b, y, u, v);
+                               *yp++ = y;
+                               *up++ = u;
+                               *vp++ = v;
+                       }
+
+                       return PF_YUV444P;
+               }
+       case mlt_image_yuv420p:
+               // This format maps with no conversion
+               {
+                       *vs_img = mlt_img;
+                       return PF_YUV420P;
+               }
+       case mlt_image_yuv422:
+               // Convert packed to planar
+               {
+                       *vs_img = mlt_pool_alloc( width * height * 2 );
+                       uint8_t* yp = *vs_img;
+                       uint8_t* up = yp + ( width * height );
+                       uint8_t* vp = up + ( width * height / 2 );
+                       int total = ( width * height / 2 ) + 1;
+
+                       while( --total )
+                       {
+                               *yp++ = *mlt_img++;
+                               *up++ = *mlt_img++;
+                               *yp++ = *mlt_img++;
+                               *vp++ = *mlt_img++;
+                       }
+
+                       return PF_YUV422P;
+               }
+       default:
+               return PF_NONE;
+       }
+}
+
+void vsimage_to_mltimage( uint8_t* vs_img, uint8_t* mlt_img, mlt_image_format mlt_format, int width, int height )
+{
+       switch( mlt_format )
+       {
+       case mlt_image_rgb24:
+               // Convert YUV444 to RGB24.
+               {
+                       int y, u, v, r, g, b;
+                       int total = width * height + 1;
+                       uint8_t* yp = vs_img;
+                       uint8_t* up = yp + ( width * height );
+                       uint8_t* vp = up + ( width * height );
+
+                       while( --total )
+                       {
+                               y = *yp++;
+                               u = *up++;
+                               v = *vp++;
+                               YUV2RGB_601_SCALED( y, u, v, r, g, b );
+                               *mlt_img++ = r;
+                               *mlt_img++ = g;
+                               *mlt_img++ = b;
+                       }
+               }
+               break;
+       case mlt_image_yuv420p:
+               // This format was never converted
+               break;
+       case mlt_image_yuv422:
+               // Convert planar to packed
+               {
+                       uint8_t* yp = vs_img;
+                       uint8_t* up = yp + ( width * height );
+                       uint8_t* vp = up + ( width * height / 2 );
+                       int total = ( width * height / 2 ) + 1;
+
+                       while( --total )
+                       {
+                               *mlt_img++ = *yp++;
+                               *mlt_img++ = *up++;
+                               *mlt_img++ = *yp++;
+                               *mlt_img++ = *vp++;
+                       }
+               }
+               break;
+       default:
+               return PF_NONE;
+       }
+}
+
+void free_vsimage( uint8_t* vs_img, VSPixelFormat format )
+{
+       if( format != PF_YUV420P )
+       {
+               mlt_pool_release( vs_img );
+       }
+}
index c9a060bf6bd4707946c7c19c5b504a8547daa7c9..de081f437162fcd77b5690898bb2da3056d93fcb 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * common.h
  * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
+ * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
  *
  * 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
 #ifndef VIDSTAB_COMMON_H_
 #define VIDSTAB_COMMON_H_
 
-extern "C" {
 #include <vid.stab/libvidstab.h>
 #include <framework/mlt.h>
-}
 
-inline VSPixelFormat convertImageFormat(mlt_image_format &format) {
-       switch (format) {
-       case mlt_image_rgb24:
-               return PF_RGB24;
-       case mlt_image_rgb24a:
-               return PF_RGBA;
-       case mlt_image_yuv420p:
-               return PF_YUV420P;
-       default:
-               return PF_NONE;
-       }
-}
+mlt_image_format validate_format( mlt_image_format format );
+VSPixelFormat mltimage_to_vsimage( mlt_image_format mlt_format, int width, int height, uint8_t* mlt_img, uint8_t** vs_img );
+void vsimage_to_mltimage( uint8_t* vs_img, uint8_t* mlt_img, mlt_image_format mlt_format, int width, int height );
+void free_vsimage( uint8_t* vs_img, VSPixelFormat format );
 
 #endif /* VIDSTAB_COMMON_H_ */
index 0dd13cc251993cfd4dee1a5f4ae4a731e29b92b0..c643a87766677f6e827ebfed1d40ab3310ab6e5b 100644 (file)
@@ -2,6 +2,7 @@
  * filter_deshake.cpp
  * Copyright (C) 2013 Marco Gittler <g.marco@freenet.de>
  * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
+ * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
  *
  * 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
 extern "C"
 {
 #include <vid.stab/libvidstab.h>
+#include "common.h"
 }
 
 #include <framework/mlt.h>
 #include <string.h>
 #include <assert.h>
-#include "common.h"
 
 #define FILTER_NAME "vid.stab.deshake"
 
@@ -41,12 +42,11 @@ typedef struct _deshake_data
 } DeshakeData;
 
 int init_deshake(DeshakeData *data, mlt_properties properties,
-               mlt_image_format *format, int *width, int *height, char* interps)
+               VSPixelFormat vs_format, int *width, int *height, char* interps)
 {
-       VSPixelFormat pf = convertImageFormat(*format);
        VSFrameInfo fiIn, fiOut;
-       vsFrameInfoInit(&fiIn, *width, *height, pf);
-       vsFrameInfoInit(&fiOut, *width, *height, pf);
+       vsFrameInfoInit(&fiIn, *width, *height, vs_format);
+       vsFrameInfoInit(&fiOut, *width, *height, vs_format);
 
        VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(FILTER_NAME);
        conf.shakiness = mlt_properties_get_int(properties, "shakiness");
@@ -96,12 +96,24 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format,
 {
        mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame);
        mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
+       uint8_t* vs_image = NULL;
+       VSPixelFormat vs_format = PF_NONE;
+
+       // VS only works on progressive frames
+       mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
 
-       *format = mlt_image_yuv420p;
+       *format = validate_format( *format );
        DeshakeData *data = static_cast<DeshakeData*>(filter->child);
 
        int error = mlt_frame_get_image(frame, image, format, width, height, 1);
-       if (!error)
+
+       // Convert the received image to a format vid.stab can handle
+       if ( !error )
+       {
+               vs_format = mltimage_to_vsimage( *format, *width, *height, *image, &vs_image );
+       }
+
+       if ( vs_image )
        {
                // Service locks are for concurrency control
                mlt_service_lock(MLT_FILTER_SERVICE(filter));
@@ -125,7 +137,7 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format,
                if (!data->initialized)
                {
                        char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp");
-                       init_deshake(data, properties, format, width, height,
+                       init_deshake(data, properties, vs_format, width, height,
                                        interps);
                        data->initialized = true;
                }
@@ -136,7 +148,7 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format,
                VSTransform motion;
                VSFrame vsFrame;
 
-               vsFrameFillFromBuffer(&vsFrame, *image, &md->fi);
+               vsFrameFillFromBuffer(&vsFrame, vs_image, &md->fi);
                vsMotionDetection(md, &localmotions, &vsFrame);
 
                motion = vsSimpleMotionsToTransform(md->fi, FILTER_NAME, &localmotions);
@@ -151,7 +163,11 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format,
                vsDoTransform(td, t);
                vsTransformFinish(td);
 
+               vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
+
                mlt_service_unlock(MLT_FILTER_SERVICE(filter));
+
+               free_vsimage( vs_image, vs_format );
        }
 
        return error;
index 4b4fe46ff3333b6f6eafd457f51341d4c68c3c17..a6d8294307f0760e4bd3100dfd8a1586c74efb4a 100644 (file)
@@ -2,6 +2,7 @@
  * filter_vidstab.cpp
  * Copyright (C) 2013 Marco Gittler <g.marco@freenet.de>
  * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
+ * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
  *
  * 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
@@ -23,12 +24,12 @@ extern "C"
 #include <vid.stab/libvidstab.h>
 #include <framework/mlt.h>
 #include <framework/mlt_animation.h>
+#include "common.h"
 }
 
 #include <sstream>
 #include <string.h>
 #include <assert.h>
-#include "common.h"
 
 typedef struct
 {
@@ -56,7 +57,11 @@ static void free_manylocalmotions( VSManyLocalMotions* mlms )
        for( int i = 0; i < vs_vector_size( mlms ); i++ )
        {
                LocalMotions* lms = (LocalMotions*)vs_vector_get( mlms, i );
-               vs_vector_del( lms );
+
+               if( lms )
+               {
+                       vs_vector_del( lms );
+               }
        }
        vs_vector_del( mlms );
 }
@@ -159,12 +164,11 @@ static void read_manylocalmotions( mlt_properties properties, VSManyLocalMotions
        mlt_animation_close( animation );
 }
 
-static vs_apply* init_apply_data( mlt_filter filter, mlt_frame frame, int width, int height, mlt_image_format format )
+static vs_apply* init_apply_data( mlt_filter filter, mlt_frame frame, VSPixelFormat vs_format, int width, int height )
 {
        mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
        vs_apply* apply_data = (vs_apply*)calloc( 1, sizeof(vs_apply) );
        memset( apply_data, 0, sizeof( vs_apply ) );
-       VSPixelFormat pf = convertImageFormat( format );
 
        const char* filterName = mlt_properties_get( properties, "mlt_service" );
        VSTransformConfig conf = vsTransformGetDefaultConfig( filterName );
@@ -201,8 +205,8 @@ static vs_apply* init_apply_data( mlt_filter filter, mlt_frame frame, int width,
        VSTransformData* td = &apply_data->td;
        VSTransformations* trans = &apply_data->trans;
        VSFrameInfo fi_src, fi_dst;
-       vsFrameInfoInit( &fi_src, width, height, pf );
-       vsFrameInfoInit( &fi_dst, width, height, pf );
+       vsFrameInfoInit( &fi_src, width, height, vs_format );
+       vsFrameInfoInit( &fi_dst, width, height, vs_format );
        vsTransformDataInit( td, &conf, &fi_src, &fi_dst );
        vsTransformationsInit( trans );
        vsLocalmotions2Transforms( td, &mlms, trans );
@@ -223,7 +227,7 @@ static void destory_apply_data( vs_apply* apply_data )
        }
 }
 
-static vs_analyze* init_analyze_data( mlt_filter filter, mlt_frame frame, mlt_image_format format, int width, int height )
+static vs_analyze* init_analyze_data( mlt_filter filter, mlt_frame frame, VSPixelFormat vs_format, int width, int height )
 {
        mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
        vs_analyze* analyze_data = (vs_analyze*)calloc( 1, sizeof(vs_analyze) );
@@ -234,9 +238,8 @@ static vs_analyze* init_analyze_data( mlt_filter filter, mlt_frame frame, mlt_im
        vs_vector_init( &analyze_data->mlms, mlt_filter_get_length2( filter, frame ) );
 
        // Initialize a VSFrameInfo to be used below
-       VSPixelFormat pf = convertImageFormat( format );
        VSFrameInfo fi;
-       vsFrameInfoInit( &fi, width, height, pf );
+       vsFrameInfoInit( &fi, width, height, vs_format );
 
        // Initialize a VSMotionDetect
        const char* filterName = mlt_properties_get( properties, "mlt_service" );
@@ -263,106 +266,112 @@ void destory_analyze_data( vs_analyze* analyze_data )
        }
 }
 
-static int get_image_and_apply( mlt_filter filter, mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+static int transform_image( mlt_filter filter, mlt_frame frame, uint8_t* vs_image, VSPixelFormat vs_format, int width, int height )
 {
        int error = 0;
        mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
        vs_data* data = (vs_data*)filter->child;
 
-       *format = mlt_image_yuv420p;
-
-       error = mlt_frame_get_image( frame, image, format, width, height, 1 );
-       if ( !error )
+       // Handle signal from app to re-init data
+       if ( mlt_properties_get_int(properties, "refresh") )
        {
-               mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
-
-               // Handle signal from app to re-init data
-               if ( mlt_properties_get_int(properties, "refresh") )
-               {
-                       mlt_properties_set(properties, "refresh", NULL);
-                       destory_apply_data( data->apply_data );
-                       data->apply_data = NULL;
-               }
-
-               // Init transform data if necessary (first time)
-               if ( !data->apply_data )
-               {
-                       data->apply_data = init_apply_data( filter, frame, *width, *height, *format );
-               }
+               mlt_properties_set(properties, "refresh", NULL);
+               destory_apply_data( data->apply_data );
+               data->apply_data = NULL;
+       }
 
-               // Apply transformations to this image
-               VSTransformData* td = &data->apply_data->td;
-               VSTransformations* trans = &data->apply_data->trans;
-               VSFrame vsFrame;
-               vsFrameFillFromBuffer( &vsFrame, *image, vsTransformGetSrcFrameInfo( td ) );
-               trans->current = mlt_filter_get_position( filter, frame );
-               vsTransformPrepare( td, &vsFrame, &vsFrame );
-               VSTransform t = vsGetNextTransform( td, trans );
-               vsDoTransform( td, t );
-               vsTransformFinish( td );
-
-               mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
+       // Init transform data if necessary (first time)
+       if ( !data->apply_data )
+       {
+               data->apply_data = init_apply_data( filter, frame, vs_format, width, height );
        }
 
+       // Apply transformations to this image
+       VSTransformData* td = &data->apply_data->td;
+       VSTransformations* trans = &data->apply_data->trans;
+       VSFrame vsFrame;
+       vsFrameFillFromBuffer( &vsFrame, vs_image, vsTransformGetSrcFrameInfo( td ) );
+       trans->current = mlt_filter_get_position( filter, frame );
+       vsTransformPrepare( td, &vsFrame, &vsFrame );
+       VSTransform t = vsGetNextTransform( td, trans );
+       vsDoTransform( td, t );
+       vsTransformFinish( td );
+
        return error;
 }
 
-
-static int get_image_and_analyze( mlt_filter filter, mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
+static void analyze_image( mlt_filter filter, mlt_frame frame, uint8_t* vs_image, VSPixelFormat vs_format, int width, int height )
 {
        mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
        vs_data* data = (vs_data*)filter->child;
        mlt_position pos = mlt_filter_get_position( filter, frame );
 
-       *format = mlt_image_yuv420p;
-
-       writable = writable || mlt_properties_get_int( properties, "show" ) ? 1 : 0;
-
-       int error = mlt_frame_get_image( frame, image, format, width, height, writable );
-       if ( !error )
+       if ( !data->analyze_data )
        {
-               // Service locks are for concurrency control
-               mlt_service_lock( MLT_FILTER_SERVICE(filter) );
-
-               if ( !data->analyze_data )
-               {
-                       data->analyze_data = init_analyze_data( filter, frame, *format, *width, *height );
-               }
-
-               // Initialize the VSFrame to be analyzed.
-               VSMotionDetect* md = &data->analyze_data->md;
-               LocalMotions localmotions;
-               VSFrame vsFrame;
-               vsFrameFillFromBuffer( &vsFrame, *image, &md->fi );
+               data->analyze_data = init_analyze_data( filter, frame, vs_format, width, height );
+       }
 
-               // Detect and save motions.
-               vsMotionDetection( md, &localmotions, &vsFrame );
-               vs_vector_set_dup( &data->analyze_data->mlms, pos, &localmotions, sizeof(LocalMotions) );
+       // Initialize the VSFrame to be analyzed.
+       VSMotionDetect* md = &data->analyze_data->md;
+       LocalMotions localmotions;
+       VSFrame vsFrame;
+       vsFrameFillFromBuffer( &vsFrame, vs_image, &md->fi );
 
-               // Publish the motions if this is the last frame.
-               if ( pos + 1 == mlt_filter_get_length2( filter, frame ) )
-               {
-                       publish_manylocalmotions( properties, &data->analyze_data->mlms );
-               }
+       // Detect and save motions.
+       vsMotionDetection( md, &localmotions, &vsFrame );
+       vs_vector_set_dup( &data->analyze_data->mlms, pos, &localmotions, sizeof(LocalMotions) );
 
-               mlt_service_unlock( MLT_FILTER_SERVICE(filter) );
+       // Publish the motions if this is the last frame.
+       if ( pos + 1 == mlt_filter_get_length2( filter, frame ) )
+       {
+               publish_manylocalmotions( properties, &data->analyze_data->mlms );
        }
-       return error;
 }
 
 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
 {
        mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame );
        mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
+       uint8_t* vs_image = NULL;
+       VSPixelFormat vs_format = PF_NONE;
+
+       // VS only works on progressive frames
+       mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
 
-       if( mlt_properties_get( properties, "results" ) )
+       *format = validate_format( *format );
+
+       int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
+
+       // Convert the received image to a format vid.stab can handle
+       if ( !error )
        {
-               return get_image_and_apply( filter, frame, image, format, width, height, writable );
+               vs_format = mltimage_to_vsimage( *format, *width, *height, *image, &vs_image );
        }
-       else
+
+       if( vs_image )
        {
-               return get_image_and_analyze( filter, frame, image, format, width, height, writable );
+               mlt_service_lock( MLT_FILTER_SERVICE(filter) );
+
+               if( mlt_properties_get( properties, "results" ) )
+               {
+                       transform_image( filter, frame, vs_image, vs_format, *width, *height );
+                       vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
+               }
+               else
+               {
+                       analyze_image( filter, frame, vs_image, vs_format, *width, *height );
+                       if( mlt_properties_get_int( properties, "show" ) == 1 )
+                       {
+                               vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
+                       }
+               }
+
+               mlt_service_unlock( MLT_FILTER_SERVICE(filter) );
+
+               free_vsimage( vs_image, vs_format );
        }
+
+       return error;
 }
 
 static mlt_frame process_filter( mlt_filter filter, mlt_frame frame )