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...