2 #include "rotateframe.h"
10 #define SQR(x) ((x) * (x))
12 RotateFrame::RotateFrame(int cpus, int width, int height)
14 int y1, y2, y_increment;
15 y_increment = height / cpus;
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);
37 RotateFrame::~RotateFrame()
39 for(int i = 0; i < cpus; i++)
44 if(float_matrix) delete [] float_matrix;
45 if(int_matrix) delete [] int_matrix;
46 if(float_rows) delete [] float_rows;
47 if(int_rows) delete [] int_rows;
51 void RotateFrame::rotate(VFrame *output,
57 this->output = output;
59 this->interpolate = interpolate;
63 if(angle == 90 || angle == 180 || angle == 270)
64 rotate_rightangle(input,
69 rotate_obliqueangle(input,
76 // Data never processed so copy if necessary
78 output->copy_from(input);
80 this->last_angle = angle;
83 int RotateFrame::get_rightdimensions(VFrame *frame,
94 diameter = frame->get_w() < frame->get_h() ? frame->get_w() : frame->get_h();
95 out_x1 = in_x1 = frame->get_w() / 2 - diameter / 2;
96 out_x2 = in_x2 = in_x1 + diameter - 1;
97 out_y1 = in_y1 = frame->get_h() / 2 - diameter / 2;
98 out_y2 = in_y2 = in_y1 + diameter - 1;
104 #define ROTATE_RIGHTANGLE(type, components) \
106 type **input_rows = (type**)input->get_rows(); \
107 type **output_rows = (type**)output->get_rows(); \
108 int height = output->get_h(); \
109 int width = output->get_w(); \
114 get_rightdimensions(input, \
124 while(in_x2 > in_x1) \
126 diameter = in_x2 - in_x1; \
127 for(int i = 0; i < diameter; i++) \
129 type temp_pixel[components]; \
130 for(int j = 0; j < components; j++) \
132 temp_pixel[j] = input_rows[in_y1 + i][in_x2 * components + j]; \
134 output_rows[in_y1 + i][in_x2 * components + j] = input_rows[in_y1][(in_x1 + i) * components + j]; \
135 output_rows[in_y1][(in_x1 + i) * components + j] = input_rows[in_y2 - i][in_x1 * components + j]; \
136 output_rows[in_y2 - i][in_x1 * components + j] = input_rows[in_y2][(in_x2 - i) * components + j]; \
137 output_rows[in_y2][(in_x2 - i) * components + j] = temp_pixel[j]; \
149 for(int i = 0, j = height - 1; i < j; i++, j--) \
151 for(int k = 0, l = width - 1; k < width; k++, l--) \
153 type temp_pixel[components]; \
154 for(int m = 0; m < components; m++) \
156 temp_pixel[m] = input_rows[j][k * components + m]; \
157 output_rows[j][k * components + m] = input_rows[i][l * components + m]; \
158 output_rows[i][l * components + m] = temp_pixel[m]; \
165 get_rightdimensions(input, \
176 while(in_x2 > in_x1) \
178 diameter = in_x2 - in_x1; \
179 for(int i = 0; i < diameter; i++) \
181 type temp_pixel[components]; \
182 for(int j = 0; j < components; j++) \
184 temp_pixel[j] = input_rows[in_y1 + i][in_x1 * components + j]; \
185 output_rows[in_y1 + i][in_x1 * components + j] = input_rows[in_y1][(in_x2 - i) * components + j]; \
186 output_rows[in_y1][(in_x2 - i) * components + j] = input_rows[in_y2 - i][in_x2 * components + j]; \
187 output_rows[in_y2 - i][in_x2 * components + j] = input_rows[in_y2][(in_x1 + i) * components + j]; \
188 output_rows[in_y2][(in_x1 + i) * components + j] = temp_pixel[j]; \
202 int RotateFrame::rotate_rightangle(VFrame *input,
208 int in_x2 = input->get_w();
209 int in_y2 = input->get_h();
210 int out_x1, out_y1, out_x2, out_y2;
213 output->clear_frame();
214 switch(output->get_color_model())
217 ROTATE_RIGHTANGLE(unsigned char, 3);
220 ROTATE_RIGHTANGLE(unsigned char, 4);
223 ROTATE_RIGHTANGLE(float, 3);
226 ROTATE_RIGHTANGLE(float, 4);
229 ROTATE_RIGHTANGLE(unsigned char, 3);
232 ROTATE_RIGHTANGLE(unsigned char, 4);
235 ROTATE_RIGHTANGLE(uint16_t, 3);
237 case BC_RGBA16161616:
238 ROTATE_RIGHTANGLE(uint16_t, 4);
241 ROTATE_RIGHTANGLE(uint16_t, 3);
243 case BC_YUVA16161616:
244 ROTATE_RIGHTANGLE(uint16_t, 4);
250 int RotateFrame::rotate_obliqueangle(VFrame *input,
256 int center_x, center_y;
259 center_x = input->get_w() / 2;
260 center_y = input->get_h() / 2;
262 if(last_angle != angle ||
263 (interpolate && !float_matrix) ||
264 (!interpolate && !int_matrix))
266 if(interpolate && !float_matrix)
268 float_matrix = new SourceCoord[input->get_w() * input->get_h()];
269 float_rows = new SourceCoord*[input->get_h()];
270 for(i = 0; i < input->get_h(); i++)
272 float_rows[i] = &float_matrix[i * input->get_w()];
276 if(!interpolate && !int_matrix)
278 int_matrix = new int[input->get_w() * input->get_h()];
279 int_rows = new int*[input->get_h()];
280 for(i = 0; i < input->get_h(); i++)
282 int_rows[i] = &int_matrix[i * input->get_w()];
289 if(last_angle != angle) need_matrix = 1;
290 if(last_interpolate != interpolate) need_matrix = 1;
294 // Last angle != angle implied by first buffer needing to be allocated
295 for(i = 0; i < cpus; i++)
297 engine[i]->generate_matrix(interpolate);
300 for(i = 0; i < cpus; i++)
302 engine[i]->wait_completion();
307 last_interpolate = interpolate;
309 // Perform the rotation
310 for(i = 0; i < cpus; i++)
312 engine[i]->perform_rotation(input, output, interpolate);
315 for(i = 0; i < cpus; i++)
317 engine[i]->wait_completion();
322 #define FILL_CENTER(type, components) \
324 type *out_pixel = ((type**)output->get_rows())[center_y] + center_x * components; \
325 type *in_pixel = ((type**)input->get_rows())[center_y] + center_x * components; \
327 out_pixel[0] = in_pixel[0]; \
328 out_pixel[1] = in_pixel[1]; \
329 out_pixel[2] = in_pixel[2]; \
330 if(components == 4) out_pixel[3] = in_pixel[3]; \
338 switch(input->get_color_model())
341 FILL_CENTER(float, 3)
344 FILL_CENTER(float, 4)
348 FILL_CENTER(unsigned char, 3)
352 FILL_CENTER(unsigned char, 4)
356 FILL_CENTER(uint16_t, 3)
358 case BC_RGBA16161616:
359 case BC_YUVA16161616:
360 FILL_CENTER(uint16_t, 4)
373 RotateEngine::RotateEngine(RotateFrame *plugin, int row1, int row2) : Thread()
375 this->plugin = plugin;
376 Thread::set_synchronous(1);
377 do_matrix = do_rotation = 0;
381 input_lock = new Condition(0, "RotateEngine::input_lock");
382 output_lock = new Condition(0, "RotateEngine::output_lock");
384 RotateEngine::~RotateEngine()
389 input_lock->unlock();
396 int RotateEngine::generate_matrix(int interpolate)
399 this->interpolate = interpolate;
400 input_lock->unlock();
404 int RotateEngine::perform_rotation(VFrame *input,
409 this->output = output;
410 this->do_rotation = 1;
411 this->interpolate = interpolate;
412 input_lock->unlock();
417 int RotateEngine::wait_completion()
419 output_lock->lock("RotateEngine::wait_completion");
423 int RotateEngine::coords_to_pixel(int &input_y, int &input_x)
425 if(input_y < 0) return -1;
427 if(input_y >= plugin->input->get_h()) return -1;
429 if(input_x < 0) return -1;
431 if(input_x >= plugin->input->get_w()) return -1;
433 return input_y * plugin->input->get_w() + input_x;
436 int RotateEngine::coords_to_pixel(SourceCoord &float_pixel, float &input_y, float &input_x)
438 if(input_y < 0) float_pixel.y = -1;
440 if(input_y >= plugin->input->get_h()) float_pixel.y = -1;
442 float_pixel.y = input_y;
444 if(input_x < 0) float_pixel.x = -1;
446 if(input_x >= plugin->input->get_w()) float_pixel.x = -1;
448 float_pixel.x = input_x;
452 int RotateEngine::create_matrix()
454 // Polar coords of pixel
455 register double k, l, magnitude, angle, offset_angle, offset_angle2;
456 register double x_offset, y_offset;
459 SourceCoord *float_row;
460 int input_x_i, input_y_i;
461 float input_x_f, input_y_f;
463 //printf("RotateEngine::create_matrix 1\n");
464 // The following is the result of pure trial and error.
466 // The source pixels are seen as if they were rotated counterclockwise so the sign is OK.
467 offset_angle = -(plugin->angle - 90) / 360 * 2 * M_PI;
468 offset_angle2 = -(plugin->angle - 270) / 360 * 2 * M_PI;
470 // Calculate an offset to add to all the pixels to compensate for the quadrant
471 y_offset = plugin->input->get_h() / 2;
472 x_offset = plugin->input->get_w() / 2;
474 for(i = row1, l = row1 - plugin->input->get_h() / 2; i < row2; i++, l++)
476 int l_suare = (int)(l * l);
478 int_row = plugin->int_rows[i];
480 float_row = plugin->float_rows[i];
482 //printf("RotateEngine::create_matrix 2 %d %f\n", i, l);
483 for(j = 0, k = -plugin->input->get_w() / 2;
484 j < plugin->input->get_w();
487 // Add offsets to input
488 // Convert to polar coords
489 magnitude = sqrt(SQR(k) + l_suare);
490 //printf("RotateEngine::create_matrix 3.2 %f %f\n", k, l);
492 angle = atan(-k / l);
498 //printf("RotateEngine::create_matrix 3.3\n");
500 angle += (l < 0) ? offset_angle2 : offset_angle;
502 // Convert back to cartesian coords
505 input_y_i = (int)(y_offset + magnitude * sin(angle));
506 input_x_i = (int)(x_offset + magnitude * cos(angle));
507 int_row[j] = coords_to_pixel(input_y_i, input_x_i);
511 input_y_f = y_offset + magnitude * sin(angle);
512 input_x_f = x_offset + magnitude * cos(angle);
513 coords_to_pixel(float_row[j], input_y_f, input_x_f);
516 //printf("RotateEngine::create_matrix 3\n");
518 //printf("RotateEngine::create_matrix 2\n");
522 #define ROTATE_NEAREST(type, components, black_chroma) \
524 type **input_rows = (type**)input->get_rows(); \
525 type **output_rows = (type**)output->get_rows(); \
527 for(int i = row1; i < row2; i++) \
529 int *int_row = plugin->int_rows[i]; \
530 for(int j = 0; j < width; j++) \
534 for(int k = 0; k < components; k++) \
535 output_rows[i][j * components + k] = 0; \
539 for(int k = 0; k < components; k++) \
540 output_rows[i][j * components + k] = *(input_rows[0] + int_row[j] * components + k); \
546 #define ROTATE_INTERPOLATE(type, components, black_chroma) \
548 type zero_pixel[] = { 0, black_chroma, black_chroma, 0 }; \
551 type **input_rows = (type**)input->get_rows(); \
552 type **output_rows = (type**)output->get_rows(); \
553 float x_fraction1, x_fraction2, y_fraction1, y_fraction2; \
554 float fraction1, fraction2, fraction3, fraction4; \
555 int x_pixel1, x_pixel2, y_pixel1, y_pixel2; \
556 type *pixel1, *pixel2, *pixel3, *pixel4; \
558 for(i = row1, k = row1; i < row2; i++, k++) \
560 SourceCoord *float_row = plugin->float_rows[i]; \
561 for(j = 0, l = 0; j < width; j++, l++) \
563 if(float_row[j].x < 0 || float_row[j].y < 0) \
565 output_rows[i][j * components + 0] = 0; \
566 output_rows[i][j * components + 1] = black_chroma; \
567 output_rows[i][j * components + 2] = black_chroma; \
568 if(components == 4) output_rows[i][j * components + 3] = 0; \
572 /* Interpolate input pixels */ \
573 x_pixel1 = (int)float_row[j].x; \
574 x_pixel2 = (int)(float_row[j].x + 1); \
575 y_pixel1 = (int)(float_row[j].y); \
576 y_pixel2 = (int)(float_row[j].y + 1); \
577 x_fraction1 = float_row[j].x - x_pixel1; \
578 x_fraction2 = (float)x_pixel2 - float_row[j].x; \
579 y_fraction1 = float_row[j].y - y_pixel1; \
580 y_fraction2 = (float)y_pixel2 - float_row[j].y; \
581 /* By trial and error this fraction order seems to work. */ \
582 fraction4 = x_fraction1 * y_fraction1; \
583 fraction3 = x_fraction2 * y_fraction1; \
584 fraction2 = x_fraction1 * y_fraction2; \
585 fraction1 = x_fraction2 * y_fraction2; \
586 pixel1 = &input_rows[y_pixel1][x_pixel1 * components]; \
587 pixel2 = (x_pixel2 >= width) ? zero_pixel : &input_rows[y_pixel1][x_pixel2 * components]; \
588 pixel3 = (y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel1 * components]; \
589 pixel4 = (x_pixel2 >= width || y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel2 * components]; \
591 for(int m = 0; m < components; m++) \
593 output_rows[i][j * components + m] = \
594 (type)((pixel1[m] * fraction1) + \
595 (pixel2[m] * fraction2) + \
596 (pixel3[m] * fraction3) + \
597 (pixel4[m] * fraction4)); \
604 int RotateEngine::perform_rotation()
606 int width = input->get_w();
607 int height = input->get_h();
611 switch(input->get_color_model())
614 ROTATE_NEAREST(unsigned char, 3, 0x0);
617 ROTATE_NEAREST(float, 3, 0x0);
620 ROTATE_NEAREST(unsigned char, 3, 0x80);
623 ROTATE_NEAREST(unsigned char, 4, 0x0);
626 ROTATE_NEAREST(float, 4, 0x0);
629 ROTATE_NEAREST(unsigned char, 4, 0x80);
633 ROTATE_NEAREST(uint16_t, 3, 0x0);
636 ROTATE_NEAREST(uint16_t, 3, 0x8000);
639 case BC_RGBA16161616:
640 ROTATE_NEAREST(uint16_t, 4, 0x0);
642 case BC_YUVA16161616:
643 ROTATE_NEAREST(uint16_t, 4, 0x8000);
649 switch(input->get_color_model())
652 ROTATE_INTERPOLATE(unsigned char, 3, 0x0);
655 ROTATE_INTERPOLATE(float, 3, 0x0);
658 ROTATE_INTERPOLATE(unsigned char, 3, 0x80);
661 ROTATE_INTERPOLATE(unsigned char, 4, 0x0);
664 ROTATE_INTERPOLATE(float, 4, 0x0);
667 ROTATE_INTERPOLATE(unsigned char, 4, 0x80);
671 ROTATE_INTERPOLATE(uint16_t, 3, 0x0);
674 ROTATE_INTERPOLATE(uint16_t, 3, 0x8000);
677 case BC_RGBA16161616:
678 ROTATE_INTERPOLATE(uint16_t, 4, 0x0);
680 case BC_YUVA16161616:
681 ROTATE_INTERPOLATE(uint16_t, 4, 0x8000);
688 void RotateEngine::run()
692 input_lock->lock("RotateEngine::run");
707 output_lock->unlock();