initial commit
[goodguy/cinelerra.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 N_("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->xbuf);
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->xbuf);
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
122 #define CREATE_TABLE(max) \
123 { \
124         for(int i = 0; i < max; i++) \
125         { \
126                 int forward_output = (int)((double)0.8588 * i + max * 0.0627 + 0.5); \
127                 int reverse_output = (int)((double)1.1644 * i - max * 0.0627 + 0.5); \
128                 forward_table[i] = CLIP(forward_output, 0, max - 1); \
129                 reverse_table[i] = CLIP(reverse_output, 0, max - 1); \
130         } \
131 }
132
133 void RGB601Main::create_table(VFrame *input_ptr)
134 {
135         switch(input_ptr->get_color_model())
136         {
137                 case BC_RGB888:
138                 case BC_YUV888:
139                 case BC_RGBA8888:
140                 case BC_YUVA8888:
141                         CREATE_TABLE(0x100);
142                         break;
143
144                 case BC_RGB161616:
145                 case BC_YUV161616:
146                 case BC_RGBA16161616:
147                 case BC_YUVA16161616:
148                         CREATE_TABLE(0x10000);
149                         break;
150         }
151 }
152
153 #define PROCESS(table, type, components, yuv) \
154 { \
155         for(int i = 0; i < h; i++) \
156         { \
157                 type *in_row = (type*)input_ptr->get_rows()[i]; \
158                 type *out_row = (type*)output_ptr->get_rows()[i]; \
159  \
160                 if(yuv) \
161                 { \
162 /* Just do Y */ \
163                         for(int j = 0; j < w; j++) \
164                         { \
165                                 out_row[j * components] = table[(int)in_row[j * components]]; \
166                                 out_row[j * components + 1] = in_row[j * components + 1]; \
167                                 out_row[j * components + 2] = in_row[j * components + 2]; \
168                         } \
169                 } \
170                 else \
171                 if(sizeof(type) == 4) \
172                 { \
173                         for(int j = 0; j < w; j++) \
174                         { \
175                                 if(table == forward_table) \
176                                 { \
177                                         out_row[j * components] = (type)(in_row[j * components] * 0.8588 + 0.0627); \
178                                         out_row[j * components + 1] = (type)(in_row[j * components + 1] * 0.8588 + 0.0627); \
179                                         out_row[j * components + 2] = (type)(in_row[j * components + 2] * 0.8588 + 0.0627); \
180                                 } \
181                                 else \
182                                 { \
183                                         out_row[j * components] = (type)(in_row[j * components] * 1.1644 - 0.0627); \
184                                         out_row[j * components + 1] = (type)(in_row[j * components + 1] * 1.1644 - 0.0627); \
185                                         out_row[j * components + 2] = (type)(in_row[j * components + 2] * 1.1644 - 0.0627); \
186                                 } \
187                         } \
188                 } \
189                 else \
190                 { \
191                         for(int j = 0; j < w; j++) \
192                         { \
193                                 out_row[j * components] = table[(int)in_row[j * components]]; \
194                                 out_row[j * components + 1] = table[(int)in_row[j * components + 1]]; \
195                                 out_row[j * components + 2] = table[(int)in_row[j * components + 2]]; \
196                         } \
197                 } \
198         } \
199 }
200
201 void RGB601Main::process(int *table, VFrame *input_ptr, VFrame *output_ptr)
202 {
203         int w = input_ptr->get_w();
204         int h = input_ptr->get_h();
205
206         if(config.direction == 1)
207                 switch(input_ptr->get_color_model())
208                 {
209                         case BC_YUV888:
210                                 PROCESS(forward_table, unsigned char, 3, 1);
211                                 break;
212                         case BC_YUVA8888:
213                                 PROCESS(forward_table, unsigned char, 4, 1);
214                                 break;
215                         case BC_YUV161616:
216                                 PROCESS(forward_table, u_int16_t, 3, 1);
217                                 break;
218                         case BC_YUVA16161616:
219                                 PROCESS(forward_table, u_int16_t, 4, 1);
220                                 break;
221                         case BC_RGB888:
222                                 PROCESS(forward_table, unsigned char, 3, 0);
223                                 break;
224                         case BC_RGBA8888:
225                                 PROCESS(forward_table, unsigned char, 4, 0);
226                                 break;
227                         case BC_RGB_FLOAT:
228                                 PROCESS(forward_table, float, 3, 0);
229                                 break;
230                         case BC_RGBA_FLOAT:
231                                 PROCESS(forward_table, float, 4, 0);
232                                 break;
233                         case BC_RGB161616:
234                                 PROCESS(forward_table, u_int16_t, 3, 0);
235                                 break;
236                         case BC_RGBA16161616:
237                                 PROCESS(forward_table, u_int16_t, 4, 0);
238                                 break;
239                 }
240         else
241         if(config.direction == 2)
242                 switch(input_ptr->get_color_model())
243                 {
244                         case BC_YUV888:
245                                 PROCESS(reverse_table, unsigned char, 3, 1);
246                                 break;
247                         case BC_YUVA8888:
248                                 PROCESS(reverse_table, unsigned char, 4, 1);
249                                 break;
250                         case BC_YUV161616:
251                                 PROCESS(reverse_table, u_int16_t, 3, 1);
252                                 break;
253                         case BC_YUVA16161616:
254                                 PROCESS(reverse_table, u_int16_t, 4, 1);
255                                 break;
256                         case BC_RGB888:
257                                 PROCESS(reverse_table, unsigned char, 3, 0);
258                                 break;
259                         case BC_RGBA8888:
260                                 PROCESS(reverse_table, unsigned char, 4, 0);
261                                 break;
262                         case BC_RGB_FLOAT:
263                                 PROCESS(reverse_table, float, 3, 0);
264                                 break;
265                         case BC_RGBA_FLOAT:
266                                 PROCESS(reverse_table, float, 4, 0);
267                                 break;
268                         case BC_RGB161616:
269                                 PROCESS(reverse_table, u_int16_t, 3, 0);
270                                 break;
271                         case BC_RGBA16161616:
272                                 PROCESS(reverse_table, u_int16_t, 4, 0);
273                                 break;
274                 }
275 }
276
277 int RGB601Main::process_buffer(VFrame *frame,
278         int64_t start_position,
279         double frame_rate)
280 {
281         load_configuration();
282
283 // Set parameters for aggregation with previous or next effect.
284         frame->get_params()->update("RGB601_DIRECTION", config.direction);
285
286         read_frame(frame,
287                 0,
288                 start_position,
289                 frame_rate,
290                 get_use_opengl());
291
292 // Deinterlace effects may aggregate this one,
293         if(get_use_opengl() &&
294                 (prev_effect_is(_("Frames to fields")) ||
295                 next_effect_is(_("Frames to fields"))))
296         {
297                 return 0;
298         }
299
300         if(get_use_opengl() && config.direction)
301         {
302                 run_opengl();
303                 return 0;
304         }
305
306
307         create_table(frame);
308
309         if(config.direction == 1)
310                 process(forward_table, frame, frame);
311         else
312         if(config.direction == 2)
313                 process(reverse_table, frame, frame);
314
315         return 0;
316 }
317
318 int RGB601Main::handle_opengl()
319 {
320 #ifdef HAVE_GL
321         static const char *yuv_fwd_frag =
322                 "uniform sampler2D tex;\n"
323                 "void main()\n"
324                 "{\n"
325                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
326                 "       gl_FragColor.r = gl_FragColor.r * 0.8588 + 0.0627;\n"
327                 "}\n";
328         static const char *yuv_rev_frag =
329                 "uniform sampler2D tex;\n"
330                 "void main()\n"
331                 "{\n"
332                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
333                 "       gl_FragColor.r = gl_FragColor.r * 1.1644 - 0.0627;\n"
334                 "}\n";
335         static const char *rgb_fwd_frag =
336                 "uniform sampler2D tex;\n"
337                 "void main()\n"
338                 "{\n"
339                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
340                 "       gl_FragColor.rgb = gl_FragColor.rgb * vec3(0.8588, 0.8588, 0.8588) + vec3(0.0627, 0.0627, 0.0627);\n"
341                 "}\n";
342         static const char *rgb_rev_frag =
343                 "uniform sampler2D tex;\n"
344                 "void main()\n"
345                 "{\n"
346                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
347                 "       gl_FragColor.rgb = gl_FragColor.rgb * vec3(1.1644, 1.1644, 1.1644) - vec3(0.0627, 0.0627, 0.0627);\n"
348                 "}\n";
349
350
351         get_output()->to_texture();
352         get_output()->enable_opengl();
353         get_output()->bind_texture(0);
354
355         unsigned int frag_shader = 0;
356         switch( get_output()->get_color_model() ) {
357         case BC_YUV888:
358         case BC_YUVA8888:
359                 frag_shader = VFrame::make_shader(0,
360                         config.direction == 1 ? yuv_fwd_frag : yuv_rev_frag,
361                         0);
362                 break;
363
364         default:
365                 frag_shader = VFrame::make_shader(0,
366                         config.direction == 1 ? rgb_fwd_frag : rgb_rev_frag,
367                         0);
368                 break;
369         }
370
371         if( frag_shader > 0 ) {
372                 glUseProgram(frag_shader);
373                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
374         }
375         VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
376         get_output()->draw_texture();
377         glUseProgram(0);
378         get_output()->set_opengl_state(VFrame::SCREEN);
379 #endif
380         return 0;
381 }
382
383
384