1 #include "colormodels.h"
4 #include "rgb601window.h"
9 PluginClient* new_plugin(PluginServer *server)
11 return new RGB601Main(server);
15 RGB601Config::RGB601Config()
23 RGB601Main::RGB601Main(PluginServer *server)
24 : PluginVClient(server)
30 RGB601Main::~RGB601Main()
34 // Set result to 0 to indicate a server side close
35 thread->window->set_done(0);
36 thread->completion.lock();
44 char* RGB601Main::plugin_title() { return "Inverse Telecine"; }
45 int RGB601Main::is_realtime() { return 1; }
47 int RGB601Main::load_defaults()
49 char directory[1024], string[1024];
50 // set the default directory
51 sprintf(directory, "%srgb601.rc", BCASTDIR);
54 defaults = new Defaults(directory);
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);
64 int RGB601Main::save_defaults()
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);
74 void RGB601Main::load_configuration()
76 KeyFrame *prev_keyframe, *next_keyframe;
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);
85 void RGB601Main::save_data(KeyFrame *keyframe)
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);
97 output.terminate_string();
100 void RGB601Main::read_data(KeyFrame *keyframe)
104 input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
111 result = input.read_tag();
115 if(input.tag.title_is("RGB601"))
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);
125 // if(new_threshold != config.auto_threshold)
127 // config.auto_threshold = new_threshold;
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);
141 int RGB601Main::start_realtime()
148 total_average = project_frame_rate;
149 // total_average = 5;
153 int RGB601Main::stop_realtime()
155 if(temp_frame[0]) delete temp_frame[0];
156 if(temp_frame[1]) delete temp_frame[1];
162 // Use all channels to get more info
163 #define COMPARE_ROWS(result, row1, row2, type, width, components) \
165 for(int i = 0; i < width * components; i++) \
167 result += labs(((type*)row1)[i] - ((type*)row2)[i]); \
171 int64_t RGB601Main::compare_fields(VFrame *frame1, VFrame *frame2, int field)
174 for(int row = field; row < frame1->get_h(); row += 2)
176 switch(frame1->get_color_model())
181 frame1->get_rows()[row],
182 frame2->get_rows()[row],
191 frame1->get_rows()[row],
192 frame2->get_rows()[row],
201 frame1->get_rows()[row],
202 frame2->get_rows()[row],
208 case BC_RGBA16161616:
209 case BC_YUVA16161616:
211 frame1->get_rows()[row],
212 frame2->get_rows()[row],
222 // Pattern A B BC CD D
223 int RGB601Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
225 load_configuration();
227 // Determine position in pattern
228 int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
230 //printf("RGB601Main::process_realtime %d %d\n", pattern_position, config.first_field);
231 if(!temp_frame[0]) temp_frame[0] = new VFrame(0,
234 input_ptr->get_color_model(),
236 if(!temp_frame[1]) temp_frame[1] = new VFrame(0,
239 input_ptr->get_color_model(),
242 int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
244 // Determine where in the pattern we are
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 *
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)
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)
267 temp_frame[1]->copy_from(input_ptr);
269 // Adjust threshold over time
273 // average = threshold;
275 //printf("RGB601Main::process_realtime %d %lld %lld %lld %lld\n", state, average, threshold, field1, field2);
280 for(int i = 0; i < input_ptr->get_h(); i++)
282 if((i + new_field) & 1)
283 memcpy(output_ptr->get_rows()[i],
284 input_ptr->get_rows()[i],
287 memcpy(output_ptr->get_rows()[i],
288 temp_frame[0]->get_rows()[i],
294 if((field1 > threshold && field2 > threshold) ||
295 (field1 <= threshold && field2 <= threshold) ||
300 // Compute new threshold for next time
301 average = (int64_t)(average * total_average +
303 field2) / (total_average + 2);
305 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
306 output_ptr->copy_from(input_ptr);
309 if(field1 <= threshold && field2 >= threshold)
311 // BC bottom field new
315 // Compute new threshold for next time
316 average = (int64_t)(average * total_average +
317 field1) / (total_average + 1);
319 for(int i = 0; i < input_ptr->get_h(); i++)
322 memcpy(output_ptr->get_rows()[i],
323 temp_frame[0]->get_rows()[i],
326 memcpy(output_ptr->get_rows()[i],
327 input_ptr->get_rows()[i],
332 if(field1 >= threshold && field2 <= threshold)
338 // Compute new threshold for next time
339 average = (int64_t)(average * total_average +
340 field2) / (total_average + 1);
342 for(int i = 0; i < input_ptr->get_h(); i++)
345 memcpy(output_ptr->get_rows()[i],
346 input_ptr->get_rows()[i],
349 memcpy(output_ptr->get_rows()[i],
350 temp_frame[0]->get_rows()[i],
356 VFrame *temp = temp_frame[0];
357 temp_frame[0] = temp_frame[1];
358 temp_frame[1] = temp;
361 switch(pattern_position)
366 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
367 output_ptr->copy_from(input_ptr);
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);
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]);
383 // Combine previous field with current field.
384 for(int i = 0; i < input_ptr->get_h(); i++)
386 if((i + config.first_field) & 1)
387 memcpy(output_ptr->get_rows()[i],
388 input_ptr->get_rows()[i],
391 memcpy(output_ptr->get_rows()[i],
392 temp_frame[1]->get_rows()[i],
401 int RGB601Main::show_gui()
403 load_configuration();
404 thread = new RGB601Thread(this);
409 int RGB601Main::set_string()
411 if(thread) thread->window->set_title(gui_string);
415 void RGB601Main::raise_window()
419 thread->window->raise_window();
420 thread->window->flush();