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