5 #include "rgb601window.h"
10 PluginClient* new_plugin(PluginServer *server)
12 return new RGB601Main(server);
16 RGB601Config::RGB601Config()
24 RGB601Main::RGB601Main(PluginServer *server)
25 : PluginVClient(server)
31 RGB601Main::~RGB601Main()
35 // Set result to 0 to indicate a server side close
36 thread->window->set_done(0);
37 thread->completion.lock();
45 char* RGB601Main::plugin_title() { return "Inverse Telecine"; }
46 int RGB601Main::is_realtime() { return 1; }
48 int RGB601Main::load_defaults()
50 char directory[1024], string[1024];
51 // set the default directory
52 sprintf(directory, "%s/rgb601.rc", File::get_config_path());
55 defaults = new Defaults(directory);
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);
65 int RGB601Main::save_defaults()
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);
75 void RGB601Main::load_configuration()
77 KeyFrame *prev_keyframe, *next_keyframe;
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);
86 void RGB601Main::save_data(KeyFrame *keyframe)
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);
98 output.tag.set_title("/RGB601");
100 output.terminate_string();
103 void RGB601Main::read_data(KeyFrame *keyframe)
107 input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
114 result = input.read_tag();
118 if(input.tag.title_is("RGB601"))
120 config.frame_offset = input.tag.get_property("FRAME_OFFSET", config.frame_offset);
121 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
122 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
123 new_threshold = input.tag.get_property("AUTO_THRESHOLD", config.auto_threshold);
128 // if(new_threshold != config.auto_threshold)
130 // config.auto_threshold = new_threshold;
136 thread->window->frame_offset->update((long)config.frame_offset);
137 thread->window->first_field->update(config.first_field);
138 thread->window->automatic->update(config.automatic);
139 // thread->window->threshold->update(config.auto_threshold);
144 int RGB601Main::start_realtime()
151 total_average = project_frame_rate;
152 // total_average = 5;
156 int RGB601Main::stop_realtime()
158 if(temp_frame[0]) delete temp_frame[0];
159 if(temp_frame[1]) delete temp_frame[1];
165 // Use all channels to get more info
166 #define COMPARE_ROWS(result, row1, row2, type, width, components) \
168 for(int i = 0; i < width * components; i++) \
170 result += labs(((type*)row1)[i] - ((type*)row2)[i]); \
174 int64_t RGB601Main::compare_fields(VFrame *frame1, VFrame *frame2, int field)
177 for(int row = field; row < frame1->get_h(); row += 2)
179 switch(frame1->get_color_model())
184 frame1->get_rows()[row],
185 frame2->get_rows()[row],
194 frame1->get_rows()[row],
195 frame2->get_rows()[row],
204 frame1->get_rows()[row],
205 frame2->get_rows()[row],
211 case BC_RGBA16161616:
212 case BC_YUVA16161616:
214 frame1->get_rows()[row],
215 frame2->get_rows()[row],
225 // Pattern A B BC CD D
226 int RGB601Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
228 load_configuration();
230 // Determine position in pattern
231 int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
233 //printf("RGB601Main::process_realtime %d %d\n", pattern_position, config.first_field);
234 if(!temp_frame[0]) temp_frame[0] = new VFrame(0,
237 input_ptr->get_color_model(),
239 if(!temp_frame[1]) temp_frame[1] = new VFrame(0,
242 input_ptr->get_color_model(),
245 int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
247 // Determine where in the pattern we are
250 int64_t field1 = compare_fields(temp_frame[0], input_ptr, 0);
251 int64_t field2 = compare_fields(temp_frame[0], input_ptr, 1);
252 int64_t threshold = (int64_t)(config.auto_threshold *
256 // if(input_ptr->get_color_model() == BC_RGBA8888 ||
257 // input_ptr->get_color_model() == BC_RGBA16161616 ||
258 // input_ptr->get_color_model() == BC_YUVA8888 ||
259 // input_ptr->get_color_model() == BC_YUVA16161616)
264 if(input_ptr->get_color_model() == BC_RGB161616 ||
265 input_ptr->get_color_model() == BC_RGBA16161616 ||
266 input_ptr->get_color_model() == BC_YUV161616 ||
267 input_ptr->get_color_model() == BC_YUVA16161616)
270 temp_frame[1]->copy_from(input_ptr);
272 // Adjust threshold over time
276 // average = threshold;
278 //printf("RGB601Main::process_realtime %d %lld %lld %lld %lld\n", state, average, threshold, field1, field2);
283 for(int i = 0; i < input_ptr->get_h(); i++)
285 if((i + new_field) & 1)
286 memcpy(output_ptr->get_rows()[i],
287 input_ptr->get_rows()[i],
290 memcpy(output_ptr->get_rows()[i],
291 temp_frame[0]->get_rows()[i],
297 if((field1 > threshold && field2 > threshold) ||
298 (field1 <= threshold && field2 <= threshold) ||
303 // Compute new threshold for next time
304 average = (int64_t)(average * total_average +
306 field2) / (total_average + 2);
308 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
309 output_ptr->copy_from(input_ptr);
312 if(field1 <= threshold && field2 >= threshold)
314 // BC bottom field new
318 // Compute new threshold for next time
319 average = (int64_t)(average * total_average +
320 field1) / (total_average + 1);
322 for(int i = 0; i < input_ptr->get_h(); i++)
325 memcpy(output_ptr->get_rows()[i],
326 temp_frame[0]->get_rows()[i],
329 memcpy(output_ptr->get_rows()[i],
330 input_ptr->get_rows()[i],
335 if(field1 >= threshold && field2 <= threshold)
341 // Compute new threshold for next time
342 average = (int64_t)(average * total_average +
343 field2) / (total_average + 1);
345 for(int i = 0; i < input_ptr->get_h(); i++)
348 memcpy(output_ptr->get_rows()[i],
349 input_ptr->get_rows()[i],
352 memcpy(output_ptr->get_rows()[i],
353 temp_frame[0]->get_rows()[i],
359 VFrame *temp = temp_frame[0];
360 temp_frame[0] = temp_frame[1];
361 temp_frame[1] = temp;
364 switch(pattern_position)
369 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
370 output_ptr->copy_from(input_ptr);
374 temp_frame[0]->copy_from(input_ptr);
375 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
376 output_ptr->copy_from(input_ptr);
380 // Save one field for next frame. Reuse previous frame.
381 temp_frame[1]->copy_from(input_ptr);
382 output_ptr->copy_from(temp_frame[0]);
386 // Combine previous field with current field.
387 for(int i = 0; i < input_ptr->get_h(); i++)
389 if((i + config.first_field) & 1)
390 memcpy(output_ptr->get_rows()[i],
391 input_ptr->get_rows()[i],
394 memcpy(output_ptr->get_rows()[i],
395 temp_frame[1]->get_rows()[i],
404 int RGB601Main::show_gui()
406 load_configuration();
407 thread = new RGB601Thread(this);
412 int RGB601Main::set_string()
414 if(thread) thread->window->set_title(gui_string);
418 void RGB601Main::raise_window()
422 thread->window->raise_window();
423 thread->window->flush();