3 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "interpolatevideo.h"
27 #include "motionscan.h"
28 #include "opticflow.h"
36 OpticFlowMacroblock::OpticFlowMacroblock()
43 void OpticFlowMacroblock::copy_from(OpticFlowMacroblock *src)
49 this->is_valid = src->is_valid;
50 // Temporaries for blending macroblocks
51 this->angle1 = src->angle1;
52 this->angle2 = src->angle2;
53 this->dist = src->dist;
54 this->visible = src->visible;
63 OpticFlowPackage::OpticFlowPackage()
74 OpticFlowUnit::OpticFlowUnit(OpticFlow *server)
77 this->server = server;
81 OpticFlowUnit::~OpticFlowUnit()
86 void OpticFlowUnit::process_package(LoadPackage *package)
88 OpticFlowPackage *pkg = (OpticFlowPackage*)package;
89 InterpolateVideo *plugin = server->plugin;
90 int w = plugin->frames[0]->get_w();
91 int h = plugin->frames[0]->get_h();
92 struct timeval start_time;
93 gettimeofday(&start_time, 0);
95 if(!motion) motion = new MotionScan(1, 1);
97 motion->set_test_match(0);
98 // printf("OpticFlowUnit::process_package %d %d %d\n",
101 // pkg->macroblock1);
103 for(int i = pkg->macroblock0; i < pkg->macroblock1; i++)
105 OpticFlowMacroblock *mb = plugin->macroblocks.get(i);
106 motion->scan_frame(plugin->frames[0],
107 // Frame after motion
109 100 * plugin->config.search_radius / w,
110 100 * plugin->config.search_radius / h,
111 100 * plugin->config.macroblock_size / w,
112 100 * plugin->config.macroblock_size / h,
115 MotionScan::TRACK_PREVIOUS,
116 MotionScan::CALCULATE,
117 // Get it to do the subpixel step
118 MotionScan::STABILIZE,
122 MIN(MAX_SEARCH_STEPS, plugin->config.search_radius * plugin->config.search_radius),
127 // Degrees from center to maximum angle
129 // Accumulated angle from previous frames
131 // Total number of angles to test in each pass
136 mb->dx = motion->dx_result;
137 mb->dy = motion->dy_result;
138 // mb->is_valid = motion->result_valid;
142 struct timeval end_time;
143 gettimeofday(&end_time, 0);
144 // printf("OpticFlowUnit::process_package %d %d\n",
146 // end_time.tv_sec * 1000 + end_time.tv_usec / 1000 -
147 // start_time.tv_sec * 1000 - start_time.tv_usec / 1000);
155 OpticFlow::OpticFlow(InterpolateVideo *plugin,
160 : LoadServer(total_clients,
163 this->plugin = plugin;
167 OpticFlow::~OpticFlow()
171 void OpticFlow::init_packages()
173 //printf("OpticFlow::init_packages %d %d\n", __LINE__, get_total_packages());
174 for(int i = 0; i < get_total_packages(); i++)
176 OpticFlowPackage *pkg = (OpticFlowPackage*)get_package(i);
177 pkg->macroblock0 = plugin->total_macroblocks * i / get_total_packages();
178 pkg->macroblock1 = plugin->total_macroblocks * (i + 1) / get_total_packages();
182 LoadClient* OpticFlow::new_client()
184 return new OpticFlowUnit(this);
187 LoadPackage* OpticFlow::new_package()
189 return new OpticFlowPackage;
198 WarpPackage::WarpPackage()
209 WarpUnit::WarpUnit(Warp *server)
212 this->server = server;
215 WarpUnit::~WarpUnit()
220 #define AVERAGE2(type, components, max) \
222 type *prev0 = (type*)prev_rows[(int)prev_y0] + ((int)prev_x0) * components; \
223 type *prev1 = (type*)prev_rows[(int)prev_y0] + ((int)prev_x1) * components; \
224 type *prev2 = (type*)prev_rows[(int)prev_y1] + ((int)prev_x0) * components; \
225 type *prev3 = (type*)prev_rows[(int)prev_y1] + ((int)prev_x1) * components; \
229 type *next0 = (type*)next_rows[(int)next_y0] + ((int)next_x0) * components; \
230 type *next1 = (type*)next_rows[(int)next_y0] + ((int)next_x1) * components; \
231 type *next2 = (type*)next_rows[(int)next_y1] + ((int)next_x0) * components; \
232 type *next3 = (type*)next_rows[(int)next_y1] + ((int)next_x1) * components; \
236 type *out_row = (type*)out_rows[i] + j * components; \
238 for(int k = 0; k < components; k++) \
241 prev_alpha * (*prev0 * prev_fraction_x0 * prev_fraction_y0 + \
242 *prev1 * prev_fraction_x1 * prev_fraction_y0 + \
243 *prev2 * prev_fraction_x0 * prev_fraction_y1 + \
244 *prev3 * prev_fraction_x1 * prev_fraction_y1) + \
245 next_alpha * (*next0 * next_fraction_x0 * next_fraction_y0 + \
246 *next1 * next_fraction_x1 * next_fraction_y0 + \
247 *next2 * next_fraction_x0 * next_fraction_y1 + \
248 *next3 * next_fraction_x1 * next_fraction_y1); \
249 CLAMP(value, 0, max); \
250 *out_row++ = (type)value; \
263 void WarpUnit::process_package(LoadPackage *package)
265 WarpPackage *pkg = (WarpPackage*)package;
266 InterpolateVideo *plugin = server->plugin;
267 int w = plugin->frames[0]->get_w();
268 int h = plugin->frames[0]->get_h();
269 unsigned char **prev_rows = plugin->frames[0]->get_rows();
270 unsigned char **next_rows = plugin->frames[1]->get_rows();
271 unsigned char **out_rows = plugin->get_output()->get_rows();
272 int color_model = plugin->get_output()->get_color_model();
273 int macroblock_size = plugin->config.macroblock_size;
275 float lowest_fraction = plugin->lowest_fraction;
276 //float highest_fraction = 1.0 - lowest_fraction;
278 float prev_alpha = lowest_fraction;
279 float next_alpha = 1.0 - prev_alpha;
280 //printf("WarpUnit::process_package %d %p %d %d\n", __LINE__, this, pkg->y1, pkg->y2);
282 // Count all macroblocks as valid
283 for(int i = pkg->y1; i < pkg->y2; i++)
285 for(int j = 0; j < w; j++)
287 // Get the motion vector for each pixel, based on the nearest motion vectors
288 int x_macroblock = j / macroblock_size;
289 int y_macroblock = i / macroblock_size;
291 int x_macroblock2 = x_macroblock + 1;
292 int y_macroblock2 = y_macroblock + 1;
294 x_macroblock2 = MIN(x_macroblock2, plugin->x_macroblocks - 1);
295 y_macroblock2 = MIN(y_macroblock2, plugin->y_macroblocks - 1);
297 float x_fraction = (float)(j - x_macroblock * macroblock_size) / macroblock_size;
298 float y_fraction = (float)(i - y_macroblock * macroblock_size) / macroblock_size;
300 OpticFlowMacroblock *mb;
301 mb = plugin->macroblocks.get(
302 x_macroblock + y_macroblock * plugin->x_macroblocks);
304 float dx = (float)mb->dx * (1.0 - x_fraction) * (1.0 - y_fraction);
305 float dy = (float)mb->dy * (1.0 - x_fraction) * (1.0 - y_fraction);
307 mb = plugin->macroblocks.get(
308 x_macroblock2 + y_macroblock * plugin->x_macroblocks);
309 dx += (float)mb->dx * (x_fraction) * (1.0 - y_fraction);
310 dy += (float)mb->dy * (x_fraction) * (1.0 - y_fraction);
312 mb = plugin->macroblocks.get(
313 x_macroblock + y_macroblock2 * plugin->x_macroblocks);
314 dx += (float)mb->dx * (1.0 - x_fraction) * (y_fraction);
315 dy += (float)mb->dy * (1.0 - x_fraction) * (y_fraction);
317 mb = plugin->macroblocks.get(
318 x_macroblock2 + y_macroblock2 * plugin->x_macroblocks);
319 dx += (float)mb->dx * (x_fraction) * (y_fraction);
320 dy += (float)mb->dy * (x_fraction) * (y_fraction);
322 dx /= (float)OVERSAMPLE;
323 dy /= (float)OVERSAMPLE;
328 // 4 pixels from prev frame
329 float prev_x0 = (float)j + dx * (1.0 - lowest_fraction);
330 float prev_y0 = (float)i + dy * (1.0 - lowest_fraction);
331 float prev_x1 = prev_x0 + 1;
332 float prev_y1 = prev_y0 + 1;
333 float prev_fraction_x1 = prev_x0 - floor(prev_x0);
334 float prev_fraction_x0 = 1.0 - prev_fraction_x1;
335 float prev_fraction_y1 = prev_y0 - floor(prev_y0);
336 float prev_fraction_y0 = 1.0 - prev_fraction_y1;
339 // 4 pixels from next frame
340 float next_x0 = (float)j - dx * plugin->lowest_fraction;
341 float next_y0 = (float)i - dy * plugin->lowest_fraction;
342 float next_x1 = next_x0 + 1;
343 float next_y1 = next_y0 + 1;
344 float next_fraction_x1 = next_x0 - floor(next_x0);
345 float next_fraction_x0 = 1.0 - next_fraction_x1;
346 float next_fraction_y1 = next_y0 - floor(next_y0);
347 float next_fraction_y0 = 1.0 - next_fraction_y1;
350 CLAMP(prev_x0, 0, w - 1);
351 CLAMP(prev_y0, 0, h - 1);
352 CLAMP(prev_x1, 0, w - 1);
353 CLAMP(prev_y1, 0, h - 1);
355 CLAMP(next_x0, 0, w - 1);
356 CLAMP(next_y0, 0, h - 1);
357 CLAMP(next_x1, 0, w - 1);
358 CLAMP(next_y1, 0, h - 1);
360 //printf("WarpUnit::process_package %d\n", __LINE__);
365 AVERAGE2(float, 3, 1.0);
369 AVERAGE2(unsigned char, 3, 0xff);
372 AVERAGE2(float, 4, 1.0);
376 AVERAGE2(unsigned char, 4, 0xff);
379 //printf("WarpUnit::process_package %d\n", __LINE__);
389 Warp::Warp(InterpolateVideo *plugin,
392 : LoadServer(total_clients,
395 this->plugin = plugin;
403 void Warp::init_packages()
405 int out_h = plugin->frames[0]->get_h();
406 for(int i = 0; i < get_total_packages(); i++)
408 WarpPackage *pkg = (WarpPackage*)get_package(i);
409 pkg->y1 = out_h * i / get_total_packages();
410 pkg->y2 = out_h * (i + 1) / get_total_packages();
414 LoadClient* Warp::new_client()
416 return new WarpUnit(this);
419 LoadPackage* Warp::new_package()
421 return new WarpPackage;
431 BlendPackage::BlendPackage()
443 BlendMacroblockUnit::BlendMacroblockUnit(BlendMacroblock *server)
446 this->server = server;
449 BlendMacroblockUnit::~BlendMacroblockUnit()
453 void BlendMacroblockUnit::process_package(LoadPackage *package)
455 BlendPackage *pkg = (BlendPackage*)package;
456 InterpolateVideo *plugin = server->plugin;
458 for(int i = pkg->number0; i < pkg->number1; i++)
460 plugin->blend_macroblock(plugin->invalid_blocks.get(i));
473 BlendMacroblock::BlendMacroblock(InterpolateVideo *plugin,
476 : LoadServer(total_clients,
479 this->plugin = plugin;
483 BlendMacroblock::~BlendMacroblock()
487 void BlendMacroblock::init_packages()
489 for(int i = 0; i < get_total_packages(); i++)
491 BlendPackage *pkg = (BlendPackage*)get_package(i);
492 pkg->number0 = plugin->invalid_blocks.size() * i / get_total_packages();
493 pkg->number1 = plugin->invalid_blocks.size() * (i + 1) / get_total_packages();
499 LoadClient* BlendMacroblock::new_client()
501 return new BlendMacroblockUnit(this);
504 LoadPackage* BlendMacroblock::new_package()
506 return new BlendPackage;