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-hv.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 plugin->config.search_radius,
110 plugin->config.search_radius,
111 plugin->config.macroblock_size,
112 plugin->config.macroblock_size,
115 MotionScan::TRACK_PREVIOUS,
116 MotionScan::CALCULATE,
117 // Get it to do the subpixel step
118 MotionScan::STABILIZE,
132 mb->dx = motion->dx_result;
133 mb->dy = motion->dy_result;
134 // mb->is_valid = motion->result_valid;
138 struct timeval end_time;
139 gettimeofday(&end_time, 0);
140 // printf("OpticFlowUnit::process_package %d %d\n",
142 // end_time.tv_sec * 1000 + end_time.tv_usec / 1000 -
143 // start_time.tv_sec * 1000 - start_time.tv_usec / 1000);
151 OpticFlow::OpticFlow(InterpolateVideo *plugin,
156 : LoadServer(total_clients,
159 this->plugin = plugin;
163 OpticFlow::~OpticFlow()
167 void OpticFlow::init_packages()
169 //printf("OpticFlow::init_packages %d %d\n", __LINE__, get_total_packages());
170 for(int i = 0; i < get_total_packages(); i++)
172 OpticFlowPackage *pkg = (OpticFlowPackage*)get_package(i);
173 pkg->macroblock0 = plugin->total_macroblocks * i / get_total_packages();
174 pkg->macroblock1 = plugin->total_macroblocks * (i + 1) / get_total_packages();
178 LoadClient* OpticFlow::new_client()
180 return new OpticFlowUnit(this);
183 LoadPackage* OpticFlow::new_package()
185 return new OpticFlowPackage;
194 WarpPackage::WarpPackage()
205 WarpUnit::WarpUnit(Warp *server)
208 this->server = server;
211 WarpUnit::~WarpUnit()
216 #define AVERAGE2(type, components, max) \
218 type *prev0 = (type*)prev_rows[(int)prev_y0] + ((int)prev_x0) * components; \
219 type *prev1 = (type*)prev_rows[(int)prev_y0] + ((int)prev_x1) * components; \
220 type *prev2 = (type*)prev_rows[(int)prev_y1] + ((int)prev_x0) * components; \
221 type *prev3 = (type*)prev_rows[(int)prev_y1] + ((int)prev_x1) * components; \
225 type *next0 = (type*)next_rows[(int)next_y0] + ((int)next_x0) * components; \
226 type *next1 = (type*)next_rows[(int)next_y0] + ((int)next_x1) * components; \
227 type *next2 = (type*)next_rows[(int)next_y1] + ((int)next_x0) * components; \
228 type *next3 = (type*)next_rows[(int)next_y1] + ((int)next_x1) * components; \
232 type *out_row = (type*)out_rows[i] + j * components; \
234 for(int k = 0; k < components; k++) \
237 prev_alpha * (*prev0 * prev_fraction_x0 * prev_fraction_y0 + \
238 *prev1 * prev_fraction_x1 * prev_fraction_y0 + \
239 *prev2 * prev_fraction_x0 * prev_fraction_y1 + \
240 *prev3 * prev_fraction_x1 * prev_fraction_y1) + \
241 next_alpha * (*next0 * next_fraction_x0 * next_fraction_y0 + \
242 *next1 * next_fraction_x1 * next_fraction_y0 + \
243 *next2 * next_fraction_x0 * next_fraction_y1 + \
244 *next3 * next_fraction_x1 * next_fraction_y1); \
245 CLAMP(value, 0, max); \
246 *out_row++ = (type)value; \
259 void WarpUnit::process_package(LoadPackage *package)
261 WarpPackage *pkg = (WarpPackage*)package;
262 InterpolateVideo *plugin = server->plugin;
263 int w = plugin->frames[0]->get_w();
264 int h = plugin->frames[0]->get_h();
265 unsigned char **prev_rows = plugin->frames[0]->get_rows();
266 unsigned char **next_rows = plugin->frames[1]->get_rows();
267 unsigned char **out_rows = plugin->get_output()->get_rows();
268 int color_model = plugin->get_output()->get_color_model();
269 int macroblock_size = plugin->config.macroblock_size;
271 float lowest_fraction = plugin->lowest_fraction;
272 //float highest_fraction = 1.0 - lowest_fraction;
274 float prev_alpha = lowest_fraction;
275 float next_alpha = 1.0 - prev_alpha;
276 //printf("WarpUnit::process_package %d %p %d %d\n", __LINE__, this, pkg->y1, pkg->y2);
278 // Count all macroblocks as valid
279 for(int i = pkg->y1; i < pkg->y2; i++)
281 for(int j = 0; j < w; j++)
283 // Get the motion vector for each pixel, based on the nearest motion vectors
284 int x_macroblock = j / macroblock_size;
285 int y_macroblock = i / macroblock_size;
287 int x_macroblock2 = x_macroblock + 1;
288 int y_macroblock2 = y_macroblock + 1;
290 x_macroblock2 = MIN(x_macroblock2, plugin->x_macroblocks - 1);
291 y_macroblock2 = MIN(y_macroblock2, plugin->y_macroblocks - 1);
293 float x_fraction = (float)(j - x_macroblock * macroblock_size) / macroblock_size;
294 float y_fraction = (float)(i - y_macroblock * macroblock_size) / macroblock_size;
296 OpticFlowMacroblock *mb;
297 mb = plugin->macroblocks.get(
298 x_macroblock + y_macroblock * plugin->x_macroblocks);
300 float dx = (float)mb->dx * (1.0 - x_fraction) * (1.0 - y_fraction);
301 float dy = (float)mb->dy * (1.0 - x_fraction) * (1.0 - y_fraction);
303 mb = plugin->macroblocks.get(
304 x_macroblock2 + y_macroblock * plugin->x_macroblocks);
305 dx += (float)mb->dx * (x_fraction) * (1.0 - y_fraction);
306 dy += (float)mb->dy * (x_fraction) * (1.0 - y_fraction);
308 mb = plugin->macroblocks.get(
309 x_macroblock + y_macroblock2 * plugin->x_macroblocks);
310 dx += (float)mb->dx * (1.0 - x_fraction) * (y_fraction);
311 dy += (float)mb->dy * (1.0 - x_fraction) * (y_fraction);
313 mb = plugin->macroblocks.get(
314 x_macroblock2 + y_macroblock2 * plugin->x_macroblocks);
315 dx += (float)mb->dx * (x_fraction) * (y_fraction);
316 dy += (float)mb->dy * (x_fraction) * (y_fraction);
318 dx /= (float)OVERSAMPLE;
319 dy /= (float)OVERSAMPLE;
324 // 4 pixels from prev frame
325 float prev_x0 = (float)j + dx * (1.0 - lowest_fraction);
326 float prev_y0 = (float)i + dy * (1.0 - lowest_fraction);
327 float prev_x1 = prev_x0 + 1;
328 float prev_y1 = prev_y0 + 1;
329 float prev_fraction_x1 = prev_x0 - floor(prev_x0);
330 float prev_fraction_x0 = 1.0 - prev_fraction_x1;
331 float prev_fraction_y1 = prev_y0 - floor(prev_y0);
332 float prev_fraction_y0 = 1.0 - prev_fraction_y1;
335 // 4 pixels from next frame
336 float next_x0 = (float)j - dx * plugin->lowest_fraction;
337 float next_y0 = (float)i - dy * plugin->lowest_fraction;
338 float next_x1 = next_x0 + 1;
339 float next_y1 = next_y0 + 1;
340 float next_fraction_x1 = next_x0 - floor(next_x0);
341 float next_fraction_x0 = 1.0 - next_fraction_x1;
342 float next_fraction_y1 = next_y0 - floor(next_y0);
343 float next_fraction_y0 = 1.0 - next_fraction_y1;
346 CLAMP(prev_x0, 0, w - 1);
347 CLAMP(prev_y0, 0, h - 1);
348 CLAMP(prev_x1, 0, w - 1);
349 CLAMP(prev_y1, 0, h - 1);
351 CLAMP(next_x0, 0, w - 1);
352 CLAMP(next_y0, 0, h - 1);
353 CLAMP(next_x1, 0, w - 1);
354 CLAMP(next_y1, 0, h - 1);
356 //printf("WarpUnit::process_package %d\n", __LINE__);
361 AVERAGE2(float, 3, 1.0);
365 AVERAGE2(unsigned char, 3, 0xff);
368 AVERAGE2(float, 4, 1.0);
372 AVERAGE2(unsigned char, 4, 0xff);
375 //printf("WarpUnit::process_package %d\n", __LINE__);
385 Warp::Warp(InterpolateVideo *plugin,
388 : LoadServer(total_clients,
391 this->plugin = plugin;
399 void Warp::init_packages()
401 int out_h = plugin->frames[0]->get_h();
402 for(int i = 0; i < get_total_packages(); i++)
404 WarpPackage *pkg = (WarpPackage*)get_package(i);
405 pkg->y1 = out_h * i / get_total_packages();
406 pkg->y2 = out_h * (i + 1) / get_total_packages();
410 LoadClient* Warp::new_client()
412 return new WarpUnit(this);
415 LoadPackage* Warp::new_package()
417 return new WarpPackage;
427 BlendPackage::BlendPackage()
439 BlendMacroblockUnit::BlendMacroblockUnit(BlendMacroblock *server)
442 this->server = server;
445 BlendMacroblockUnit::~BlendMacroblockUnit()
449 void BlendMacroblockUnit::process_package(LoadPackage *package)
451 BlendPackage *pkg = (BlendPackage*)package;
452 InterpolateVideo *plugin = server->plugin;
454 for(int i = pkg->number0; i < pkg->number1; i++)
456 plugin->blend_macroblock(plugin->invalid_blocks.get(i));
469 BlendMacroblock::BlendMacroblock(InterpolateVideo *plugin,
472 : LoadServer(total_clients,
475 this->plugin = plugin;
479 BlendMacroblock::~BlendMacroblock()
483 void BlendMacroblock::init_packages()
485 for(int i = 0; i < get_total_packages(); i++)
487 BlendPackage *pkg = (BlendPackage*)get_package(i);
488 pkg->number0 = plugin->invalid_blocks.size() * i / get_total_packages();
489 pkg->number1 = plugin->invalid_blocks.size() * (i + 1) / get_total_packages();
495 LoadClient* BlendMacroblock::new_client()
497 return new BlendMacroblockUnit(this);
500 LoadPackage* BlendMacroblock::new_package()
502 return new BlendPackage;