2 * filter_autotrack_rectangle.c
5 * /author Zachary Drew, Copyright 2005
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include "filter_motion_est.h"
24 #include "arrow_code.h"
26 #include <framework/mlt.h>
33 #define MIN(a,b) ((a) > (b) ? (b) : (a))
35 #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
36 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
38 void caculate_motion( struct motion_vector_s *vectors,
39 mlt_geometry_item boundry,
41 int macroblock_height,
49 // translate pixel units (from bounds) to macroblock units
50 // make sure whole macroblock stay within bounds
51 int left_mb = ( boundry->x + macroblock_width - 1 ) / macroblock_width;
52 int top_mb = ( boundry->y + macroblock_height - 1 ) / macroblock_height;
53 int right_mb = ( boundry->x + boundry->w ) / macroblock_width - 1;
54 int bottom_mb = ( boundry->y + boundry->h ) / macroblock_height - 1;
58 int average_x = 0, average_y = 0;
60 #define CURRENT ( vectors + j*mv_buffer_width + i )
62 for( i = left_mb; i <= right_mb; i++ ){
63 for( j = top_mb; j <= bottom_mb; j++ )
66 average_x += CURRENT->dx;
67 average_y += CURRENT->dy;
77 int average2_x = 0, average2_y = 0;
78 for( i = left_mb; i <= right_mb; i++ ){
79 for( j = top_mb; j <= bottom_mb; j++ ){
81 if( ABS(CURRENT->dx - average_x) < 3 &&
82 ABS(CURRENT->dy - average_y) < 3 )
85 average2_x += CURRENT->dx;
86 average2_y += CURRENT->dy;
93 boundry->x -= (double)average2_x / (double)n;
94 boundry->y -= (double)average2_y / (double)n;
102 if ( boundry->x + boundry->w > width )
103 boundry->x = width - boundry->w;
105 if ( boundry->y + boundry->h > height )
106 boundry->y = height - boundry->h;
109 // Image stack(able) method
110 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
113 // Get the filter object
114 mlt_filter filter = mlt_frame_pop_service( frame );
116 // Get the filter's property object
117 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
119 // Get the frame properties
120 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
122 // Get the frame position
123 mlt_position position = mlt_filter_get_position( filter, frame );
126 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
129 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr );
131 mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
133 // Get the geometry object
134 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
136 // Get the current geometry item
137 struct mlt_geometry_item_s boundry;
138 mlt_geometry_fetch(geometry, &boundry, position);
140 // Get the motion vectors
141 struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL );
143 // Cleanse the geometry item
144 boundry.w = boundry.x < 0 ? boundry.w + boundry.x : boundry.w;
145 boundry.h = boundry.y < 0 ? boundry.h + boundry.y : boundry.h;
146 boundry.x = boundry.x < 0 ? 0 : boundry.x;
147 boundry.y = boundry.y < 0 ? 0 : boundry.y;
148 boundry.w = boundry.w < 0 ? 0 : boundry.w;
149 boundry.h = boundry.h < 0 ? 0 : boundry.h;
151 // How did the rectangle move?
152 if( vectors != NULL &&
153 boundry.key != 1 ) // Paused?
156 int method = mlt_properties_get_int( filter_properties, "method" );
158 // Get the size of macroblocks in pixel units
159 int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" );
160 int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" );
161 int mv_buffer_width = *width / macroblock_width;
163 caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height );
166 // Make the geometry object a real boy
173 mlt_geometry_insert(geometry, &boundry);
174 mlt_geometry_interpolate(geometry);
177 mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
179 if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
181 init_arrows( format, *width, *height );
182 draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100);
185 if( mlt_properties_get_int( filter_properties, "_serialize" ) == 1 )
187 // Add the vector change to the list
188 mlt_geometry key_frames = mlt_properties_get_data( filter_properties, "motion_vector_list", NULL );
191 key_frames = mlt_geometry_init();
192 mlt_properties_set_data( filter_properties, "motion_vector_list", key_frames, 0,
193 (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise );
195 mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) );
199 struct mlt_geometry_item_s item;
200 item.frame = (int) mlt_frame_get_position( frame );
207 item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1;
209 mlt_geometry_insert( key_frames, &item );
213 if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 )
215 mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL );
217 mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out");
219 // Because filter_obscure needs to be rewritten to use mlt_geometry
221 sprintf( geom, "%d/%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
222 mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom );
223 mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom );
226 if( mlt_properties_get_int( filter_properties, "collect" ) == 1 )
228 fprintf( stderr, "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
235 static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
237 // Get the filter object
238 mlt_filter filter = mlt_frame_pop_service( frame );
240 // Get the filter's property object
241 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
243 // Get the frame properties
244 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
246 // Get the frame position
247 mlt_position position = mlt_filter_get_position( filter, frame );
249 mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
251 // Get the geometry object
252 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
253 if (geometry == NULL) {
254 mlt_geometry geom = mlt_geometry_init();
255 char *arg = mlt_properties_get(filter_properties, "geometry");
257 // Initialize with the supplied geometry
258 struct mlt_geometry_item_s item;
259 mlt_geometry_parse_item( geom, &item, arg );
265 mlt_geometry_insert( geom, &item );
266 mlt_geometry_interpolate( geom );
267 mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
268 geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
271 mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
273 // Get the current geometry item
274 mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) );
275 mlt_geometry_fetch(geometry, geometry_item, position);
277 // Cleanse the geometry item
278 geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w;
279 geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h;
280 geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x;
281 geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y;
282 geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w;
283 geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h;
285 mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );
288 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
291 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr );
296 /** Filter processing.
299 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
302 /* modify the frame with the current geometry */
303 mlt_frame_push_service( frame, this);
304 mlt_frame_push_get_image( frame, attach_boundry_to_frame );
305 mlt_properties properties = MLT_FILTER_PROPERTIES( this );
307 /* apply the motion estimation filter */
308 mlt_filter motion_est = mlt_properties_get_data( properties, "_motion_est", NULL );
309 /* Pass motion_est properties */
310 mlt_properties_pass( MLT_FILTER_PROPERTIES( motion_est ), properties, "motion_est." );
311 mlt_filter_process( motion_est, frame);
313 /* calculate the new geometry based on the motion */
314 mlt_frame_push_service( frame, this);
315 mlt_frame_push_get_image( frame, filter_get_image );
318 /* visualize the motion vectors */
319 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 )
321 mlt_filter vismv = mlt_properties_get_data( properties, "_vismv", NULL );
324 mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) );
325 vismv = mlt_factory_filter( profile, "vismv", NULL );
326 mlt_properties_set_data( properties, "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL );
329 mlt_filter_process( vismv, frame );
332 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 )
334 mlt_filter obscure = mlt_properties_get_data( properties, "_obscure", NULL );
335 if( obscure == NULL )
337 mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) );
338 obscure = mlt_factory_filter( profile, "obscure", NULL );
339 mlt_properties_set_data( properties, "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL );
342 mlt_filter_process( obscure, frame );
348 /** Constructor for the filter.
352 mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
354 mlt_filter this = mlt_filter_new( );
357 this->process = filter_process;
359 // Initialize with the supplied geometry if ther is one
361 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg );
363 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100/100:100x100" );
365 // create an instance of the motion_est and obscure filter
366 mlt_filter motion_est = mlt_factory_filter( profile, "motion_est", NULL );
367 if( motion_est != NULL )
368 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL );
370 mlt_filter_close( this );
380 /** This source code will self destruct in 5...4...3...