1 #include "bcdisplayinfo.h"
6 #include "overlayframe.h"
16 REGISTER_PLUGIN(ShapeWipeMain)
18 ShapeWipeW2B::ShapeWipeW2B(ShapeWipeMain *plugin,
19 ShapeWipeWindow *window,
24 plugin->direction == 0,
27 this->plugin = plugin;
28 this->window = window;
31 int ShapeWipeW2B::handle_event()
34 plugin->direction = 0;
35 window->right->update(0);
36 plugin->send_configure_change();
40 ShapeWipeB2W::ShapeWipeB2W(ShapeWipeMain *plugin,
41 ShapeWipeWindow *window,
46 plugin->direction == 1,
49 this->plugin = plugin;
50 this->window = window;
53 int ShapeWipeB2W::handle_event()
56 plugin->direction = 1;
57 window->left->update(0);
58 plugin->send_configure_change();
62 ShapeWipeAntiAlias::ShapeWipeAntiAlias(ShapeWipeMain *plugin,
63 ShapeWipeWindow *window,
66 : BC_CheckBox (x,y,plugin->antialias, _("Anti-aliasing"))
68 this->plugin = plugin;
69 this->window = window;
72 int ShapeWipeAntiAlias::handle_event()
74 plugin->antialias = get_value();
75 plugin->send_configure_change();
79 ShapeWipePreserveAspectRatio::ShapeWipePreserveAspectRatio(ShapeWipeMain *plugin,
80 ShapeWipeWindow *window,
83 : BC_CheckBox (x,y,plugin->preserve_aspect, _("Preserve shape aspect ratio"))
85 this->plugin = plugin;
86 this->window = window;
89 int ShapeWipePreserveAspectRatio::handle_event()
91 plugin->preserve_aspect = get_value();
92 plugin->send_configure_change();
96 ShapeWipeFilename::ShapeWipeFilename(
97 ShapeWipeMain *plugin,
98 ShapeWipeWindow *window,
102 : BC_TextBox(x,y,180,1, value)
104 this->plugin = plugin;
105 this->window = window;
109 int ShapeWipeFilename::handle_event()
112 strcpy(plugin->filename, get_text());
113 plugin->send_configure_change();
117 ShapeWipeBrowseButton::ShapeWipeBrowseButton(
118 ShapeWipeMain *plugin,
119 ShapeWipeWindow *window,
120 ShapeWipeFilename *filename,
123 : BC_GenericButton(x,y,_("Browse..."))
125 this->plugin = plugin;
126 this->window = window;
127 this->filename = filename;
130 int ShapeWipeBrowseButton::handle_event()
133 ShapeWipeLoad window(filename, filename->get_text());
134 window.create_objects();
135 window.update_filter("*.png");
136 result = window.run_window();
140 filename->update(window.get_submitted_path());
141 strcpy(plugin->filename, window.get_submitted_path());
142 plugin->send_configure_change();
148 ShapeWipeLoad::ShapeWipeLoad(
149 ShapeWipeFilename *filename,
150 char *init_directory)
156 _("Choose a Wipe Shape"))
158 this->filename = filename;
161 ShapeWipeWindow::ShapeWipeWindow(ShapeWipeMain *plugin, int x, int y)
162 : BC_Window(plugin->gui_string,
173 this->plugin = plugin;
176 int ShapeWipeWindow::close_event()
182 void ShapeWipeWindow::create_objects()
185 add_subwindow(new BC_Title(x, y, _("Direction:")));
187 add_subwindow(left = new ShapeWipeW2B(plugin,
192 add_subwindow(right = new ShapeWipeB2W(plugin,
197 add_subwindow(new BC_Title(x, y, _("Shape:")));
200 add_subwindow(filename_widget = new
201 ShapeWipeFilename(plugin,
207 add_subwindow(new ShapeWipeBrowseButton(
214 add_subwindow(new ShapeWipeAntiAlias(
220 add_subwindow(new ShapeWipePreserveAspectRatio(
229 PLUGIN_THREAD_OBJECT(ShapeWipeMain, ShapeWipeThread, ShapeWipeWindow)
231 ShapeWipeMain::ShapeWipeMain(PluginServer *server)
232 : PluginVClient(server)
235 strcpy(filename, DEFAULT_SHAPE); // is defined by a -D compiler instruction
236 last_read_filename[0] = '\0';
237 pattern_image = NULL;
242 last_preserve_aspect = 0;
243 PLUGIN_CONSTRUCTOR_MACRO
246 ShapeWipeMain::~ShapeWipeMain()
248 reset_pattern_image();
249 PLUGIN_DESTRUCTOR_MACRO
252 char* ShapeWipeMain::plugin_title() { return N_("Shape Wipe"); }
253 int ShapeWipeMain::is_video() { return 1; }
254 int ShapeWipeMain::is_transition() { return 1; }
255 int ShapeWipeMain::uses_gui() { return 1; }
257 SHOW_GUI_MACRO(ShapeWipeMain, ShapeWipeThread);
258 SET_STRING_MACRO(ShapeWipeMain)
259 RAISE_WINDOW_MACRO(ShapeWipeMain)
262 VFrame* ShapeWipeMain::new_picon()
264 return new VFrame(picon_png);
267 int ShapeWipeMain::load_defaults()
269 char directory[BCTEXTLEN];
270 // set the default directory
271 sprintf(directory, "%sshapewipe.rc", BCASTDIR);
274 defaults = new Defaults(directory);
277 direction = defaults->get("DIRECTION", direction);
278 antialias = defaults->get("ANTIALIAS", antialias);
279 preserve_aspect = defaults->get("PRESERVE_ASPECT", preserve_aspect);
280 defaults->get("FILENAME", filename);
284 int ShapeWipeMain::save_defaults()
286 defaults->update("DIRECTION", direction);
287 defaults->update("ANTIALIAS", antialias);
288 defaults->update("PRESERVE_ASPECT", preserve_aspect);
289 defaults->update("FILENAME", filename);
294 void ShapeWipeMain::save_data(KeyFrame *keyframe)
297 output.set_shared_string(keyframe->data, MESSAGESIZE);
298 output.tag.set_title("SHAPEWIPE");
299 output.tag.set_property("DIRECTION", direction);
300 output.tag.set_property("ANTIALIAS", antialias);
301 output.tag.set_property("PRESERVE_ASPECT", preserve_aspect);
302 output.tag.set_property("FILENAME", filename);
304 output.terminate_string();
307 void ShapeWipeMain::read_data(KeyFrame *keyframe)
311 input.set_shared_string(keyframe->data, strlen(keyframe->data));
313 while(!input.read_tag())
315 if(input.tag.title_is("SHAPEWIPE"))
317 direction = input.tag.get_property("DIRECTION", direction);
318 antialias = input.tag.get_property("ANTIALIAS", antialias);
319 preserve_aspect = input.tag.get_property("PRESERVE_ASPECT", preserve_aspect);
320 input.tag.get_property("FILENAME", filename);
325 void ShapeWipeMain::load_configuration()
327 read_data(get_prev_keyframe(get_source_position()));
330 int ShapeWipeMain::read_pattern_image(int new_frame_width, int new_frame_height)
348 frame_width = new_frame_width;
349 frame_height = new_frame_height;
351 FILE *fp = fopen(filename, "rb");
357 fread(header, 1, 8, fp);
358 is_png = !png_sig_cmp(header, 0, 8);
365 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
366 png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL);
373 /* Tell libpng we already checked the first 8 bytes */
374 png_set_sig_bytes(png_ptr, 8);
376 info_ptr = png_create_info_struct(png_ptr);
379 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
383 end_info = png_create_info_struct(png_ptr);
386 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
390 png_init_io(png_ptr, fp);
391 png_read_info(png_ptr, info_ptr);
393 color_type = png_get_color_type(png_ptr, info_ptr);
394 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
395 width = png_get_image_width (png_ptr, info_ptr);
396 height = png_get_image_height(png_ptr, info_ptr);
398 /* Skip the alpha channel if present
399 * stripping alpha currently doesn't work in conjunction with
400 * converting to grayscale in libpng */
401 if (color_type & PNG_COLOR_MASK_ALPHA)
406 /* Convert 16 bit data to 8 bit */
407 if (bit_depth == 16) png_set_strip_16(png_ptr);
409 /* Expand to 1 pixel per byte if necessary */
410 if (bit_depth < 8) png_set_packing(png_ptr);
412 /* Convert to grayscale */
413 if (color_type == PNG_COLOR_TYPE_RGB
414 || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
415 png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1);
417 /* Allocate memory to hold the original png image */
418 image = (png_bytep*)malloc(sizeof(png_bytep)*height);
419 for (row = 0; row < height; row++)
421 image[row] = (png_byte*)malloc(sizeof(png_byte)*width*pixel_width);
424 /* Allocate memory for the pattern image that will actually be
425 * used for the wipe */
426 pattern_image = (unsigned char**)malloc(sizeof(unsigned char*)*frame_height);
429 png_read_image(png_ptr, image);
430 png_read_end(png_ptr, end_info);
432 double row_factor, col_factor;
433 double row_offset = 0.5, col_offset = 0.5; // for rounding
435 if (preserve_aspect && aspect_w != 0 && aspect_h != 0)
437 row_factor = (height-1)/aspect_h;
438 col_factor = (width-1)/aspect_w;
439 if (row_factor < col_factor)
440 col_factor = row_factor;
442 row_factor = col_factor;
443 row_factor *= aspect_h/(double)(frame_height-1);
444 col_factor *= aspect_w/(double)(frame_width-1);
446 // center the pattern over the frame
447 row_offset += (height-1-(frame_height-1)*row_factor)/2;
448 col_offset += (width-1-(frame_width-1)*col_factor)/2;
452 // Stretch (or shrink) the pattern image to fill the frame
453 row_factor = (double)(height-1)/(double)(frame_height-1);
454 col_factor = (double)(width-1)/(double)(frame_width-1);
457 for (scaled_row = 0; scaled_row < frame_height; scaled_row++)
459 row = (int)(row_factor*scaled_row + row_offset);
460 pattern_image[scaled_row] = (unsigned char*)malloc(sizeof(unsigned char)*frame_width);
461 for (scaled_col = 0; scaled_col < frame_width; scaled_col++)
463 col = (int)(col_factor*scaled_col + col_offset)*pixel_width;
464 value = image[row][col];
465 pattern_image[scaled_row][scaled_col] = value;
466 if (value < min_value) min_value = value;
467 if (value > max_value) max_value = value;
472 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
474 /* Deallocate the original image as it is no longer needed */
475 for (row = 0; row < height; row++)
483 void ShapeWipeMain::reset_pattern_image()
486 if (pattern_image != NULL)
488 for (row = 0; row < frame_height; row++)
490 free (pattern_image[row]);
492 free (pattern_image);
493 pattern_image = NULL;
494 min_value = 256, max_value = 0; // are recalc'd in read_pattern_image
498 #define SHAPEWIPE(type, components) \
501 type **in_rows = (type**)incoming->get_rows(); \
502 type **out_rows = (type**)outgoing->get_rows(); \
507 for(j = 0; j < h; j++) \
509 in_row = (type*) in_rows[j]; \
510 out_row = (type*)out_rows[j]; \
511 pattern_row = pattern_image[j]; \
514 for(k = 0; k < w; k++) \
516 value = pattern_row[k]; \
517 if ((direction == 0 && value >= threshold) || \
518 (direction == 1 && value <= threshold)) \
520 out_row[col_offset] = in_row[col_offset]; \
521 out_row[col_offset + 1] = in_row[col_offset + 1]; \
522 out_row[col_offset + 2] = in_row[col_offset + 2]; \
523 if(components == 4) \
524 out_row[col_offset + 3] = in_row[col_offset + 3]; \
526 col_offset += components; \
531 #define COMPARE1(x,y) \
533 if (pattern_image[x][y] <= threshold) opacity++; \
536 #define COMPARE2(x,y) \
538 if (pattern_image[x][y] >= threshold) opacity++; \
541 // components is always 4
542 #define BLEND_ONLY_4_NORMAL(temp_type, type, max, chroma_offset,x,y) \
544 const int bits = sizeof(type) * 8; \
545 temp_type blend_opacity = (temp_type)(alpha * ((temp_type)1 << bits) + 0.5); \
546 temp_type blend_transparency = ((temp_type)1 << bits) - blend_opacity; \
549 type* in_row = (type*)incoming->get_rows()[x]; \
550 type* output = (type*)outgoing->get_rows()[x]; \
552 output[col] = ((temp_type)in_row[col] * blend_opacity + output[col] * blend_transparency) >> bits; \
553 output[col+1] = ((temp_type)in_row[col+1] * blend_opacity + output[col+1] * blend_transparency) >> bits; \
554 output[col+2] = ((temp_type)in_row[col+2] * blend_opacity + output[col+2] * blend_transparency) >> bits; \
558 // components is always 3
559 #define BLEND_ONLY_3_NORMAL(temp_type, type, max, chroma_offset,x,y) \
561 const int bits = sizeof(type) * 8; \
562 temp_type blend_opacity = (temp_type)(alpha * ((temp_type)1 << bits) + 0.5); \
563 temp_type blend_transparency = ((temp_type)1 << bits) - blend_opacity; \
566 type* in_row = (type*)incoming->get_rows()[x]; \
567 type* output = (type*)outgoing->get_rows()[x]; \
569 output[col] = ((temp_type)in_row[col] * blend_opacity + output[col] * blend_transparency) >> bits; \
570 output[col+1] = ((temp_type)in_row[col+1] * blend_opacity + output[col+1] * blend_transparency) >> bits; \
571 output[col+2] = ((temp_type)in_row[col+2] * blend_opacity + output[col+2] * blend_transparency) >> bits; \
574 /* opacity is defined as opacity of incoming frame */
575 #define BLEND(x,y,total) \
577 float pixel_opacity = (float)opacity / total; \
578 float alpha = pixel_opacity; \
579 float pixel_transparency = 1.0 - pixel_opacity; \
582 if (pixel_opacity > 0.0) \
584 switch(incoming->get_color_model()) \
588 float *in_row = (float*)incoming->get_rows()[x]; \
589 float *out_row = (float*)outgoing->get_rows()[x]; \
591 out_row[col] = in_row[col] * pixel_opacity + \
592 out_row[col] * pixel_transparency; \
593 out_row[col+1] = in_row[col+1] * pixel_opacity + \
594 out_row[col+1] * pixel_transparency; \
595 out_row[col+2] = in_row[col+2] * pixel_opacity + \
596 out_row[col+2] * pixel_transparency; \
599 case BC_RGBA_FLOAT: \
601 float *in_row = (float*)incoming->get_rows()[x]; \
602 float *out_row = (float*)outgoing->get_rows()[x]; \
604 out_row[col] = in_row[col] * pixel_opacity + \
605 out_row[col] * pixel_transparency; \
606 out_row[col+1] = in_row[col+1] * pixel_opacity + \
607 out_row[col+1] * pixel_transparency; \
608 out_row[col+2] = in_row[col+2] * pixel_opacity + \
609 out_row[col+2] * pixel_transparency; \
613 BLEND_ONLY_3_NORMAL(uint32_t, unsigned char, 0xff, 0,x,y); \
616 BLEND_ONLY_3_NORMAL(int32_t, unsigned char, 0xff, 0x80,x,y); \
619 BLEND_ONLY_4_NORMAL(uint32_t, unsigned char, 0xff, 0,x,y); \
622 BLEND_ONLY_4_NORMAL(int32_t, unsigned char, 0xff, 0x80,x,y); \
625 BLEND_ONLY_3_NORMAL(uint64_t, uint16_t, 0xffff, 0,x,y); \
628 BLEND_ONLY_3_NORMAL(int64_t, uint16_t, 0xffff, 0x8000,x,y); \
630 case BC_RGBA16161616: \
631 BLEND_ONLY_4_NORMAL(uint64_t, uint16_t, 0xffff, 0,x,y); \
633 case BC_YUVA16161616: \
634 BLEND_ONLY_4_NORMAL(int64_t, uint16_t, 0xffff, 0x8000,x,y); \
640 int ShapeWipeMain::process_realtime(VFrame *incoming, VFrame *outgoing)
642 unsigned char *pattern_row;
644 unsigned char threshold;
649 load_configuration();
651 int w = incoming->get_w();
652 int h = incoming->get_h();
654 if (strncmp(filename,last_read_filename,BCTEXTLEN)
655 || preserve_aspect != last_preserve_aspect)
657 reset_pattern_image();
660 if (!pattern_image) {
661 read_pattern_image(w, h);
662 strncpy(last_read_filename, filename, BCTEXTLEN);
663 last_preserve_aspect = preserve_aspect;
668 fprintf(stderr, "Shape Wipe: cannot load shape %s\n", filename);
674 threshold = (unsigned char)(
675 (float)PluginClient::get_source_position() /
676 (float)PluginClient::get_total_len() *
677 (float)(max_value - min_value))
682 threshold = (unsigned char)((max_value - min_value) - (
683 (float)PluginClient::get_source_position() /
684 (float)PluginClient::get_total_len() *
685 (float)(max_value - min_value)))
693 /* Top left corner */
702 for (k = 1; k < w-1; k++)
714 /* Top right corner */
723 for (j = 1; j < h-1; j++)
736 for (j = 1; j < h-1; j++)
738 for (k = 1; k < w-1; k++)
755 for (j = 1; j < h-1; j++)
767 /* Bottom left corner */
776 for (k = 1; k < w-1; k++)
788 /* Bottom right corner */
798 /* Top left corner */
807 for (k = 1; k < w-1; k++)
819 /* Top right corner */
828 for (j = 1; j < h-1; j++)
841 for (j = 1; j < h-1; j++)
843 for (k = 1; k < w-1; k++)
860 for (j = 1; j < h-1; j++)
872 /* Bottom left corner */
881 for (k = 1; k < w-1; k++)
893 /* Bottom right corner */
904 switch(incoming->get_color_model())
911 SHAPEWIPE(unsigned char, 3)
918 SHAPEWIPE(unsigned char, 4)
922 SHAPEWIPE(uint16_t, 3)
924 case BC_RGBA16161616:
925 case BC_YUVA16161616:
926 SHAPEWIPE(uint16_t, 4)