--- /dev/null
+#include "clip.h"
+#include "bccmodels.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "yuv411.h"
+#include "yuv411win.h"
+#include "language.h"
+
+#include <stdint.h>
+#include <string.h>
+
+REGISTER_PLUGIN(yuv411Main)
+
+
+yuv411Config::yuv411Config()
+{
+ int_horizontal = 0;
+ avg_vertical = 0;
+ inpainting = 0;
+ offset = 1;
+ thresh = 4;
+ bias = 1;
+}
+
+void yuv411Config::copy_from(yuv411Config &that)
+{
+ int_horizontal = that.int_horizontal;
+ avg_vertical = that.avg_vertical;
+ inpainting = that.inpainting;
+ offset = that.offset;
+ thresh = that.thresh;
+ bias = that.bias;
+}
+
+int yuv411Config::equivalent(yuv411Config &that)
+{
+ return int_horizontal == that.int_horizontal &&
+ avg_vertical == that.avg_vertical &&
+ inpainting == that.inpainting &&
+ offset == that.offset &&
+ thresh == that.thresh &&
+ bias == that.bias;
+}
+
+void yuv411Config::interpolate(yuv411Config &prev,
+ yuv411Config &next,
+ long prev_frame,
+ long next_frame,
+ long current_frame)
+{
+ this->int_horizontal = prev.int_horizontal;
+ this->avg_vertical = prev.avg_vertical;
+ this->inpainting = prev.inpainting;
+ this->offset = prev.offset;
+ this->thresh = prev.thresh;
+ this->bias = prev.bias;
+}
+
+
+yuv411Main::yuv411Main(PluginServer *server)
+ : PluginVClient(server)
+{
+ this->server = server;
+ this->temp_frame = 0;
+ colormodel = -1;
+}
+
+yuv411Main::~yuv411Main()
+{
+ delete temp_frame;
+}
+
+const char *yuv411Main::plugin_title() { return _("YUV411"); }
+int yuv411Main::is_realtime() { return 1; }
+
+#define YUV411_MACRO(type, components) \
+{ \
+ type **input_rows = ((type**)input_ptr->get_rows()), **in_rows = input_rows; \
+ type **output_rows = ((type**)output_ptr->get_rows()), **out_rows = output_rows; \
+ if( config.avg_vertical ) { \
+ if( config.int_horizontal ) \
+ in_rows = out_rows = ((type**)temp_frame->get_rows()); \
+ for( int i=0,h3=h-3; i<h3; i+=4 ) { \
+ type *in_row0 = input_rows[i+0], *in_row1 = input_rows[i+1]; \
+ type *in_row2 = input_rows[i+2], *in_row3 = input_rows[i+3]; \
+ type *out_row0 = out_rows[i+0], *out_row1 = out_rows[i+1]; \
+ type *out_row2 = out_rows[i+2], *out_row3 = out_rows[i+3]; \
+ for( int k = 0; k<w; ++k ) { \
+ for( int uv=1; uv<=2; ++uv ) { \
+ out_row0[uv] = out_row2[uv] = (in_row0[uv]+in_row2[uv]+1)/2; \
+ out_row1[uv] = out_row3[uv] = (in_row1[uv]+in_row3[uv]+1)/2; \
+ } \
+ in_row0 += components; in_row1 += components; \
+ in_row2 += components; in_row3 += components; \
+ out_row0 += components; out_row1 += components; \
+ out_row2 += components; out_row3 += components; \
+ } \
+ } \
+ } \
+ \
+ if( config.int_horizontal ) { \
+ if( config.inpainting ) { \
+ int kmax = w-7+config.offset; \
+ for( int i=0; i<h; ++i ) { \
+ type *in_row0 = in_rows[i+0], *out_row0 = output_rows[i+0]; \
+ for( int k=config.offset; k<kmax; k+=4 ) { \
+ int k0 = (k+0) * components, a = in_row0[k0]; \
+ int b, d = 0, k4 = (k+4) * components; \
+ for( int jk=k0,n=4; --n>=0; a=b ) { \
+ b = in_row0[jk+=components]; \
+ d += a<b ? b-a : a-b; d += config.bias; \
+ } \
+ if( d < config.thresh ) { \
+ for( int jk=k0,n=4; --n>0; ) { \
+ jk += components; \
+ for( int uv=1; uv<=2; ++uv ) { \
+ out_row0[jk+uv] = (n*in_row0[jk+uv] + (4-n)*in_row0[k4+uv]+2)/4; \
+ } \
+ } \
+ } \
+ else { \
+ int t = 0; a = in_row0[k0]; \
+ for( int jk=k0,n=4; --n>0; a=b ) { \
+ b = in_row0[jk+=components]; \
+ t += a<b ? b-a : a-b; t += config.bias; \
+ for( int uv=1; uv<=2; ++uv ) { \
+ out_row0[jk+uv] = (2*((d-t)*in_row0[k0+uv] + t*in_row0[k4+uv])+d)/(2*d); \
+ } \
+ } \
+ } \
+ } \
+ } \
+ } \
+ else { \
+ int kmax = w-7+config.offset; \
+ for( int i=0; i<h; ++i ) { \
+ type *in_row0 = in_rows[i]; \
+ type *out_row0 = output_rows[i]; \
+ for( int k=config.offset; k<kmax; k+=4 ) { \
+ for( int uv=1; uv<=2; ++uv ) { \
+ int sum, avg, k0 = (k+0) * components, k4 = (k+4) * components; \
+ sum = in_row0[k0 + uv]; sum += in_row0[(k0+=components) + uv]; \
+ sum += in_row0[k4 + uv]; sum += in_row0[(k4+=components) + uv]; \
+ avg = (sum + 2) / 4; \
+ out_row0[(k0+=components)+uv] = avg; \
+ out_row0[(k0+=components)+uv] = avg; \
+ } \
+ } \
+ } \
+ } \
+ } \
+}
+
+int yuv411Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
+{
+ load_configuration();
+ int w = input_ptr->get_w();
+ int h = input_ptr->get_h();
+ int colormodel = input_ptr->get_color_model();
+
+ if( input_ptr == output_ptr ||
+ ( config.avg_vertical && config.int_horizontal ) ) {
+ if( temp_frame && (temp_frame->get_color_model() != colormodel ||
+ temp_frame->get_w() != w || temp_frame->get_h() != h) ) {
+ delete temp_frame;
+ temp_frame = 0;
+ }
+ if( !temp_frame )
+ temp_frame = new VFrame(w, h, colormodel);
+ if( input_ptr == output_ptr ) {
+ temp_frame->copy_from(input_ptr);
+ input_ptr = temp_frame;
+ }
+ }
+
+ switch( colormodel ) {
+ case BC_YUV888:
+ YUV411_MACRO(unsigned char, 3);
+ break;
+ case BC_YUVA8888:
+ YUV411_MACRO(unsigned char, 4);
+ break;
+ }
+
+ if( this->colormodel != colormodel ) {
+ this->colormodel = colormodel;
+ send_render_gui(this);
+ }
+
+ return 0;
+}
+
+
+NEW_WINDOW_MACRO(yuv411Main, yuv411Window)
+
+LOAD_CONFIGURATION_MACRO(yuv411Main, yuv411Config)
+
+void yuv411Main::update_gui()
+{
+ if(thread)
+ {
+ load_configuration();
+ thread->window->lock_window();
+ yuv411Window *window = (yuv411Window *)thread->window;
+ window->update_enables();
+ window->avg_vertical->update((int)config.avg_vertical);
+ window->int_horizontal->update((int)config.int_horizontal);
+ window->inpainting->update((int)config.inpainting);
+ window->offset->update((int)config.offset);
+ window->thresh->update((int)config.thresh);
+ window->bias->update((int)config.bias);
+ window->unlock_window();
+ }
+}
+
+void yuv411Main::render_gui(void *data)
+{
+ if(thread) {
+ thread->window->lock_window();
+ yuv411Window *window = (yuv411Window *)thread->window;
+ yuv411Main *client = (yuv411Main *)data;
+ switch( client->colormodel ) {
+ case BC_YUV888:
+ case BC_YUVA8888:
+ window->show_warning(0);
+ break;
+ default:
+ window->show_warning(1);
+ break;
+ }
+ window->unlock_window();
+ }
+}
+
+void yuv411Main::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// cause data to be stored directly in text
+ output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+
+ output.tag.set_title("YUV411");
+ output.tag.set_property("OFFSET",config.offset);
+ output.tag.set_property("THRESH",config.thresh);
+ output.tag.set_property("BIAS",config.bias);
+ output.append_tag();
+ if(config.avg_vertical) {
+ output.tag.set_title("VERTICAL");
+ output.append_tag();
+ }
+ if(config.int_horizontal) {
+ output.tag.set_title("HORIZONTAL");
+ output.append_tag();
+ }
+ if(config.inpainting ) {
+ output.tag.set_title("INPAINTING");
+ output.append_tag();
+ }
+ output.terminate_string();
+}
+
+void yuv411Main::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+
+ input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+ int result = 0;
+ config.avg_vertical = config.int_horizontal = 0;
+ config.inpainting = 0;
+ config.offset = 1;
+ config.thresh = 4;
+ config.bias = 1;
+
+ while(!(result = input.read_tag()) ) {
+ if( input.tag.title_is("YUV411") ) {
+ config.offset = input.tag.get_property("OFFSET",config.offset);
+ config.thresh = input.tag.get_property("THRESH",config.thresh);
+ config.bias = input.tag.get_property("BIAS",config.bias);
+ }
+ else if(input.tag.title_is("VERTICAL")) {
+ config.avg_vertical = 1;
+ }
+ else if(input.tag.title_is("HORIZONTAL")) {
+ config.int_horizontal = 1;
+ }
+ else if(input.tag.title_is("INPAINTING")) {
+ config.inpainting = 1;
+ }
+ }
+}
+
--- /dev/null
+#include "bcdisplayinfo.h"
+#include "yuv411win.h"
+#include "language.h"
+
+yuv411Window::yuv411Window(yuv411Main *client)
+ : PluginClientWindow(client, 250, 220, 250, 220, 0)
+{
+ this->client = client;
+}
+
+yuv411Window::~yuv411Window()
+{
+}
+
+void yuv411Window::create_objects()
+{
+ int x = 10, y = 10, x1=90;
+ add_tool(avg_vertical = new yuv411Toggle(client,
+ &(client->config.avg_vertical),
+ _("Vertical average"),
+ x,
+ y));
+ y += 30;
+ add_tool(int_horizontal = new yuv411Toggle(client,
+ &(client->config.int_horizontal),
+ _("Horizontal interpolate"),
+ x,
+ y));
+ y += 30;
+ add_tool(inpainting = new yuv411Toggle(client,
+ &(client->config.inpainting),
+ _("Inpainting method"),
+ x,
+ y));
+ y += 30;
+ add_subwindow(new BC_Title(x, y, _("Offset:")));
+ add_subwindow(offset=new yuv411Offset(client,x1,y));
+ y += 30;
+ add_subwindow(new BC_Title(x, y, _("Threshold:")));
+ add_subwindow(thresh=new yuv411Thresh(client,x1,y));
+ y += 30;
+ add_subwindow(new BC_Title(x, y, _("Bias:")));
+ add_subwindow(bias=new yuv411Bias(client,x1,y));
+ y += 30;
+ show_window();
+ flush();
+
+ yuv_warning = new BC_Title(x, y, _("Warning: colormodel not YUV"),MEDIUMFONT,RED);
+ add_subwindow(yuv_warning);
+ yuv_warning->hide_window();
+}
+
+int yuv411Window::close_event()
+{
+ set_done(1);
+ return 1;
+}
+
+yuv411Toggle::yuv411Toggle(yuv411Main *client, int *output, char *string, int x, int y)
+ : BC_CheckBox(x, y, *output, string)
+{
+ this->client = client;
+ this->output = output;
+}
+yuv411Toggle::~yuv411Toggle()
+{
+}
+int yuv411Toggle::handle_event()
+{
+ *output = get_value();
+ ((yuv411Window*)client->thread->window)->update_enables();
+ client->send_configure_change();
+ return 1;
+}
+
+yuv411Offset::yuv411Offset(yuv411Main *client, int x, int y)
+ : BC_FSlider(x, y, 0, 100, 100, (float)0, (float)2,
+ (float)client->config.offset)
+{
+ this->client = client;
+ set_precision(1.0);
+}
+int yuv411Offset::handle_event()
+{
+ client->config.offset = get_value();
+ client->send_configure_change();
+ return 1;
+}
+
+yuv411Thresh::yuv411Thresh(yuv411Main *client, int x, int y)
+ : BC_FSlider(x, y, 0, 100, 100, (float)1, (float)100,
+ (float)client->config.thresh)
+{
+ this->client = client;
+ set_precision(1.0);
+}
+int yuv411Thresh::handle_event()
+{
+ client->config.thresh = get_value();
+ client->send_configure_change();
+ return 1;
+}
+
+yuv411Bias::yuv411Bias(yuv411Main *client, int x, int y)
+ : BC_FSlider(x, y, 0, 100, 100, (float)0, (float)25,
+ (float)client->config.bias)
+{
+ this->client = client;
+ set_precision(1.0);
+}
+
+int yuv411Bias::handle_event()
+{
+ client->config.bias = get_value();
+ client->send_configure_change();
+ return 1;
+}
+
+void yuv411Window::update_enables()
+{
+ yuv411Config &config = client->config;
+ if( !config.int_horizontal && config.inpainting ) {
+ config.inpainting = 0;
+ inpainting->set_value(0);
+ }
+ if( config.int_horizontal ) {
+ inpainting->enable();
+ offset->show_window();
+ }
+ else {
+ inpainting->disable();
+ offset->hide_window();
+ }
+ if( config.int_horizontal && config.inpainting ) {
+ thresh->show_window();
+ bias->show_window();
+ }
+ else {
+ thresh->hide_window();
+ bias->hide_window();
+ }
+}
+
+void yuv411Window::show_warning(int warn)
+{
+ if( warn )
+ yuv_warning->show_window();
+ else
+ yuv_warning->hide_window();
+}
+
+