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.terminate_string();
101 void RGB601Main::read_data(KeyFrame *keyframe)
105 input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
112 result = input.read_tag();
116 if(input.tag.title_is("RGB601"))
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);
126 // if(new_threshold != config.auto_threshold)
128 // config.auto_threshold = new_threshold;
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);
142 int RGB601Main::start_realtime()
149 total_average = project_frame_rate;
150 // total_average = 5;
154 int RGB601Main::stop_realtime()
156 if(temp_frame[0]) delete temp_frame[0];
157 if(temp_frame[1]) delete temp_frame[1];
163 // Use all channels to get more info
164 #define COMPARE_ROWS(result, row1, row2, type, width, components) \
166 for(int i = 0; i < width * components; i++) \
168 result += labs(((type*)row1)[i] - ((type*)row2)[i]); \
172 int64_t RGB601Main::compare_fields(VFrame *frame1, VFrame *frame2, int field)
175 for(int row = field; row < frame1->get_h(); row += 2)
177 switch(frame1->get_color_model())
182 frame1->get_rows()[row],
183 frame2->get_rows()[row],
192 frame1->get_rows()[row],
193 frame2->get_rows()[row],
202 frame1->get_rows()[row],
203 frame2->get_rows()[row],
209 case BC_RGBA16161616:
210 case BC_YUVA16161616:
212 frame1->get_rows()[row],
213 frame2->get_rows()[row],
223 // Pattern A B BC CD D
224 int RGB601Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
226 load_configuration();
228 // Determine position in pattern
229 int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
231 //printf("RGB601Main::process_realtime %d %d\n", pattern_position, config.first_field);
232 if(!temp_frame[0]) temp_frame[0] = new VFrame(0,
235 input_ptr->get_color_model(),
237 if(!temp_frame[1]) temp_frame[1] = new VFrame(0,
240 input_ptr->get_color_model(),
243 int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
245 // Determine where in the pattern we are
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 *
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)
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)
268 temp_frame[1]->copy_from(input_ptr);
270 // Adjust threshold over time
274 // average = threshold;
276 //printf("RGB601Main::process_realtime %d %lld %lld %lld %lld\n", state, average, threshold, field1, field2);
281 for(int i = 0; i < input_ptr->get_h(); i++)
283 if((i + new_field) & 1)
284 memcpy(output_ptr->get_rows()[i],
285 input_ptr->get_rows()[i],
288 memcpy(output_ptr->get_rows()[i],
289 temp_frame[0]->get_rows()[i],
295 if((field1 > threshold && field2 > threshold) ||
296 (field1 <= threshold && field2 <= threshold) ||
301 // Compute new threshold for next time
302 average = (int64_t)(average * total_average +
304 field2) / (total_average + 2);
306 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
307 output_ptr->copy_from(input_ptr);
310 if(field1 <= threshold && field2 >= threshold)
312 // BC bottom field new
316 // Compute new threshold for next time
317 average = (int64_t)(average * total_average +
318 field1) / (total_average + 1);
320 for(int i = 0; i < input_ptr->get_h(); i++)
323 memcpy(output_ptr->get_rows()[i],
324 temp_frame[0]->get_rows()[i],
327 memcpy(output_ptr->get_rows()[i],
328 input_ptr->get_rows()[i],
333 if(field1 >= threshold && field2 <= threshold)
339 // Compute new threshold for next time
340 average = (int64_t)(average * total_average +
341 field2) / (total_average + 1);
343 for(int i = 0; i < input_ptr->get_h(); i++)
346 memcpy(output_ptr->get_rows()[i],
347 input_ptr->get_rows()[i],
350 memcpy(output_ptr->get_rows()[i],
351 temp_frame[0]->get_rows()[i],
357 VFrame *temp = temp_frame[0];
358 temp_frame[0] = temp_frame[1];
359 temp_frame[1] = temp;
362 switch(pattern_position)
367 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
368 output_ptr->copy_from(input_ptr);
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);
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]);
384 // Combine previous field with current field.
385 for(int i = 0; i < input_ptr->get_h(); i++)
387 if((i + config.first_field) & 1)
388 memcpy(output_ptr->get_rows()[i],
389 input_ptr->get_rows()[i],
392 memcpy(output_ptr->get_rows()[i],
393 temp_frame[1]->get_rows()[i],
402 int RGB601Main::show_gui()
404 load_configuration();
405 thread = new RGB601Thread(this);
410 int RGB601Main::set_string()
412 if(thread) thread->window->set_title(gui_string);
416 void RGB601Main::raise_window()
420 thread->window->raise_window();
421 thread->window->flush();