2 * filter_shape.c -- Arbitrary alpha channel shaping
3 * Copyright (C) 2005 Visual Media Fx Inc.
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "filter_shape.h"
23 #include <framework/mlt_factory.h>
24 #include <framework/mlt_frame.h>
25 #include <framework/mlt_producer.h>
26 #include <framework/mlt_geometry.h>
28 inline double smoothstep( const double e1
, const double e2
, const double a
)
30 if ( a
< e1
) return 0.0;
31 if ( a
> e2
) return 1.0;
32 double v
= ( a
- e1
) / ( e2
- e1
);
33 return ( v
* v
* ( 3 - 2 * v
) );
36 /** Get the images and apply the luminance of the mask to the alpha of the frame.
39 static int filter_get_image( mlt_frame
this, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
41 // Fetch the data from the stack (mix, mask, filter)
42 double mix
= mlt_deque_pop_back_double( MLT_FRAME_IMAGE_STACK( this ) );
43 mlt_frame mask
= mlt_frame_pop_service( this );
44 mlt_filter filter
= mlt_frame_pop_service( this );
46 // Obtain the constants
47 double softness
= mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter
), "softness" );
48 int use_luminance
= mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter
), "use_luminance" );
49 int invert
= mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter
), "invert" ) * 255;
52 if ( mlt_frame_get_image( this, image
, format
, width
, height
, writable
) == 0 )
54 // Get the alpha mask of the source
55 uint8_t *alpha
= mlt_frame_get_alpha_mask( this );
57 // Obtain a scaled/distorted mask to match
58 uint8_t *mask_img
= NULL
;
59 mlt_image_format mask_fmt
= mlt_image_yuv422
;
60 mlt_properties_set_int( MLT_FRAME_PROPERTIES( mask
), "distort", 1 );
61 mlt_properties_pass_list( MLT_FRAME_PROPERTIES( mask
), MLT_FRAME_PROPERTIES( this ), "deinterlace,deinterlace_method,rescale.interp" );
63 if ( mlt_frame_get_image( mask
, &mask_img
, &mask_fmt
, width
, height
, 0 ) == 0 )
65 int size
= *width
* *height
;
71 uint8_t *q
= mlt_frame_get_alpha_mask( mask
);
74 a
= ( double )*q
++ / 255.0;
75 b
= 1.0 - smoothstep( a
, a
+ softness
, mix
);
76 *p
= ( uint8_t )( *p
* b
) ^ invert
;
80 else if ( mix
!= 1.0 )
82 uint8_t *q
= mask_img
;
85 a
= ( ( double )*q
- 16 ) / 235.0;
86 b
= smoothstep( a
, a
+ softness
, mix
);
87 *p
= ( uint8_t )( *p
* b
) ^ invert
;
98 /** Filter processing.
101 static mlt_frame
filter_process( mlt_filter
this, mlt_frame frame
)
103 // Obtain the shape instance
104 char *resource
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "resource" );
105 mlt_producer producer
= mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "instance", NULL
);
107 // Get the key framed values
108 mlt_geometry alpha
= mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "_alpha", NULL
);
109 char *alpha_data
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "mix" );
110 double alpha_mix
= 0.0;
112 // Calculate the position and length
113 int position
= mlt_frame_get_position( frame
) - mlt_filter_get_in( this );
114 int in
= mlt_filter_get_in( this );
115 int out
= mlt_filter_get_out( this );
118 // Special case for attached filters - in/out come through on the frame
121 in
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame
), "in" );
122 out
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame
), "out" );
125 // Duration of the shape
126 length
= out
- in
+ 1;
128 // If we haven't created the instance or it's changed
129 if ( producer
== NULL
|| strcmp( resource
, mlt_properties_get( MLT_PRODUCER_PROPERTIES( producer
), "resource" ) ) )
131 producer
= mlt_factory_producer( NULL
, resource
);
132 if ( producer
!= NULL
)
133 mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer
), "eof", "loop" );
134 mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "instance", producer
, 0, ( mlt_destructor
)mlt_producer_close
, NULL
);
137 // Construct the geometry item if needed, otherwise refresh it
140 alpha
= mlt_geometry_init( );
141 mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "_alpha", alpha
, 0, ( mlt_destructor
)mlt_geometry_close
, NULL
);
142 mlt_geometry_parse( alpha
, alpha_data
, length
, 100, 100 );
146 mlt_geometry_refresh( alpha
, alpha_data
, length
, 100, 100 );
149 // We may still not have a producer in which case, we do nothing
150 if ( producer
!= NULL
)
152 mlt_frame mask
= NULL
;
153 struct mlt_geometry_item_s item
;
154 mlt_geometry_fetch( alpha
, &item
, position
);
156 mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer
), MLT_FILTER_PROPERTIES( this ), "producer." );
157 mlt_producer_seek( producer
, position
);
158 if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer
), &mask
, 0 ) == 0 )
160 char *name
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" );
161 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame
), name
, mask
, 0, ( mlt_destructor
)mlt_frame_close
, NULL
);
162 mlt_frame_push_service( frame
, this );
163 mlt_frame_push_service( frame
, mask
);
164 mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( frame
), alpha_mix
/ 100.0 );
165 mlt_frame_push_get_image( frame
, filter_get_image
);
166 if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "audio_match" ) )
167 mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame
), "meta.volume", alpha_mix
/ 100.0 );
174 /** Constructor for the filter.
177 mlt_filter
filter_shape_init( char *arg
)
179 mlt_filter
this = mlt_filter_new( );
182 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "resource", arg
);
183 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "mix", "100" );
184 mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "audio_match", 1 );
185 mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "invert", 0 );
186 mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "softness", 0.1 );
187 this->process
= filter_process
;