update ru.po per andrew, fix bg pixmaps tweak, confirm pref update segv, scaling...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / yuv411 / yuv411.C
1 #include "clip.h"
2 #include "bccmodels.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "yuv411.h"
6 #include "yuv411win.h"
7 #include "language.h"
8
9 #include <stdint.h>
10 #include <string.h>
11
12 REGISTER_PLUGIN(yuv411Main)
13
14
15 yuv411Config::yuv411Config()
16 {
17         reset();
18 }
19
20 void yuv411Config::reset()
21 {
22         int_horizontal = 0;
23         avg_vertical = 0;
24         inpainting = 0;
25         offset = 1;
26         thresh = 4;
27         bias = 1;
28 }
29
30 void yuv411Config::copy_from(yuv411Config &that)
31 {
32         int_horizontal = that.int_horizontal;
33         avg_vertical = that.avg_vertical;
34         inpainting = that.inpainting;
35         offset = that.offset;
36         thresh = that.thresh;
37         bias = that.bias;
38 }
39
40 int yuv411Config::equivalent(yuv411Config &that)
41 {
42         return int_horizontal == that.int_horizontal &&
43                 avg_vertical == that.avg_vertical &&
44                 inpainting == that.inpainting &&
45                 offset == that.offset &&
46                 thresh == that.thresh &&
47                 bias == that.bias;
48 }
49
50 void yuv411Config::interpolate(yuv411Config &prev,
51         yuv411Config &next,
52         long prev_frame,
53         long next_frame,
54         long current_frame)
55 {
56         this->int_horizontal = prev.int_horizontal;
57         this->avg_vertical = prev.avg_vertical;
58         this->inpainting = prev.inpainting;
59         this->offset = prev.offset;
60         this->thresh = prev.thresh;
61         this->bias = prev.bias;
62 }
63
64
65 yuv411Main::yuv411Main(PluginServer *server)
66  : PluginVClient(server)
67 {
68         this->server = server;
69         this->temp_frame = 0;
70         colormodel = -1;
71 }
72
73 yuv411Main::~yuv411Main()
74 {
75         delete temp_frame;
76 }
77
78 const char *yuv411Main::plugin_title() { return N_("YUV411"); }
79 int yuv411Main::is_realtime() { return 1; }
80
81 #define YUV411_MACRO(type, components) \
82 { \
83     type **input_rows = ((type**)input_ptr->get_rows()), **in_rows = input_rows; \
84     type **output_rows = ((type**)output_ptr->get_rows()), **out_rows = output_rows; \
85     if( config.avg_vertical ) { \
86         if( config.int_horizontal ) \
87             in_rows = out_rows = ((type**)temp_frame->get_rows()); \
88         for( int i=0,h3=h-3; i<h3; i+=4 ) { \
89             type *in_row0 = input_rows[i+0], *in_row1 = input_rows[i+1]; \
90             type *in_row2 = input_rows[i+2], *in_row3 = input_rows[i+3]; \
91             type *out_row0 = out_rows[i+0], *out_row1 = out_rows[i+1]; \
92             type *out_row2 = out_rows[i+2], *out_row3 = out_rows[i+3]; \
93             for( int k = 0; k<w; ++k ) { \
94                 for( int uv=1; uv<=2; ++uv ) { \
95                    out_row0[uv] = out_row2[uv] = (in_row0[uv]+in_row2[uv]+1)/2; \
96                    out_row1[uv] = out_row3[uv] = (in_row1[uv]+in_row3[uv]+1)/2; \
97                 } \
98                 in_row0 += components; in_row1 += components; \
99                 in_row2 += components; in_row3 += components; \
100                 out_row0 += components; out_row1 += components; \
101                 out_row2 += components; out_row3 += components; \
102             } \
103         } \
104     } \
105  \
106     if( config.int_horizontal ) { \
107         if( config.inpainting ) { \
108             int kmax = w-7+config.offset; \
109             for( int i=0; i<h; ++i ) { \
110                 type *in_row0 = in_rows[i+0], *out_row0 = output_rows[i+0]; \
111                 for( int k=config.offset; k<kmax; k+=4 ) { \
112                     int k0 = (k+0) * components, a = in_row0[k0]; \
113                     int b, d = 0, k4 = (k+4) * components; \
114                     for( int jk=k0,n=4; --n>=0; a=b ) { \
115                         b = in_row0[jk+=components]; \
116                         d += a<b ? b-a : a-b;  d += config.bias; \
117                     } \
118                     if( d < config.thresh ) { \
119                         for( int jk=k0,n=4; --n>0; ) { \
120                             jk += components; \
121                             for( int uv=1; uv<=2; ++uv ) { \
122                                 out_row0[jk+uv] = (n*in_row0[jk+uv] + (4-n)*in_row0[k4+uv]+2)/4; \
123                             } \
124                         } \
125                     } \
126                     else { \
127                         int t = 0;  a = in_row0[k0]; \
128                         for( int jk=k0,n=4; --n>0; a=b ) { \
129                             b = in_row0[jk+=components]; \
130                             t += a<b ? b-a : a-b;  t += config.bias; \
131                             for( int uv=1; uv<=2; ++uv ) { \
132                               out_row0[jk+uv] = (2*((d-t)*in_row0[k0+uv] + t*in_row0[k4+uv])+d)/(2*d); \
133                             } \
134                         } \
135                     } \
136                 } \
137             } \
138         } \
139         else { \
140             int kmax = w-7+config.offset; \
141             for( int i=0; i<h; ++i ) { \
142                 type *in_row0 = in_rows[i]; \
143                 type *out_row0 = output_rows[i]; \
144                 for( int k=config.offset; k<kmax; k+=4 ) { \
145                     for( int uv=1; uv<=2; ++uv ) { \
146                         int sum, avg, k0 = (k+0) * components, k4 = (k+4) * components; \
147                         sum  = in_row0[k0 + uv]; sum += in_row0[(k0+=components) + uv]; \
148                         sum += in_row0[k4 + uv]; sum += in_row0[(k4+=components) + uv]; \
149                         avg = (sum + 2) / 4; \
150                         out_row0[(k0+=components)+uv] = avg; \
151                         out_row0[(k0+=components)+uv] = avg; \
152                     } \
153                 } \
154             } \
155         } \
156     } \
157 }
158
159 int yuv411Main::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
160 {
161         load_configuration();
162         int w = input_ptr->get_w();
163         int h = input_ptr->get_h();
164         colormodel = input_ptr->get_color_model();
165
166         if( input_ptr == output_ptr ||
167             ( config.avg_vertical && config.int_horizontal ) ) {
168                 if( temp_frame && (temp_frame->get_color_model() != colormodel ||
169                     temp_frame->get_w() != w || temp_frame->get_h() != h) ) {
170                         delete temp_frame;
171                         temp_frame = 0;
172                 }
173                 if( !temp_frame )
174                         temp_frame = new VFrame(w, h, colormodel, 0);
175                 if( input_ptr == output_ptr ) {
176                         temp_frame->copy_from(input_ptr);
177                         input_ptr = temp_frame;
178                 }
179         }
180
181         switch( colormodel ) {
182         case BC_YUV888:
183                 YUV411_MACRO(unsigned char, 3);
184                 break;
185         case BC_YUVA8888:
186                 YUV411_MACRO(unsigned char, 4);
187                 break;
188         }
189
190         send_render_gui(this);
191         return 0;
192 }
193
194
195 NEW_WINDOW_MACRO(yuv411Main, yuv411Window)
196
197 LOAD_CONFIGURATION_MACRO(yuv411Main, yuv411Config)
198
199 void yuv411Main::update_gui()
200 {
201         if(thread)
202         {
203                 load_configuration();
204                 thread->window->lock_window();
205                 yuv411Window *window = (yuv411Window *)thread->window;
206                 window->update_enables();
207                 window->avg_vertical->update((int)config.avg_vertical);
208                 window->int_horizontal->update((int)config.int_horizontal);
209                 window->inpainting->update((int)config.inpainting);
210                 window->offset->update((int)config.offset);
211                 window->thresh->update((int)config.thresh);
212                 window->bias->update((int)config.bias);
213                 window->unlock_window();
214         }
215 }
216
217 void yuv411Main::render_gui(void *data)
218 {
219         if(thread) {
220                 yuv411Window *window = (yuv411Window *)thread->window;
221                 yuv411Main *client = (yuv411Main *)data;
222                 if( window->colormodel != client->colormodel ) {
223                         int warn = 1;
224                         switch( client->colormodel ) {
225                         case BC_YUV888:
226                         case BC_YUVA8888:
227                                 warn = 0;
228                                 break;
229                         }
230                         if( warn == window->yuv_warning->is_hidden() ) {
231                                 window->lock_window("yuv411Main::render_gui");
232                                 window->show_warning(warn);
233                                 window->colormodel = client->colormodel;
234                                 window->unlock_window();
235                         }
236                 }
237         }
238 }
239
240 void yuv411Main::save_data(KeyFrame *keyframe)
241 {
242         FileXML output;
243
244 // cause data to be stored directly in text
245         output.set_shared_output(keyframe->xbuf);
246
247         output.tag.set_title("YUV411");
248         output.tag.set_property("OFFSET",config.offset);
249         output.tag.set_property("THRESH",config.thresh);
250         output.tag.set_property("BIAS",config.bias);
251         output.append_tag();
252         if(config.avg_vertical) {
253                 output.tag.set_title("VERTICAL");
254                 output.append_tag();
255                 output.tag.set_title("/VERTICAL");
256                 output.append_tag();
257         }
258         if(config.int_horizontal) {
259                 output.tag.set_title("HORIZONTAL");
260                 output.append_tag();
261                 output.tag.set_title("/HORIZONTAL");
262                 output.append_tag();
263         }
264         if(config.inpainting ) {
265                 output.tag.set_title("INPAINTING");
266                 output.append_tag();
267                 output.tag.set_title("/INPAINTING");
268                 output.append_tag();
269         }
270         output.tag.set_title("/YUV411");
271         output.append_tag();
272         output.terminate_string();
273 }
274
275 void yuv411Main::read_data(KeyFrame *keyframe)
276 {
277         FileXML input;
278
279         input.set_shared_input(keyframe->xbuf);
280
281         int result = 0;
282         config.avg_vertical = config.int_horizontal = 0;
283         config.inpainting = 0;
284         config.offset = 1;
285         config.thresh = 4;
286         config.bias = 1;
287
288         while(!(result = input.read_tag()) ) {
289                 if( input.tag.title_is("YUV411") ) {
290                         config.offset = input.tag.get_property("OFFSET",config.offset);
291                         config.thresh = input.tag.get_property("THRESH",config.thresh);
292                         config.bias = input.tag.get_property("BIAS",config.bias);
293                 }
294                 else if(input.tag.title_is("VERTICAL")) {
295                         config.avg_vertical = 1;
296                 }
297                 else if(input.tag.title_is("HORIZONTAL")) {
298                         config.int_horizontal = 1;
299                 }
300                 else if(input.tag.title_is("INPAINTING")) {
301                         config.inpainting = 1;
302                 }
303         }
304 }
305