Hi.
For a long time, i wanted to introduce the region filter in Kdenlive. I am
almost ready on the Kdenlive GUI side, and here is the patch that fixes
several issues (mem leak & other problems) in the MLT region filter /
transition.
This patch makes the region filter work fine for me in multitrack playlists.
Not sure about using the transition region alone as I never really managed to
make it work, but my patch shouldn't make it worse..
For those not knowing it, a region filter example:
melt color:blue -attach region:+hello.txt in=0 out=200 a_track=0 b_track=1
filter0=sepia
will apply a sepia filter on a zone defined by the text "hello" over the blue
clip.
regards
jb
diff --git a/src/modules/core/filter_region.c b/src/modules/core/filter_region.c
index 8fd8e8d..16bc43b 100644
--- a/src/modules/core/filter_region.c
+++ b/src/modules/core/filter_region.c
@@ -30,10 +30,16 @@
/** Filter processing.
*/
-static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+
+static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
{
+ // Get the filter
+ mlt_filter this = mlt_frame_pop_service( frame );
+
// Get the properties of the filter
mlt_properties properties = MLT_FILTER_PROPERTIES( this );
+
+ mlt_service_lock( MLT_FILTER_SERVICE( this ) );
// Get the region transition
mlt_transition transition = mlt_properties_get_data( properties, "_transition", NULL );
@@ -51,14 +57,32 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
// Pass a reference to this filter down
mlt_properties_set_data( MLT_TRANSITION_PROPERTIES( transition ), "_region_filter", this, 0, NULL, NULL );
}
+
+ mlt_service_unlock( MLT_FILTER_SERVICE( this ) );
// Pass all properties down
mlt_properties_pass( MLT_TRANSITION_PROPERTIES( transition ), properties, "" );
-
+
+ mlt_position position = mlt_filter_get_position( this, frame );
+
+ mlt_frame_set_position( frame, position );
+
// Process the frame
- return mlt_transition_process( transition, frame, NULL );
+ mlt_transition_process( transition, frame, NULL );
+
+ return mlt_frame_get_image( frame, image, format, width, height, writable );
+}
+
+static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
+{
+
+ mlt_frame_push_service( frame, this );
+ mlt_frame_push_get_image( frame, filter_get_image );
+
+ return frame;
}
+
/** Constructor for the filter.
*/
diff --git a/src/modules/core/transition_region.c b/src/modules/core/transition_region.c
index 4486d23..9df4e6d 100644
--- a/src/modules/core/transition_region.c
+++ b/src/modules/core/transition_region.c
@@ -111,26 +111,27 @@ static uint8_t *filter_get_alpha_mask( mlt_frame this )
mlt_frame_get_image( shape_frame, &image, &format, ®ion_width, ®ion_height, 0 );
alpha = mlt_frame_get_alpha_mask( shape_frame );
+
+ int size = region_width * region_height;
+ uint8_t *alpha_duplicate = mlt_pool_alloc( size );
// Generate from the Y component of the image if no alpha available
if ( alpha == NULL )
{
- int size = region_width * region_height;
- uint8_t *p = mlt_pool_alloc( size );
- alpha = p;
while ( size -- )
{
- *p ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 );
+ *alpha_duplicate ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 );
image ++;
}
- mlt_frame_set_alpha( this, alpha, region_width * region_height, mlt_pool_release );
+
}
else
{
- mlt_frame_set_alpha( this, alpha, region_width * region_height, NULL );
+ // Duplicate alpha
+ memcpy( alpha_duplicate, alpha, size );
}
- return alpha;
+ return alpha_duplicate;
}
/** Do it :-).
@@ -149,6 +150,9 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
// Get the properties of the transition
mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
+
+ // Get the properties of the a frame
+ mlt_properties a_props = MLT_FRAME_PROPERTIES( frame );
mlt_service_lock( MLT_TRANSITION_SERVICE( this ) );
@@ -262,8 +266,8 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
}
}
- mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "width", *width );
- mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "height", *height );
+ mlt_properties_set_int( a_props, "width", *width );
+ mlt_properties_set_int( a_props, "height", *height );
// Only continue if we have both filter and composite
if ( composite != NULL )
@@ -279,25 +283,35 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
// Index to hold the count
int i = 0;
+
+ mlt_properties b_props;
// We will get the 'b frame' from the composite only if it's NULL (region filter)
if ( b_frame == NULL )
{
// Copy the region
b_frame = composite_copy_region( composite, frame, position );
-
+
+ // Get the properties of the b frame
+ b_props = MLT_FRAME_PROPERTIES( b_frame );
+
// Ensure a destructor
char *name = mlt_properties_get( properties, "_unique_id" );
- mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
+ mlt_properties_set_data( a_props, name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
+
+ // Filter only, we want to composite over itself
+ if ( mlt_properties_get_int( properties, "filter_only" ) )
+ {
+ frame = composite_copy_region( composite, b_frame, position );
+ mlt_properties_set_data( MLT_FRAME_PROPERTIES( b_frame ), name, frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
+ }
}
-
- // filter_only prevents copying the alpha channel of the shape to the output frame
- // by compositing filtered frame over itself
- if ( mlt_properties_get_int( properties, "filter_only" ) )
+ else
{
- frame = composite_copy_region( composite, b_frame, position );
+ // Get the properties of the b frame
+ b_props = MLT_FRAME_PROPERTIES( b_frame );
}
-
+
// Make sure the filter is in the correct position
while ( filter != NULL )
{
@@ -311,18 +325,19 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
// Get the next filter
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 )
mlt_service_apply_filters( MLT_FILTER_SERVICE( filter ), b_frame, 0 );
+
// Hmm - this is probably going to go wrong....
mlt_frame_set_position( frame, position );
-
+
// Get the b frame and process with composite if successful
mlt_transition_process( composite, frame, b_frame );
-
+
// If we have a shape producer copy the alpha mask from the shape frame to the b_frame
if ( strcmp( resource, "rectangle" ) != 0 )
{
@@ -376,14 +391,14 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &shape_frame, 0 ) == 0 )
{
// Ensure that the shape frame will be closed
- mlt_properties_set_data( MLT_FRAME_PROPERTIES( b_frame ), "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
+ mlt_properties_set_data( b_props, "shape_frame", shape_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
// Specify the callback for evaluation
b_frame->get_alpha_mask = filter_get_alpha_mask;
}
}
}
-
+
// Get the image
error = mlt_frame_get_image( frame, image, format, width, height, 0 );
}
@@ -396,10 +411,10 @@ static int transition_get_image( mlt_frame frame, uint8_t **image, mlt_image_for
/** Filter processing.
*/
-static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame )
+static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame )
{
// Push the transition on to the frame
- mlt_frame_push_service( a_frame, this );
+ mlt_frame_push_service( a_frame, transition );
// Push the b_frame on to the stack
mlt_frame_push_frame( a_frame, b_frame );
@@ -417,16 +432,16 @@ static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt
mlt_transition transition_region_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
// Create a new transition
- mlt_transition this = mlt_transition_new( );
+ mlt_transition transition = mlt_transition_new( );
// Further initialisation
- if ( this != NULL )
+ if ( transition != NULL )
{
// Get the properties from the transition
- mlt_properties properties = MLT_TRANSITION_PROPERTIES( this );
+ mlt_properties properties = MLT_TRANSITION_PROPERTIES( transition );
// Assign the transition process method
- this->process = transition_process;
+ transition->process = transition_process;
// Default factory
mlt_properties_set( properties, "factory", mlt_environment( "MLT_PRODUCER" ) );
@@ -439,6 +454,6 @@ mlt_transition transition_region_init( mlt_profile profile, mlt_service_type typ
}
// Return the transition
- return this;
+ return transition;
}
------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
_______________________________________________
Mlt-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mlt-devel