2 * filter_imagestab.c -- video stabilization with code from http://vstab.sourceforge.net/
3 * Copyright (c) 2011 Marco Gittler <g.marco@freenet.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <framework/mlt_filter.h>
21 #include <framework/mlt_frame.h>
22 #include <framework/mlt_log.h>
23 #include <framework/mlt_producer.h>
24 #include <framework/mlt_geometry.h>
32 #include "stab/vector.h"
33 #include "stab/utils.h"
34 #include "stab/estimate.h"
35 #include "stab/resample.h"
49 static void serialize_vectors( videostab self, mlt_position length )
51 mlt_geometry g = mlt_geometry_init();
55 struct mlt_geometry_item_s item;
58 // Initialize geometry item
59 item.key = item.f[0] = item.f[1] = 1;
60 item.f[2] = item.f[3] = item.f[4] = 0;
62 for ( i = 0; i < length; i++ )
64 // Set the geometry item
66 item.x = self->pos_h[i].x;
67 item.y = self->pos_h[i].y;
69 // Add the geometry item
70 mlt_geometry_insert( g, &item );
73 // Put the analysis results in a property
74 mlt_geometry_set_length( g, length );
75 mlt_properties_set_data( MLT_FILTER_PROPERTIES( self->parent ), "vectors", g, 0,
76 (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise );
80 static void deserialize_vectors( videostab self, char *vectors, mlt_position length )
82 mlt_geometry g = mlt_geometry_init();
84 // Parse the property as a geometry
85 if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) )
87 struct mlt_geometry_item_s item;
90 // Copy the geometry items to a vc array for interp()
91 for ( i = 0; i < length; i++ )
93 mlt_geometry_fetch( g, &item, i );
94 self->pos_h[i].x = item.x;
95 self->pos_h[i].y = item.y;
100 mlt_log_warning( MLT_FILTER_SERVICE(self->parent), "failed to parse vectors\n" );
103 // We are done with this mlt_geometry
104 if ( g ) mlt_geometry_close( g );
107 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
109 mlt_filter filter = mlt_frame_pop_service( frame );
110 *format = mlt_image_rgb24;
111 mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "consumer_deinterlace", 1 );
112 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
114 if ( !error && *image )
116 videostab self = filter->child;
117 mlt_position length = mlt_filter_get_length2( filter, frame );
121 // Service locks are for concurrency control
122 mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
123 if ( !self->initialized )
125 // Initialize our context
126 self->initialized = 1;
127 self->es = es_init( w, h );
128 self->pos_i = (vc*) malloc( length * sizeof(vc) );
129 self->pos_h = (vc*) malloc( length * sizeof(vc) );
130 self->pos_y = (vc*) malloc( h * sizeof(vc) );
131 self->rs = rs_init( w, h );
133 char *vectors = mlt_properties_get( MLT_FILTER_PROPERTIES(filter), "vectors" );
137 int pos = (int) mlt_filter_get_position( filter, frame );
138 self->pos_i[pos] = vc_add( pos == 0 ? vc_zero() : self->pos_i[pos - 1], es_estimate( self->es, *image ) );
141 if ( pos == length - 1 )
143 mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE(filter) );
144 double fps = mlt_profile_fps( profile );
146 // Filter and store the results
147 hipass( self->pos_i, self->pos_h, length, fps );
148 serialize_vectors( self, length );
152 if ( self->initialized != 2 )
154 // Load analysis results from property
155 self->initialized = 2;
156 deserialize_vectors( self, vectors, length );
158 if ( self->initialized == 2 )
161 float shutter_angle = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame) , "shutterangle" );
162 float pos = mlt_filter_get_position( filter, frame );
165 for (i = 0; i < h; i ++)
166 self->pos_y[i] = interp( self->lanc_kernels,self->pos_h, length, pos + (i - h / 2.0) * shutter_angle / (h * 360.0) );
167 rs_resample( self->lanc_kernels,self->rs, *image, self->pos_y );
170 mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
175 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
177 mlt_frame_push_service( frame, filter );
178 mlt_frame_push_get_image( frame, filter_get_image );
182 void filter_close( mlt_filter parent )
184 videostab self = parent->child;
185 if ( self->es ) es_free( self->es );
186 if ( self->pos_i ) free( self->pos_i );
187 if ( self->pos_h ) free( self->pos_h );
188 if ( self->pos_y ) free( self->pos_y );
189 if ( self->rs ) rs_free( self->rs );
190 if ( self->lanc_kernels) free_lanc_kernels(self->lanc_kernels);
192 parent->close = NULL;
193 parent->child = NULL;
196 mlt_filter filter_videostab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
198 videostab self = calloc( 1, sizeof(*self) );
201 mlt_filter parent = mlt_filter_new();
207 parent->child = self;
208 parent->close = filter_close;
209 parent->process = filter_process;
210 self->parent = parent;
211 mlt_properties_set( MLT_FILTER_PROPERTIES(parent), "shutterangle", "0" ); // 0 - 180 , default 0
212 self->lanc_kernels=prepare_lanc_kernels();