4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
26 REGISTER_PLUGIN(RGBShiftEffect)
33 RGBShiftConfig::RGBShiftConfig()
38 void RGBShiftConfig::reset()
45 void RGBShiftConfig::copy_from(RGBShiftConfig &src)
47 r_dx = src.r_dx; r_dy = src.r_dy;
48 g_dx = src.g_dx; g_dy = src.g_dy;
49 b_dx = src.b_dx; b_dy = src.b_dy;
52 int RGBShiftConfig::equivalent(RGBShiftConfig &src)
54 return EQUIV(r_dx, src.r_dx) && EQUIV(g_dx, src.g_dx) && EQUIV(b_dx, src.b_dx) &&
55 EQUIV(r_dy, src.r_dy) && EQUIV(g_dy, src.g_dy) && EQUIV(b_dy, src.b_dy);
58 void RGBShiftConfig::interpolate(RGBShiftConfig &prev,
64 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
65 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
67 r_dx = prev.r_dx * prev_scale + next.r_dx * next_scale;
68 r_dy = prev.r_dy * prev_scale + next.r_dy * next_scale;
69 g_dx = prev.g_dx * prev_scale + next.g_dx * next_scale;
70 g_dy = prev.g_dy * prev_scale + next.g_dy * next_scale;
71 b_dx = prev.b_dx * prev_scale + next.b_dx * next_scale;
72 b_dy = prev.b_dy * prev_scale + next.b_dy * next_scale;
82 RGBShiftLevel::RGBShiftLevel(RGBShiftEffect *plugin, int *output, int x, int y)
83 : BC_ISlider(x, y, 0, 200, 200, -MAXVALUE, MAXVALUE, *output)
85 this->plugin = plugin;
86 this->output = output;
89 int RGBShiftLevel::handle_event()
91 *output = get_value();
92 plugin->send_configure_change();
97 RGBShiftReset::RGBShiftReset(RGBShiftEffect *plugin, RGBShiftWindow *window, int x, int y)
98 : BC_GenericButton(x, y, _("Reset"))
100 this->plugin = plugin;
101 this->window = window;
103 RGBShiftReset::~RGBShiftReset()
106 int RGBShiftReset::handle_event()
108 plugin->config.reset();
110 plugin->send_configure_change();
115 RGBShiftWindow::RGBShiftWindow(RGBShiftEffect *plugin)
116 : PluginClientWindow(plugin, 300, 230, 300, 230, 0)
118 this->plugin = plugin;
121 void RGBShiftWindow::create_objects()
123 int x = 10, y = 10, x1 = 50;
124 add_subwindow(new BC_Title(x, y, _("R_dx:")));
125 add_subwindow(r_dx = new RGBShiftLevel(plugin, &plugin->config.r_dx, x1, y));
127 add_subwindow(new BC_Title(x, y, _("R_dy:")));
128 add_subwindow(r_dy = new RGBShiftLevel(plugin, &plugin->config.r_dy, x1, y));
130 add_subwindow(new BC_Title(x, y, _("G_dx:")));
131 add_subwindow(g_dx = new RGBShiftLevel(plugin, &plugin->config.g_dx, x1, y));
133 add_subwindow(new BC_Title(x, y, _("G_dy:")));
134 add_subwindow(g_dy = new RGBShiftLevel(plugin, &plugin->config.g_dy, x1, y));
136 add_subwindow(new BC_Title(x, y, _("B_dx:")));
137 add_subwindow(b_dx = new RGBShiftLevel(plugin, &plugin->config.b_dx, x1, y));
139 add_subwindow(new BC_Title(x, y, _("B_dy:")));
140 add_subwindow(b_dy = new RGBShiftLevel(plugin, &plugin->config.b_dy, x1, y));
143 add_subwindow(reset = new RGBShiftReset(plugin, this, x, y));
151 void RGBShiftWindow::update()
153 r_dx->update(plugin->config.r_dx);
154 r_dy->update(plugin->config.r_dy);
155 g_dx->update(plugin->config.g_dx);
156 g_dy->update(plugin->config.g_dy);
157 b_dx->update(plugin->config.b_dx);
158 b_dy->update(plugin->config.b_dy);
166 RGBShiftEffect::RGBShiftEffect(PluginServer *server)
167 : PluginVClient(server)
171 RGBShiftEffect::~RGBShiftEffect()
176 const char* RGBShiftEffect::plugin_title() { return N_("RGBShift"); }
177 int RGBShiftEffect::is_realtime() { return 1; }
180 NEW_WINDOW_MACRO(RGBShiftEffect, RGBShiftWindow)
181 LOAD_CONFIGURATION_MACRO(RGBShiftEffect, RGBShiftConfig)
183 void RGBShiftEffect::update_gui()
187 RGBShiftWindow *yuv_wdw = (RGBShiftWindow*)thread->window;
188 yuv_wdw->lock_window("RGBShiftEffect::update_gui");
189 load_configuration();
190 yuv_wdw->r_dx->update(config.r_dx);
191 yuv_wdw->r_dy->update(config.r_dy);
192 yuv_wdw->g_dx->update(config.g_dx);
193 yuv_wdw->g_dy->update(config.g_dy);
194 yuv_wdw->b_dx->update(config.b_dx);
195 yuv_wdw->b_dy->update(config.b_dy);
196 yuv_wdw->unlock_window();
200 void RGBShiftEffect::save_data(KeyFrame *keyframe)
203 output.set_shared_output(keyframe->xbuf);
204 output.tag.set_title("RGBSHIFT");
205 output.tag.set_property("R_DX", config.r_dx);
206 output.tag.set_property("R_DY", config.r_dy);
207 output.tag.set_property("G_DX", config.g_dx);
208 output.tag.set_property("G_DY", config.g_dy);
209 output.tag.set_property("B_DX", config.b_dx);
210 output.tag.set_property("B_DY", config.b_dy);
212 output.tag.set_title("/RGBSHIFT");
214 output.append_newline();
215 output.terminate_string();
218 void RGBShiftEffect::read_data(KeyFrame *keyframe)
221 input.set_shared_input(keyframe->xbuf);
222 while(!input.read_tag())
224 if(input.tag.title_is("RGBSHIFT"))
226 config.r_dx = input.tag.get_property("R_DX", config.r_dx);
227 config.r_dy = input.tag.get_property("R_DY", config.r_dy);
228 config.g_dx = input.tag.get_property("G_DX", config.g_dx);
229 config.g_dy = input.tag.get_property("G_DY", config.g_dy);
230 config.b_dx = input.tag.get_property("B_DX", config.b_dx);
231 config.b_dy = input.tag.get_property("B_DY", config.b_dy);
236 #define RGB_MACRO(type, temp_type, components) \
238 for(int i = 0; i < h; i++) { \
239 int ri = i + config.r_dy, gi = i + config.g_dy, bi = i + config.b_dy; \
240 type *in_r = ri >= 0 && ri < h ? (type *)frame->get_rows()[ri] : 0; \
241 type *in_g = gi >= 0 && gi < h ? (type *)frame->get_rows()[gi] : 0; \
242 type *in_b = bi >= 0 && bi < h ? (type *)frame->get_rows()[bi] : 0; \
243 type *out_row = (type *)output->get_rows()[i]; \
244 for(int j = 0; j < w; j++) { \
245 int rj = j + config.r_dx, gj = j + config.g_dx, bj = j + config.b_dx; \
246 type *rp = in_r && rj >= 0 && rj < w ? in_r + rj*components: 0; \
247 type *gp = in_g && gj >= 0 && gj < w ? in_g + gj*components: 0; \
248 type *bp = in_b && bj >= 0 && bj < w ? in_b + bj*components: 0; \
249 out_row[0] = rp ? rp[0] : 0; \
250 out_row[1] = gp ? gp[1] : 0; \
251 out_row[2] = bp ? bp[2] : 0; \
252 out_row += components; \
257 #define YUV_MACRO(type, temp_type, components) \
259 for(int i = 0; i < h; i++) { \
260 int ri = i + config.r_dy, gi = i + config.g_dy, bi = i + config.b_dy; \
261 uint8_t *in_r = ri >= 0 && ri < h ? (uint8_t *)frame->get_rows()[ri] : 0; \
262 uint8_t *in_g = gi >= 0 && gi < h ? (uint8_t *)frame->get_rows()[gi] : 0; \
263 uint8_t *in_b = bi >= 0 && bi < h ? (uint8_t *)frame->get_rows()[bi] : 0; \
264 type *out_row = (type *)output->get_rows()[i]; \
265 for(int j = 0; j < w; j++) { \
266 int rj = j + config.r_dx, gj = j + config.g_dx, bj = j + config.b_dx; \
267 uint8_t *rp = in_r && rj >= 0 && rj < w ? in_r + rj*3: 0; \
268 uint8_t *gp = in_g && gj >= 0 && gj < w ? in_g + gj*3: 0; \
269 uint8_t *bp = in_b && bj >= 0 && bj < w ? in_b + bj*3: 0; \
271 temp_type r = rp ? rp[0] : 0; \
272 temp_type g = gp ? gp[1] : 0; \
273 temp_type b = bp ? bp[2] : 0; \
274 if( sizeof(type) == 4 ) \
275 YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v); \
276 else if( sizeof(type) == 2 ) \
277 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
279 YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \
283 out_row += components; \
288 int RGBShiftEffect::process_realtime(VFrame *input, VFrame *output)
290 load_configuration();
292 if( EQUIV(config.r_dx, 0) && EQUIV(config.g_dx, 0) && EQUIV(config.b_dx, 0) &&
293 EQUIV(config.r_dy, 0) && EQUIV(config.g_dy, 0) && EQUIV(config.b_dy, 0) ) {
294 if(input->get_rows()[0] != output->get_rows()[0])
295 output->copy_from(input);
299 int w = input->get_w(), h = input->get_h();
300 int color_model = input->get_color_model();
301 int is_yuv = BC_CModels::is_yuv(color_model);
302 if( is_yuv ) color_model = BC_RGB888;
303 VFrame *frame = input;
304 if( input->get_rows()[0] == output->get_rows()[0] || !is_yuv ) {
305 if( temp_frame && ( temp_frame->get_color_model() != color_model ||
306 temp_frame->get_w() != w || temp_frame->get_h() != h ) ) {
307 delete temp_frame; temp_frame = 0;
310 temp_frame = new VFrame(w, h, color_model, 0);
312 if( color_model != input->get_color_model() )
313 BC_CModels::transfer(frame->get_rows(), input->get_rows(),
314 frame->get_y(), frame->get_u(), frame->get_v(),
315 input->get_y(), input->get_u(), input->get_v(),
316 0, 0, input->get_w(), input->get_h(),
317 0, 0, frame->get_w(), frame->get_h(),
318 input->get_color_model(), frame->get_color_model(), 0,
319 input->get_bytes_per_line(), w);
321 frame->copy_from(input);
324 switch( input->get_color_model() ) {
325 case BC_YUV888: YUV_MACRO(unsigned char, int, 3); break;
326 case BC_YUV161616: YUV_MACRO(uint16_t, int, 3); break;
327 case BC_YUVA8888: YUV_MACRO(unsigned char, int, 4); break;
328 case BC_YUVA16161616: YUV_MACRO(uint16_t, int, 4); break;
329 case BC_RGB_FLOAT: RGB_MACRO(float, float, 3); break;
330 case BC_RGB888: RGB_MACRO(unsigned char, int, 3); break;
331 case BC_RGB161616: RGB_MACRO(uint16_t, int, 3); break;
332 case BC_RGBA_FLOAT: RGB_MACRO(float, float, 4); break;
333 case BC_RGBA8888: RGB_MACRO(unsigned char, int, 4); break;
334 case BC_RGBA16161616: RGB_MACRO(uint16_t, int, 4); break;