]> git.sesse.net Git - mlt/blob - src/modules/plusgpl/filter_burn.c
Move burningtv into plusgpl module.
[mlt] / src / modules / plusgpl / 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                 mlt_service_lock( MLT_FILTER_SERVICE( filter ) );
107
108                 diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "_diff", NULL );
109                 if (diff == NULL)
110                 {
111                         diff = mlt_pool_alloc(video_area*sizeof(unsigned char));
112                         mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_diff", 
113                                         diff, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
114                 }
115
116                 buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "_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                 if (burn_foreground == 1) {
126                         /* to burn the foreground, we need a background */
127                         background = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), 
128                                                 "_background", NULL );
129                         if (background == NULL)
130                         {
131                                 background = mlt_pool_alloc(video_area*sizeof(RGB32));
132                                 image_bgset_y(background, src, video_area, y_threshold);
133                                 mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_background", 
134                                         background, video_area*sizeof(RGB32), mlt_pool_release, NULL );
135                         }
136                 }
137
138                 mlt_service_unlock( MLT_FILTER_SERVICE( filter ) );
139
140                 if (burn_foreground == 1) {
141                         image_bgsubtract_y(diff, background, src, video_area, y_threshold);
142                 } else {
143                         /* default */
144                         image_y_over(diff, src, video_area, y_threshold);
145                 }
146         
147                 for(x=1; x<video_width-1; x++) {
148                         v = 0;
149                         for(y=0; y<video_height-1; y++) {
150                                 w = diff[y*video_width+x];
151                                 buffer[y*video_width+x] |= v ^ w;
152                                 v = w;
153                         }
154                 }
155                 for(x=1; x<video_width-1; x++) {
156                         i = video_width + x;
157                         for(y=1; y<video_height; y++) {
158                                 v = buffer[i];
159                                 if(v<Decay)
160                                         buffer[i-video_width] = 0;
161                                 else
162                                         buffer[i-video_width+fastrand()%3-1] = v - (fastrand()&Decay);
163                                 i += video_width;
164                         }
165                 }
166         
167                 i = 1;
168                 for(y=0; y<video_height; y++) {
169                         for(x=1; x<video_width-1; x++) {
170                                 /* FIXME: endianess? */
171                                 a = (src[i] & 0xfefeff) + palette[buffer[i]];
172                                 b = a & 0x1010100;
173                                 dest[i] = a | (b - (b >> 8));
174                                 i++;
175                         }
176                         i += 2;
177                 }
178         }
179
180         return error;
181 }
182
183 /** Filter processing.
184 */
185
186 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
187 {
188         // Push the frame filter
189         mlt_frame_push_service( frame, this );
190         mlt_frame_push_get_image( frame, filter_get_image );
191
192         return frame;
193 }
194
195 /** Constructor for the filter.
196 */
197
198 mlt_filter filter_burn_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
199 {
200         mlt_filter this = mlt_filter_new( );
201         if ( this != NULL )
202         {
203                 this->process = filter_process;
204                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "foreground", "0" );
205                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "threshold", MAGIC_THRESHOLD );
206         }
207         if (!palette[128])
208         {
209                 makePalette();
210         }
211         return this;
212 }
213