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
22 #include "bcdisplayinfo.h"
29 #include "pluginvclient.h"
44 void copy_from(YUVShiftConfig &src);
45 int equivalent(YUVShiftConfig &src);
46 void interpolate(YUVShiftConfig &prev,
52 int y_dx, y_dy, u_dx, u_dy, v_dx, v_dy;
55 class YUVShiftLevel : public BC_ISlider
58 YUVShiftLevel(YUVShiftEffect *plugin, int *output, int x, int y);
60 YUVShiftEffect *plugin;
64 class YUVShiftWindow : public PluginClientWindow
67 YUVShiftWindow(YUVShiftEffect *plugin);
68 void create_objects();
69 YUVShiftLevel *y_dx, *y_dy, *u_dx, *u_dy, *v_dx, *v_dy;
70 YUVShiftEffect *plugin;
75 class YUVShiftEffect : public PluginVClient
79 YUVShiftEffect(PluginServer *server);
83 PLUGIN_CLASS_MEMBERS(YUVShiftConfig)
84 int process_realtime(VFrame *input, VFrame *output);
86 void save_data(KeyFrame *keyframe);
87 void read_data(KeyFrame *keyframe);
95 REGISTER_PLUGIN(YUVShiftEffect)
103 YUVShiftConfig::YUVShiftConfig()
110 void YUVShiftConfig::copy_from(YUVShiftConfig &src)
112 y_dx = src.y_dx; y_dy = src.y_dy;
113 u_dx = src.u_dx; u_dy = src.u_dy;
114 v_dx = src.v_dx; v_dy = src.v_dy;
117 int YUVShiftConfig::equivalent(YUVShiftConfig &src)
119 return EQUIV(y_dx, src.y_dx) && EQUIV(u_dx, src.u_dx) && EQUIV(v_dx, src.v_dx) &&
120 EQUIV(y_dy, src.y_dy) && EQUIV(u_dy, src.u_dy) && EQUIV(v_dy, src.v_dy);
123 void YUVShiftConfig::interpolate(YUVShiftConfig &prev,
124 YUVShiftConfig &next,
129 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
130 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
132 y_dx = prev.y_dx * prev_scale + next.y_dx * next_scale;
133 y_dy = prev.y_dy * prev_scale + next.y_dy * next_scale;
134 u_dx = prev.u_dx * prev_scale + next.u_dx * next_scale;
135 u_dy = prev.u_dy * prev_scale + next.u_dy * next_scale;
136 v_dx = prev.v_dx * prev_scale + next.v_dx * next_scale;
137 v_dy = prev.v_dy * prev_scale + next.v_dy * next_scale;
147 YUVShiftLevel::YUVShiftLevel(YUVShiftEffect *plugin, int *output, int x, int y)
148 : BC_ISlider(x, y, 0, 200, 200, -MAXVALUE, MAXVALUE, *output)
150 this->plugin = plugin;
151 this->output = output;
154 int YUVShiftLevel::handle_event()
156 *output = get_value();
157 plugin->send_configure_change();
162 YUVShiftWindow::YUVShiftWindow(YUVShiftEffect *plugin)
163 : PluginClientWindow(plugin, 300, 200, 300, 200, 0)
165 this->plugin = plugin;
168 void YUVShiftWindow::create_objects()
170 int x = 10, y = 10, x1 = 50;
171 add_subwindow(new BC_Title(x, y, _("Y_dx:")));
172 add_subwindow(y_dx = new YUVShiftLevel(plugin, &plugin->config.y_dx, x1, y));
174 add_subwindow(new BC_Title(x, y, _("Y_dy:")));
175 add_subwindow(y_dy = new YUVShiftLevel(plugin, &plugin->config.y_dy, x1, y));
177 add_subwindow(new BC_Title(x, y, _("U_dx:")));
178 add_subwindow(u_dx = new YUVShiftLevel(plugin, &plugin->config.u_dx, x1, y));
180 add_subwindow(new BC_Title(x, y, _("U_dy:")));
181 add_subwindow(u_dy = new YUVShiftLevel(plugin, &plugin->config.u_dy, x1, y));
183 add_subwindow(new BC_Title(x, y, _("V_dx:")));
184 add_subwindow(v_dx = new YUVShiftLevel(plugin, &plugin->config.v_dx, x1, y));
186 add_subwindow(new BC_Title(x, y, _("V_dy:")));
187 add_subwindow(v_dy = new YUVShiftLevel(plugin, &plugin->config.v_dy, x1, y));
201 YUVShiftEffect::YUVShiftEffect(PluginServer *server)
202 : PluginVClient(server)
206 YUVShiftEffect::~YUVShiftEffect()
211 const char* YUVShiftEffect::plugin_title() { return N_("YUVShift"); }
212 int YUVShiftEffect::is_realtime() { return 1; }
215 NEW_WINDOW_MACRO(YUVShiftEffect, YUVShiftWindow)
216 LOAD_CONFIGURATION_MACRO(YUVShiftEffect, YUVShiftConfig)
218 void YUVShiftEffect::update_gui()
222 YUVShiftWindow *yuv_wdw = (YUVShiftWindow*)thread->window;
223 yuv_wdw->lock_window("YUVShiftEffect::update_gui");
224 load_configuration();
225 yuv_wdw->y_dx->update(config.y_dx);
226 yuv_wdw->y_dy->update(config.y_dy);
227 yuv_wdw->u_dx->update(config.u_dx);
228 yuv_wdw->u_dy->update(config.u_dy);
229 yuv_wdw->v_dx->update(config.v_dx);
230 yuv_wdw->v_dy->update(config.v_dy);
231 yuv_wdw->unlock_window();
235 void YUVShiftEffect::save_data(KeyFrame *keyframe)
238 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
239 output.tag.set_title("YUVSHIFT");
240 output.tag.set_property("Y_DX", config.y_dx);
241 output.tag.set_property("Y_DY", config.y_dy);
242 output.tag.set_property("U_DX", config.u_dx);
243 output.tag.set_property("U_DY", config.u_dy);
244 output.tag.set_property("V_DX", config.v_dx);
245 output.tag.set_property("V_DY", config.v_dy);
247 output.tag.set_title("/YUVSHIFT");
249 output.append_newline();
250 output.terminate_string();
253 void YUVShiftEffect::read_data(KeyFrame *keyframe)
256 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
257 while(!input.read_tag())
259 if(input.tag.title_is("YUVSHIFT"))
261 config.y_dx = input.tag.get_property("Y_DX", config.y_dx);
262 config.y_dy = input.tag.get_property("Y_DY", config.y_dy);
263 config.u_dx = input.tag.get_property("U_DX", config.u_dx);
264 config.u_dy = input.tag.get_property("U_DY", config.u_dy);
265 config.v_dx = input.tag.get_property("V_DX", config.v_dx);
266 config.v_dy = input.tag.get_property("V_DY", config.v_dy);
272 #define YUV_MACRO(type, temp_type, components) \
274 for(int i = 0; i < h; i++) { \
275 int yi = i + config.y_dy, ui = i + config.u_dy, vi = i + config.v_dy; \
276 type *in_y = yi >= 0 && yi < h ? (type *)frame->get_rows()[yi] : 0; \
277 type *in_u = ui >= 0 && ui < h ? (type *)frame->get_rows()[ui] : 0; \
278 type *in_v = vi >= 0 && vi < h ? (type *)frame->get_rows()[vi] : 0; \
279 type *out_row = (type *)output->get_rows()[i]; \
280 for(int j = 0; j < w; j++) { \
281 int yj = j + config.y_dx, uj = j + config.u_dx, vj = j + config.v_dx; \
282 type *yp = in_y && yj >= 0 && yj < w ? in_y + yj*components: 0; \
283 type *up = in_u && uj >= 0 && uj < w ? in_u + uj*components: 0; \
284 type *vp = in_v && vj >= 0 && vj < w ? in_v + vj*components: 0; \
285 out_row[0] = yp ? yp[0] : 0; \
286 out_row[1] = up ? up[1] : (1<<(8*sizeof(type)-1)); \
287 out_row[2] = vp ? vp[2] : (1<<(8*sizeof(type)-1)); \
288 out_row += components; \
293 #define RGB_MACRO(type, temp_type, components) \
295 for(int i = 0; i < h; i++) { \
296 int yi = i + config.y_dy, ui = i + config.u_dy, vi = i + config.v_dy; \
297 uint8_t *in_y = yi >= 0 && yi < h ? (uint8_t *)frame->get_rows()[yi] : 0; \
298 uint8_t *in_u = ui >= 0 && ui < h ? (uint8_t *)frame->get_rows()[ui] : 0; \
299 uint8_t *in_v = vi >= 0 && vi < h ? (uint8_t *)frame->get_rows()[vi] : 0; \
300 type *out_row = (type *)output->get_rows()[i]; \
301 for(int j = 0; j < w; j++) { \
302 int yj = j + config.y_dx, uj = j + config.u_dx, vj = j + config.v_dx; \
303 uint8_t *yp = in_y && yj >= 0 && yj < w ? in_y + yj*3: 0; \
304 uint8_t *up = in_u && uj >= 0 && uj < w ? in_u + uj*3: 0; \
305 uint8_t *vp = in_v && vj >= 0 && vj < w ? in_v + vj*3: 0; \
307 temp_type y = yp ? yp[0] : 0x00; \
308 temp_type u = up ? up[1] : 0x80; \
309 temp_type v = vp ? vp[2] : 0x80; \
310 if( sizeof(type) == 4 ) \
311 YUV::yuv.yuv_to_rgb_f(r, g, b, y/255., (u-128.)/255., (v-128.)/255.); \
312 else if( sizeof(type) == 2 ) \
313 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
315 YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \
319 out_row += components; \
324 int YUVShiftEffect::process_realtime(VFrame *input, VFrame *output)
326 load_configuration();
328 if( EQUIV(config.y_dx, 0) && EQUIV(config.u_dx, 0) && EQUIV(config.v_dx, 0) &&
329 EQUIV(config.y_dy, 0) && EQUIV(config.u_dy, 0) && EQUIV(config.v_dy, 0) ) {
330 if(input->get_rows()[0] != output->get_rows()[0])
331 output->copy_from(input);
335 int w = input->get_w(), h = input->get_h();
336 int color_model = input->get_color_model();
337 int is_yuv = BC_CModels::is_yuv(color_model);
338 if( !is_yuv ) color_model = BC_YUV888;
339 VFrame *frame = input;
340 if( input->get_rows()[0] == output->get_rows()[0] || !is_yuv ) {
341 if( temp_frame && ( temp_frame->get_color_model() != color_model ||
342 temp_frame->get_w() != w || temp_frame->get_h() != h ) ) {
343 delete temp_frame; temp_frame = 0;
346 temp_frame = new VFrame(w, h, color_model, 0);
348 if( color_model != input->get_color_model() )
349 BC_CModels::transfer(frame->get_rows(), input->get_rows(),
350 frame->get_y(), frame->get_u(), frame->get_v(),
351 input->get_y(), input->get_u(), input->get_v(),
352 0, 0, input->get_w(), input->get_h(),
353 0, 0, frame->get_w(), frame->get_h(),
354 input->get_color_model(), frame->get_color_model(), 0,
355 input->get_bytes_per_line(), w);
357 frame->copy_from(input);
360 switch( input->get_color_model() ) {
361 case BC_YUV888: YUV_MACRO(unsigned char, int, 3); break;
362 case BC_YUV161616: YUV_MACRO(uint16_t, int, 3); break;
363 case BC_YUVA8888: YUV_MACRO(unsigned char, int, 4); break;
364 case BC_YUVA16161616: YUV_MACRO(uint16_t, int, 4); break;
365 case BC_RGB_FLOAT: RGB_MACRO(float, float, 3); break;
366 case BC_RGB888: RGB_MACRO(unsigned char, int, 3); break;
367 case BC_RGB161616: RGB_MACRO(uint16_t, int, 3); break;
368 case BC_RGBA_FLOAT: RGB_MACRO(float, float, 4); break;
369 case BC_RGBA8888: RGB_MACRO(unsigned char, int, 4); break;
370 case BC_RGBA16161616: RGB_MACRO(uint16_t, int, 4); break;