static void deserialize_vectors( videostab self, char *vectors, mlt_position length ) { mlt_geometry g = mlt_geometry_init(); // Parse the property as a geometry if ( g && !mlt_geometry_parse( g, vectors, length, -1, -1 ) ) { struct mlt_geometry_item_s item; int i; // Copy the geometry items to a vc array for interp() for ( i = 0; i < length; i++ ) { mlt_geometry_fetch( g, &item, i ); self->pos_h[i].x = item.x; self->pos_h[i].y = item.y; } } else { mlt_log_warning( MLT_FILTER_SERVICE(self->parent), "failed to parse vectors\n" ); } // We are done with this mlt_geometry if ( g ) mlt_geometry_close( g ); }
static int attach_boundry_to_frame( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter's property object mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position 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, "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 int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); if( error != 0 ) mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle attach_boundry_to_frame", stderr ); return error; }
static void geometry_calculate( mlt_transition transition, const char *store, struct mlt_geometry_item_s *output, double position ) { mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition ); mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); int mirror_off = mlt_properties_get_int( properties, "mirror_off" ); int repeat_off = mlt_properties_get_int( properties, "repeat_off" ); int length = mlt_geometry_get_length( geometry ); // Allow wrapping if ( !repeat_off && position >= length && length != 0 ) { int section = position / length; position -= section * length; if ( !mirror_off && section % 2 == 1 ) position = length - position; } // Fetch the key for the position mlt_geometry_fetch( geometry, output, position ); }
char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ) { geometry g = self->local; struct mlt_geometry_item_s item; char *ret = malloc( 1000 ); int used = 0; int size = 1000; if ( in == -1 ) in = 0; if ( out == -1 ) out = mlt_geometry_get_length( self ); if ( ret != NULL ) { char temp[ 100 ]; strcpy( ret, "" ); item.frame = in; while( 1 ) { strcpy( temp, "" ); // If it's the first frame, then it's not necessarily a key if ( item.frame == in ) { if ( mlt_geometry_fetch( self, &item, item.frame ) ) break; // If the first key is larger than the current position // then do nothing here if ( g->item->data.frame > item.frame ) { item.frame ++; continue; } // To ensure correct seeding, ensure all values are fixed item.f[0] = 1; item.f[1] = 1; item.f[2] = 1; item.f[3] = 1; item.f[4] = 1; } // Typically, we move from key to key else if ( item.frame < out ) { if ( mlt_geometry_next_key( self, &item, item.frame ) ) break; // Special case - crop at the out point if ( item.frame > out ) mlt_geometry_fetch( self, &item, out ); } // We've handled the last key else { break; } if ( item.frame - in != 0 ) sprintf( temp, "%d=", item.frame - in ); if ( item.f[0] ) sprintf( temp + strlen( temp ), "%g", item.x ); if ( item.f[1] ) { strcat( temp, "/" ); sprintf( temp + strlen( temp ), "%g", item.y ); } if ( item.f[2] ) { strcat( temp, ":" ); sprintf( temp + strlen( temp ), "%g", item.w ); } if ( item.f[3] ) { strcat( temp, "x" ); sprintf( temp + strlen( temp ), "%g", item.h ); } if ( item.f[4] ) { strcat( temp, ":" ); sprintf( temp + strlen( temp ), "%g", item.mix ); } if ( used + strlen( temp ) + 2 > size ) // +2 for ';' and NULL { size += 1000; ret = realloc( ret, size ); } if ( ret != NULL && used != 0 ) { used ++; strcat( ret, ";" ); } if ( ret != NULL ) { used += strlen( temp ); strcat( ret, temp ); } item.frame ++; } } return ret; }
int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *value ) { int ret = 0; // Get the local/private structure geometry g = self->local; if ( value != NULL && strcmp( value, "" ) ) { char *p = strchr( value, '=' ); int count = 0; double temp; // Determine if a position has been specified if ( p != NULL ) { temp = atof( value ); if ( temp > -1 && temp < 1 ) item->frame = temp * g->length; else item->frame = temp; value = p + 1; } // Special case - frame < 0 if ( item->frame < 0 ) item->frame += g->length; // Obtain the current value at this position - self allows new // frames to be created which don't specify all values mlt_geometry_fetch( self, item, item->frame ); // Special case - when an empty string is specified, all values are fixed // TODO: Check if this is logical - it's convenient, but it's also odd... if ( !*value ) { item->f[0] = 1; item->f[1] = 1; item->f[2] = 1; item->f[3] = 1; item->f[4] = 1; } // Iterate through the remainder of value while( *value ) { // Get the value temp = strtod( value, &p ); // Check if a value was specified if ( p != value ) { // Handle the % case if ( *p == '%' ) { if ( count == 0 || count == 2 ) temp *= g->nw / 100.0; else if ( count == 1 || count == 3 ) temp *= g->nh / 100.0; p ++; } // Special case - distort token if ( *p == '!' || *p == '*' ) { p ++; item->distort = 1; } // Actually, we don't care about the delimiter at all.. if ( *p ) p ++; // Assign to the item switch( count ) { case 0: item->x = temp; item->f[0] = 1; break; case 1: item->y = temp; item->f[1] = 1; break; case 2: item->w = temp; item->f[2] = 1; break; case 3: item->h = temp; item->f[3] = 1; break; case 4: item->mix = temp; item->f[4] = 1; break; } } else { p ++; } // Update the value pointer value = p; count ++; } } else { ret = 1; } return ret; }
// Image stack(able) method static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { // Get the filter object mlt_filter filter = mlt_frame_pop_service( frame ); // Get the filter's property object mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position 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 ); 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, "filter_geometry", NULL); // Get the current geometry item struct mlt_geometry_item_s boundry; mlt_geometry_fetch(geometry, &boundry, 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 && boundry.key != 1 ) // Paused? { int method = mlt_properties_get_int( filter_properties, "method" ); // Get the size of macroblocks in pixel units int macroblock_height = mlt_properties_get_int( frame_properties, "motion_est.macroblock_height" ); 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, *width, *height ); // 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_geometry_interpolate(geometry); } 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; }