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"
25 #include <framework/mlt.h>
32 #define MIN(a,b) ((a) > (b) ? (b) : (a))
34 #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
35 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
38 static inline int clip(int a, int amin, int amax)
50 * draws an line from (ex, ey) -> (sx, sy).
51 * Credits: modified from ffmpeg project
52 * @param ystride stride/linesize of the image
53 * @param xstride stride/element size of the image
54 * @param color color of the arrow
56 static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, int w, int h, int xstride, int ystride, int color){
59 // buf[sy*ystride + sx*xstride]= color;
60 buf[sy*ystride + sx]+= color;
67 if(ABS(ex - sx) > ABS(ey - sy)){
72 buf+= sx*xstride + sy*ystride;
75 for(x= 0; x <= ex; x++){
78 buf[ y *ystride + x*xstride]= (color*(0x10000-fr))>>16;
79 buf[(y+1)*ystride + x*xstride]= (color* fr )>>16;
86 buf+= sx*xstride + sy*ystride;
88 if(ey) f= ((ex-sx)<<16)/ey;
90 for(y= 0; y <= ey; y++){
93 buf[y*ystride + x *xstride]= (color*(0x10000-fr))>>16;;
94 buf[y*ystride + (x+1)*xstride]= (color* fr )>>16;;
100 * draws an arrow from (ex, ey) -> (sx, sy).
101 * Credits: modified from ffmpeg project
102 * @param stride stride/linesize of the image
103 * @param color color of the arrow
105 static __attribute__((used)) void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int w, int h, int xstride, int ystride, int color){
108 // sx= clip(sx, -100, w+100);
109 // sy= clip(sy, -100, h+100);
110 // ex= clip(ex, -100, w+100);
111 // ey= clip(ey, -100, h+100);
116 if(dx*dx + dy*dy > 3*3){
119 int length= sqrt((rx*rx + ry*ry)<<8);
121 //FIXME subpixel accuracy
122 rx= ROUNDED_DIV(rx*3<<4, length);
123 ry= ROUNDED_DIV(ry*3<<4, length);
125 draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, xstride, ystride, color);
126 draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, xstride, ystride, color);
128 draw_line(buf, sx, sy, ex, ey, w, h, xstride, ystride, color);
131 void caculate_motion( struct motion_vector_s *vectors,
132 mlt_geometry_item boundry,
133 int macroblock_width,
134 int macroblock_height,
140 // translate pixel units (from bounds) to macroblock units
141 // make sure whole macroblock stay within bounds
143 int left_mb = boundry->x / macroblock_width;
144 left_mb += ( (int)boundry->x % macroblock_width == 0 ) ? 0 : 1 ;
145 int top_mb = boundry->y / macroblock_height;
146 top_mb += ( (int)boundry->y % macroblock_height == 0 ) ? 0 : 1 ;
148 int right_mb = (boundry->x + boundry->w + 1) / macroblock_width;
149 right_mb -= ( (int)(boundry->x + boundry->w + 1) % macroblock_width == 0 ) ? 0 : 1 ;
150 int bottom_mb = (boundry->y + boundry->h + 1) / macroblock_height;
151 bottom_mb -= ( (int)(boundry->y + boundry->h + 1) % macroblock_height == 0 ) ? 0 : 1 ;
155 int average_x = 0, average_y = 0;
157 #define CURRENT ( vectors + j*mv_buffer_width + i )
159 for( i = left_mb; i <= right_mb; i++ ){
160 for( j = top_mb; j <= bottom_mb; j++ ){
164 average_x += CURRENT->dx;
165 average_y += CURRENT->dy;
175 int average2_x = 0, average2_y = 0;
176 for( i = left_mb; i <= right_mb; i++ ){
177 for( j = top_mb; j <= bottom_mb; j++ ){
179 if( ABS(CURRENT->dx - average_x) < 5 &&
180 ABS(CURRENT->dy - average_y) < 5 )
182 average2_x += CURRENT->dx;
183 average2_y += CURRENT->dy;
188 boundry->x -= average2_x/n;
189 boundry->y -= average2_y/n;
194 // Image stack(able) method
195 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
198 // Get the filter object
199 mlt_filter filter = mlt_frame_pop_service( frame );
201 // Get the filter's property object
202 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
204 // Get the frame properties
205 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
207 // Get the frame position
208 mlt_position position = mlt_frame_get_position( frame );
211 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
214 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr );
216 // Get the geometry object
217 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
219 // Get the current geometry item
220 struct mlt_geometry_item_s boundry;
221 mlt_geometry_fetch(geometry, &boundry, position);
222 //fprintf(stderr, "process %d\n", position);
224 // Get the motion vectors
225 struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL );
227 // How did the rectangle move?
228 if( vectors != NULL ) {
230 int method = mlt_properties_get_int( filter_properties, "method" );
232 // Get the size of macroblocks in pixel units
233 int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" );
234 int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" );
235 int mv_buffer_width = *width / macroblock_width;
237 caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method );
249 // boundry.frame = position;
251 mlt_geometry_insert(geometry, &boundry);
254 if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
258 // Calculate the size of our steps (the number of bytes that seperate adjacent pixels in X and Y direction)
260 case mlt_image_yuv422:
262 ystep = xstep * *width;
270 draw_line(*image, boundry.x, boundry.y, boundry.x, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff);
271 draw_line(*image, boundry.x, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff);
272 draw_line(*image, boundry.x + boundry.w, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y, *width, *height, xstep, ystep, 0xff);
273 draw_line(*image, boundry.x + boundry.w, boundry.y, boundry.x, boundry.y, *width, *height, xstep, ystep, 0xff);
279 static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
281 // Get the filter object
282 mlt_filter filter = mlt_frame_pop_service( frame );
284 // Get the filter's property object
285 mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
287 // Get the frame properties
288 mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
290 // Get the frame position
291 mlt_position position = mlt_frame_get_position( frame );
293 // gEt the geometry object
294 mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
296 // Get the current geometry item
297 mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) );
298 mlt_geometry_fetch(geometry, geometry_item, position);
299 //fprintf(stderr, "attach %d\n", position);
301 mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );
304 int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
307 mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr );
312 /** Filter processing.
315 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
318 //mlt_properties_debug(MLT_SERVICE_PROPERTIES(mlt_service_consumer(mlt_filter_service(this))), "consumer!", stderr);
321 /* modify the frame with the current geometry */
322 mlt_frame_push_service( frame, this);
323 mlt_frame_push_get_image( frame, attach_boundry_to_frame );
327 /* apply the motion estimation filter */
328 mlt_filter motion_est = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_motion_est", NULL );
329 mlt_filter_process( motion_est, frame);
333 /* calculate the new geometry based on the motion */
334 mlt_frame_push_service( frame, this);
335 mlt_frame_push_get_image( frame, filter_get_image );
338 /* visualize the motion vectors */
339 if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 )
341 mlt_filter vismv = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_vismv", NULL );
342 if( vismv == NULL ) {
343 vismv = mlt_factory_filter( "vismv", NULL );
344 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL );
347 mlt_filter_process( vismv, frame );
354 /** Constructor for the filter.
358 mlt_filter filter_autotrack_rectangle_init( char *arg )
360 mlt_filter this = mlt_filter_new( );
363 this->process = filter_process;
366 mlt_geometry geometry = mlt_geometry_init();
368 // Initialize with the supplied geometry
371 struct mlt_geometry_item_s item;
373 mlt_geometry_parse_item( geometry, &item, arg );
379 mlt_geometry_insert( geometry, &item );
383 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "geometry", geometry, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
385 mlt_filter motion_est = mlt_factory_filter("motion_est", NULL);
386 if( motion_est != NULL )
387 mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL );
389 mlt_filter_close( this );
393 //mlt_events_init( this );
394 //mlt_events_listen(mlt_service_consumer(mlt_filter_service(this)
400 /** This source code will self destruct in 5...4...3...