3 * Copyright (C) 2016 Eric Olson
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 #include "bccmodels.h"
26 #include "yuv411win.h"
32 REGISTER_PLUGIN(yuv411Main)
35 yuv411Config::yuv411Config()
40 void yuv411Config::reset()
50 void yuv411Config::copy_from(yuv411Config &that)
52 int_horizontal = that.int_horizontal;
53 avg_vertical = that.avg_vertical;
54 inpainting = that.inpainting;
60 int yuv411Config::equivalent(yuv411Config &that)
62 return int_horizontal == that.int_horizontal &&
63 avg_vertical == that.avg_vertical &&
64 inpainting == that.inpainting &&
65 offset == that.offset &&
66 thresh == that.thresh &&
70 void yuv411Config::interpolate(yuv411Config &prev,
76 this->int_horizontal = prev.int_horizontal;
77 this->avg_vertical = prev.avg_vertical;
78 this->inpainting = prev.inpainting;
79 this->offset = prev.offset;
80 this->thresh = prev.thresh;
81 this->bias = prev.bias;
85 yuv411Main::yuv411Main(PluginServer *server)
86 : PluginVClient(server)
88 this->server = server;
93 yuv411Main::~yuv411Main()
98 const char *yuv411Main::plugin_title() { return N_("YUV411"); }
99 int yuv411Main::is_realtime() { return 1; }
101 #define YUV411_MACRO(type, components) \
103 type **input_rows = ((type**)input_ptr->get_rows()), **in_rows = input_rows; \
104 type **output_rows = ((type**)output_ptr->get_rows()), **out_rows = output_rows; \
105 if( config.avg_vertical ) { \
106 if( config.int_horizontal ) \
107 in_rows = out_rows = ((type**)temp_frame->get_rows()); \
108 for( int i=0,h3=h-3; i<h3; i+=4 ) { \
109 type *in_row0 = input_rows[i+0], *in_row1 = input_rows[i+1]; \
110 type *in_row2 = input_rows[i+2], *in_row3 = input_rows[i+3]; \
111 type *out_row0 = out_rows[i+0], *out_row1 = out_rows[i+1]; \
112 type *out_row2 = out_rows[i+2], *out_row3 = out_rows[i+3]; \
113 for( int k = 0; k<w; ++k ) { \
114 for( int uv=1; uv<=2; ++uv ) { \
115 out_row0[uv] = out_row2[uv] = (in_row0[uv]+in_row2[uv]+1)/2; \
116 out_row1[uv] = out_row3[uv] = (in_row1[uv]+in_row3[uv]+1)/2; \
118 in_row0 += components; in_row1 += components; \
119 in_row2 += components; in_row3 += components; \
120 out_row0 += components; out_row1 += components; \
121 out_row2 += components; out_row3 += components; \
126 if( config.int_horizontal ) { \
127 if( config.inpainting ) { \
128 int kmax = w-7+config.offset; \
129 for( int i=0; i<h; ++i ) { \
130 type *in_row0 = in_rows[i+0], *out_row0 = output_rows[i+0]; \
131 for( int k=config.offset; k<kmax; k+=4 ) { \
132 int k0 = (k+0) * components, a = in_row0[k0]; \
133 int b, d = 0, k4 = (k+4) * components; \
134 for( int jk=k0,n=4; --n>=0; a=b ) { \
135 b = in_row0[jk+=components]; \
136 d += a<b ? b-a : a-b; d += config.bias; \
138 if( d < config.thresh ) { \
139 for( int jk=k0,n=4; --n>0; ) { \
141 for( int uv=1; uv<=2; ++uv ) { \
142 out_row0[jk+uv] = (n*in_row0[jk+uv] + (4-n)*in_row0[k4+uv]+2)/4; \
147 int t = 0; a = in_row0[k0]; \
148 for( int jk=k0,n=4; --n>0; a=b ) { \
149 b = in_row0[jk+=components]; \
150 t += a<b ? b-a : a-b; t += config.bias; \
151 for( int uv=1; uv<=2; ++uv ) { \
152 out_row0[jk+uv] = (2*((d-t)*in_row0[k0+uv] + t*in_row0[k4+uv])+d)/(2*d); \
160 int kmax = w-7+config.offset; \
161 for( int i=0; i<h; ++i ) { \
162 type *in_row0 = in_rows[i]; \
163 type *out_row0 = output_rows[i]; \
164 for( int k=config.offset; k<kmax; k+=4 ) { \
165 for( int uv=1; uv<=2; ++uv ) { \
166 int sum, avg, k0 = (k+0) * components, k4 = (k+4) * components; \
167 sum = in_row0[k0 + uv]; sum += in_row0[(k0+=components) + uv]; \
168 sum += in_row0[k4 + uv]; sum += in_row0[(k4+=components) + uv]; \
169 avg = (sum + 2) / 4; \
170 out_row0[(k0+=components)+uv] = avg; \
171 out_row0[(k0+=components)+uv] = avg; \
179 int yuv411Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
181 load_configuration();
182 int w = input_ptr->get_w();
183 int h = input_ptr->get_h();
184 colormodel = input_ptr->get_color_model();
186 if( input_ptr == output_ptr ||
187 ( config.avg_vertical && config.int_horizontal ) ) {
188 if( temp_frame && (temp_frame->get_color_model() != colormodel ||
189 temp_frame->get_w() != w || temp_frame->get_h() != h) ) {
194 temp_frame = new VFrame(w, h, colormodel, 0);
195 if( input_ptr == output_ptr ) {
196 temp_frame->copy_from(input_ptr);
197 input_ptr = temp_frame;
201 switch( colormodel ) {
203 YUV411_MACRO(unsigned char, 3);
206 YUV411_MACRO(unsigned char, 4);
210 send_render_gui(this);
215 NEW_WINDOW_MACRO(yuv411Main, yuv411Window)
217 LOAD_CONFIGURATION_MACRO(yuv411Main, yuv411Config)
219 void yuv411Main::update_gui()
223 load_configuration();
224 thread->window->lock_window();
225 yuv411Window *window = (yuv411Window *)thread->window;
226 window->update_enables();
227 window->avg_vertical->update((int)config.avg_vertical);
228 window->int_horizontal->update((int)config.int_horizontal);
229 window->inpainting->update((int)config.inpainting);
230 window->offset->update((int)config.offset);
231 window->thresh->update((int)config.thresh);
232 window->bias->update((int)config.bias);
233 window->unlock_window();
237 void yuv411Main::render_gui(void *data)
240 yuv411Window *window = (yuv411Window *)thread->window;
241 yuv411Main *client = (yuv411Main *)data;
242 if( window->colormodel != client->colormodel ) {
244 switch( client->colormodel ) {
250 if( warn == window->yuv_warning->is_hidden() ) {
251 window->lock_window("yuv411Main::render_gui");
252 window->show_warning(warn);
253 window->colormodel = client->colormodel;
254 window->unlock_window();
260 void yuv411Main::save_data(KeyFrame *keyframe)
264 // cause data to be stored directly in text
265 output.set_shared_output(keyframe->xbuf);
267 output.tag.set_title("YUV411");
268 output.tag.set_property("OFFSET",config.offset);
269 output.tag.set_property("THRESH",config.thresh);
270 output.tag.set_property("BIAS",config.bias);
272 if(config.avg_vertical) {
273 output.tag.set_title("VERTICAL");
275 output.tag.set_title("/VERTICAL");
278 if(config.int_horizontal) {
279 output.tag.set_title("HORIZONTAL");
281 output.tag.set_title("/HORIZONTAL");
284 if(config.inpainting ) {
285 output.tag.set_title("INPAINTING");
287 output.tag.set_title("/INPAINTING");
290 output.tag.set_title("/YUV411");
292 output.terminate_string();
295 void yuv411Main::read_data(KeyFrame *keyframe)
299 input.set_shared_input(keyframe->xbuf);
302 config.avg_vertical = config.int_horizontal = 0;
303 config.inpainting = 0;
308 while(!(result = input.read_tag()) ) {
309 if( input.tag.title_is("YUV411") ) {
310 config.offset = input.tag.get_property("OFFSET",config.offset);
311 config.thresh = input.tag.get_property("THRESH",config.thresh);
312 config.bias = input.tag.get_property("BIAS",config.bias);
314 else if(input.tag.title_is("VERTICAL")) {
315 config.avg_vertical = 1;
317 else if(input.tag.title_is("HORIZONTAL")) {
318 config.int_horizontal = 1;
320 else if(input.tag.title_is("INPAINTING")) {
321 config.inpainting = 1;