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_frame_get_position( 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 // Get the geometry object
132 mlt_geometry geometry
= mlt_properties_get_data(filter_properties
, "filter_geometry", NULL
);
134 // Get the current geometry item
135 struct mlt_geometry_item_s boundry
;
136 mlt_geometry_fetch(geometry
, &boundry
, position
);
138 // Get the motion vectors
139 struct motion_vector_s
*vectors
= mlt_properties_get_data( frame_properties
, "motion_est.vectors", NULL
);
141 // How did the rectangle move?
142 if( vectors
!= NULL
&&
143 boundry
.key
!= 1 ) // Paused?
146 int method
= mlt_properties_get_int( filter_properties
, "method" );
148 // Get the size of macroblocks in pixel units
149 int macroblock_height
= mlt_properties_get_int( frame_properties
, "motion_est.macroblock_height" );
150 int macroblock_width
= mlt_properties_get_int( frame_properties
, "motion_est.macroblock_width" );
151 int mv_buffer_width
= *width
/ macroblock_width
;
153 caculate_motion( vectors
, &boundry
, macroblock_width
, macroblock_height
, mv_buffer_width
, method
, *width
, *height
);
156 // Make the geometry object a real boy
163 mlt_geometry_insert(geometry
, &boundry
);
166 if( mlt_properties_get_int( filter_properties
, "debug" ) == 1 )
168 init_arrows( format
, *width
, *height
);
169 draw_rectangle_outline(*image
, boundry
.x
, boundry
.y
, boundry
.w
, boundry
.h
, 100);
172 if( mlt_properties_get_int( filter_properties
, "obscure" ) == 1 )
174 mlt_filter obscure
= mlt_properties_get_data( filter_properties
, "_obscure", NULL
);
176 mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure
), filter_properties
, "in, out");
178 // Because filter_obscure needs to be rewritten to use mlt_geometry
180 sprintf( geom
, "%d,%d:%dx%d", (int)boundry
.x
, (int)boundry
.y
, (int)boundry
.w
, (int)boundry
.h
);
181 mlt_properties_set( MLT_FILTER_PROPERTIES( obscure
), "start", geom
);
182 mlt_properties_set( MLT_FILTER_PROPERTIES( obscure
), "end", geom
);
185 if( mlt_properties_get_int( filter_properties
, "collect" ) == 1 )
187 printf( "%d,%d,%d,%d\n", (int)boundry
.x
, (int)boundry
.y
, (int)boundry
.w
, (int)boundry
.h
);
194 static int attach_boundry_to_frame( mlt_frame frame
, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
196 // Get the filter object
197 mlt_filter filter
= mlt_frame_pop_service( frame
);
199 // Get the filter's property object
200 mlt_properties filter_properties
= MLT_FILTER_PROPERTIES(filter
);
202 // Get the frame properties
203 mlt_properties frame_properties
= MLT_FRAME_PROPERTIES(frame
);
205 // Get the frame position
206 mlt_position position
= mlt_frame_get_position( frame
);
208 // Get the geometry object
209 mlt_geometry geometry
= mlt_properties_get_data(filter_properties
, "filter_geometry", NULL
);
210 if (geometry
== NULL
) {
211 mlt_geometry geom
= mlt_geometry_init();
212 char *arg
= mlt_properties_get(filter_properties
, "geometry");
214 // Initialize with the supplied geometry
215 struct mlt_geometry_item_s item
;
216 mlt_geometry_parse_item( geom
, &item
, arg
);
222 mlt_geometry_insert( geom
, &item
);
223 mlt_properties_set_data( filter_properties
, "filter_geometry", geom
, 0, (mlt_destructor
)mlt_geometry_close
, (mlt_serialiser
)mlt_geometry_serialise
);
224 geometry
= mlt_properties_get_data(filter_properties
, "filter_geometry", NULL
);
227 // Get the current geometry item
228 mlt_geometry_item geometry_item
= mlt_pool_alloc( sizeof( struct mlt_geometry_item_s
) );
229 mlt_geometry_fetch(geometry
, geometry_item
, position
);
231 mlt_properties_set_data( frame_properties
, "bounds", geometry_item
, sizeof( struct mlt_geometry_item_s
), mlt_pool_release
, NULL
);
234 int error
= mlt_frame_get_image( frame
, image
, format
, width
, height
, 1 );
237 mlt_properties_debug( frame_properties
, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr
);
242 /** Filter processing.
245 static mlt_frame
filter_process( mlt_filter
this, mlt_frame frame
)
248 /* modify the frame with the current geometry */
249 mlt_frame_push_service( frame
, this);
250 mlt_frame_push_get_image( frame
, attach_boundry_to_frame
);
254 /* apply the motion estimation filter */
255 mlt_filter motion_est
= mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_motion_est", NULL
);
256 mlt_filter_process( motion_est
, frame
);
260 /* calculate the new geometry based on the motion */
261 mlt_frame_push_service( frame
, this);
262 mlt_frame_push_get_image( frame
, filter_get_image
);
265 /* visualize the motion vectors */
266 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 )
268 mlt_filter vismv
= mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_vismv", NULL
);
271 mlt_profile profile
= mlt_service_profile( MLT_FILTER_SERVICE( this ) );
272 vismv
= mlt_factory_filter( profile
, "vismv", NULL
);
273 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv
, 0, (mlt_destructor
)mlt_filter_close
, NULL
);
276 mlt_filter_process( vismv
, frame
);
279 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 )
281 mlt_filter obscure
= mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_obscure", NULL
);
282 if( obscure
== NULL
)
284 mlt_profile profile
= mlt_service_profile( MLT_FILTER_SERVICE( this ) );
285 obscure
= mlt_factory_filter( profile
, "obscure", NULL
);
286 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_obscure", obscure
, 0, (mlt_destructor
)mlt_filter_close
, NULL
);
289 mlt_filter_process( obscure
, frame
);
295 /** Constructor for the filter.
299 mlt_filter
filter_autotrack_rectangle_init( mlt_profile profile
, mlt_service_type type
, const char *id
, char *arg
)
301 mlt_filter
this = mlt_filter_new( );
304 this->process
= filter_process
;
306 // Initialize with the supplied geometry if ther is one
308 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg
);
310 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100,100:100x100" );
312 // create an instance of the motion_est and obscure filter
313 mlt_filter motion_est
= mlt_factory_filter( profile
, "motion_est", NULL
);
314 if( motion_est
!= NULL
)
315 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est
, 0, (mlt_destructor
)mlt_filter_close
, NULL
);
317 mlt_filter_close( this );
327 /** This source code will self destruct in 5...4...3...