2 #include "rotateframe.h"
9 #define SQR(x) ((x) * (x))
11 RotateFrame::RotateFrame(int cpus, int width, int height)
13 int y1, y2, y_increment;
14 y_increment = height / cpus;
18 //printf("RotateFrame::RotateFrame 1\n");
19 engine = new RotateEngine*[cpus];
20 for(int i = 0; i < cpus; i++)
22 y2 = y1 + y_increment;
23 if(i == cpus - 1 && y2 < height - 1) y2 = height - 1;
24 engine[i] = new RotateEngine(this, y1, y2);
35 //printf("RotateFrame::RotateFrame 2\n");
38 RotateFrame::~RotateFrame()
40 for(int i = 0; i < cpus; i++)
45 if(float_matrix) delete [] float_matrix;
46 if(int_matrix) delete [] int_matrix;
47 if(float_rows) delete [] float_rows;
48 if(int_rows) delete [] int_rows;
52 void RotateFrame::rotate(VFrame *output,
58 this->output = output;
60 this->interpolate = interpolate;
64 if(angle == 90 || angle == 180 || angle == 270)
65 rotate_rightangle(input,
70 rotate_obliqueangle(input,
77 // Data never processed so copy if necessary
79 output->copy_from(input);
81 this->last_angle = angle;
84 int RotateFrame::get_rightdimensions(VFrame *frame,
95 diameter = frame->get_w() < frame->get_h() ? frame->get_w() : frame->get_h();
96 out_x1 = in_x1 = frame->get_w() / 2 - diameter / 2;
97 out_x2 = in_x2 = in_x1 + diameter - 1;
98 out_y1 = in_y1 = frame->get_h() / 2 - diameter / 2;
99 out_y2 = in_y2 = in_y1 + diameter - 1;
105 #define ROTATE_RIGHTANGLE(type, components) \
107 type **input_rows = (type**)input->get_rows(); \
108 type **output_rows = (type**)output->get_rows(); \
109 int height = output->get_h(); \
110 int width = output->get_w(); \
115 get_rightdimensions(input, \
125 while(in_x2 > in_x1) \
127 diameter = in_x2 - in_x1; \
128 for(int i = 0; i < diameter; i++) \
130 type temp_pixel[components]; \
131 for(int j = 0; j < components; j++) \
133 temp_pixel[j] = input_rows[in_y1 + i][in_x2 * components + j]; \
135 output_rows[in_y1 + i][in_x2 * components + j] = input_rows[in_y1][(in_x1 + i) * components + j]; \
136 output_rows[in_y1][(in_x1 + i) * components + j] = input_rows[in_y2 - i][in_x1 * components + j]; \
137 output_rows[in_y2 - i][in_x1 * components + j] = input_rows[in_y2][(in_x2 - i) * components + j]; \
138 output_rows[in_y2][(in_x2 - i) * components + j] = temp_pixel[j]; \
150 for(int i = 0, j = height - 1; i < j; i++, j--) \
152 for(int k = 0, l = width - 1; k < width; k++, l--) \
154 type temp_pixel[components]; \
155 for(int m = 0; m < components; m++) \
157 temp_pixel[m] = input_rows[j][k * components + m]; \
158 output_rows[j][k * components + m] = input_rows[i][l * components + m]; \
159 output_rows[i][l * components + m] = temp_pixel[m]; \
166 get_rightdimensions(input, \
177 while(in_x2 > in_x1) \
179 diameter = in_x2 - in_x1; \
180 for(int i = 0; i < diameter; i++) \
182 type temp_pixel[components]; \
183 for(int j = 0; j < components; j++) \
185 temp_pixel[j] = input_rows[in_y1 + i][in_x1 * components + j]; \
186 output_rows[in_y1 + i][in_x1 * components + j] = input_rows[in_y1][(in_x2 - i) * components + j]; \
187 output_rows[in_y1][(in_x2 - i) * components + j] = input_rows[in_y2 - i][in_x2 * components + j]; \
188 output_rows[in_y2 - i][in_x2 * components + j] = input_rows[in_y2][(in_x1 + i) * components + j]; \
189 output_rows[in_y2][(in_x1 + i) * components + j] = temp_pixel[j]; \
203 int RotateFrame::rotate_rightangle(VFrame *input,
209 int in_x2 = input->get_w();
210 int in_y2 = input->get_h();
211 int out_x1, out_y1, out_x2, out_y2;
214 output->clear_frame();
215 switch(output->get_color_model())
218 ROTATE_RIGHTANGLE(unsigned char, 3);
221 ROTATE_RIGHTANGLE(unsigned char, 4);
224 ROTATE_RIGHTANGLE(float, 3);
227 ROTATE_RIGHTANGLE(float, 4);
230 ROTATE_RIGHTANGLE(unsigned char, 3);
233 ROTATE_RIGHTANGLE(unsigned char, 4);
236 ROTATE_RIGHTANGLE(uint16_t, 3);
238 case BC_RGBA16161616:
239 ROTATE_RIGHTANGLE(uint16_t, 4);
242 ROTATE_RIGHTANGLE(uint16_t, 3);
244 case BC_YUVA16161616:
245 ROTATE_RIGHTANGLE(uint16_t, 4);
251 int RotateFrame::rotate_obliqueangle(VFrame *input,
257 int center_x, center_y;
260 center_x = input->get_w() / 2;
261 center_y = input->get_h() / 2;
263 if(last_angle != angle ||
264 (interpolate && !float_matrix) ||
265 (!interpolate && !int_matrix))
267 if(interpolate && !float_matrix)
269 float_matrix = new SourceCoord[input->get_w() * input->get_h()];
270 float_rows = new SourceCoord*[input->get_h()];
271 for(i = 0; i < input->get_h(); i++)
273 float_rows[i] = &float_matrix[i * input->get_w()];
277 if(!interpolate && !int_matrix)
279 int_matrix = new int[input->get_w() * input->get_h()];
280 int_rows = new int*[input->get_h()];
281 for(i = 0; i < input->get_h(); i++)
283 int_rows[i] = &int_matrix[i * input->get_w()];
290 if(last_angle != angle) need_matrix = 1;
291 if(last_interpolate != interpolate) need_matrix = 1;
295 // Last angle != angle implied by first buffer needing to be allocated
296 for(i = 0; i < cpus; i++)
298 engine[i]->generate_matrix(interpolate);
301 for(i = 0; i < cpus; i++)
303 engine[i]->wait_completion();
308 last_interpolate = interpolate;
310 // Perform the rotation
311 for(i = 0; i < cpus; i++)
313 engine[i]->perform_rotation(input, output, interpolate);
316 for(i = 0; i < cpus; i++)
318 engine[i]->wait_completion();
323 #define FILL_CENTER(type, components) \
325 type *out_pixel = ((type**)output->get_rows())[center_y] + center_x * components; \
326 type *in_pixel = ((type**)input->get_rows())[center_y] + center_x * components; \
328 out_pixel[0] = in_pixel[0]; \
329 out_pixel[1] = in_pixel[1]; \
330 out_pixel[2] = in_pixel[2]; \
331 if(components == 4) out_pixel[3] = in_pixel[3]; \
339 switch(input->get_color_model())
342 FILL_CENTER(float, 3)
345 FILL_CENTER(float, 4)
349 FILL_CENTER(unsigned char, 3)
353 FILL_CENTER(unsigned char, 4)
357 FILL_CENTER(uint16_t, 3)
359 case BC_RGBA16161616:
360 case BC_YUVA16161616:
361 FILL_CENTER(uint16_t, 4)
374 RotateEngine::RotateEngine(RotateFrame *plugin, int row1, int row2) : Thread()
376 this->plugin = plugin;
377 Thread::set_synchronous(1);
378 do_matrix = do_rotation = 0;
382 input_lock = new Condition(0, "RotateEngine::input_lock");
383 output_lock = new Condition(0, "RotateEngine::output_lock");
385 RotateEngine::~RotateEngine()
390 input_lock->unlock();
397 int RotateEngine::generate_matrix(int interpolate)
400 this->interpolate = interpolate;
401 input_lock->unlock();
405 int RotateEngine::perform_rotation(VFrame *input,
410 this->output = output;
411 this->do_rotation = 1;
412 this->interpolate = interpolate;
413 input_lock->unlock();
418 int RotateEngine::wait_completion()
420 output_lock->lock("RotateEngine::wait_completion");
424 int RotateEngine::coords_to_pixel(int &input_y, int &input_x)
426 if(input_y < 0) return -1;
428 if(input_y >= plugin->input->get_h()) return -1;
430 if(input_x < 0) return -1;
432 if(input_x >= plugin->input->get_w()) return -1;
434 return input_y * plugin->input->get_w() + input_x;
437 int RotateEngine::coords_to_pixel(SourceCoord &float_pixel, float &input_y, float &input_x)
439 if(input_y < 0) float_pixel.y = -1;
441 if(input_y >= plugin->input->get_h()) float_pixel.y = -1;
443 float_pixel.y = input_y;
445 if(input_x < 0) float_pixel.x = -1;
447 if(input_x >= plugin->input->get_w()) float_pixel.x = -1;
449 float_pixel.x = input_x;
453 int RotateEngine::create_matrix()
455 // Polar coords of pixel
456 register double k, l, magnitude, angle, offset_angle, offset_angle2;
457 register double x_offset, y_offset;
460 SourceCoord *float_row;
461 int input_x_i, input_y_i;
462 float input_x_f, input_y_f;
464 //printf("RotateEngine::create_matrix 1\n");
465 // The following is the result of pure trial and error.
467 // The source pixels are seen as if they were rotated counterclockwise so the sign is OK.
468 offset_angle = -(plugin->angle - 90) / 360 * 2 * M_PI;
469 offset_angle2 = -(plugin->angle - 270) / 360 * 2 * M_PI;
471 // Calculate an offset to add to all the pixels to compensate for the quadrant
472 y_offset = plugin->input->get_h() / 2;
473 x_offset = plugin->input->get_w() / 2;
475 for(i = row1, l = row1 - plugin->input->get_h() / 2; i < row2; i++, l++)
477 int l_suare = (int)(l * l);
479 int_row = plugin->int_rows[i];
481 float_row = plugin->float_rows[i];
483 //printf("RotateEngine::create_matrix 2 %d %f\n", i, l);
484 for(j = 0, k = -plugin->input->get_w() / 2;
485 j < plugin->input->get_w();
488 // Add offsets to input
489 // Convert to polar coords
490 magnitude = sqrt(SQR(k) + l_suare);
491 //printf("RotateEngine::create_matrix 3.2 %f %f\n", k, l);
493 angle = atan(-k / l);
499 //printf("RotateEngine::create_matrix 3.3\n");
501 angle += (l < 0) ? offset_angle2 : offset_angle;
503 // Convert back to cartesian coords
506 input_y_i = (int)(y_offset + magnitude * sin(angle));
507 input_x_i = (int)(x_offset + magnitude * cos(angle));
508 int_row[j] = coords_to_pixel(input_y_i, input_x_i);
512 input_y_f = y_offset + magnitude * sin(angle);
513 input_x_f = x_offset + magnitude * cos(angle);
514 coords_to_pixel(float_row[j], input_y_f, input_x_f);
517 //printf("RotateEngine::create_matrix 3\n");
519 //printf("RotateEngine::create_matrix 2\n");
523 #define ROTATE_NEAREST(type, components, black_chroma) \
525 type **input_rows = (type**)input->get_rows(); \
526 type **output_rows = (type**)output->get_rows(); \
528 for(int i = row1; i < row2; i++) \
530 int *int_row = plugin->int_rows[i]; \
531 for(int j = 0; j < width; j++) \
535 for(int k = 0; k < components; k++) \
536 output_rows[i][j * components + k] = 0; \
540 for(int k = 0; k < components; k++) \
541 output_rows[i][j * components + k] = *(input_rows[0] + int_row[j] * components + k); \
547 #define ROTATE_INTERPOLATE(type, components, black_chroma) \
549 type zero_pixel[] = { 0, black_chroma, black_chroma, 0 }; \
552 type **input_rows = (type**)input->get_rows(); \
553 type **output_rows = (type**)output->get_rows(); \
554 float x_fraction1, x_fraction2, y_fraction1, y_fraction2; \
555 float fraction1, fraction2, fraction3, fraction4; \
556 int x_pixel1, x_pixel2, y_pixel1, y_pixel2; \
557 type *pixel1, *pixel2, *pixel3, *pixel4; \
559 for(i = row1, k = row1; i < row2; i++, k++) \
561 SourceCoord *float_row = plugin->float_rows[i]; \
562 for(j = 0, l = 0; j < width; j++, l++) \
564 if(float_row[j].x < 0 || float_row[j].y < 0) \
566 output_rows[i][j * components + 0] = 0; \
567 output_rows[i][j * components + 1] = black_chroma; \
568 output_rows[i][j * components + 2] = black_chroma; \
569 if(components == 4) output_rows[i][j * components + 3] = 0; \
573 /* Interpolate input pixels */ \
574 x_pixel1 = (int)float_row[j].x; \
575 x_pixel2 = (int)(float_row[j].x + 1); \
576 y_pixel1 = (int)(float_row[j].y); \
577 y_pixel2 = (int)(float_row[j].y + 1); \
578 x_fraction1 = float_row[j].x - x_pixel1; \
579 x_fraction2 = (float)x_pixel2 - float_row[j].x; \
580 y_fraction1 = float_row[j].y - y_pixel1; \
581 y_fraction2 = (float)y_pixel2 - float_row[j].y; \
582 /* By trial and error this fraction order seems to work. */ \
583 fraction4 = x_fraction1 * y_fraction1; \
584 fraction3 = x_fraction2 * y_fraction1; \
585 fraction2 = x_fraction1 * y_fraction2; \
586 fraction1 = x_fraction2 * y_fraction2; \
587 pixel1 = &input_rows[y_pixel1][x_pixel1 * components]; \
588 pixel2 = (x_pixel2 >= width) ? zero_pixel : &input_rows[y_pixel1][x_pixel2 * components]; \
589 pixel3 = (y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel1 * components]; \
590 pixel4 = (x_pixel2 >= width || y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel2 * components]; \
592 for(int m = 0; m < components; m++) \
594 output_rows[i][j * components + m] = \
595 (type)((pixel1[m] * fraction1) + \
596 (pixel2[m] * fraction2) + \
597 (pixel3[m] * fraction3) + \
598 (pixel4[m] * fraction4)); \
605 int RotateEngine::perform_rotation()
607 int width = input->get_w();
608 int height = input->get_h();
612 switch(input->get_color_model())
615 ROTATE_NEAREST(unsigned char, 3, 0x0);
618 ROTATE_NEAREST(float, 3, 0x0);
621 ROTATE_NEAREST(unsigned char, 3, 0x80);
624 ROTATE_NEAREST(unsigned char, 4, 0x0);
627 ROTATE_NEAREST(float, 4, 0x0);
630 ROTATE_NEAREST(unsigned char, 4, 0x80);
634 ROTATE_NEAREST(uint16_t, 3, 0x0);
637 ROTATE_NEAREST(uint16_t, 3, 0x8000);
640 case BC_RGBA16161616:
641 ROTATE_NEAREST(uint16_t, 4, 0x0);
643 case BC_YUVA16161616:
644 ROTATE_NEAREST(uint16_t, 4, 0x8000);
650 switch(input->get_color_model())
653 ROTATE_INTERPOLATE(unsigned char, 3, 0x0);
656 ROTATE_INTERPOLATE(float, 3, 0x0);
659 ROTATE_INTERPOLATE(unsigned char, 3, 0x80);
662 ROTATE_INTERPOLATE(unsigned char, 4, 0x0);
665 ROTATE_INTERPOLATE(float, 4, 0x0);
668 ROTATE_INTERPOLATE(unsigned char, 4, 0x80);
672 ROTATE_INTERPOLATE(uint16_t, 3, 0x0);
675 ROTATE_INTERPOLATE(uint16_t, 3, 0x8000);
678 case BC_RGBA16161616:
679 ROTATE_INTERPOLATE(uint16_t, 4, 0x0);
681 case BC_YUVA16161616:
682 ROTATE_INTERPOLATE(uint16_t, 4, 0x8000);
689 void RotateEngine::run()
693 input_lock->lock("RotateEngine::run");
708 output_lock->unlock();