]> git.sesse.net Git - mlt/blobdiff - src/modules/motion_est/filter_autotrack_rectangle.c
Move burningtv into plusgpl module.
[mlt] / src / modules / motion_est / filter_autotrack_rectangle.c
index 87d36dd28d2ea3125059ccac9272b38dc1b72017..e6caff199b499973fd0121f570c20a50cfea2d12 100644 (file)
@@ -40,7 +40,9 @@ void caculate_motion( struct motion_vector_s *vectors,
                      int macroblock_width,
                      int macroblock_height,
                      int mv_buffer_width,
-                     int method )
+                     int method,
+                     int width,
+                     int height )
 {
 
 
@@ -90,6 +92,18 @@ void caculate_motion( struct motion_vector_s *vectors,
 
        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
@@ -106,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 );
@@ -114,8 +128,10 @@ 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;
@@ -124,6 +140,14 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format
        // 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 &&
            boundry.key != 1 ) // Paused?
@@ -136,7 +160,7 @@ 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 );
 
 
                // Make the geometry object a real boy
@@ -147,13 +171,63 @@ static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format
                boundry.f[3] = 1;
                boundry.f[4] = 1;
                mlt_geometry_insert(geometry, &boundry);
+               mlt_geometry_interpolate(geometry);
        }
 
-               if( mlt_properties_get_int( filter_properties, "debug" ) == 1 )
+       mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
+
+       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, "_serialize" ) == 1 )
+       {
+               // Add the vector change to the list
+               mlt_geometry key_frames = mlt_properties_get_data( filter_properties, "motion_vector_list", NULL );
+               if ( !key_frames )
+               {
+                       key_frames = mlt_geometry_init();
+                       mlt_properties_set_data( filter_properties, "motion_vector_list", key_frames, 0,
+                                                (mlt_destructor) mlt_geometry_close, (mlt_serialiser) mlt_geometry_serialise );
+                       if ( key_frames )
+                               mlt_geometry_set_length( key_frames, mlt_filter_get_length2( filter, frame ) );
+               }
+               if ( key_frames )
+               {
+                       struct mlt_geometry_item_s item;
+                       item.frame = (int) mlt_frame_get_position( frame );
+                       item.key = 1;
+                       item.x = boundry.x;
+                       item.y = boundry.y;
+                       item.w = boundry.w;
+                       item.h = boundry.h;
+                       item.mix = 0;
+                       item.f[0] = item.f[1] = item.f[2] = item.f[3] = 1;
+                       item.f[4] = 0;
+                       mlt_geometry_insert( key_frames, &item );
+               }
+       }
+       
+       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 )
+       {
+               fprintf( stderr, "%d,%d,%d,%d\n", (int)boundry.x, (int)boundry.y, (int)boundry.w, (int)boundry.h );
+               fflush( stdout );
+       }
 
        return error;
 }
@@ -170,15 +244,44 @@ 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);
+       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_geometry_interpolate( geom );
+               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);
 
+       // 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 );
 
        // Get the new image
@@ -199,15 +302,14 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
         /* modify the frame with the current geometry */
        mlt_frame_push_service( frame, this);
        mlt_frame_push_get_image( frame, attach_boundry_to_frame );
-
-
+       mlt_properties properties = MLT_FILTER_PROPERTIES( this );
 
        /* apply the motion estimation filter */
-       mlt_filter motion_est = mlt_properties_get_data( MLT_FILTER_PROPERTIES(this), "_motion_est", NULL ); 
+       mlt_filter motion_est = mlt_properties_get_data( properties, "_motion_est", NULL ); 
+       /* Pass motion_est properties */
+       mlt_properties_pass( MLT_FILTER_PROPERTIES( motion_est ), properties, "motion_est." );
        mlt_filter_process( motion_est, frame);
 
-
-
        /* calculate the new geometry based on the motion */
        mlt_frame_push_service( frame, this);
        mlt_frame_push_get_image( frame, filter_get_image );
@@ -216,15 +318,29 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
        /* visualize the motion vectors */
        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 );
-                       mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "_vismv", vismv, 0, (mlt_destructor)mlt_filter_close, NULL );
+               mlt_filter vismv = mlt_properties_get_data( properties, "_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( properties, "_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( properties, "_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( properties, "_obscure", obscure, 0, (mlt_destructor)mlt_filter_close, NULL );
+               }
+
+               mlt_filter_process( obscure, frame );
+       }
 
        return frame;
 }
@@ -233,36 +349,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 );
-
-               }
-
-               // ... and attach it to the frame
-               mlt_properties_set_data( MLT_FILTER_PROPERTIES(this), "geometry", geometry, 0, (mlt_destructor)mlt_geometry_close, (mlt_serialiser)mlt_geometry_serialise );
-
-               // create an instance of the motion_est filter
-               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 {