framework: remove global profile, rather share one mlt_profile across a service netwo...
[melted] / 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 /* FIXME: endianess? */
46 static void makePalette(void)
47 {
48 int i, r, g, b;
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 palette[i] = ((r<<16)|(g<<8)|b) & 0xfefeff;
53 }
54 for(i=MaxColor; i<256; i++) {
55 if(r<255)r++;if(r<255)r++;if(r<255)r++;
56 if(g<255)g++;
57 if(g<255)g++;
58 if(b<255)b++;
59 if(b<255)b++;
60 palette[i] = ((r<<16)|(g<<8)|b) & 0xfefeff;
61 }
62 }
63
64 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
65 {
66 RGB32 *background;
67 unsigned char *diff;
68 unsigned char *buffer;
69
70 // Get the filter
71 mlt_filter filter = mlt_frame_pop_service( this );
72
73 // Get the image
74 int error = mlt_frame_get_image( this, image, format, width, height, 1 );
75
76 // Only process if we have no error and a valid colour space
77 if ( error == 0 && *format == mlt_image_yuv422 )
78 {
79 // Get the "Burn the foreground" value
80 int burn_foreground = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "foreground" );
81 int y_threshold = image_set_threshold_y(
82 mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "threshold" ));
83
84 // We'll process pixel by pixel
85 int x = 0;
86 int y = 0;
87 int i;
88
89 int video_width = *width;
90 int video_height = *height;
91 int video_area = video_width * video_height;
92 // We need to create a new frame as this effect modifies the input
93 RGB32 *dest = mlt_pool_alloc( video_area * sizeof(RGB32) );
94 RGB32 *src = (RGB32*)dest;
95
96 unsigned char v, w;
97 RGB32 a, b;
98
99 mlt_convert_yuv422_to_rgb24a(*image, (uint8_t *)dest, video_area);
100
101
102 diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
103 "_diff", NULL );
104 if (diff == NULL)
105 {
106 diff = mlt_pool_alloc(video_area*sizeof(unsigned char));
107 mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_diff",
108 diff, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
109 }
110
111 buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
112 "_buffer", NULL );
113 if (buffer == NULL)
114 {
115 buffer = mlt_pool_alloc(video_area*sizeof(unsigned char));
116 memset(buffer, 0, video_area*sizeof(unsigned char));
117 mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_buffer",
118 buffer, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
119 }
120
121
122 if (burn_foreground == 1) {
123 /* to burn the foreground, we need a background */
124 background = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
125 "_background", NULL );
126 if (background == NULL)
127 {
128 background = mlt_pool_alloc(video_area*sizeof(RGB32));
129 image_bgset_y(background, src, video_area, y_threshold);
130 mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_background",
131 background, video_area*sizeof(RGB32), mlt_pool_release, NULL );
132 }
133 }
134
135 if (burn_foreground == 1) {
136 image_bgsubtract_y(diff, background, src, video_area, y_threshold);
137 } else {
138 /* default */
139 image_y_over(diff, src, video_area, y_threshold);
140 }
141
142 for(x=1; x<video_width-1; x++) {
143 v = 0;
144 for(y=0; y<video_height-1; y++) {
145 w = diff[y*video_width+x];
146 buffer[y*video_width+x] |= v ^ w;
147 v = w;
148 }
149 }
150 for(x=1; x<video_width-1; x++) {
151 i = video_width + x;
152 for(y=1; y<video_height; y++) {
153 v = buffer[i];
154 if(v<Decay)
155 buffer[i-video_width] = 0;
156 else
157 buffer[i-video_width+fastrand()%3-1] = v - (fastrand()&Decay);
158 i += video_width;
159 }
160 }
161
162 i = 1;
163 for(y=0; y<video_height; y++) {
164 for(x=1; x<video_width-1; x++) {
165 /* FIXME: endianess? */
166 a = (src[i] & 0xfefeff) + palette[buffer[i]];
167 b = a & 0x1010100;
168 dest[i] = a | (b - (b >> 8));
169 i++;
170 }
171 i += 2;
172 }
173
174 mlt_convert_rgb24a_to_yuv422((uint8_t *)dest, *width, *height, *width * sizeof(RGB32),
175 *image, NULL );
176
177 mlt_pool_release(dest);
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