]> git.sesse.net Git - mlt/blob - src/modules/effectv/filter_burn.c
42a1f2d877d777ba28199ae42c8ac6d9a9ab0870
[mlt] / src / modules / effectv / filter_burn.c
1 /*
2  * filter_burn.c -- burning filter
3  * Copyright (C) 2007 Stephane Fillod
4  *
5  * Filter taken from EffecTV - Realtime Digital Video Effector
6  * Copyright (C) 2001-2006 FUKUCHI Kentaro
7  *
8  * BurningTV - burns incoming objects.
9  * Copyright (C) 2001-2002 FUKUCHI Kentaro
10  *
11  * Fire routine is taken from Frank Jan Sorensen's demo program.
12  *
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #include <framework/mlt_filter.h>
30 #include <framework/mlt_frame.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include "utils.h"
37
38
39 #define MaxColor 120
40 #define Decay 15
41 #define MAGIC_THRESHOLD "50"
42
43 static RGB32 palette[256];
44
45 static void makePalette(void)
46 {
47         int i, r, g, b;
48         uint8_t *p = (uint8_t*) palette;
49
50         for(i=0; i<MaxColor; i++) {
51                 HSItoRGB(4.6-1.5*i/MaxColor, (double)i/MaxColor, (double)i/MaxColor, &r, &g, &b);
52                 *p++ = r & 0xfe;
53                 *p++ = g & 0xfe;
54                 *p++ = b & 0xfe;
55                 p++;
56         }
57         for(i=MaxColor; i<256; i++) {
58                 if(r<255)r++;if(r<255)r++;if(r<255)r++;
59                 if(g<255)g++;
60                 if(g<255)g++;
61                 if(b<255)b++;
62                 if(b<255)b++;
63                 *p++ = r & 0xfe;
64                 *p++ = g & 0xfe;
65                 *p++ = b & 0xfe;
66                 p++;
67         }
68 }
69
70 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
71 {
72         RGB32 *background;
73         unsigned char *diff;
74         unsigned char *buffer;
75
76         // Get the filter
77         mlt_filter filter = mlt_frame_pop_service( this );
78
79         // Get the image
80         *format = mlt_image_rgb24a;
81         int error = mlt_frame_get_image( this, image, format, width, height, 1 );
82
83         // Only process if we have no error and a valid colour space
84         if ( error == 0 )
85         {
86                 // Get the "Burn the foreground" value
87                 int burn_foreground = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "foreground" );
88                 int y_threshold = image_set_threshold_y(
89                                 mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "threshold" ));
90
91                 // We'll process pixel by pixel
92                 int x = 0;
93                 int y = 0;
94                 int i;
95
96                 int video_width = *width;
97                 int video_height = *height;
98                 int video_area = video_width * video_height;
99                 // We need to create a new frame as this effect modifies the input
100                 RGB32 *dest = (RGB32*)*image;
101                 RGB32 *src = (RGB32*)*image;
102
103                 unsigned char v, w;
104                 RGB32 a, b;
105
106                 diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), 
107                                                 "_diff", NULL );
108                 if (diff == NULL)
109                 {
110                         diff = mlt_pool_alloc(video_area*sizeof(unsigned char));
111                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_diff", 
112                                         diff, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
113                 }
114
115                 buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), 
116                                                 "_buffer", NULL );
117                 if (buffer == NULL)
118                 {
119                         buffer = mlt_pool_alloc(video_area*sizeof(unsigned char));
120                         memset(buffer, 0, video_area*sizeof(unsigned char));
121                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_buffer", 
122                                         buffer, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
123                 }
124
125
126                 if (burn_foreground == 1) {
127                         /* to burn the foreground, we need a background */
128                         background = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), 
129                                                 "_background", NULL );
130                         if (background == NULL)
131                         {
132                                 background = mlt_pool_alloc(video_area*sizeof(RGB32));
133                                 image_bgset_y(background, src, video_area, y_threshold);
134                                 mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_background", 
135                                         background, video_area*sizeof(RGB32), mlt_pool_release, NULL );
136                         }
137                 }
138
139                 if (burn_foreground == 1) {
140                         image_bgsubtract_y(diff, background, src, video_area, y_threshold);
141                 } else {
142                         /* default */
143                         image_y_over(diff, src, video_area, y_threshold);
144                 }
145         
146                 for(x=1; x<video_width-1; x++) {
147                         v = 0;
148                         for(y=0; y<video_height-1; y++) {
149                                 w = diff[y*video_width+x];
150                                 buffer[y*video_width+x] |= v ^ w;
151                                 v = w;
152                         }
153                 }
154                 for(x=1; x<video_width-1; x++) {
155                         i = video_width + x;
156                         for(y=1; y<video_height; y++) {
157                                 v = buffer[i];
158                                 if(v<Decay)
159                                         buffer[i-video_width] = 0;
160                                 else
161                                         buffer[i-video_width+fastrand()%3-1] = v - (fastrand()&Decay);
162                                 i += video_width;
163                         }
164                 }
165         
166                 i = 1;
167                 for(y=0; y<video_height; y++) {
168                         for(x=1; x<video_width-1; x++) {
169                                 /* FIXME: endianess? */
170                                 a = (src[i] & 0xfefeff) + palette[buffer[i]];
171                                 b = a & 0x1010100;
172                                 dest[i] = a | (b - (b >> 8));
173                                 i++;
174                         }
175                         i += 2;
176                 }
177         }
178
179         return error;
180 }
181
182 /** Filter processing.
183 */
184
185 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
186 {
187         // Push the frame filter
188         mlt_frame_push_service( frame, this );
189         mlt_frame_push_get_image( frame, filter_get_image );
190
191         return frame;
192 }
193
194 /** Constructor for the filter.
195 */
196
197 mlt_filter filter_burn_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
198 {
199         mlt_filter this = mlt_filter_new( );
200         if ( this != NULL )
201         {
202                 this->process = filter_process;
203                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "foreground", "0" );
204                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "threshold", MAGIC_THRESHOLD );
205         }
206         if (!palette[128])
207         {
208                 makePalette();
209         }
210         return this;
211 }
212