update internationalization data
[goodguy/history.git] / cinelerra-5.0 / plugins / rgb601 / ivtc.C.2
1 #include "colormodels.h"
2 #include "filexml.h"
3 #include "rgb601.h"
4 #include "rgb601window.h"
5
6 #include <stdio.h>
7 #include <string.h>
8
9 PluginClient* new_plugin(PluginServer *server)
10 {
11         return new RGB601Main(server);
12 }
13
14
15 RGB601Config::RGB601Config()
16 {
17         frame_offset = 0;
18         first_field = 0;
19         automatic = 1;
20         auto_threshold = 2;
21 }
22
23 RGB601Main::RGB601Main(PluginServer *server)
24  : PluginVClient(server)
25 {
26         thread = 0;
27         load_defaults();
28 }
29
30 RGB601Main::~RGB601Main()
31 {
32         if(thread)
33         {
34 // Set result to 0 to indicate a server side close
35                 thread->window->set_done(0);
36                 thread->completion.lock();
37                 delete thread;
38         }
39
40         save_defaults();
41         delete defaults;
42 }
43
44 char* RGB601Main::plugin_title() { return _("Inverse Telecine"); }
45 int RGB601Main::is_realtime() { return 1; }
46
47 int RGB601Main::load_defaults()
48 {
49         char directory[1024], string[1024];
50 // set the default directory
51         sprintf(directory, "%srgb601.rc", BCASTDIR);
52
53 // load the defaults
54         defaults = new Defaults(directory);
55         defaults->load();
56
57         config.frame_offset = defaults->get("FRAME_OFFSET", config.frame_offset);
58         config.first_field = defaults->get("FIRST_FIELD", config.first_field);
59         config.automatic = defaults->get("AUTOMATIC", config.automatic);
60         config.auto_threshold = defaults->get("AUTO_THRESHOLD", config.auto_threshold);
61         return 0;
62 }
63
64 int RGB601Main::save_defaults()
65 {
66         defaults->update("FRAME_OFFSET", config.frame_offset);
67         defaults->update("FIRST_FIELD", config.first_field);
68         defaults->update("AUTOMATIC", config.automatic);
69         defaults->update("AUTO_THRESHOLD", config.auto_threshold);
70         defaults->save();
71         return 0;
72 }
73
74 void RGB601Main::load_configuration()
75 {
76         KeyFrame *prev_keyframe, *next_keyframe;
77
78         prev_keyframe = get_prev_keyframe(-1);
79         next_keyframe = get_next_keyframe(-1);
80 // Must also switch between interpolation between keyframes and using first keyframe
81         read_data(prev_keyframe);
82 }
83
84
85 void RGB601Main::save_data(KeyFrame *keyframe)
86 {
87         FileXML output;
88
89 // cause data to be stored directly in text
90         output.set_shared_string(keyframe->get_data(), -MESSAGESIZE);
91         output.tag.set_title("RGB601");
92         output.tag.set_property("FRAME_OFFSET", config.frame_offset);
93         output.tag.set_property("FIRST_FIELD", config.first_field);
94         output.tag.set_property("AUTOMATIC", config.automatic);
95         output.tag.set_property("AUTO_THRESHOLD", config.auto_threshold);
96         output.append_tag();
97         output.terminate_string();
98 }
99
100 void RGB601Main::read_data(KeyFrame *keyframe)
101 {
102         FileXML input;
103
104         input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
105
106         int result = 0;
107         float new_threshold;
108
109         while(!result)
110         {
111                 result = input.read_tag();
112
113                 if(!result)
114                 {
115                         if(input.tag.title_is("RGB601"))
116                         {
117                                 config.frame_offset = input.tag.get_property("FRAME_OFFSET", config.frame_offset);
118                                 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
119                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
120                                 new_threshold = input.tag.get_property("AUTO_THRESHOLD", config.auto_threshold);
121                         }
122                 }
123         }
124
125 //      if(new_threshold != config.auto_threshold)
126 //      {
127 //              config.auto_threshold = new_threshold;
128 //              average = -1;
129 //      }
130
131         if(thread) 
132         {
133                 thread->window->frame_offset->update((long)config.frame_offset);
134                 thread->window->first_field->update(config.first_field);
135                 thread->window->automatic->update(config.automatic);
136 //              thread->window->threshold->update(config.auto_threshold);
137         }
138 }
139
140
141 int RGB601Main::start_realtime()
142 {
143         temp_frame[0] = 0;
144         temp_frame[1] = 0;
145         state = 0;
146         new_field = 0;
147         average = 0;
148         total_average = project_frame_rate;
149 //      total_average = 5;
150         return 0;
151 }
152
153 int RGB601Main::stop_realtime()
154 {
155         if(temp_frame[0]) delete temp_frame[0];
156         if(temp_frame[1]) delete temp_frame[1];
157         temp_frame[0] = 0;
158         temp_frame[1] = 0;
159         return 0;
160 }
161
162 // Use all channels to get more info
163 #define COMPARE_ROWS(result, row1, row2, type, width, components) \
164 { \
165         for(int i = 0; i < width * components; i++) \
166         { \
167                 result += labs(((type*)row1)[i] - ((type*)row2)[i]); \
168         } \
169 }
170
171 int64_t RGB601Main::compare_fields(VFrame *frame1, VFrame *frame2, int field)
172 {
173         int64_t result = 0;
174         for(int row = field; row < frame1->get_h(); row += 2)
175         {
176                 switch(frame1->get_color_model())
177                 {
178                         case BC_RGB888:
179                         case BC_YUV888:
180                                 COMPARE_ROWS(result, 
181                                         frame1->get_rows()[row], 
182                                         frame2->get_rows()[row], 
183                                         unsigned char, 
184                                         frame1->get_w(), 
185                                         3);
186                                 break;
187
188                         case BC_RGBA8888:
189                         case BC_YUVA8888:
190                                 COMPARE_ROWS(result, 
191                                         frame1->get_rows()[row], 
192                                         frame2->get_rows()[row], 
193                                         unsigned char, 
194                                         frame1->get_w(),
195                                         4);
196                                 break;
197
198                         case BC_RGB161616:
199                         case BC_YUV161616:
200                                 COMPARE_ROWS(result, 
201                                         frame1->get_rows()[row], 
202                                         frame2->get_rows()[row], 
203                                         u_int16_t, 
204                                         frame1->get_w(),
205                                         3);
206                                 break;
207                         
208                         case BC_RGBA16161616:
209                         case BC_YUVA16161616:
210                                 COMPARE_ROWS(result, 
211                                         frame1->get_rows()[row], 
212                                         frame2->get_rows()[row], 
213                                         u_int16_t, 
214                                         frame1->get_w(),
215                                         4);
216                                 break;
217                 }
218         }
219         return result;
220 }
221
222 // Pattern A B BC CD D
223 int RGB601Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
224 {
225         load_configuration();
226
227 // Determine position in pattern
228         int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
229
230 //printf("RGB601Main::process_realtime %d %d\n", pattern_position, config.first_field);
231         if(!temp_frame[0]) temp_frame[0] = new VFrame(0,
232                 input_ptr->get_w(),
233                 input_ptr->get_h(),
234                 input_ptr->get_color_model(),
235                 -1);
236         if(!temp_frame[1]) temp_frame[1] = new VFrame(0,
237                 input_ptr->get_w(),
238                 input_ptr->get_h(),
239                 input_ptr->get_color_model(),
240                 -1);
241
242         int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
243
244 // Determine where in the pattern we are
245         if(config.automatic)
246         {
247                 int64_t field1 = compare_fields(temp_frame[0], input_ptr, 0);
248                 int64_t field2 = compare_fields(temp_frame[0], input_ptr, 1);
249                 int64_t threshold = (int64_t)(config.auto_threshold * 
250                         input_ptr->get_w() * 
251                         input_ptr->get_h());
252
253 //              if(input_ptr->get_color_model() == BC_RGBA8888 ||
254 //                      input_ptr->get_color_model() == BC_RGBA16161616 ||
255 //                      input_ptr->get_color_model() == BC_YUVA8888 ||
256 //                      input_ptr->get_color_model() == BC_YUVA16161616)
257 //                      threshold *= 4;
258 //              else
259                         threshold *= 3;
260
261                 if(input_ptr->get_color_model() == BC_RGB161616 ||
262                         input_ptr->get_color_model() == BC_RGBA16161616 ||
263                         input_ptr->get_color_model() == BC_YUV161616 ||
264                         input_ptr->get_color_model() == BC_YUVA16161616)
265                         threshold *= 0x100;
266
267                 temp_frame[1]->copy_from(input_ptr);
268
269 // Adjust threshold over time
270 //              if(average >= 0)
271                         threshold = average;
272 //              else
273 //                      average = threshold;
274
275 //printf("RGB601Main::process_realtime %d %lld %lld %lld %lld\n", state, average, threshold, field1, field2);
276 // CD
277                 if(state == 3)
278                 {
279                         state = 4;
280                         for(int i = 0; i < input_ptr->get_h(); i++)
281                         {
282                                 if((i + new_field) & 1)
283                                         memcpy(output_ptr->get_rows()[i], 
284                                                 input_ptr->get_rows()[i],
285                                                 row_size);
286                                 else
287                                         memcpy(output_ptr->get_rows()[i],
288                                                 temp_frame[0]->get_rows()[i],
289                                                 row_size);
290                         }
291                 }
292                 else
293 // A or B or D
294                 if((field1 > threshold && field2 > threshold) ||
295                         (field1 <= threshold && field2 <= threshold) ||
296                         state == 4)
297                 {
298                         state = 0;
299
300 // Compute new threshold for next time
301                         average = (int64_t)(average * total_average + 
302                                 field1 + 
303                                 field2) / (total_average + 2);
304
305                         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
306                                 output_ptr->copy_from(input_ptr);
307                 }
308                 else
309                 if(field1 <= threshold && field2 >= threshold)
310                 {
311 // BC bottom field new
312                         state = 3;
313                         new_field = 1;
314
315 // Compute new threshold for next time
316                         average = (int64_t)(average * total_average + 
317                                 field1) / (total_average + 1);
318
319                         for(int i = 0; i < input_ptr->get_h(); i++)
320                         {
321                                 if(i & 1)
322                                         memcpy(output_ptr->get_rows()[i], 
323                                                 temp_frame[0]->get_rows()[i],
324                                                 row_size);
325                                 else
326                                         memcpy(output_ptr->get_rows()[i],
327                                                 input_ptr->get_rows()[i],
328                                                 row_size);
329                         }
330                 }
331                 else
332                 if(field1 >= threshold && field2 <= threshold)
333                 {
334 // BC top field new
335                         state = 3;
336                         new_field = 0;
337
338 // Compute new threshold for next time
339                         average = (int64_t)(average * total_average + 
340                                 field2) / (total_average + 1);
341
342                         for(int i = 0; i < input_ptr->get_h(); i++)
343                         {
344                                 if(i & 1)
345                                         memcpy(output_ptr->get_rows()[i],
346                                                 input_ptr->get_rows()[i],
347                                                 row_size);
348                                 else
349                                         memcpy(output_ptr->get_rows()[i], 
350                                                 temp_frame[0]->get_rows()[i],
351                                                 row_size);
352                         }
353                 }
354
355 // Swap temp frames
356                 VFrame *temp = temp_frame[0];
357                 temp_frame[0] = temp_frame[1];
358                 temp_frame[1] = temp;
359         }
360         else
361         switch(pattern_position)
362         {
363 // Direct copy
364                 case 0:
365                 case 4:
366                         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
367                                 output_ptr->copy_from(input_ptr);
368                         break;
369
370                 case 1:
371                         temp_frame[0]->copy_from(input_ptr);
372                         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
373                                 output_ptr->copy_from(input_ptr);
374                         break;
375
376                 case 2:
377 // Save one field for next frame.  Reuse previous frame.
378                         temp_frame[1]->copy_from(input_ptr);
379                         output_ptr->copy_from(temp_frame[0]);
380                         break;
381
382                 case 3:
383 // Combine previous field with current field.
384                         for(int i = 0; i < input_ptr->get_h(); i++)
385                         {
386                                 if((i + config.first_field) & 1)
387                                         memcpy(output_ptr->get_rows()[i], 
388                                                 input_ptr->get_rows()[i],
389                                                 row_size);
390                                 else
391                                         memcpy(output_ptr->get_rows()[i], 
392                                                 temp_frame[1]->get_rows()[i],
393                                                 row_size);
394                         }
395                         break;
396         }
397
398         return 0;
399 }
400
401 int RGB601Main::show_gui()
402 {
403         load_configuration();
404         thread = new RGB601Thread(this);
405         thread->start();
406         return 0;
407 }
408
409 int RGB601Main::set_string()
410 {
411         if(thread) thread->window->set_title(gui_string);
412         return 0;
413 }
414
415 void RGB601Main::raise_window()
416 {
417         if(thread)
418         {
419                 thread->window->raise_window();
420                 thread->window->flush();
421         }
422 }
423
424
425