00001 #include "condition.h"
00002 #include "rotateframe.h"
00003 #include "vframe.h"
00004
00005 #include <math.h>
00006 #include <stdint.h>
00007 #include <stdio.h>
00008 #include <unistd.h>
00009
00010 #define SQR(x) ((x) * (x))
00011
00012 RotateFrame::RotateFrame(int cpus, int width, int height)
00013 {
00014 int y1, y2, y_increment;
00015 y_increment = height / cpus;
00016 y1 = 0;
00017 this->cpus = cpus;
00018
00019 engine = new RotateEngine*[cpus];
00020 for(int i = 0; i < cpus; i++)
00021 {
00022 y2 = y1 + y_increment;
00023 if(i == cpus - 1 && y2 < height - 1) y2 = height - 1;
00024 engine[i] = new RotateEngine(this, y1, y2);
00025 engine[i]->start();
00026 y1 += y_increment;
00027 }
00028
00029 float_matrix = 0;
00030 int_matrix = 0;
00031 int_rows = 0;
00032 float_rows = 0;
00033 last_angle = 0;
00034 last_interpolate = 0;
00035 }
00036
00037 RotateFrame::~RotateFrame()
00038 {
00039 for(int i = 0; i < cpus; i++)
00040 {
00041 delete engine[i];
00042 }
00043 delete [] engine;
00044 if(float_matrix) delete [] float_matrix;
00045 if(int_matrix) delete [] int_matrix;
00046 if(float_rows) delete [] float_rows;
00047 if(int_rows) delete [] int_rows;
00048 }
00049
00050
00051 void RotateFrame::rotate(VFrame *output,
00052 VFrame *input,
00053 double angle,
00054 int interpolate)
00055 {
00056 this->angle = angle;
00057 this->output = output;
00058 this->input = input;
00059 this->interpolate = interpolate;
00060
00061 if(angle != 0)
00062 {
00063 if(angle == 90 || angle == 180 || angle == 270)
00064 rotate_rightangle(input,
00065 output,
00066 (int)angle);
00067 else
00068 {
00069 rotate_obliqueangle(input,
00070 output,
00071 angle,
00072 interpolate);
00073 }
00074 }
00075 else
00076
00077 {
00078 output->copy_from(input);
00079 }
00080 this->last_angle = angle;
00081 }
00082
00083 int RotateFrame::get_rightdimensions(VFrame *frame,
00084 int &diameter,
00085 int &in_x1,
00086 int &in_y1,
00087 int &in_x2,
00088 int &in_y2,
00089 int &out_x1,
00090 int &out_y1,
00091 int &out_x2,
00092 int &out_y2)
00093 {
00094 diameter = frame->get_w() < frame->get_h() ? frame->get_w() : frame->get_h();
00095 out_x1 = in_x1 = frame->get_w() / 2 - diameter / 2;
00096 out_x2 = in_x2 = in_x1 + diameter - 1;
00097 out_y1 = in_y1 = frame->get_h() / 2 - diameter / 2;
00098 out_y2 = in_y2 = in_y1 + diameter - 1;
00099 return 0;
00100 }
00101
00102
00103
00104 #define ROTATE_RIGHTANGLE(type, components) \
00105 { \
00106 type **input_rows = (type**)input->get_rows(); \
00107 type **output_rows = (type**)output->get_rows(); \
00108 int height = output->get_h(); \
00109 int width = output->get_w(); \
00110 \
00111 switch(angle) \
00112 { \
00113 case 90: \
00114 get_rightdimensions(input, \
00115 diameter, \
00116 in_x1, \
00117 in_y1, \
00118 in_x2, \
00119 in_y2, \
00120 out_x1, \
00121 out_y1, \
00122 out_x2, \
00123 out_y2); \
00124 while(in_x2 > in_x1) \
00125 { \
00126 diameter = in_x2 - in_x1; \
00127 for(int i = 0; i < diameter; i++) \
00128 { \
00129 type temp_pixel[components]; \
00130 for(int j = 0; j < components; j++) \
00131 { \
00132 temp_pixel[j] = input_rows[in_y1 + i][in_x2 * components + j]; \
00133 \
00134 output_rows[in_y1 + i][in_x2 * components + j] = input_rows[in_y1][(in_x1 + i) * components + j]; \
00135 output_rows[in_y1][(in_x1 + i) * components + j] = input_rows[in_y2 - i][in_x1 * components + j]; \
00136 output_rows[in_y2 - i][in_x1 * components + j] = input_rows[in_y2][(in_x2 - i) * components + j]; \
00137 output_rows[in_y2][(in_x2 - i) * components + j] = temp_pixel[j]; \
00138 } \
00139 } \
00140 \
00141 in_x2--; \
00142 in_x1++; \
00143 in_y2--; \
00144 in_y1++; \
00145 } \
00146 break; \
00147 \
00148 case 180: \
00149 for(int i = 0, j = height - 1; i < j; i++, j--) \
00150 { \
00151 for(int k = 0, l = width - 1; k < width; k++, l--) \
00152 { \
00153 type temp_pixel[components]; \
00154 for(int m = 0; m < components; m++) \
00155 { \
00156 temp_pixel[m] = input_rows[j][k * components + m]; \
00157 output_rows[j][k * components + m] = input_rows[i][l * components + m]; \
00158 output_rows[i][l * components + m] = temp_pixel[m]; \
00159 } \
00160 } \
00161 } \
00162 break; \
00163 \
00164 case 270: \
00165 get_rightdimensions(input, \
00166 diameter, \
00167 in_x1, \
00168 in_y1, \
00169 in_x2, \
00170 in_y2, \
00171 out_x1, \
00172 out_y1, \
00173 out_x2, \
00174 out_y2); \
00175 \
00176 while(in_x2 > in_x1) \
00177 { \
00178 diameter = in_x2 - in_x1; \
00179 for(int i = 0; i < diameter; i++) \
00180 { \
00181 type temp_pixel[components]; \
00182 for(int j = 0; j < components; j++) \
00183 { \
00184 temp_pixel[j] = input_rows[in_y1 + i][in_x1 * components + j]; \
00185 output_rows[in_y1 + i][in_x1 * components + j] = input_rows[in_y1][(in_x2 - i) * components + j]; \
00186 output_rows[in_y1][(in_x2 - i) * components + j] = input_rows[in_y2 - i][in_x2 * components + j]; \
00187 output_rows[in_y2 - i][in_x2 * components + j] = input_rows[in_y2][(in_x1 + i) * components + j]; \
00188 output_rows[in_y2][(in_x1 + i) * components + j] = temp_pixel[j]; \
00189 } \
00190 } \
00191 \
00192 in_x2--; \
00193 in_x1++; \
00194 in_y2--; \
00195 in_y1++; \
00196 } \
00197 break; \
00198 } \
00199 }
00200
00201
00202 int RotateFrame::rotate_rightangle(VFrame *input,
00203 VFrame *output,
00204 int angle)
00205 {
00206 int in_x1 = 0;
00207 int in_y1 = 0;
00208 int in_x2 = input->get_w();
00209 int in_y2 = input->get_h();
00210 int out_x1, out_y1, out_x2, out_y2;
00211 int diameter;
00212
00213 output->clear_frame();
00214 switch(output->get_color_model())
00215 {
00216 case BC_RGB888:
00217 ROTATE_RIGHTANGLE(unsigned char, 3);
00218 break;
00219 case BC_RGBA8888:
00220 ROTATE_RIGHTANGLE(unsigned char, 4);
00221 break;
00222 case BC_RGB_FLOAT:
00223 ROTATE_RIGHTANGLE(float, 3);
00224 break;
00225 case BC_RGBA_FLOAT:
00226 ROTATE_RIGHTANGLE(float, 4);
00227 break;
00228 case BC_YUV888:
00229 ROTATE_RIGHTANGLE(unsigned char, 3);
00230 break;
00231 case BC_YUVA8888:
00232 ROTATE_RIGHTANGLE(unsigned char, 4);
00233 break;
00234 case BC_RGB161616:
00235 ROTATE_RIGHTANGLE(uint16_t, 3);
00236 break;
00237 case BC_RGBA16161616:
00238 ROTATE_RIGHTANGLE(uint16_t, 4);
00239 break;
00240 case BC_YUV161616:
00241 ROTATE_RIGHTANGLE(uint16_t, 3);
00242 break;
00243 case BC_YUVA16161616:
00244 ROTATE_RIGHTANGLE(uint16_t, 4);
00245 break;
00246 }
00247 return 0;
00248 }
00249
00250 int RotateFrame::rotate_obliqueangle(VFrame *input,
00251 VFrame *output,
00252 double angle,
00253 int interpolate)
00254 {
00255 int i;
00256 int center_x, center_y;
00257 int need_matrix = 0;
00258
00259 center_x = input->get_w() / 2;
00260 center_y = input->get_h() / 2;
00261
00262 if(last_angle != angle ||
00263 (interpolate && !float_matrix) ||
00264 (!interpolate && !int_matrix))
00265 {
00266 if(interpolate && !float_matrix)
00267 {
00268 float_matrix = new SourceCoord[input->get_w() * input->get_h()];
00269 float_rows = new SourceCoord*[input->get_h()];
00270 for(i = 0; i < input->get_h(); i++)
00271 {
00272 float_rows[i] = &float_matrix[i * input->get_w()];
00273 }
00274 }
00275 else
00276 if(!interpolate && !int_matrix)
00277 {
00278 int_matrix = new int[input->get_w() * input->get_h()];
00279 int_rows = new int*[input->get_h()];
00280 for(i = 0; i < input->get_h(); i++)
00281 {
00282 int_rows[i] = &int_matrix[i * input->get_w()];
00283 }
00284 }
00285
00286 need_matrix = 1;
00287 }
00288
00289 if(last_angle != angle) need_matrix = 1;
00290 if(last_interpolate != interpolate) need_matrix = 1;
00291
00292 if(need_matrix)
00293 {
00294
00295 for(i = 0; i < cpus; i++)
00296 {
00297 engine[i]->generate_matrix(interpolate);
00298 }
00299
00300 for(i = 0; i < cpus; i++)
00301 {
00302 engine[i]->wait_completion();
00303 }
00304 }
00305
00306 last_angle = angle;
00307 last_interpolate = interpolate;
00308
00309
00310 for(i = 0; i < cpus; i++)
00311 {
00312 engine[i]->perform_rotation(input, output, interpolate);
00313 }
00314
00315 for(i = 0; i < cpus; i++)
00316 {
00317 engine[i]->wait_completion();
00318 }
00319
00320
00321
00322 #define FILL_CENTER(type, components) \
00323 { \
00324 type *out_pixel = ((type**)output->get_rows())[center_y] + center_x * components; \
00325 type *in_pixel = ((type**)input->get_rows())[center_y] + center_x * components; \
00326 \
00327 out_pixel[0] = in_pixel[0]; \
00328 out_pixel[1] = in_pixel[1]; \
00329 out_pixel[2] = in_pixel[2]; \
00330 if(components == 4) out_pixel[3] = in_pixel[3]; \
00331 }
00332
00333
00334
00335
00336
00337
00338 switch(input->get_color_model())
00339 {
00340 case BC_RGB_FLOAT:
00341 FILL_CENTER(float, 3)
00342 break;
00343 case BC_RGBA_FLOAT:
00344 FILL_CENTER(float, 4)
00345 break;
00346 case BC_RGB888:
00347 case BC_YUV888:
00348 FILL_CENTER(unsigned char, 3)
00349 break;
00350 case BC_RGBA8888:
00351 case BC_YUVA8888:
00352 FILL_CENTER(unsigned char, 4)
00353 break;
00354 case BC_RGB161616:
00355 case BC_YUV161616:
00356 FILL_CENTER(uint16_t, 3)
00357 break;
00358 case BC_RGBA16161616:
00359 case BC_YUVA16161616:
00360 FILL_CENTER(uint16_t, 4)
00361 break;
00362 }
00363 return 0;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373 RotateEngine::RotateEngine(RotateFrame *plugin, int row1, int row2) : Thread()
00374 {
00375 this->plugin = plugin;
00376 Thread::set_synchronous(1);
00377 do_matrix = do_rotation = 0;
00378 done = 0;
00379 this->row1 = row1;
00380 this->row2 = row2;
00381 input_lock = new Condition(0, "RotateEngine::input_lock");
00382 output_lock = new Condition(0, "RotateEngine::output_lock");
00383 }
00384 RotateEngine::~RotateEngine()
00385 {
00386 if(!done)
00387 {
00388 done = 1;
00389 input_lock->unlock();
00390 join();
00391 }
00392 delete input_lock;
00393 delete output_lock;
00394 }
00395
00396 int RotateEngine::generate_matrix(int interpolate)
00397 {
00398 this->do_matrix = 1;
00399 this->interpolate = interpolate;
00400 input_lock->unlock();
00401 return 0;
00402 }
00403
00404 int RotateEngine::perform_rotation(VFrame *input,
00405 VFrame *output,
00406 int interpolate)
00407 {
00408 this->input = input;
00409 this->output = output;
00410 this->do_rotation = 1;
00411 this->interpolate = interpolate;
00412 input_lock->unlock();
00413 return 0;
00414 }
00415
00416
00417 int RotateEngine::wait_completion()
00418 {
00419 output_lock->lock("RotateEngine::wait_completion");
00420 return 0;
00421 }
00422
00423 int RotateEngine::coords_to_pixel(int &input_y, int &input_x)
00424 {
00425 if(input_y < 0) return -1;
00426 else
00427 if(input_y >= plugin->input->get_h()) return -1;
00428 else
00429 if(input_x < 0) return -1;
00430 else
00431 if(input_x >= plugin->input->get_w()) return -1;
00432 else
00433 return input_y * plugin->input->get_w() + input_x;
00434 }
00435
00436 int RotateEngine::coords_to_pixel(SourceCoord &float_pixel, float &input_y, float &input_x)
00437 {
00438 if(input_y < 0) float_pixel.y = -1;
00439 else
00440 if(input_y >= plugin->input->get_h()) float_pixel.y = -1;
00441 else
00442 float_pixel.y = input_y;
00443
00444 if(input_x < 0) float_pixel.x = -1;
00445 else
00446 if(input_x >= plugin->input->get_w()) float_pixel.x = -1;
00447 else
00448 float_pixel.x = input_x;
00449 }
00450
00451
00452 int RotateEngine::create_matrix()
00453 {
00454
00455 register double k, l, magnitude, angle, offset_angle, offset_angle2;
00456 register double x_offset, y_offset;
00457 register int i, j;
00458 int *int_row;
00459 SourceCoord *float_row;
00460 int input_x_i, input_y_i;
00461 float input_x_f, input_y_f;
00462
00463
00464
00465
00466
00467 offset_angle = -(plugin->angle - 90) / 360 * 2 * M_PI;
00468 offset_angle2 = -(plugin->angle - 270) / 360 * 2 * M_PI;
00469
00470
00471 y_offset = plugin->input->get_h() / 2;
00472 x_offset = plugin->input->get_w() / 2;
00473
00474 for(i = row1, l = row1 - plugin->input->get_h() / 2; i < row2; i++, l++)
00475 {
00476 int l_suare = (int)(l * l);
00477 if(!interpolate)
00478 int_row = plugin->int_rows[i];
00479 else
00480 float_row = plugin->float_rows[i];
00481
00482
00483 for(j = 0, k = -plugin->input->get_w() / 2;
00484 j < plugin->input->get_w();
00485 j++, k++)
00486 {
00487
00488
00489 magnitude = sqrt(SQR(k) + l_suare);
00490
00491 if(l != 0)
00492 angle = atan(-k / l);
00493 else
00494 if(k < 0)
00495 angle = M_PI / 2;
00496 else
00497 angle = M_PI * 1.5;
00498
00499
00500 angle += (l < 0) ? offset_angle2 : offset_angle;
00501
00502
00503 if(!interpolate)
00504 {
00505 input_y_i = (int)(y_offset + magnitude * sin(angle));
00506 input_x_i = (int)(x_offset + magnitude * cos(angle));
00507 int_row[j] = coords_to_pixel(input_y_i, input_x_i);
00508 }
00509 else
00510 {
00511 input_y_f = y_offset + magnitude * sin(angle);
00512 input_x_f = x_offset + magnitude * cos(angle);
00513 coords_to_pixel(float_row[j], input_y_f, input_x_f);
00514 }
00515 }
00516
00517 }
00518
00519 return 0;
00520 }
00521
00522 #define ROTATE_NEAREST(type, components, black_chroma) \
00523 { \
00524 type **input_rows = (type**)input->get_rows(); \
00525 type **output_rows = (type**)output->get_rows(); \
00526 \
00527 for(int i = row1; i < row2; i++) \
00528 { \
00529 int *int_row = plugin->int_rows[i]; \
00530 for(int j = 0; j < width; j++) \
00531 { \
00532 if(int_row[j] < 0) \
00533 { \
00534 for(int k = 0; k < components; k++) \
00535 output_rows[i][j * components + k] = 0; \
00536 } \
00537 else \
00538 { \
00539 for(int k = 0; k < components; k++) \
00540 output_rows[i][j * components + k] = *(input_rows[0] + int_row[j] * components + k); \
00541 } \
00542 } \
00543 } \
00544 }
00545
00546 #define ROTATE_INTERPOLATE(type, components, black_chroma) \
00547 { \
00548 type zero_pixel[] = { 0, black_chroma, black_chroma, 0 }; \
00549 int i, j; \
00550 float k, l; \
00551 type **input_rows = (type**)input->get_rows(); \
00552 type **output_rows = (type**)output->get_rows(); \
00553 float x_fraction1, x_fraction2, y_fraction1, y_fraction2; \
00554 float fraction1, fraction2, fraction3, fraction4; \
00555 int x_pixel1, x_pixel2, y_pixel1, y_pixel2; \
00556 type *pixel1, *pixel2, *pixel3, *pixel4; \
00557 \
00558 for(i = row1, k = row1; i < row2; i++, k++) \
00559 { \
00560 SourceCoord *float_row = plugin->float_rows[i]; \
00561 for(j = 0, l = 0; j < width; j++, l++) \
00562 { \
00563 if(float_row[j].x < 0 || float_row[j].y < 0) \
00564 { \
00565 output_rows[i][j * components + 0] = 0; \
00566 output_rows[i][j * components + 1] = black_chroma; \
00567 output_rows[i][j * components + 2] = black_chroma; \
00568 if(components == 4) output_rows[i][j * components + 3] = 0; \
00569 } \
00570 else \
00571 { \
00572 \
00573 x_pixel1 = (int)float_row[j].x; \
00574 x_pixel2 = (int)(float_row[j].x + 1); \
00575 y_pixel1 = (int)(float_row[j].y); \
00576 y_pixel2 = (int)(float_row[j].y + 1); \
00577 x_fraction1 = float_row[j].x - x_pixel1; \
00578 x_fraction2 = (float)x_pixel2 - float_row[j].x; \
00579 y_fraction1 = float_row[j].y - y_pixel1; \
00580 y_fraction2 = (float)y_pixel2 - float_row[j].y; \
00581 \
00582 fraction4 = x_fraction1 * y_fraction1; \
00583 fraction3 = x_fraction2 * y_fraction1; \
00584 fraction2 = x_fraction1 * y_fraction2; \
00585 fraction1 = x_fraction2 * y_fraction2; \
00586 pixel1 = &input_rows[y_pixel1][x_pixel1 * components]; \
00587 pixel2 = (x_pixel2 >= width) ? zero_pixel : &input_rows[y_pixel1][x_pixel2 * components]; \
00588 pixel3 = (y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel1 * components]; \
00589 pixel4 = (x_pixel2 >= width || y_pixel2 >= height) ? zero_pixel : &input_rows[y_pixel2][x_pixel2 * components]; \
00590 \
00591 for(int m = 0; m < components; m++) \
00592 { \
00593 output_rows[i][j * components + m] = \
00594 (type)((pixel1[m] * fraction1) + \
00595 (pixel2[m] * fraction2) + \
00596 (pixel3[m] * fraction3) + \
00597 (pixel4[m] * fraction4)); \
00598 } \
00599 } \
00600 } \
00601 } \
00602 }
00603
00604 int RotateEngine::perform_rotation()
00605 {
00606 int width = input->get_w();
00607 int height = input->get_h();
00608
00609 if(!interpolate)
00610 {
00611 switch(input->get_color_model())
00612 {
00613 case BC_RGB888:
00614 ROTATE_NEAREST(unsigned char, 3, 0x0);
00615 break;
00616 case BC_RGB_FLOAT:
00617 ROTATE_NEAREST(float, 3, 0x0);
00618 break;
00619 case BC_YUV888:
00620 ROTATE_NEAREST(unsigned char, 3, 0x80);
00621 break;
00622 case BC_RGBA8888:
00623 ROTATE_NEAREST(unsigned char, 4, 0x0);
00624 break;
00625 case BC_RGBA_FLOAT:
00626 ROTATE_NEAREST(float, 4, 0x0);
00627 break;
00628 case BC_YUVA8888:
00629 ROTATE_NEAREST(unsigned char, 4, 0x80);
00630 break;
00631
00632 case BC_RGB161616:
00633 ROTATE_NEAREST(uint16_t, 3, 0x0);
00634 break;
00635 case BC_YUV161616:
00636 ROTATE_NEAREST(uint16_t, 3, 0x8000);
00637 break;
00638
00639 case BC_RGBA16161616:
00640 ROTATE_NEAREST(uint16_t, 4, 0x0);
00641 break;
00642 case BC_YUVA16161616:
00643 ROTATE_NEAREST(uint16_t, 4, 0x8000);
00644 break;
00645 }
00646 }
00647 else
00648 {
00649 switch(input->get_color_model())
00650 {
00651 case BC_RGB888:
00652 ROTATE_INTERPOLATE(unsigned char, 3, 0x0);
00653 break;
00654 case BC_RGB_FLOAT:
00655 ROTATE_INTERPOLATE(float, 3, 0x0);
00656 break;
00657 case BC_YUV888:
00658 ROTATE_INTERPOLATE(unsigned char, 3, 0x80);
00659 break;
00660 case BC_RGBA8888:
00661 ROTATE_INTERPOLATE(unsigned char, 4, 0x0);
00662 break;
00663 case BC_RGBA_FLOAT:
00664 ROTATE_INTERPOLATE(float, 4, 0x0);
00665 break;
00666 case BC_YUVA8888:
00667 ROTATE_INTERPOLATE(unsigned char, 4, 0x80);
00668 break;
00669
00670 case BC_RGB161616:
00671 ROTATE_INTERPOLATE(uint16_t, 3, 0x0);
00672 break;
00673 case BC_YUV161616:
00674 ROTATE_INTERPOLATE(uint16_t, 3, 0x8000);
00675 break;
00676
00677 case BC_RGBA16161616:
00678 ROTATE_INTERPOLATE(uint16_t, 4, 0x0);
00679 break;
00680 case BC_YUVA16161616:
00681 ROTATE_INTERPOLATE(uint16_t, 4, 0x8000);
00682 break;
00683 }
00684 }
00685 return 0;
00686 }
00687
00688 void RotateEngine::run()
00689 {
00690 while(!done)
00691 {
00692 input_lock->lock("RotateEngine::run");
00693 if(done) return;
00694
00695 if(do_matrix)
00696 {
00697 create_matrix();
00698 }
00699 else
00700 if(do_rotation)
00701 {
00702 perform_rotation();
00703 }
00704
00705 do_matrix = 0;
00706 do_rotation = 0;
00707 output_lock->unlock();
00708 }
00709 }