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)))
39 static inline int clip(int a, int amin, int amax)
49 void caculate_motion( struct motion_vector_s *vectors,
50 mlt_geometry_item boundry,
52 int macroblock_height,
58 // translate pixel units (from bounds) to macroblock units
59 // make sure whole macroblock stay within bounds
61 int left_mb = boundry->x / macroblock_width;
62 left_mb += ( (int)boundry->x % macroblock_width == 0 ) ? 0 : 1 ;
63 int top_mb = boundry->y / macroblock_height;
64 top_mb += ( (int)boundry->y % macroblock_height == 0 ) ? 0 : 1 ;
66 int right_mb = (boundry->x + boundry->w + 1) / macroblock_width;
67 right_mb -= ( (int)(boundry->x + boundry->w + 1) % macroblock_width == 0 ) ? 0 : 1 ;
68 int bottom_mb = (boundry->y + boundry->h + 1) / macroblock_height;
69 bottom_mb -= ( (int)(boundry->y + boundry->h + 1) % macroblock_height == 0 ) ? 0 : 1 ;
73 int average_x = 0, average_y = 0;
75 #define CURRENT ( vectors + j*mv_buffer_width + i )
77 for( i = left_mb; i <= right_mb; i++ ){
78 for( j = top_mb; j <= bottom_mb; j++ ){
82 average_x += CURRENT->dx;
83 average_y += CURRENT->dy;
93 int average2_x = 0, average2_y = 0;
94 for( i = left_mb; i <= right_mb; i++ ){
95 for( j = top_mb; j <= bottom_mb; j++ ){
97 if( ABS(CURRENT->dx - average_x) < 5 &&
98 ABS(CURRENT->dy - average_y) < 5 )
101 average2_x += CURRENT->dx;
102 average2_y += CURRENT->dy;
107 if ( n == 0 ) return;
109 boundry->x -= average2_x / n;
110 boundry->y -= average2_y / n;
113 // Image stack(able) method
114 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
117 // Get the filter object
118 mlt_filter filter = mlt_frame_pop_service( frame );
120 // Get the filter's property object
121 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
123 // Get the frame properties
124 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
126 // Get the frame position
127 mlt_position position = mlt_frame_get_position( frame );
130 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
133 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr );
135 // Get the geometry object
136 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
138 // Get the current geometry item
139 struct mlt_geometry_item_s boundry;
140 mlt_geometry_fetch(geometry, &boundry, position);
142 // Get the motion vectors
143 struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL );
145 // How did the rectangle move?
146 if( vectors != NULL ) {
148 int method = mlt_properties_get_int( filter_properties, "method" );
150 // Get the size of macroblocks in pixel units
151 int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" );
152 int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" );
153 int mv_buffer_width = *width / macroblock_width;
155 caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method );
159 // Turn the geometry object into a real boy
166 mlt_geometry_insert(geometry, &boundry);
169 if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
172 init_arrows( format, *width, *height );
173 draw_line(*image, boundry.x, boundry.y, boundry.x, boundry.y + boundry.h, 100);
174 draw_line(*image, boundry.x, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y + boundry.h, 100);
175 draw_line(*image, boundry.x + boundry.w, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y, 100);
176 draw_line(*image, boundry.x + boundry.w, boundry.y, boundry.x, boundry.y, 100);
181 static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
183 // Get the filter object
184 mlt_filter filter = mlt_frame_pop_service( frame );
186 // Get the filter's property object
187 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
189 // Get the frame properties
190 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
192 // Get the frame position
193 mlt_position position = mlt_frame_get_position( frame );
195 // gEt the geometry object
196 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
198 // Get the current geometry item
199 mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) );
200 mlt_geometry_fetch(geometry, geometry_item, position);
201 //fprintf(stderr, "attach %d\n", position);
203 mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );
206 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
209 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr );
214 /** Filter processing.
217 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
220 /* modify the frame with the current geometry */
221 mlt_frame_push_service( frame, this);
222 mlt_frame_push_get_image( frame, attach_boundry_to_frame );
226 /* apply the motion estimation filter */
227 mlt_filter motion_est = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_motion_est", NULL );
228 mlt_filter_process( motion_est, frame);
232 /* calculate the new geometry based on the motion */
233 mlt_frame_push_service( frame, this);
234 mlt_frame_push_get_image( frame, filter_get_image );
237 /* visualize the motion vectors */
238 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 )
240 mlt_filter vismv = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_vismv", NULL );
241 if( vismv == NULL ) {
242 vismv = mlt_factory_filter( "vismv", NULL );
243 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL );
246 mlt_filter_process( vismv, frame );
253 /** Constructor for the filter.
257 mlt_filter filter_autotrack_rectangle_init( char *arg )
259 mlt_filter this = mlt_filter_new( );
262 this->process = filter_process;
265 mlt_geometry geometry = mlt_geometry_init();
267 // Initialize with the supplied geometry
270 struct mlt_geometry_item_s item;
272 mlt_geometry_parse_item( geometry, &item, arg );
278 mlt_geometry_insert( geometry, &item );
282 // ... and attach it to the frame
283 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "geometry", geometry, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
285 // create an instance of the motion_est filter
286 mlt_filter motion_est = mlt_factory_filter("motion_est", NULL);
287 if( motion_est != NULL )
288 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL );
290 mlt_filter_close( this );
300 /** This source code will self destruct in 5...4...3...