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