*/
#include "filter_motion_est.h"
+#include "arrow_code.h"
#include <framework/mlt.h>
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
#define ABS(a) ((a) >= 0 ? (a) : (-(a)))
-// ffmpeg borrowed
-static inline int clip(int a, int amin, int amax)
-{
- if (a < amin)
- return amin;
- else if (a > amax)
- return amax;
- else
- return a;
-}
-
-
-/**
- * draws an line from (ex, ey) -> (sx, sy).
- * Credits: modified from ffmpeg project
- * @param ystride stride/linesize of the image
- * @param xstride stride/element size of the image
- * @param color color of the arrow
- */
-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){
- int t, x, y, fr, f;
-
-// buf[sy*ystride + sx*xstride]= color;
- buf[sy*ystride + sx]+= color;
-
- sx= clip(sx, 0, w-1);
- sy= clip(sy, 0, h-1);
- ex= clip(ex, 0, w-1);
- ey= clip(ey, 0, h-1);
-
- if(ABS(ex - sx) > ABS(ey - sy)){
- if(sx > ex){
- t=sx; sx=ex; ex=t;
- t=sy; sy=ey; ey=t;
- }
- buf+= sx*xstride + sy*ystride;
- ex-= sx;
- f= ((ey-sy)<<16)/ex;
- for(x= 0; x <= ex; x++){
- y = (x*f)>>16;
- fr= (x*f)&0xFFFF;
- buf[ y *ystride + x*xstride]= (color*(0x10000-fr))>>16;
- buf[(y+1)*ystride + x*xstride]= (color* fr )>>16;
- }
- }else{
- if(sy > ey){
- t=sx; sx=ex; ex=t;
- t=sy; sy=ey; ey=t;
- }
- buf+= sx*xstride + sy*ystride;
- ey-= sy;
- if(ey) f= ((ex-sx)<<16)/ey;
- else f= 0;
- for(y= 0; y <= ey; y++){
- x = (y*f)>>16;
- fr= (y*f)&0xFFFF;
- buf[y*ystride + x *xstride]= (color*(0x10000-fr))>>16;;
- buf[y*ystride + (x+1)*xstride]= (color* fr )>>16;;
- }
- }
-}
-
-/**
- * draws an arrow from (ex, ey) -> (sx, sy).
- * Credits: modified from ffmpeg project
- * @param stride stride/linesize of the image
- * @param color color of the arrow
- */
-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){
- int dx,dy;
-
-// sx= clip(sx, -100, w+100);
-// sy= clip(sy, -100, h+100);
-// ex= clip(ex, -100, w+100);
-// ey= clip(ey, -100, h+100);
-
- dx= ex - sx;
- dy= ey - sy;
-
- if(dx*dx + dy*dy > 3*3){
- int rx= dx + dy;
- int ry= -dx + dy;
- int length= sqrt((rx*rx + ry*ry)<<8);
-
- //FIXME subpixel accuracy
- rx= ROUNDED_DIV(rx*3<<4, length);
- ry= ROUNDED_DIV(ry*3<<4, length);
-
- draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, xstride, ystride, color);
- draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, xstride, ystride, color);
- }
- draw_line(buf, sx, sy, ex, ey, w, h, xstride, ystride, color);
-}
-
void caculate_motion( struct motion_vector_s *vectors,
mlt_geometry_item boundry,
int macroblock_width,
int macroblock_height,
int mv_buffer_width,
- int method )
+ int method,
+ int width,
+ int height )
{
// translate pixel units (from bounds) to macroblock units
// make sure whole macroblock stay within bounds
- // I know; it hurts.
- int left_mb = boundry->x / macroblock_width;
- left_mb += ( (int)boundry->x % macroblock_width == 0 ) ? 0 : 1 ;
- int top_mb = boundry->y / macroblock_height;
- top_mb += ( (int)boundry->y % macroblock_height == 0 ) ? 0 : 1 ;
-
- int right_mb = (boundry->x + boundry->w + 1) / macroblock_width;
- right_mb -= ( (int)(boundry->x + boundry->w + 1) % macroblock_width == 0 ) ? 0 : 1 ;
- int bottom_mb = (boundry->y + boundry->h + 1) / macroblock_height;
- bottom_mb -= ( (int)(boundry->y + boundry->h + 1) % macroblock_height == 0 ) ? 0 : 1 ;
+ int left_mb = ( boundry->x + macroblock_width - 1 ) / macroblock_width;
+ int top_mb = ( boundry->y + macroblock_height - 1 ) / macroblock_height;
+ int right_mb = ( boundry->x + boundry->w ) / macroblock_width - 1;
+ int bottom_mb = ( boundry->y + boundry->h ) / macroblock_height - 1;
int i, j, n = 0;
#define CURRENT ( vectors + j*mv_buffer_width + i )
for( i = left_mb; i <= right_mb; i++ ){
- for( j = top_mb; j <= bottom_mb; j++ ){
-
+ for( j = top_mb; j <= bottom_mb; j++ )
+ {
n++;
-
average_x += CURRENT->dx;
average_y += CURRENT->dy;
}
}
- if ( n == 0 )
- return;
+ if ( n == 0 ) return;
average_x /= n;
average_y /= n;
+ n = 0;
int average2_x = 0, average2_y = 0;
for( i = left_mb; i <= right_mb; i++ ){
for( j = top_mb; j <= bottom_mb; j++ ){
- if( ABS(CURRENT->dx - average_x) < 5 &&
- ABS(CURRENT->dy - average_y) < 5 )
+ if( ABS(CURRENT->dx - average_x) < 3 &&
+ ABS(CURRENT->dy - average_y) < 3 )
{
+ n++;
average2_x += CURRENT->dx;
average2_y += CURRENT->dy;
}
}
}
-
- boundry->x -= average2_x/n;
- boundry->y -= average2_y/n;
+ if ( n == 0 ) return;
+
+ boundry->x -= (double)average2_x / (double)n;
+ boundry->y -= (double)average2_y / (double)n;
+
+ if ( boundry->x < 0 )
+ boundry->x = 0;
+ if ( boundry->y < 0 )
+ boundry->y = 0;
+
+ if ( boundry->x + boundry->w > width )
+ boundry->x = width - boundry->w;
+
+ if ( boundry->y + boundry->h > height )
+ boundry->y = height - boundry->h;
}
// Image stack(able) method
// Get the current geometry item
struct mlt_geometry_item_s boundry;
mlt_geometry_fetch(geometry, &boundry, position);
-//fprintf(stderr, "process %d\n", position);
// Get the motion vectors
struct motion_vector_s *vectors = mlt_properties_get_data( frame_properties, "motion_est.vectors", NULL );
-
+
// How did the rectangle move?
- if( vectors != NULL ) {
+ if( vectors != NULL &&
+ boundry.key != 1 ) // Paused?
+ {
int method = mlt_properties_get_int( filter_properties, "method" );
int macroblock_width = mlt_properties_get_int( frame_properties, "motion_est.macroblock_width" );
int mv_buffer_width = *width / macroblock_width;
- caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method );
-
- }
+ caculate_motion( vectors, &boundry, macroblock_width, macroblock_height, mv_buffer_width, method, *width, *height );
- boundry.key = 1;
- boundry.f[0] = 1;
- boundry.f[1] = 1;
- boundry.f[2] = 1;
- boundry.f[3] = 1;
- boundry.f[4] = 1;
-
-// boundry.frame = position;
-
- mlt_geometry_insert(geometry, &boundry);
+ // Make the geometry object a real boy
+ boundry.key = 1;
+ boundry.f[0] = 1;
+ boundry.f[1] = 1;
+ boundry.f[2] = 1;
+ boundry.f[3] = 1;
+ boundry.f[4] = 1;
+ mlt_geometry_insert(geometry, &boundry);
+ }
+ if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
+ {
+ init_arrows( format, *width, *height );
+ draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100);
+ }
- if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
+ if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 )
{
- int xstep, ystep;
-
- // Calculate the size of our steps (the number of bytes that seperate adjacent pixels in X and Y direction)
- switch( *format ) {
- case mlt_image_yuv422:
- xstep = 2;
- ystep = xstep * *width;
- break;
- default:
- // I don't know
- return -1;
- break;
- }
+ mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL );
- draw_line(*image, boundry.x, boundry.y, boundry.x, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff);
- draw_line(*image, boundry.x, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y + boundry.h, *width, *height, xstep, ystep, 0xff);
- draw_line(*image, boundry.x + boundry.w, boundry.y + boundry.h, boundry.x + boundry.w, boundry.y, *width, *height, xstep, ystep, 0xff);
- draw_line(*image, boundry.x + boundry.w, boundry.y, boundry.x, boundry.y, *width, *height, xstep, ystep, 0xff);
+ mlt_properties_pass_list( MLT_FILTER_PROPERTIES(obscure), filter_properties, "in, out");
+ // Because filter_obscure needs to be rewritten to use mlt_geometry
+ char geom[100];
+ sprintf( geom, "%d,%d:%dx%d", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
+ mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "start", geom );
+ mlt_properties_set( MLT_FILTER_PROPERTIES( obscure ), "end", geom );
}
+
+ if( mlt_properties_get_int( filter_properties, "collect" ) == 1 )
+ {
+ printf( "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
+ fflush( stdout );
+ }
+
return error;
}
// Get the frame position
mlt_position position = mlt_frame_get_position( frame );
- // gEt the geometry object
+ // Get the geometry object
mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
// Get the current geometry item
mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) );
mlt_geometry_fetch(geometry, geometry_item, position);
-//fprintf(stderr, "attach %d\n", position);
mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );
static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
{
- //mlt_properties_debug(MLT_SERVICE_PROPERTIES(mlt_service_consumer(mlt_filter_service(this))), "consumer!", stderr);
-
-
/* modify the frame with the current geometry */
mlt_frame_push_service( frame, this);
mlt_frame_push_get_image( frame, attach_boundry_to_frame );
if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "debug" ) == 1 )
{
mlt_filter vismv = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_vismv", NULL );
- if( vismv == NULL ) {
+ if( vismv == NULL )
+ {
vismv = mlt_factory_filter( "vismv", NULL );
mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL );
}
mlt_filter_process( vismv, frame );
}
+ if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(this), "obscure" ) == 1 )
+ {
+ mlt_filter obscure = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_obscure", NULL );
+ if( obscure == NULL )
+ {
+ obscure = mlt_factory_filter( "obscure", NULL );
+ mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL );
+ }
+
+ mlt_filter_process( obscure, frame );
+ }
return frame;
}
}
+ // ... and attach it to the filter
mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "geometry", geometry, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
- mlt_filter motion_est = mlt_factory_filter("motion_est", NULL);
+ // create an instance of the motion_est and obscure filter
+ mlt_filter motion_est = mlt_factory_filter( "motion_est", NULL );
if( motion_est != NULL )
mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_motion_est", motion_est, 0, (mlt_destructor)mlt_filter_close, NULL );
else {
return NULL;
}
- //mlt_events_init( this );
- //mlt_events_listen(mlt_service_consumer(mlt_filter_service(this)
+
}
return this;