1 #include "colormodels.h"
5 #include "ivtcwindow.h"
10 PluginClient* new_plugin(PluginServer *server)
12 return new IVTCMain(server);
16 IVTCConfig::IVTCConfig()
24 IVTCMain::IVTCMain(PluginServer *server)
25 : PluginVClient(server)
35 // Set result to 0 to indicate a server side close
36 thread->window->set_done(0);
37 thread->completion.lock();
45 char* IVTCMain::plugin_title() { return "Inverse Telecine"; }
46 int IVTCMain::is_realtime() { return 1; }
48 VFrame* IVTCMain::new_picon()
50 return new VFrame(picon_png);
53 int IVTCMain::load_defaults()
55 char directory[1024], string[1024];
56 // set the default directory
57 sprintf(directory, "%sivtc.rc", BCASTDIR);
60 defaults = new Defaults(directory);
63 config.frame_offset = defaults->get("FRAME_OFFSET", config.frame_offset);
64 config.first_field = defaults->get("FIRST_FIELD", config.first_field);
65 config.automatic = defaults->get("AUTOMATIC", config.automatic);
66 config.auto_threshold = defaults->get("AUTO_THRESHOLD", config.auto_threshold);
70 int IVTCMain::save_defaults()
72 defaults->update("FRAME_OFFSET", config.frame_offset);
73 defaults->update("FIRST_FIELD", config.first_field);
74 defaults->update("AUTOMATIC", config.automatic);
75 defaults->update("AUTO_THRESHOLD", config.auto_threshold);
80 void IVTCMain::load_configuration()
82 KeyFrame *prev_keyframe, *next_keyframe;
84 prev_keyframe = get_prev_keyframe(-1);
85 next_keyframe = get_next_keyframe(-1);
86 // Must also switch between interpolation between keyframes and using first keyframe
87 read_data(prev_keyframe);
91 void IVTCMain::save_data(KeyFrame *keyframe)
95 // cause data to be stored directly in text
96 output.set_shared_string(keyframe->data, MESSAGESIZE);
97 output.tag.set_title("IVTC");
98 output.tag.set_property("FRAME_OFFSET", config.frame_offset);
99 output.tag.set_property("FIRST_FIELD", config.first_field);
100 output.tag.set_property("AUTOMATIC", config.automatic);
101 output.tag.set_property("AUTO_THRESHOLD", config.auto_threshold);
103 output.terminate_string();
106 void IVTCMain::read_data(KeyFrame *keyframe)
110 input.set_shared_string(keyframe->data, strlen(keyframe->data));
117 result = input.read_tag();
121 if(input.tag.title_is("IVTC"))
123 config.frame_offset = input.tag.get_property("FRAME_OFFSET", config.frame_offset);
124 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
125 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
126 new_threshold = input.tag.get_property("AUTO_THRESHOLD", config.auto_threshold);
131 // if(new_threshold != config.auto_threshold)
133 // config.auto_threshold = new_threshold;
139 thread->window->frame_offset->update((long)config.frame_offset);
140 thread->window->first_field->update(config.first_field);
141 thread->window->automatic->update(config.automatic);
142 // thread->window->threshold->update(config.auto_threshold);
147 int IVTCMain::start_realtime()
154 total_average = project_frame_rate;
155 // total_average = 5;
159 int IVTCMain::stop_realtime()
161 if(temp_frame[0]) delete temp_frame[0];
162 if(temp_frame[1]) delete temp_frame[1];
168 // Use all channels to get more info
169 #define COMPARE_ROWS(result, row1, row2, type, width, components) \
171 for(int i = 0; i < width * components; i++) \
173 result += labs(((type*)row1)[i] - ((type*)row2)[i]); \
177 int64_t IVTCMain::compare_fields(VFrame *frame1, VFrame *frame2, int field)
180 for(int row = field; row < frame1->get_h(); row += 2)
182 switch(frame1->get_color_model())
187 frame1->get_rows()[row],
188 frame2->get_rows()[row],
197 frame1->get_rows()[row],
198 frame2->get_rows()[row],
207 frame1->get_rows()[row],
208 frame2->get_rows()[row],
214 case BC_RGBA16161616:
215 case BC_YUVA16161616:
217 frame1->get_rows()[row],
218 frame2->get_rows()[row],
228 // Pattern A B BC CD D
229 int IVTCMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
231 load_configuration();
233 // Determine position in pattern
234 int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
236 //printf("IVTCMain::process_realtime %d %d\n", pattern_position, config.first_field);
237 if(!temp_frame[0]) temp_frame[0] = new VFrame(0,
240 input_ptr->get_color_model(),
242 if(!temp_frame[1]) temp_frame[1] = new VFrame(0,
245 input_ptr->get_color_model(),
248 int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
250 // Determine where in the pattern we are
253 int64_t field1 = compare_fields(temp_frame[0], input_ptr, 0);
254 int64_t field2 = compare_fields(temp_frame[0], input_ptr, 1);
255 int64_t threshold = (int64_t)(config.auto_threshold *
259 // if(input_ptr->get_color_model() == BC_RGBA8888 ||
260 // input_ptr->get_color_model() == BC_RGBA16161616 ||
261 // input_ptr->get_color_model() == BC_YUVA8888 ||
262 // input_ptr->get_color_model() == BC_YUVA16161616)
267 if(input_ptr->get_color_model() == BC_RGB161616 ||
268 input_ptr->get_color_model() == BC_RGBA16161616 ||
269 input_ptr->get_color_model() == BC_YUV161616 ||
270 input_ptr->get_color_model() == BC_YUVA16161616)
273 temp_frame[1]->copy_from(input_ptr);
275 // Adjust threshold over time
279 // average = threshold;
281 //printf("IVTCMain::process_realtime %d %lld %lld %lld %lld\n", state, average, threshold, field1, field2);
286 for(int i = 0; i < input_ptr->get_h(); i++)
288 if((i + new_field) & 1)
289 memcpy(output_ptr->get_rows()[i],
290 input_ptr->get_rows()[i],
293 memcpy(output_ptr->get_rows()[i],
294 temp_frame[0]->get_rows()[i],
300 if((field1 > threshold && field2 > threshold) ||
301 (field1 <= threshold && field2 <= threshold) ||
306 // Compute new threshold for next time
307 average = (int64_t)(average * total_average +
309 field2) / (total_average + 2);
311 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
312 output_ptr->copy_from(input_ptr);
315 if(field1 <= threshold && field2 >= threshold)
317 // BC bottom field new
321 // Compute new threshold for next time
322 average = (int64_t)(average * total_average +
323 field1) / (total_average + 1);
325 for(int i = 0; i < input_ptr->get_h(); i++)
328 memcpy(output_ptr->get_rows()[i],
329 temp_frame[0]->get_rows()[i],
332 memcpy(output_ptr->get_rows()[i],
333 input_ptr->get_rows()[i],
338 if(field1 >= threshold && field2 <= threshold)
344 // Compute new threshold for next time
345 average = (int64_t)(average * total_average +
346 field2) / (total_average + 1);
348 for(int i = 0; i < input_ptr->get_h(); i++)
351 memcpy(output_ptr->get_rows()[i],
352 input_ptr->get_rows()[i],
355 memcpy(output_ptr->get_rows()[i],
356 temp_frame[0]->get_rows()[i],
362 VFrame *temp = temp_frame[0];
363 temp_frame[0] = temp_frame[1];
364 temp_frame[1] = temp;
367 switch(pattern_position)
372 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
373 output_ptr->copy_from(input_ptr);
377 temp_frame[0]->copy_from(input_ptr);
378 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
379 output_ptr->copy_from(input_ptr);
383 // Save one field for next frame. Reuse previous frame.
384 temp_frame[1]->copy_from(input_ptr);
385 output_ptr->copy_from(temp_frame[0]);
389 // Combine previous field with current field.
390 for(int i = 0; i < input_ptr->get_h(); i++)
392 if((i + config.first_field) & 1)
393 memcpy(output_ptr->get_rows()[i],
394 input_ptr->get_rows()[i],
397 memcpy(output_ptr->get_rows()[i],
398 temp_frame[1]->get_rows()[i],
407 int IVTCMain::show_gui()
409 load_configuration();
410 thread = new IVTCThread(this);
415 int IVTCMain::set_string()
417 if(thread) thread->window->set_title(gui_string);
421 void IVTCMain::raise_window()
425 thread->window->raise_window();
426 thread->window->flush();