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 && ( !use_luminance
|| ( int )mix
!= 1 ) )
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 ( ( int )mix
!= 1 )
82 uint8_t *q
= mask_img
;
83 // Ensure softness tends to zero has mix tends to 1
84 softness
*= ( 1.0 - mix
);
87 a
= ( ( double )*q
- 16 ) / 235.0;
88 b
= smoothstep( a
, a
+ softness
, mix
);
89 *p
= ( uint8_t )( *p
* b
) ^ invert
;
100 /** Filter processing.
103 static mlt_frame
filter_process( mlt_filter
this, mlt_frame frame
)
105 // Obtain the shape instance
106 char *resource
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "resource" );
107 char *last_resource
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_resource" );
108 mlt_producer producer
= mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "instance", NULL
);
110 // Get the key framed values
111 mlt_geometry alpha
= mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "_alpha", NULL
);
112 char *alpha_data
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "mix" );
113 double alpha_mix
= 0.0;
115 // Calculate the position and length
116 int position
= mlt_frame_get_position( frame
) - mlt_filter_get_in( this );
117 int in
= mlt_filter_get_in( this );
118 int out
= mlt_filter_get_out( this );
121 // Special case for attached filters - in/out come through on the frame
124 in
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame
), "in" );
125 out
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame
), "out" );
129 // Duration of the shape
130 length
= out
- in
+ 1;
132 // If we haven't created the instance or it's changed
133 if ( producer
== NULL
|| strcmp( resource
, last_resource
) )
136 char *extension
= strrchr( resource
, '.' );
138 // Store the last resource now
139 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "_resource", resource
);
141 // This is a hack - the idea is that we can indirectly reference the
142 // luma modules pgm or png images by a short cut like %luma01.pgm - we then replace
143 // the % with the full path to the image and use it if it exists, if not, check for
144 // the file ending in a .png, and failing that, default to a fade in
145 if ( strchr( resource
, '%' ) )
148 sprintf( temp
, "%s/lumas/%s/%s", mlt_factory_prefix( ), mlt_environment( "MLT_NORMALISATION" ), strchr( resource
, '%' ) + 1 );
149 test
= fopen( temp
, "r" );
153 strcat( temp
, ".png" );
154 test
= fopen( temp
, "r" );
160 strcpy( temp
, "colour:0x00000080" );
163 extension
= strrchr( resource
, '.' );
166 producer
= mlt_factory_producer( NULL
, resource
);
167 if ( producer
!= NULL
)
168 mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer
), "eof", "loop" );
169 mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "instance", producer
, 0, ( mlt_destructor
)mlt_producer_close
, NULL
);
172 // Construct the geometry item if needed, otherwise refresh it
175 alpha
= mlt_geometry_init( );
176 mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "_alpha", alpha
, 0, ( mlt_destructor
)mlt_geometry_close
, NULL
);
177 mlt_geometry_parse( alpha
, alpha_data
, length
, 100, 100 );
181 mlt_geometry_refresh( alpha
, alpha_data
, length
, 100, 100 );
184 // We may still not have a producer in which case, we do nothing
185 if ( producer
!= NULL
)
187 mlt_frame mask
= NULL
;
188 struct mlt_geometry_item_s item
;
189 mlt_geometry_fetch( alpha
, &item
, position
);
191 mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer
), MLT_FILTER_PROPERTIES( this ), "producer." );
192 mlt_producer_seek( producer
, position
);
193 if ( mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer
), &mask
, 0 ) == 0 )
195 char *name
= mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" );
196 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame
), name
, mask
, 0, ( mlt_destructor
)mlt_frame_close
, NULL
);
197 mlt_frame_push_service( frame
, this );
198 mlt_frame_push_service( frame
, mask
);
199 mlt_deque_push_back_double( MLT_FRAME_IMAGE_STACK( frame
), alpha_mix
/ 100.0 );
200 mlt_frame_push_get_image( frame
, filter_get_image
);
201 if ( mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "audio_match" ) )
203 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame
), "meta.mixdown", 1 );
204 mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame
), "meta.volume", alpha_mix
/ 100.0 );
212 /** Constructor for the filter.
215 mlt_filter
filter_shape_init( char *arg
)
217 mlt_filter
this = mlt_filter_new( );
220 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "resource", arg
);
221 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "mix", "100" );
222 mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "audio_match", 1 );
223 mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "invert", 0 );
224 mlt_properties_set_double( MLT_FILTER_PROPERTIES( this ), "softness", 0.1 );
225 this->process
= filter_process
;