3 * Copyright (C) 2013 Marco Gittler <g.marco@freenet.de>
4 * Copyright (C) 2013 Jakub Ksiezniak <j.ksiezniak@gmail.com>
5 * Copyright (C) 2014 Brian Matherly <pez4brian@yahoo.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <vid.stab/libvidstab.h>
25 #include <framework/mlt.h>
26 #include <framework/mlt_animation.h>
37 VSManyLocalMotions mlms;
43 VSTransformations trans;
48 vs_analyze* analyze_data;
52 /** Free all data used by a VSManyLocalMotions instance.
55 static void free_manylocalmotions( VSManyLocalMotions* mlms )
57 for( int i = 0; i < vs_vector_size( mlms ); i++ )
59 LocalMotions* lms = (LocalMotions*)vs_vector_get( mlms, i );
66 vs_vector_del( mlms );
69 /** Serialize a VSManyLocalMotions instance and store it in the properties.
71 * Each LocalMotions instance is converted to a string and stored in an animation.
72 * Then, the entire animation is serialized and stored in the properties.
73 * \param properties the filter properties
74 * \param mlms an initialized VSManyLocalMotions instance
77 static void publish_manylocalmotions( mlt_properties properties, VSManyLocalMotions* mlms )
79 mlt_animation animation = mlt_animation_new();
80 mlt_animation_item_s item;
82 // Initialize animation item.
84 item.keyframe_type = mlt_keyframe_discrete;
85 item.property = mlt_property_init();
87 // Convert each LocalMotions instance to a string and add it to the animation.
88 for( int i = 0; i < vs_vector_size( mlms ); i++ )
90 LocalMotions* lms = (LocalMotions*)vs_vector_get( mlms, i );
92 int size = vs_vector_size( lms );
94 std::ostringstream oss;
95 for ( int j = 0; j < size; ++j )
97 LocalMotion* lm = (LocalMotion*)vs_vector_get( lms, j );
98 oss << lm->v.x << ' ';
99 oss << lm->v.y << ' ';
100 oss << lm->f.x << ' ';
101 oss << lm->f.y << ' ';
102 oss << lm->f.size << ' ';
103 oss << lm->contrast << ' ';
104 oss << lm->match << ' ';
106 mlt_property_set_string( item.property, oss.str().c_str() );
107 mlt_animation_insert( animation, &item );
110 // Serialize and store the animation.
111 char* motion_str = mlt_animation_serialize( animation );
112 mlt_properties_set( properties, "results", motion_str );
114 mlt_property_close( item.property );
115 mlt_animation_close( animation );
119 /** Get the motions data from the properties and convert it to a VSManyLocalMotions.
121 * Each LocalMotions instance is converted to a string and stored in an animation.
122 * Then, the entire animation is serialized and stored in the properties.
123 * \param properties the filter properties
124 * \param mlms an initialized (but empty) VSManyLocalMotions instance
127 static void read_manylocalmotions( mlt_properties properties, VSManyLocalMotions* mlms )
129 mlt_animation_item_s item;
130 item.property = mlt_property_init();
131 mlt_animation animation = mlt_animation_new();
132 // Get the results property which represents the VSManyLocalMotions
133 char* motion_str = mlt_properties_get( properties, "results" );
135 mlt_animation_parse( animation, motion_str, 0, 0, NULL );
137 int length = mlt_animation_get_length( animation );
139 for ( int i = 0; i <= length; ++i )
142 vs_vector_init( &lms, 0 );
144 // Get the animation item that represents the LocalMotions
145 mlt_animation_get_item( animation, &item, i );
147 // Convert the property to a real LocalMotions
148 std::istringstream iss( mlt_property_get_string( item.property ) );
152 iss >> lm.v.x >> lm.v.y >> lm.f.x >> lm.f.y >> lm.f.size >> lm.contrast >> lm.match;
155 vs_vector_append_dup( &lms, &lm, sizeof(lm) );
159 // Add the LocalMotions to the ManyLocalMotions
160 vs_vector_set_dup( mlms, i, &lms, sizeof(LocalMotions) );
163 mlt_property_close( item.property );
164 mlt_animation_close( animation );
167 static vs_apply* init_apply_data( mlt_filter filter, mlt_frame frame, VSPixelFormat vs_format, int width, int height )
169 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
170 vs_apply* apply_data = (vs_apply*)calloc( 1, sizeof(vs_apply) );
171 memset( apply_data, 0, sizeof( vs_apply ) );
173 const char* filterName = mlt_properties_get( properties, "mlt_service" );
174 VSTransformConfig conf = vsTransformGetDefaultConfig( filterName );
175 conf.smoothing = mlt_properties_get_int( properties, "smoothing" );
176 conf.maxShift = mlt_properties_get_int( properties, "maxshift" );
177 conf.maxAngle = mlt_properties_get_double( properties, "maxangle" );
178 conf.crop = (VSBorderType)mlt_properties_get_int( properties, "crop" );
179 conf.zoom = mlt_properties_get_int( properties, "zoom" );
180 conf.optZoom = mlt_properties_get_int( properties, "optzoom" );
181 conf.zoomSpeed = mlt_properties_get_double( properties, "zoomspeed" );
182 conf.relative = mlt_properties_get_int( properties, "relative" );
183 conf.invert = mlt_properties_get_int( properties, "invert" );
184 if ( mlt_properties_get_int( properties, "tripod" ) != 0 )
186 // Virtual tripod mode: relative=False, smoothing=0
191 // by default a bilinear interpolation is selected
192 const char *interps = mlt_properties_get( MLT_FRAME_PROPERTIES( frame ), "rescale.interp" );
193 conf.interpolType = VS_BiLinear;
194 if (strcmp(interps, "nearest") == 0 || strcmp(interps, "neighbor") == 0)
195 conf.interpolType = VS_Zero;
196 else if (strcmp(interps, "tiles") == 0 || strcmp(interps, "fast_bilinear") == 0)
197 conf.interpolType = VS_Linear;
200 VSManyLocalMotions mlms;
201 vs_vector_init( &mlms, mlt_filter_get_length2( filter, frame ) );
202 read_manylocalmotions( properties, &mlms );
204 // Convert motions to VSTransformations
205 VSTransformData* td = &apply_data->td;
206 VSTransformations* trans = &apply_data->trans;
207 VSFrameInfo fi_src, fi_dst;
208 vsFrameInfoInit( &fi_src, width, height, vs_format );
209 vsFrameInfoInit( &fi_dst, width, height, vs_format );
210 vsTransformDataInit( td, &conf, &fi_src, &fi_dst );
211 vsTransformationsInit( trans );
212 vsLocalmotions2Transforms( td, &mlms, trans );
213 vsPreprocessTransforms( td, trans );
215 free_manylocalmotions( &mlms );
220 static void destory_apply_data( vs_apply* apply_data )
224 vsTransformDataCleanup( &apply_data->td );
225 vsTransformationsCleanup( &apply_data->trans );
230 static vs_analyze* init_analyze_data( mlt_filter filter, mlt_frame frame, VSPixelFormat vs_format, int width, int height )
232 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
233 vs_analyze* analyze_data = (vs_analyze*)calloc( 1, sizeof(vs_analyze) );
234 memset( analyze_data, 0, sizeof(vs_analyze) );
236 // Initialize the VSManyLocalMotions vector where motion data will be
237 // stored for each frame.
238 vs_vector_init( &analyze_data->mlms, mlt_filter_get_length2( filter, frame ) );
240 // Initialize a VSFrameInfo to be used below
242 vsFrameInfoInit( &fi, width, height, vs_format );
244 // Initialize a VSMotionDetect
245 const char* filterName = mlt_properties_get( properties, "mlt_service" );
246 VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig( filterName );
247 conf.shakiness = mlt_properties_get_int( properties, "shakiness" );
248 conf.accuracy = mlt_properties_get_int( properties, "accuracy" );
249 conf.stepSize = mlt_properties_get_int( properties, "stepsize" );
250 conf.algo = mlt_properties_get_int( properties, "algo" );
251 conf.contrastThreshold = mlt_properties_get_double( properties, "mincontrast" );
252 conf.show = mlt_properties_get_int( properties, "show" );
253 conf.virtualTripod = mlt_properties_get_int( properties, "tripod" );
254 vsMotionDetectInit( &analyze_data->md, &conf, &fi );
259 void destory_analyze_data( vs_analyze* analyze_data )
263 vsMotionDetectionCleanup( &analyze_data->md );
264 free_manylocalmotions( &analyze_data->mlms );
265 free( analyze_data );
269 static int transform_image( mlt_filter filter, mlt_frame frame, uint8_t* vs_image, VSPixelFormat vs_format, int width, int height )
272 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
273 vs_data* data = (vs_data*)filter->child;
275 // Handle signal from app to re-init data
276 if ( mlt_properties_get_int(properties, "refresh") )
278 mlt_properties_set(properties, "refresh", NULL);
279 destory_apply_data( data->apply_data );
280 data->apply_data = NULL;
283 // Init transform data if necessary (first time)
284 if ( !data->apply_data )
286 data->apply_data = init_apply_data( filter, frame, vs_format, width, height );
289 // Apply transformations to this image
290 VSTransformData* td = &data->apply_data->td;
291 VSTransformations* trans = &data->apply_data->trans;
293 vsFrameFillFromBuffer( &vsFrame, vs_image, vsTransformGetSrcFrameInfo( td ) );
294 trans->current = mlt_filter_get_position( filter, frame );
295 vsTransformPrepare( td, &vsFrame, &vsFrame );
296 VSTransform t = vsGetNextTransform( td, trans );
297 vsDoTransform( td, t );
298 vsTransformFinish( td );
303 static void analyze_image( mlt_filter filter, mlt_frame frame, uint8_t* vs_image, VSPixelFormat vs_format, int width, int height )
305 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
306 vs_data* data = (vs_data*)filter->child;
307 mlt_position pos = mlt_filter_get_position( filter, frame );
309 if ( !data->analyze_data )
311 data->analyze_data = init_analyze_data( filter, frame, vs_format, width, height );
314 // Initialize the VSFrame to be analyzed.
315 VSMotionDetect* md = &data->analyze_data->md;
316 LocalMotions localmotions;
318 vsFrameFillFromBuffer( &vsFrame, vs_image, &md->fi );
320 // Detect and save motions.
321 vsMotionDetection( md, &localmotions, &vsFrame );
322 vs_vector_set_dup( &data->analyze_data->mlms, pos, &localmotions, sizeof(LocalMotions) );
324 // Publish the motions if this is the last frame.
325 if ( pos + 1 == mlt_filter_get_length2( filter, frame ) )
327 publish_manylocalmotions( properties, &data->analyze_data->mlms );
331 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
333 mlt_filter filter = (mlt_filter)mlt_frame_pop_service( frame );
334 mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
335 uint8_t* vs_image = NULL;
336 VSPixelFormat vs_format = PF_NONE;
338 // VS only works on progressive frames
339 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 );
341 *format = validate_format( *format );
343 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
345 // Convert the received image to a format vid.stab can handle
348 vs_format = mltimage_to_vsimage( *format, *width, *height, *image, &vs_image );
353 mlt_service_lock( MLT_FILTER_SERVICE(filter) );
355 if( mlt_properties_get( properties, "results" ) )
357 transform_image( filter, frame, vs_image, vs_format, *width, *height );
358 vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
362 analyze_image( filter, frame, vs_image, vs_format, *width, *height );
363 if( mlt_properties_get_int( properties, "show" ) == 1 )
365 vsimage_to_mltimage( vs_image, *image, *format, *width, *height );
369 mlt_service_unlock( MLT_FILTER_SERVICE(filter) );
371 free_vsimage( vs_image, vs_format );
377 static mlt_frame process_filter( mlt_filter filter, mlt_frame frame )
379 mlt_frame_push_service( frame, filter );
380 mlt_frame_push_get_image( frame, get_image );
384 static void filter_close( mlt_filter filter )
386 vs_data* data = (vs_data*)filter->child;
389 if ( data->analyze_data ) destory_analyze_data( data->analyze_data );
390 if ( data->apply_data ) destory_apply_data( data->apply_data );
393 filter->close = NULL;
394 filter->child = NULL;
395 filter->parent.close = NULL;
396 mlt_service_close( &filter->parent );
402 mlt_filter filter_vidstab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
404 mlt_filter filter = mlt_filter_new();
405 vs_data* data = (vs_data*)calloc( 1, sizeof(vs_data) );
407 if ( filter && data )
409 data->analyze_data = NULL;
410 data->apply_data = NULL;
412 filter->close = filter_close;
413 filter->child = data;
414 filter->process = process_filter;
416 mlt_properties properties = MLT_FILTER_PROPERTIES(filter);
418 //properties for analyze
419 mlt_properties_set(properties, "shakiness", "4");
420 mlt_properties_set(properties, "accuracy", "4");
421 mlt_properties_set(properties, "stepsize", "6");
422 mlt_properties_set(properties, "algo", "1");
423 mlt_properties_set(properties, "mincontrast", "0.3");
424 mlt_properties_set(properties, "show", "0");
425 mlt_properties_set(properties, "tripod", "0");
427 // properties for apply
428 mlt_properties_set(properties, "smoothing", "15");
429 mlt_properties_set(properties, "maxshift", "-1");
430 mlt_properties_set(properties, "maxangle", "-1");
431 mlt_properties_set(properties, "crop", "0");
432 mlt_properties_set(properties, "invert", "0");
433 mlt_properties_set(properties, "relative", "1");
434 mlt_properties_set(properties, "zoom", "0");
435 mlt_properties_set(properties, "optzoom", "1");
436 mlt_properties_set(properties, "zoomspeed", "0.25");
438 mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION);
444 mlt_filter_close( filter );