r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / deinterlace / deinterlace.C
blob01500f4b5d325a041e57330a5df413d730eb1b21
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 "language.h"
8 #include "picon_png.h"
9 #include "vframe.h"
19 #include <stdint.h>
20 #include <string.h>
23 REGISTER_PLUGIN(DeInterlaceMain)
28 DeInterlaceConfig::DeInterlaceConfig()
30         mode = DEINTERLACE_EVEN;
31         adaptive = 1;
32         threshold = 40;
35 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
37         return mode == that.mode &&
38                 adaptive == that.adaptive &&
39                 threshold == that.threshold;
42 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
44         mode = that.mode;
45         adaptive = that.adaptive;
46         threshold = that.threshold;
49 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev, 
50         DeInterlaceConfig &next, 
51         int64_t prev_frame, 
52         int64_t next_frame, 
53         int64_t current_frame)
55         copy_from(prev);
61 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
62  : PluginVClient(server)
64         PLUGIN_CONSTRUCTOR_MACRO
65         temp = 0;
68 DeInterlaceMain::~DeInterlaceMain()
70         PLUGIN_DESTRUCTOR_MACRO
71         if(temp) delete temp;
74 char* DeInterlaceMain::plugin_title() { return N_("Deinterlace"); }
75 int DeInterlaceMain::is_realtime() { return 1; }
79 #define DEINTERLACE_EVEN_MACRO(type, components, dominance) \
80 { \
81         int w = input->get_w(); \
82         int h = input->get_h(); \
83  \
84         for(int i = 0; i < h - 1; i += 2) \
85         { \
86                 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
87                 type *output_row1 = (type*)output->get_rows()[i]; \
88                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
89                 memcpy(output_row1, input_row, w * components * sizeof(type)); \
90                 memcpy(output_row2, input_row, w * components * sizeof(type)); \
91         } \
94 #define DEINTERLACE_AVG_EVEN_MACRO(type, temp_type, components, dominance) \
95 { \
96         int w = input->get_w(); \
97         int h = input->get_h(); \
98         changed_rows = 0; \
99  \
100         type **in_rows = (type**)input->get_rows(); \
101         type **out_rows = (type**)temp->get_rows(); \
102         int max_h = h - 1; \
103         temp_type abs_diff = 0, total = 0; \
105         for(int i = 0; i < max_h; i += 2) \
106         { \
107                 int in_number1 = dominance ? i - 1 : i + 0; \
108                 int in_number2 = dominance ? i + 1 : i + 2; \
109                 int out_number1 = dominance ? i - 1 : i; \
110                 int out_number2 = dominance ? i : i + 1; \
111                 in_number1 = MAX(in_number1, 0); \
112                 in_number2 = MIN(in_number2, max_h); \
113                 out_number1 = MAX(out_number1, 0); \
114                 out_number2 = MIN(out_number2, max_h); \
116                 type *input_row1 = in_rows[in_number1]; \
117                 type *input_row2 = in_rows[in_number2]; \
118                 type *input_row3 = in_rows[out_number2]; \
119                 type *temp_row1 = out_rows[out_number1]; \
120                 type *temp_row2 = out_rows[out_number2]; \
121                 temp_type sum = 0; \
122                 temp_type accum_r, accum_b, accum_g, accum_a; \
124                 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
125                 for(int j = 0; j < w; j++) \
126                 { \
127                         accum_r = (*input_row1++) + (*input_row2++); \
128                         accum_g = (*input_row1++) + (*input_row2++); \
129                         accum_b = (*input_row1++) + (*input_row2++); \
130                         if(components == 4) \
131                                 accum_a = (*input_row1++) + (*input_row2++); \
132                         accum_r /= 2; \
133                         accum_g /= 2; \
134                         accum_b /= 2; \
135                         accum_a /= 2; \
137                         total += *input_row3; \
138                         sum = ((temp_type)*input_row3++) - accum_r; \
139                         abs_diff += (sum < 0 ? -sum : sum); \
140                         *temp_row2++ = accum_r; \
142                         total += *input_row3; \
143                         sum = ((temp_type)*input_row3++) - accum_g; \
144                         abs_diff += (sum < 0 ? -sum : sum); \
145                         *temp_row2++ = accum_g; \
147                         total += *input_row3; \
148                         sum = ((temp_type)*input_row3++) - accum_b; \
149                         abs_diff += (sum < 0 ? -sum : sum); \
150                         *temp_row2++ = accum_b; \
152                         if(components == 4) \
153                         { \
154                                 total += *input_row3; \
155                                 sum = ((temp_type)*input_row3++) - accum_a; \
156                                 abs_diff += (sum < 0 ? -sum : sum); \
157                                 *temp_row2++ = accum_a; \
158                         } \
159                 } \
160         } \
162         temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; \
163 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
164         if(abs_diff > threshold || !config.adaptive) \
165         { \
166                 output->copy_from(temp); \
167                 changed_rows = 240; \
168         } \
169         else \
170         { \
171                 output->copy_from(input); \
172                 changed_rows = 0; \
173         } \
177 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
178 { \
179         int w = input->get_w(); \
180         int h = input->get_h(); \
182         for(int i = 0; i < h - 1; i += 2) \
183         { \
184                 type *input_row1 = (type*)input->get_rows()[i]; \
185                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
186                 type *output_row1 = (type*)output->get_rows()[i]; \
187                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
188                 type result; \
190                 for(int j = 0; j < w * components; j++) \
191                 { \
192                         result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
193                         output_row1[j] = result; \
194                         output_row2[j] = result; \
195                 } \
196         } \
199 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
200 { \
201         int w = input->get_w(); \
202         int h = input->get_h(); \
204         for(int i = dominance; i < h - 1; i += 2) \
205         { \
206                 type *input_row1 = (type*)input->get_rows()[i]; \
207                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
208                 type *output_row1 = (type*)output->get_rows()[i]; \
209                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
210                 type temp1, temp2; \
212                 for(int j = 0; j < w * components; j++) \
213                 { \
214                         temp1 = input_row1[j]; \
215                         temp2 = input_row2[j]; \
216                         output_row1[j] = temp2; \
217                         output_row2[j] = temp1; \
218                 } \
219         } \
223 void DeInterlaceMain::deinterlace_even(VFrame *input, VFrame *output, int dominance)
225         switch(input->get_color_model())
226         {
227                 case BC_RGB888:
228                 case BC_YUV888:
229                         DEINTERLACE_EVEN_MACRO(unsigned char, 3, dominance);
230                         break;
231                 case BC_RGB_FLOAT:
232                         DEINTERLACE_EVEN_MACRO(float, 3, dominance);
233                         break;
234                 case BC_RGBA8888:
235                 case BC_YUVA8888:
236                         DEINTERLACE_EVEN_MACRO(unsigned char, 4, dominance);
237                         break;
238                 case BC_RGBA_FLOAT:
239                         DEINTERLACE_EVEN_MACRO(float, 4, dominance);
240                         break;
241                 case BC_RGB161616:
242                 case BC_YUV161616:
243                         DEINTERLACE_EVEN_MACRO(uint16_t, 3, dominance);
244                         break;
245                 case BC_RGBA16161616:
246                 case BC_YUVA16161616:
247                         DEINTERLACE_EVEN_MACRO(uint16_t, 4, dominance);
248                         break;
249         }
252 void DeInterlaceMain::deinterlace_avg_even(VFrame *input, VFrame *output, int dominance)
254         switch(input->get_color_model())
255         {
256                 case BC_RGB888:
257                 case BC_YUV888:
258                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 3, dominance);
259                         break;
260                 case BC_RGB_FLOAT:
261                         DEINTERLACE_AVG_EVEN_MACRO(float, double, 3, dominance);
262                         break;
263                 case BC_RGBA8888:
264                 case BC_YUVA8888:
265                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 4, dominance);
266                         break;
267                 case BC_RGBA_FLOAT:
268                         DEINTERLACE_AVG_EVEN_MACRO(float, double, 4, dominance);
269                         break;
270                 case BC_RGB161616:
271                 case BC_YUV161616:
272                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 3, dominance);
273                         break;
274                 case BC_RGBA16161616:
275                 case BC_YUVA16161616:
276                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 4, dominance);
277                         break;
278         }
281 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
283         switch(input->get_color_model())
284         {
285                 case BC_RGB888:
286                 case BC_YUV888:
287                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
288                         break;
289                 case BC_RGB_FLOAT:
290                         DEINTERLACE_AVG_MACRO(float, double, 3);
291                         break;
292                 case BC_RGBA8888:
293                 case BC_YUVA8888:
294                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
295                         break;
296                 case BC_RGBA_FLOAT:
297                         DEINTERLACE_AVG_MACRO(float, double, 4);
298                         break;
299                 case BC_RGB161616:
300                 case BC_YUV161616:
301                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
302                         break;
303                 case BC_RGBA16161616:
304                 case BC_YUVA16161616:
305                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
306                         break;
307         }
310 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
312         switch(input->get_color_model())
313         {
314                 case BC_RGB888:
315                 case BC_YUV888:
316                         DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
317                         break;
318                 case BC_RGB_FLOAT:
319                         DEINTERLACE_SWAP_MACRO(float, 3, dominance);
320                         break;
321                 case BC_RGBA8888:
322                 case BC_YUVA8888:
323                         DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
324                         break;
325                 case BC_RGBA_FLOAT:
326                         DEINTERLACE_SWAP_MACRO(float, 4, dominance);
327                         break;
328                 case BC_RGB161616:
329                 case BC_YUV161616:
330                         DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
331                         break;
332                 case BC_RGBA16161616:
333                 case BC_YUVA16161616:
334                         DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
335                         break;
336         }
340 int DeInterlaceMain::process_realtime(VFrame *input, VFrame *output)
342         changed_rows = input->get_h();
343         load_configuration();
344         if(!temp)
345                 temp = new VFrame(0,
346                         input->get_w(),
347                         input->get_h(),
348                         input->get_color_model());
350         switch(config.mode)
351         {
352                 case DEINTERLACE_NONE:
353                         output->copy_from(input);
354                         break;
355                 case DEINTERLACE_EVEN:
356                         deinterlace_even(input, output, 0);
357                         break;
358                 case DEINTERLACE_ODD:
359                         deinterlace_even(input, output, 1);
360                         break;
361                 case DEINTERLACE_AVG:
362                         deinterlace_avg(input, output);
363                         break;
364                 case DEINTERLACE_AVG_EVEN:
365                         deinterlace_avg_even(input, output, 0);
366                         break;
367                 case DEINTERLACE_AVG_ODD:
368                         deinterlace_avg_even(input, output, 1);
369                         break;
370                 case DEINTERLACE_SWAP_ODD:
371                         deinterlace_swap(input, output, 1);
372                         break;
373                 case DEINTERLACE_SWAP_EVEN:
374                         deinterlace_swap(input, output, 0);
375                         break;
376         }
377         send_render_gui(&changed_rows);
378         return 0;
381 void DeInterlaceMain::render_gui(void *data)
383         if(thread)
384         {
385                 thread->window->lock_window();
386                 char string[BCTEXTLEN];
387                 thread->window->get_status_string(string, *(int*)data);
388                 thread->window->status->update(string);
389                 thread->window->flush();
390                 thread->window->unlock_window();
391         }
394 SHOW_GUI_MACRO(DeInterlaceMain, DeInterlaceThread)
395 RAISE_WINDOW_MACRO(DeInterlaceMain)
396 SET_STRING_MACRO(DeInterlaceMain)
397 NEW_PICON_MACRO(DeInterlaceMain)
398 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
401 int DeInterlaceMain::load_defaults()
403         char directory[BCTEXTLEN], string[BCTEXTLEN];
404         sprintf(directory, "%sdeinterlace.rc", BCASTDIR);
405         
406         defaults = new Defaults(directory);
407         defaults->load();
408         config.mode = defaults->get("MODE", config.mode);
409         config.adaptive = defaults->get("ADAPTIVE", config.adaptive);
410         config.threshold = defaults->get("THRESHOLD", config.threshold);
411         return 0;
415 int DeInterlaceMain::save_defaults()
417         defaults->update("MODE", config.mode);
418         defaults->update("ADAPTIVE", config.adaptive);
419         defaults->update("THRESHOLD", config.threshold);
420         defaults->save();
421         return 0;
424 void DeInterlaceMain::save_data(KeyFrame *keyframe)
426         FileXML output;
427         output.set_shared_string(keyframe->data, MESSAGESIZE);
428         output.tag.set_title("DEINTERLACE");
429         output.tag.set_property("MODE", config.mode);
430         output.tag.set_property("ADAPTIVE", config.adaptive);
431         output.tag.set_property("THRESHOLD", config.threshold);
432         output.append_tag();
433         output.terminate_string();
436 void DeInterlaceMain::read_data(KeyFrame *keyframe)
438         FileXML input;
439         input.set_shared_string(keyframe->data, strlen(keyframe->data));
441         while(!input.read_tag())
442         {
443                 if(input.tag.title_is("DEINTERLACE"))
444                 {
445                         config.mode = input.tag.get_property("MODE", config.mode);
446                         config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
447                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
448                 }
449         }
453 void DeInterlaceMain::update_gui()
455         if(thread) 
456         {
457                 load_configuration();
458                 thread->window->lock_window();
459                 thread->window->set_mode(config.mode, 0);
460                 thread->window->adaptive->update(config.adaptive);
461                 thread->window->threshold->update(config.threshold);
462                 thread->window->unlock_window();
463         }