}
else
{
- mlt_properties properties = mlt_producer_properties( this );
- mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
- int count = mlt_properties_get_int( properties, "_filter_count" );
- int i;
-
// Get the frame from the implementation
result = this->get_frame( this, frame, index );
-
- // Process the frame with the attached filters
- for ( i = 0; i < count; i ++ )
- if ( filters[ i ] != NULL )
- mlt_filter_process( filters[ i ], *frame );
}
// Copy the fps and speed of the producer onto the frame
int mlt_producer_attach( mlt_producer this, mlt_filter filter )
{
- int error = this == NULL || filter == NULL;
- if ( error == 0 )
- {
- int i = 0;
- int size = 0;
- mlt_properties properties = mlt_producer_properties( this );
- mlt_filter *filters = mlt_properties_get_data( properties, "_filters", &size );
- int count = mlt_properties_get_int( properties, "_filter_count" );
-
- for ( i = 0; error == 0 && i < count; i ++ )
- if ( filters[ i ] == filter )
- error = 1;
-
- if ( error == 0 )
- {
- if ( count == size )
- {
- size += 10;
- filters = realloc( filters, size * sizeof( mlt_filter ) );
- mlt_properties_set_data( properties, "_filters", filters, size, NULL, NULL );
- }
-
- if ( filters != NULL )
- {
- mlt_properties_inc_ref( mlt_filter_properties( filter ) );
- filters[ count ++ ] = filter;
- mlt_properties_set_int( properties, "_filter_count", count );
- }
- else
- {
- error = 2;
- }
- }
- }
- return error;
+ return mlt_service_attach( mlt_producer_service( this ), filter );
}
/** Detach a filter.
int mlt_producer_detach( mlt_producer this, mlt_filter filter )
{
- int error = this == NULL || filter == NULL;
- if ( error == 0 )
- {
- int i = 0;
- int size = 0;
- mlt_properties properties = mlt_producer_properties( this );
- mlt_filter *filters = mlt_properties_get_data( properties, "_filters", &size );
- int count = mlt_properties_get_int( properties, "_filter_count" );
-
- for ( i = 0; i < count; i ++ )
- if ( filters[ i ] == filter )
- break;
-
- if ( i < count )
- {
- mlt_filter filter = filters[ i ];
- filters[ i ] = NULL;
- for ( i ++ ; i < count; i ++ )
- filters[ i - 1 ] = filters[ i ];
- mlt_properties_set_int( properties, "_filter_count", -- count );
- mlt_filter_close( filter );
- }
- }
- return error;
+ return mlt_service_detach( mlt_producer_service( this ), filter );
}
/** Retrieve a filter.
mlt_filter mlt_producer_filter( mlt_producer this, int index )
{
- mlt_filter filter = NULL;
- if ( this != NULL )
- {
- mlt_properties properties = mlt_producer_properties( this );
- mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
- int count = mlt_properties_get_int( properties, "_filter_count" );
- if ( index >= 0 && index < count )
- filter = filters[ index ];
- }
- return filter;
+ return mlt_service_filter( mlt_producer_service( this ), index );
}
/** Close the producer.
{
if ( this != NULL && mlt_properties_dec_ref( mlt_producer_properties( this ) ) <= 0 )
{
- mlt_properties properties = mlt_producer_properties( this );
- mlt_filter *filters = mlt_properties_get_data( properties, "_filters", NULL );
- int count = mlt_properties_get_int( properties, "_filter_count" );
-
- while( count -- )
- mlt_producer_detach( this, filters[ 0 ] );
-
this->parent.close = NULL;
if ( this->close != NULL )
#include "config.h"
#include "mlt_service.h"
+#include "mlt_filter.h"
#include "mlt_frame.h"
#include <stdio.h>
#include <stdlib.h>
int count;
mlt_service *in;
mlt_service out;
+ int filter_count;
+ int filter_size;
+ mlt_filter *filters;
}
mlt_service_base;
return self != NULL ? &self->parent : NULL;
}
+/** Recursively apply attached filters
+*/
+
+static void apply_filters( mlt_service this, mlt_frame frame, int index )
+{
+ mlt_properties properties = mlt_service_properties( this );
+ mlt_service_base *base = this->local;
+ int i;
+
+ if ( mlt_properties_get_int( properties, "_filter_private" ) == 0 )
+ {
+ // Process the frame with the attached filters
+ for ( i = 0; i < base->filter_count; i ++ )
+ {
+ if ( base->filters[ i ] != NULL )
+ {
+ mlt_filter_process( base->filters[ i ], frame );
+ apply_filters( mlt_filter_service( base->filters[ i ] ), frame, index );
+ }
+ }
+ }
+}
+
/** Obtain a frame.
*/
int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index )
{
if ( this != NULL )
- return this->get_frame( this, frame, index );
+ {
+ int result = this->get_frame( this, frame, index );
+ if ( result == 0 )
+ apply_filters( this, *frame, index );
+ return result;
+ }
*frame = mlt_frame_init( );
return 0;
}
+/** Attach a filter.
+*/
+
+int mlt_service_attach( mlt_service this, mlt_filter filter )
+{
+ int error = this == NULL || filter == NULL;
+ if ( error == 0 )
+ {
+ int i = 0;
+ mlt_properties properties = mlt_service_properties( this );
+ mlt_service_base *base = this->local;
+
+ for ( i = 0; error == 0 && i < base->filter_count; i ++ )
+ if ( base->filters[ i ] == filter )
+ error = 1;
+
+ if ( error == 0 )
+ {
+ if ( base->filter_count == base->filter_size )
+ {
+ base->filter_size += 10;
+ base->filters = realloc( base->filters, base->filter_size * sizeof( mlt_filter ) );
+ }
+
+ if ( base->filters != NULL )
+ {
+ mlt_properties_inc_ref( mlt_filter_properties( filter ) );
+ base->filters[ base->filter_count ++ ] = filter;
+ mlt_events_fire( properties, "service-changed", NULL );
+ }
+ else
+ {
+ error = 2;
+ }
+ }
+ }
+ return error;
+}
+
+/** Detach a filter.
+*/
+
+int mlt_service_detach( mlt_service this, mlt_filter filter )
+{
+ int error = this == NULL || filter == NULL;
+ if ( error == 0 )
+ {
+ int i = 0;
+ mlt_service_base *base = this->local;
+ mlt_properties properties = mlt_service_properties( this );
+
+ for ( i = 0; i < base->filter_count; i ++ )
+ if ( base->filters[ i ] == filter )
+ break;
+
+ if ( i < base->filter_count )
+ {
+ base->filters[ i ] = NULL;
+ for ( i ++ ; i < base->filter_count; i ++ )
+ base->filters[ i - 1 ] = base->filters[ i ];
+ base->filter_count --;
+ mlt_filter_close( filter );
+ mlt_events_fire( properties, "service-changed", NULL );
+ }
+ }
+ return error;
+}
+
+/** Retrieve a filter.
+*/
+
+mlt_filter mlt_service_filter( mlt_service this, int index )
+{
+ mlt_filter filter = NULL;
+ if ( this != NULL )
+ {
+ mlt_service_base *base = this->local;
+ if ( index >= 0 && index < base->filter_count )
+ filter = base->filters[ index ];
+ }
+ return filter;
+}
+
/** Close the service.
*/
{
mlt_service_base *base = this->local;
int i = 0;
+ int count = base->filter_count;
+ while( count -- )
+ mlt_service_detach( this, base->filters[ 0 ] );
+ free( base->filters );
for ( i = 0; i < base->count; i ++ )
if ( base->in[ i ] != NULL )
mlt_service_close( base->in[ i ] );
+ this->parent.close = NULL;
free( base->in );
free( base );
- this->parent.close = NULL;
mlt_properties_close( &this->parent );
}
}
extern mlt_properties mlt_service_properties( mlt_service self );
extern mlt_service mlt_service_consumer( mlt_service self );
extern mlt_service mlt_service_producer( mlt_service self );
+extern int mlt_service_attach( mlt_service self, mlt_filter filter );
+extern int mlt_service_detach( mlt_service self, mlt_filter filter );
+extern mlt_filter mlt_service_filter( mlt_service self, int index );
+
extern void mlt_service_close( mlt_service self );
// I'm not sure about self one - leaving it out of docs for now (only used in consumer_westley)
{
fprintf( stderr, "Usage: inigo [ -group [ name=value ]* ]\n"
" [ -consumer id[:arg] [ name=value ]* ]\n"
- " [ -filter id[:arg] [ name=value ] * ]\n"
+ " [ -filter filter[:arg] [ name=value ] * ]\n"
+ " [ -attach filter[:arg] [ name=value ] * ]\n"
" [ -transition id[:arg] [ name=value ] * ]\n"
" [ -blank frames ]\n"
" [ -track ]\n"
// Register with the filter
mlt_properties_set_data( properties, "_transition", transition, 0, ( mlt_destructor )mlt_transition_close, NULL );
+
+ // Pass a reference to this filter down
+ mlt_properties_set_data( mlt_transition_properties( transition ), "_region_filter", this, 0, NULL, NULL );
}
// Pass all properties down
// Resource defines the shape of the region
mlt_properties_set( properties, "resource", arg == NULL ? "rectangle" : arg );
+
+ // Ensure that attached filters are handled privately
+ mlt_properties_set_int( properties, "_filter_private", 1 );
}
// Return the filter
// Get the b frame and process with composite if successful
if ( mlt_service_get_frame( service, &b_frame, 0 ) == 0 )
- mlt_transition_process( composite, frame, b_frame );
-
- // Get the image
- error = mlt_frame_get_image( frame, image, format, width, height, 1 );
+ {
+ if ( mlt_properties_get_int( properties, "reverse" ) == 0 )
+ {
+ mlt_transition_process( composite, frame, b_frame );
+
+ // Get the image
+ error = mlt_frame_get_image( frame, image, format, width, height, 1 );
+ }
+ else
+ {
+ mlt_properties a_props = mlt_frame_properties( frame );
+ mlt_properties b_props = mlt_frame_properties( b_frame );
+ mlt_transition_process( composite, b_frame, frame );
+ mlt_properties_set( a_props, "rescale.interp", "nearest" );
+ mlt_properties_set( b_props, "rescale.interp", "nearest" );
+ mlt_properties_set_int( b_props, "consumer_aspect_ratio", 1 );
+ error = mlt_frame_get_image( b_frame, image, format, width, height, 1 );
+ mlt_properties_set_data( b_props, "image", *image, 0, NULL, NULL );
+ mlt_properties_set_data( a_props, "image", *image, *width * *height * 2, mlt_pool_release, NULL );
+ mlt_properties_set_int( a_props, "width", *width );
+ mlt_properties_set_int( a_props, "height", *height );
+ }
+ }
// Close the b frame
mlt_frame_close( b_frame );
return alpha;
}
+static void apply_filters( mlt_filter this, mlt_frame frame, int index )
+{
+ mlt_service service = mlt_filter_service( this );
+ mlt_properties properties = mlt_filter_properties( this );
+ int i;
+
+ if ( index == 0 || mlt_properties_get_int( properties, "_filter_private" ) == 0 )
+ {
+ mlt_filter filter = NULL;
+ for ( i = 0; ( filter = mlt_service_filter( service, i ) ) != NULL; i ++ )
+ {
+ mlt_filter_process( filter, frame );
+ apply_filters( filter, frame, 1 );
+ }
+ }
+}
+
/** Do it :-).
*/
filter = mlt_properties_get_data( properties, id, NULL );
}
+ // Allow filters to be attached to a region filter
+ filter = mlt_properties_get_data( properties, "_region_filter", NULL );
+ if ( filter != NULL )
+ apply_filters( filter, b_frame, 0 );
+
// Hmm - this is probably going to go wrong....
mlt_frame_set_position( frame, position );
double fps = this->is_pal ? 25 : 30000.0 / 1001.0;
if ( mlt_properties_get_double( properties, "fps" ) == fps )
{
- mlt_properties_set_position( properties, "length", this->frames_in_file );
- mlt_properties_set_position( properties, "in", 0 );
- mlt_properties_set_position( properties, "out", this->frames_in_file - 1 );
+ if ( this->frames_in_file > 0 )
+ {
+ mlt_properties_set_position( properties, "length", this->frames_in_file );
+ mlt_properties_set_position( properties, "in", 0 );
+ mlt_properties_set_position( properties, "out", this->frames_in_file - 1 );
+ }
}
else
{
return result;
}
+static mlt_filter create_attach( mlt_field field, char *id, int track )
+{
+ char *arg = strchr( id, ':' );
+ if ( arg != NULL )
+ *arg ++ = '\0';
+ mlt_filter filter = mlt_factory_filter( id, arg );
+ if ( filter != NULL )
+ track_service( field, filter, ( mlt_destructor )mlt_filter_close );
+ return filter;
+}
+
static mlt_filter create_filter( mlt_field field, char *id, int track )
{
char *arg = strchr( id, ':' );
if ( group != NULL )
properties = group;
}
+ else if ( !strcmp( argv[ i ], "-attach" ) )
+ {
+ mlt_filter filter = create_attach( field, argv[ ++ i ], track );
+ if ( filter != NULL )
+ {
+ if ( properties != NULL )
+ mlt_service_attach( ( mlt_service )properties, filter );
+ properties = mlt_filter_properties( filter );
+ mlt_properties_inherit( properties, group );
+ }
+ }
else if ( !strcmp( argv[ i ], "-filter" ) )
{
mlt_filter filter = create_filter( field, argv[ ++ i ], track );
// Get sample aspect ratio
this->aspect_ratio = mlt_properties_get_double( this->properties, "aspect_ratio" );
+
+ // Ensure we don't join on a non-running object
+ this->joined = 1;
// Default display aspect ratio
this->display_aspect = 4.0 / 3.0;
{
pthread_attr_t thread_attributes;
+ consumer_stop( parent );
+
this->running = 1;
this->joined = 0;
}
}
-static inline void serialise_producer_filters( serialise_context context, mlt_service service, xmlNode *node )
+static inline void serialise_service_filters( serialise_context context, mlt_service service, xmlNode *node )
{
int i;
xmlNode *p;
{
// Get a new id - if already allocated, do nothing
char *id = westley_get_id( context, mlt_filter_service( filter ), westley_filter );
- if ( id == NULL )
- continue;
-
- p = xmlNewChild( node, NULL, "filter", NULL );
- xmlNewProp( p, "id", id );
- serialise_properties( properties, p );
+ if ( id != NULL )
+ {
+ p = xmlNewChild( node, NULL, "filter", NULL );
+ xmlNewProp( p, "id", id );
+ serialise_properties( properties, p );
+ serialise_service_filters( context, mlt_filter_service( filter ), p );
+ }
}
}
}
// Set the id
xmlNewProp( child, "id", id );
serialise_properties( properties, child );
- serialise_producer_filters( context, service, child );
+ serialise_service_filters( context, service, child );
// Add producer to the map
mlt_properties_set_int( context->hide_map, id, mlt_properties_get_int( properties, "hide" ) );
if ( hide )
xmlNewProp( track, "hide", hide == 1 ? "video" : ( hide == 2 ? "audio" : "both" ) );
}
- serialise_producer_filters( context, service, child );
+ serialise_service_filters( context, service, child );
}
}
}
}
- serialise_producer_filters( context, service, child );
+ serialise_service_filters( context, service, child );
}
else if ( strcmp( (const char*) node->name, "tractor" ) != 0 )
{
// Recurse on connected producer
serialise_service( context, mlt_service_producer( service ), child );
- serialise_producer_filters( context, service, child );
+ serialise_service_filters( context, service, child );
}
}
xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
serialise_properties( properties, child );
+ serialise_service_filters( context, service, child );
}
}
xmlNewProp( child, "out", mlt_properties_get( properties, "out" ) );
serialise_properties( properties, child );
+ serialise_service_filters( context, service, child );
}
}