remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / plugins / rgb601 / rgb601.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "clip.h"
23 #include "bccmodels.h"
24 #include "filexml.h"
25 #include "language.h"
26 #include "rgb601.h"
27 #include "rgb601window.h"
28
29 #include <stdio.h>
30 #include <string.h>
31
32
33 REGISTER_PLUGIN(RGB601Main)
34
35
36
37
38 RGB601Config::RGB601Config()
39 {
40         direction = 0;
41 }
42
43 RGB601Main::RGB601Main(PluginServer *server)
44  : PluginVClient(server)
45 {
46
47 }
48
49 RGB601Main::~RGB601Main()
50 {
51
52 }
53
54 const char* RGB601Main::plugin_title() { return _("RGB - 601"); }
55 int RGB601Main::is_realtime() { return 1; }
56
57
58 NEW_WINDOW_MACRO(RGB601Main, RGB601Window)
59
60
61 void RGB601Main::update_gui()
62 {
63         if(thread)
64         {
65                 load_configuration();
66                 thread->window->lock_window();
67                 ((RGB601Window*)thread->window)->forward->update(config.direction == 1);
68                 ((RGB601Window*)thread->window)->reverse->update(config.direction == 2);
69                 thread->window->unlock_window();
70         }
71 }
72
73
74 int RGB601Main::load_configuration()
75 {
76         KeyFrame *prev_keyframe;
77
78         prev_keyframe = get_prev_keyframe(get_source_position());
79 // Must also switch between interpolation between keyframes and using first keyframe
80         read_data(prev_keyframe);
81         return 1;
82 }
83
84
85 void RGB601Main::save_data(KeyFrame *keyframe)
86 {
87         FileXML output;
88
89 // cause data to be stored directly in text
90         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
91         output.tag.set_title("RGB601");
92         output.tag.set_property("DIRECTION", config.direction);
93         output.append_tag();
94         output.tag.set_title("/RGB601");
95         output.append_tag();
96         output.append_newline();
97         output.terminate_string();
98 }
99
100 void RGB601Main::read_data(KeyFrame *keyframe)
101 {
102         FileXML input;
103
104         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
105
106         int result = 0;
107
108         while(!result)
109         {
110                 result = input.read_tag();
111
112                 if(!result)
113                 {
114                         if(input.tag.title_is("RGB601"))
115                         {
116                                 config.direction = input.tag.get_property("DIRECTION", config.direction);
117                         }
118                 }
119         }
120
121         if(thread)
122         {
123                 ((RGB601Window*)thread->window)->update();
124         }
125 }
126
127
128 #define CREATE_TABLE(max) \
129 { \
130         for(int i = 0; i < max; i++) \
131         { \
132                 int forward_output = (int)((double)0.8588 * i + max * 0.0627 + 0.5); \
133                 int reverse_output = (int)((double)1.1644 * i - max * 0.0627 + 0.5); \
134                 forward_table[i] = CLIP(forward_output, 0, max - 1); \
135                 reverse_table[i] = CLIP(reverse_output, 0, max - 1); \
136         } \
137 }
138
139 void RGB601Main::create_table(VFrame *input_ptr)
140 {
141         switch(input_ptr->get_color_model())
142         {
143                 case BC_RGB888:
144                 case BC_YUV888:
145                 case BC_RGBA8888:
146                 case BC_YUVA8888:
147                         CREATE_TABLE(0x100);
148                         break;
149
150                 case BC_RGB161616:
151                 case BC_YUV161616:
152                 case BC_RGBA16161616:
153                 case BC_YUVA16161616:
154                         CREATE_TABLE(0x10000);
155                         break;
156         }
157 }
158
159 #define PROCESS(table, type, components, yuv) \
160 { \
161         for(int i = 0; i < h; i++) \
162         { \
163                 type *in_row = (type*)input_ptr->get_rows()[i]; \
164                 type *out_row = (type*)output_ptr->get_rows()[i]; \
165  \
166                 if(yuv) \
167                 { \
168 /* Just do Y */ \
169                         for(int j = 0; j < w; j++) \
170                         { \
171                                 out_row[j * components] = table[(int)in_row[j * components]]; \
172                                 out_row[j * components + 1] = in_row[j * components + 1]; \
173                                 out_row[j * components + 2] = in_row[j * components + 2]; \
174                         } \
175                 } \
176                 else \
177                 if(sizeof(type) == 4) \
178                 { \
179                         for(int j = 0; j < w; j++) \
180                         { \
181                                 if(table == forward_table) \
182                                 { \
183                                         out_row[j * components] = (type)(in_row[j * components] * 0.8588 + 0.0627); \
184                                         out_row[j * components + 1] = (type)(in_row[j * components + 1] * 0.8588 + 0.0627); \
185                                         out_row[j * components + 2] = (type)(in_row[j * components + 2] * 0.8588 + 0.0627); \
186                                 } \
187                                 else \
188                                 { \
189                                         out_row[j * components] = (type)(in_row[j * components] * 1.1644 - 0.0627); \
190                                         out_row[j * components + 1] = (type)(in_row[j * components + 1] * 1.1644 - 0.0627); \
191                                         out_row[j * components + 2] = (type)(in_row[j * components + 2] * 1.1644 - 0.0627); \
192                                 } \
193                         } \
194                 } \
195                 else \
196                 { \
197                         for(int j = 0; j < w; j++) \
198                         { \
199                                 out_row[j * components] = table[(int)in_row[j * components]]; \
200                                 out_row[j * components + 1] = table[(int)in_row[j * components + 1]]; \
201                                 out_row[j * components + 2] = table[(int)in_row[j * components + 2]]; \
202                         } \
203                 } \
204         } \
205 }
206
207 void RGB601Main::process(int *table, VFrame *input_ptr, VFrame *output_ptr)
208 {
209         int w = input_ptr->get_w();
210         int h = input_ptr->get_h();
211
212         if(config.direction == 1)
213                 switch(input_ptr->get_color_model())
214                 {
215                         case BC_YUV888:
216                                 PROCESS(forward_table, unsigned char, 3, 1);
217                                 break;
218                         case BC_YUVA8888:
219                                 PROCESS(forward_table, unsigned char, 4, 1);
220                                 break;
221                         case BC_YUV161616:
222                                 PROCESS(forward_table, u_int16_t, 3, 1);
223                                 break;
224                         case BC_YUVA16161616:
225                                 PROCESS(forward_table, u_int16_t, 4, 1);
226                                 break;
227                         case BC_RGB888:
228                                 PROCESS(forward_table, unsigned char, 3, 0);
229                                 break;
230                         case BC_RGBA8888:
231                                 PROCESS(forward_table, unsigned char, 4, 0);
232                                 break;
233                         case BC_RGB_FLOAT:
234                                 PROCESS(forward_table, float, 3, 0);
235                                 break;
236                         case BC_RGBA_FLOAT:
237                                 PROCESS(forward_table, float, 4, 0);
238                                 break;
239                         case BC_RGB161616:
240                                 PROCESS(forward_table, u_int16_t, 3, 0);
241                                 break;
242                         case BC_RGBA16161616:
243                                 PROCESS(forward_table, u_int16_t, 4, 0);
244                                 break;
245                 }
246         else
247         if(config.direction == 2)
248                 switch(input_ptr->get_color_model())
249                 {
250                         case BC_YUV888:
251                                 PROCESS(reverse_table, unsigned char, 3, 1);
252                                 break;
253                         case BC_YUVA8888:
254                                 PROCESS(reverse_table, unsigned char, 4, 1);
255                                 break;
256                         case BC_YUV161616:
257                                 PROCESS(reverse_table, u_int16_t, 3, 1);
258                                 break;
259                         case BC_YUVA16161616:
260                                 PROCESS(reverse_table, u_int16_t, 4, 1);
261                                 break;
262                         case BC_RGB888:
263                                 PROCESS(reverse_table, unsigned char, 3, 0);
264                                 break;
265                         case BC_RGBA8888:
266                                 PROCESS(reverse_table, unsigned char, 4, 0);
267                                 break;
268                         case BC_RGB_FLOAT:
269                                 PROCESS(reverse_table, float, 3, 0);
270                                 break;
271                         case BC_RGBA_FLOAT:
272                                 PROCESS(reverse_table, float, 4, 0);
273                                 break;
274                         case BC_RGB161616:
275                                 PROCESS(reverse_table, u_int16_t, 3, 0);
276                                 break;
277                         case BC_RGBA16161616:
278                                 PROCESS(reverse_table, u_int16_t, 4, 0);
279                                 break;
280                 }
281 }
282
283 int RGB601Main::process_buffer(VFrame *frame,
284         int64_t start_position,
285         double frame_rate)
286 {
287         load_configuration();
288
289 // Set parameters for aggregation with previous or next effect.
290         frame->get_params()->update("RGB601_DIRECTION", config.direction);
291
292         read_frame(frame,
293                 0,
294                 start_position,
295                 frame_rate,
296                 get_use_opengl());
297
298 // Deinterlace effects may aggregate this one,
299         if(get_use_opengl() &&
300                 (prev_effect_is(_("Frames to fields")) ||
301                 next_effect_is(_("Frames to fields"))))
302         {
303                 return 0;
304         }
305
306         if(get_use_opengl() && config.direction)
307         {
308                 run_opengl();
309                 return 0;
310         }
311
312
313         create_table(frame);
314
315         if(config.direction == 1)
316                 process(forward_table, frame, frame);
317         else
318         if(config.direction == 2)
319                 process(reverse_table, frame, frame);
320
321         return 0;
322 }
323
324 int RGB601Main::handle_opengl()
325 {
326 #ifdef HAVE_GL
327         static const char *yuv_fwd_frag =
328                 "uniform sampler2D tex;\n"
329                 "void main()\n"
330                 "{\n"
331                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
332                 "       gl_FragColor.r = gl_FragColor.r * 0.8588 + 0.0627;\n"
333                 "}\n";
334         static const char *yuv_rev_frag =
335                 "uniform sampler2D tex;\n"
336                 "void main()\n"
337                 "{\n"
338                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
339                 "       gl_FragColor.r = gl_FragColor.r * 1.1644 - 0.0627;\n"
340                 "}\n";
341         static const char *rgb_fwd_frag =
342                 "uniform sampler2D tex;\n"
343                 "void main()\n"
344                 "{\n"
345                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
346                 "       gl_FragColor.rgb = gl_FragColor.rgb * vec3(0.8588, 0.8588, 0.8588) + vec3(0.0627, 0.0627, 0.0627);\n"
347                 "}\n";
348         static const char *rgb_rev_frag =
349                 "uniform sampler2D tex;\n"
350                 "void main()\n"
351                 "{\n"
352                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
353                 "       gl_FragColor.rgb = gl_FragColor.rgb * vec3(1.1644, 1.1644, 1.1644) - vec3(0.0627, 0.0627, 0.0627);\n"
354                 "}\n";
355
356
357         get_output()->to_texture();
358         get_output()->enable_opengl();
359         get_output()->bind_texture(0);
360
361         unsigned int frag_shader = 0;
362         switch(get_output()->get_color_model())
363         {
364                 case BC_YUV888:
365                 case BC_YUVA8888:
366                         frag_shader = VFrame::make_shader(0,
367                                 config.direction == 1 ? yuv_fwd_frag : yuv_rev_frag,
368                                 0);
369                 break;
370
371                 default:
372                         frag_shader = VFrame::make_shader(0,
373                                 config.direction == 1 ? rgb_fwd_frag : rgb_rev_frag,
374                                 0);
375                 break;
376         }
377
378         if(frag_shader)
379         {
380                 glUseProgram(frag_shader);
381                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
382         }
383         VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
384         get_output()->draw_texture();
385         glUseProgram(0);
386         get_output()->set_opengl_state(VFrame::SCREEN);
387 #endif
388         return 0;
389 }
390
391
392