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