r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / deinterlace / deinterlace.C
blobb2666bd64add561e0d59ae8a8e12bb1dd39bb180
1 #include "clip.h"
2 #include "defaults.h"
3 #include "deinterlace.h"
4 #include "deinterwindow.h"
5 #include "filexml.h"
6 #include "keyframe.h"
7 #include "picon_png.h"
8 #include "vframe.h"
11 #include <libintl.h>
12 #define _(String) gettext(String)
13 #define gettext_noop(String) String
14 #define N_(String) gettext_noop (String)
22 #include <stdint.h>
23 #include <string.h>
26 REGISTER_PLUGIN(DeInterlaceMain)
31 DeInterlaceConfig::DeInterlaceConfig()
33         mode = DEINTERLACE_EVEN;
34         adaptive = 1;
35         threshold = 40;
38 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
40         return mode == that.mode &&
41                 adaptive == that.adaptive &&
42                 threshold == that.threshold;
45 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
47         mode = that.mode;
48         adaptive = that.adaptive;
49         threshold = that.threshold;
52 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev, 
53         DeInterlaceConfig &next, 
54         int64_t prev_frame, 
55         int64_t next_frame, 
56         int64_t current_frame)
58         copy_from(prev);
64 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
65  : PluginVClient(server)
67         PLUGIN_CONSTRUCTOR_MACRO
68         temp = 0;
71 DeInterlaceMain::~DeInterlaceMain()
73         PLUGIN_DESTRUCTOR_MACRO
74         if(temp) delete temp;
77 char* DeInterlaceMain::plugin_title() { return _("Deinterlace"); }
78 int DeInterlaceMain::is_realtime() { return 1; }
82 #define DEINTERLACE_EVEN_MACRO(type, components, dominance, max) \
83 { \
84         int w = input->get_w(); \
85         int h = input->get_h(); \
86  \
87         for(int i = 0; i < h - 1; i += 2) \
88         { \
89                 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
90                 type *output_row1 = (type*)output->get_rows()[i]; \
91                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
92                 memcpy(output_row1, input_row, w * components * sizeof(type)); \
93                 memcpy(output_row2, input_row, w * components * sizeof(type)); \
94         } \
97 #define DEINTERLACE_AVG_EVEN_MACRO(type, components, dominance, max) \
98 { \
99         int w = input->get_w(); \
100         int h = input->get_h(); \
101         changed_rows = 0; \
103         type **in_rows = (type**)input->get_rows(); \
104         type **out_rows = (type**)temp->get_rows(); \
105         int max_h = h - 1; \
106         int64_t abs_diff = 0, total = 0; \
108         for(int i = 0; i < max_h; i += 2) \
109         { \
110                 int in_number1 = dominance ? i - 1 : i + 0; \
111                 int in_number2 = dominance ? i + 1 : i + 2; \
112                 int out_number1 = dominance ? i - 1 : i; \
113                 int out_number2 = dominance ? i : i + 1; \
114                 in_number1 = MAX(in_number1, 0); \
115                 in_number2 = MIN(in_number2, max_h); \
116                 out_number1 = MAX(out_number1, 0); \
117                 out_number2 = MIN(out_number2, max_h); \
119                 type *input_row1 = in_rows[in_number1]; \
120                 type *input_row2 = in_rows[in_number2]; \
121                 type *input_row3 = in_rows[out_number2]; \
122                 type *temp_row1 = out_rows[out_number1]; \
123                 type *temp_row2 = out_rows[out_number2]; \
124                 int64_t sum = 0; \
125                 int64_t accum_r, accum_b, accum_g, accum_a; \
127                 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
128                 for(int j = 0; j < w; j++) \
129                 { \
130                         accum_r = (*input_row1++) + (*input_row2++); \
131                         accum_g = (*input_row1++) + (*input_row2++); \
132                         accum_b = (*input_row1++) + (*input_row2++); \
133                         if(components == 4) \
134                                 accum_a = (*input_row1++) + (*input_row2++); \
135                         accum_r >>= 1; \
136                         accum_g >>= 1; \
137                         accum_b >>= 1; \
138                         accum_a >>= 1; \
140                         total += *input_row3; \
141                         sum = ((int)*input_row3++) - accum_r; \
142                         abs_diff += (sum < 0 ? -sum : sum); \
143                         *temp_row2++ = accum_r; \
145                         total += *input_row3; \
146                         sum = ((int)*input_row3++) - accum_g; \
147                         abs_diff += (sum < 0 ? -sum : sum); \
148                         *temp_row2++ = accum_g; \
150                         total += *input_row3; \
151                         sum = ((int)*input_row3++) - accum_b; \
152                         abs_diff += (sum < 0 ? -sum : sum); \
153                         *temp_row2++ = accum_b; \
155                         if(components == 4) \
156                         { \
157                                 total += *input_row3; \
158                                 sum = ((int)*input_row3++) - accum_a; \
159                                 abs_diff += (sum < 0 ? -sum : sum); \
160                                 *temp_row2++ = accum_a; \
161                         } \
162                 } \
163         } \
165         int64_t threshold = (int64_t)total * config.threshold / THRESHOLD_SCALAR; \
166 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
167         if(abs_diff > threshold || !config.adaptive) \
168         { \
169                 output->copy_from(temp); \
170                 changed_rows = 240; \
171         } \
172         else \
173         { \
174                 output->copy_from(input); \
175                 changed_rows = 0; \
176         } \
180 #define DEINTERLACE_AVG_MACRO(type, components) \
181 { \
182         int w = input->get_w(); \
183         int h = input->get_h(); \
185         for(int i = 0; i < h - 1; i += 2) \
186         { \
187                 type *input_row1 = (type*)input->get_rows()[i]; \
188                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
189                 type *output_row1 = (type*)output->get_rows()[i]; \
190                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
191                 type result; \
193                 for(int j = 0; j < w * components; j++) \
194                 { \
195                         result = ((uint64_t)input_row1[j] + input_row2[j]) >> 1; \
196                         output_row1[j] = result; \
197                         output_row2[j] = result; \
198                 } \
199         } \
202 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
203 { \
204         int w = input->get_w(); \
205         int h = input->get_h(); \
207         for(int i = dominance; i < h - 1; i += 2) \
208         { \
209                 type *input_row1 = (type*)input->get_rows()[i]; \
210                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
211                 type *output_row1 = (type*)output->get_rows()[i]; \
212                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
213                 type temp1, temp2; \
215                 for(int j = 0; j < w * components; j++) \
216                 { \
217                         temp1 = input_row1[j]; \
218                         temp2 = input_row2[j]; \
219                         output_row1[j] = temp2; \
220                         output_row2[j] = temp1; \
221                 } \
222         } \
226 void DeInterlaceMain::deinterlace_even(VFrame *input, VFrame *output, int dominance)
228         switch(input->get_color_model())
229         {
230                 case BC_RGB888:
231                 case BC_YUV888:
232                         DEINTERLACE_EVEN_MACRO(unsigned char, 3, dominance, 0xff);
233                         break;
234                 case BC_RGBA8888:
235                 case BC_YUVA8888:
236                         DEINTERLACE_EVEN_MACRO(unsigned char, 4, dominance, 0xff);
237                         break;
238                 case BC_RGB161616:
239                 case BC_YUV161616:
240                         DEINTERLACE_EVEN_MACRO(uint16_t, 3, dominance, 0xffff);
241                         break;
242                 case BC_RGBA16161616:
243                 case BC_YUVA16161616:
244                         DEINTERLACE_EVEN_MACRO(uint16_t, 4, dominance, 0xffff);
245                         break;
246         }
249 void DeInterlaceMain::deinterlace_avg_even(VFrame *input, VFrame *output, int dominance)
251         switch(input->get_color_model())
252         {
253                 case BC_RGB888:
254                 case BC_YUV888:
255                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, 3, dominance, 0xff);
256                         break;
257                 case BC_RGBA8888:
258                 case BC_YUVA8888:
259                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, 4, dominance, 0xff);
260                         break;
261                 case BC_RGB161616:
262                 case BC_YUV161616:
263                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, 3, dominance, 0xffff);
264                         break;
265                 case BC_RGBA16161616:
266                 case BC_YUVA16161616:
267                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, 4, dominance, 0xffff);
268                         break;
269         }
272 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
274         switch(input->get_color_model())
275         {
276                 case BC_RGB888:
277                 case BC_YUV888:
278                         DEINTERLACE_AVG_MACRO(unsigned char, 3);
279                         break;
280                 case BC_RGBA8888:
281                 case BC_YUVA8888:
282                         DEINTERLACE_AVG_MACRO(unsigned char, 4);
283                         break;
284                 case BC_RGB161616:
285                 case BC_YUV161616:
286                         DEINTERLACE_AVG_MACRO(uint16_t, 3);
287                         break;
288                 case BC_RGBA16161616:
289                 case BC_YUVA16161616:
290                         DEINTERLACE_AVG_MACRO(uint16_t, 4);
291                         break;
292         }
295 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
297         switch(input->get_color_model())
298         {
299                 case BC_RGB888:
300                 case BC_YUV888:
301                         DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
302                         break;
303                 case BC_RGBA8888:
304                 case BC_YUVA8888:
305                         DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
306                         break;
307                 case BC_RGB161616:
308                 case BC_YUV161616:
309                         DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
310                         break;
311                 case BC_RGBA16161616:
312                 case BC_YUVA16161616:
313                         DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
314                         break;
315         }
319 int DeInterlaceMain::process_realtime(VFrame *input, VFrame *output)
321         changed_rows = input->get_h();
322         load_configuration();
323         if(!temp)
324                 temp = new VFrame(0,
325                         input->get_w(),
326                         input->get_h(),
327                         input->get_color_model());
329         switch(config.mode)
330         {
331                 case DEINTERLACE_NONE:
332                         output->copy_from(input);
333                         break;
334                 case DEINTERLACE_EVEN:
335                         deinterlace_even(input, output, 0);
336                         break;
337                 case DEINTERLACE_ODD:
338                         deinterlace_even(input, output, 1);
339                         break;
340                 case DEINTERLACE_AVG:
341                         deinterlace_avg(input, output);
342                         break;
343                 case DEINTERLACE_AVG_EVEN:
344                         deinterlace_avg_even(input, output, 0);
345                         break;
346                 case DEINTERLACE_AVG_ODD:
347                         deinterlace_avg_even(input, output, 1);
348                         break;
349                 case DEINTERLACE_SWAP_ODD:
350                         deinterlace_swap(input, output, 1);
351                         break;
352                 case DEINTERLACE_SWAP_EVEN:
353                         deinterlace_swap(input, output, 0);
354                         break;
355         }
356         send_render_gui(&changed_rows);
357         return 0;
360 void DeInterlaceMain::render_gui(void *data)
362         if(thread)
363         {
364                 thread->window->lock_window();
365                 char string[BCTEXTLEN];
366                 thread->window->get_status_string(string, *(int*)data);
367                 thread->window->status->update(string);
368                 thread->window->flush();
369                 thread->window->unlock_window();
370         }
373 SHOW_GUI_MACRO(DeInterlaceMain, DeInterlaceThread)
374 RAISE_WINDOW_MACRO(DeInterlaceMain)
375 SET_STRING_MACRO(DeInterlaceMain)
376 NEW_PICON_MACRO(DeInterlaceMain)
377 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
380 int DeInterlaceMain::load_defaults()
382         char directory[BCTEXTLEN], string[BCTEXTLEN];
383         sprintf(directory, "%sdeinterlace.rc", BCASTDIR);
384         
385         defaults = new Defaults(directory);
386         defaults->load();
387         config.mode = defaults->get("MODE", config.mode);
388         config.adaptive = defaults->get("ADAPTIVE", config.adaptive);
389         config.threshold = defaults->get("THRESHOLD", config.threshold);
390         return 0;
394 int DeInterlaceMain::save_defaults()
396         defaults->update("MODE", config.mode);
397         defaults->update("ADAPTIVE", config.adaptive);
398         defaults->update("THRESHOLD", config.threshold);
399         defaults->save();
400         return 0;
403 void DeInterlaceMain::save_data(KeyFrame *keyframe)
405         FileXML output;
406         output.set_shared_string(keyframe->data, MESSAGESIZE);
407         output.tag.set_title("DEINTERLACE");
408         output.tag.set_property("MODE", config.mode);
409         output.tag.set_property("ADAPTIVE", config.adaptive);
410         output.tag.set_property("THRESHOLD", config.threshold);
411         output.append_tag();
412         output.terminate_string();
415 void DeInterlaceMain::read_data(KeyFrame *keyframe)
417         FileXML input;
418         input.set_shared_string(keyframe->data, strlen(keyframe->data));
420         while(!input.read_tag())
421         {
422                 if(input.tag.title_is("DEINTERLACE"))
423                 {
424                         config.mode = input.tag.get_property("MODE", config.mode);
425                         config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
426                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
427                 }
428         }
432 void DeInterlaceMain::update_gui()
434         if(thread) 
435         {
436                 load_configuration();
437                 thread->window->lock_window();
438                 thread->window->set_mode(config.mode, 0);
439                 thread->window->adaptive->update(config.adaptive);
440                 thread->window->threshold->update(config.threshold);
441                 thread->window->unlock_window();
442         }