]> git.sesse.net Git - mlt/blobdiff - src/modules/motion_est/filter_autotrack_rectangle.c
Use '/' for coordinate delimiter instead of period.
[mlt] / src / modules / motion_est / filter_autotrack_rectangle.c
index 90efadbb97fcf0c06f6f9112fff7735d1cf85d6d..b5b0022f448d4c805601449523471ed66017a02c 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #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;
 
@@ -157,38 +60,50 @@ void caculate_motion( struct motion_vector_s *vectors,
        #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
@@ -205,7 +120,7 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format
        mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
 
        // Get the frame position
-       mlt_position position = mlt_frame_get_position( frame );
+       mlt_position position = mlt_filter_get_position( filter, frame );
 
        // Get the new image
        int error = mlt_frame_get_image( frame, image, format, width, height, 1 );
@@ -213,19 +128,30 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format
        if( error != 0 )
                mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr );
 
+       mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
+
        // Get the geometry object
-       mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
+       mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
 
        // 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 );
-                
+
+       // Cleanse the geometry item
+       boundry.w = boundry.x < 0 ? boundry.w + boundry.x : boundry.w;
+       boundry.h = boundry.y < 0 ? boundry.h + boundry.y : boundry.h;
+       boundry.x = boundry.x < 0 ? 0 : boundry.x;
+       boundry.y = boundry.y < 0 ? 0 : boundry.y;
+       boundry.w = boundry.w < 0 ? 0 : boundry.w;
+       boundry.h = boundry.h < 0 ? 0 : boundry.h;
+
        // How did the rectangle move?
-       if( vectors != NULL ) {
+       if( vectors != NULL &&
+           boundry.key != 1 ) // Paused?
+       {
 
                int method = mlt_properties_get_int( filter_properties, "method" );
 
@@ -234,45 +160,46 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format
                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);
+       }
 
+       mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
 
        if( mlt_properties_get_int( filter_properties, "debug" ) == 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;
-               }
+               init_arrows( format, *width, *height );
+               draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100);
+       }        
 
-               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);
+       if( mlt_properties_get_int( filter_properties, "obscure" ) == 1 )
+       {
+               mlt_filter obscure = mlt_properties_get_data( filter_properties, "_obscure", NULL );
 
+               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;
 }
 
@@ -288,15 +215,42 @@ static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_
        mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame);
 
        // Get the frame position
-       mlt_position position = mlt_frame_get_position( frame );
+       mlt_position position = mlt_filter_get_position( filter, frame );
+       
+       mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
 
-       // gEt the geometry object
-       mlt_geometry geometry = mlt_properties_get_data(filter_properties, "geometry", NULL);
+       // Get the geometry object
+       mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
+       if (geometry == NULL) {
+               mlt_geometry geom = mlt_geometry_init();
+               char *arg = mlt_properties_get(filter_properties, "geometry");
+
+               // Initialize with the supplied geometry
+               struct mlt_geometry_item_s item;
+               mlt_geometry_parse_item( geom, &item, arg  );
+
+               item.frame = 0;
+               item.key = 1;
+               item.mix = 100;
+
+               mlt_geometry_insert( geom, &item );
+               mlt_properties_set_data( filter_properties, "filter_geometry", geom, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
+               geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL);
+       }
+
+       mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
 
        // 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);
+
+       // Cleanse the geometry item
+       geometry_item->w = geometry_item->x < 0 ? geometry_item->w + geometry_item->x : geometry_item->w;
+       geometry_item->h = geometry_item->y < 0 ? geometry_item->h + geometry_item->y : geometry_item->h;
+       geometry_item->x = geometry_item->x < 0 ? 0 : geometry_item->x;
+       geometry_item->y = geometry_item->y < 0 ? 0 : geometry_item->y;
+       geometry_item->w = geometry_item->w < 0 ? 0 : geometry_item->w;
+       geometry_item->h = geometry_item->h < 0 ? 0 : geometry_item->h;
 
        mlt_properties_set_data( frame_properties, "bounds", geometry_item, sizeof( struct mlt_geometry_item_s ), mlt_pool_release, NULL );
 
@@ -315,9 +269,6 @@ static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_
 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 );
@@ -339,14 +290,28 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame 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 ) {
-                       vismv = mlt_factory_filter( "vismv", NULL );
+               if( vismv == NULL )
+               {
+                       mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) );
+                       vismv = mlt_factory_filter( profile, "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 )
+               {
+                       mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) );
+                       obscure = mlt_factory_filter( profile, "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;
 }
@@ -355,34 +320,21 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
 */
 
 
-mlt_filter filter_autotrack_rectangle_init( char *arg )
+mlt_filter filter_autotrack_rectangle_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
 {
        mlt_filter this = mlt_filter_new( );
        if ( this != NULL )
        {
                this->process = filter_process;
 
+               // Initialize with the supplied geometry if ther is one
+               if( arg != NULL ) 
+                       mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", arg );
+               else
+                       mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "geometry", "100/100:100x100" );
 
-               mlt_geometry geometry = mlt_geometry_init();
-
-               // Initialize with the supplied geometry
-               if( arg != NULL ) {
-
-                       struct mlt_geometry_item_s item;
-
-                       mlt_geometry_parse_item( geometry, &item, arg  );
-
-                       item.frame = 0;
-                       item.key = 1;
-                       item.mix = 100;
-
-                       mlt_geometry_insert( geometry, &item );
-
-               }
-
-               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( profile, "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 {
@@ -390,8 +342,7 @@ mlt_filter filter_autotrack_rectangle_init( char *arg )
                        return NULL;
                }
 
-               //mlt_events_init( this );
-               //mlt_events_listen(mlt_service_consumer(mlt_filter_service(this)
+
        }
 
        return this;