00001 #include "bcbitmap.h"
00002 #include "bcipc.h"
00003 #include "bcresources.h"
00004 #include "bcsignals.h"
00005 #include "bcwindow.h"
00006 #include "colormodels.h"
00007 #include "vframe.h"
00008
00009 #include <string.h>
00010 #include <unistd.h>
00011 #include <X11/extensions/Xvlib.h>
00012
00013
00014 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, unsigned char *png_data)
00015 {
00016
00017 VFrame frame;
00018
00019 frame.read_png(png_data);
00020
00021
00022 initialize(parent_window,
00023 frame.get_w(),
00024 frame.get_h(),
00025 parent_window->get_color_model(),
00026 0);
00027
00028
00029 read_frame(&frame, 0, 0, w, h);
00030 }
00031
00032 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, VFrame *frame)
00033 {
00034
00035 initialize(parent_window,
00036 frame->get_w(),
00037 frame->get_h(),
00038 parent_window->get_color_model(),
00039 0);
00040
00041
00042 read_frame(frame, 0, 0, w, h);
00043 }
00044
00045 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window,
00046 int w,
00047 int h,
00048 int color_model,
00049 int use_shm)
00050 {
00051 initialize(parent_window,
00052 w,
00053 h,
00054 color_model,
00055 use_shm ? parent_window->get_resources()->use_shm : 0);
00056 }
00057
00058 BC_Bitmap::~BC_Bitmap()
00059 {
00060 delete_data();
00061 }
00062
00063 int BC_Bitmap::initialize(BC_WindowBase *parent_window,
00064 int w,
00065 int h,
00066 int color_model,
00067 int use_shm)
00068 {
00069 this->parent_window = parent_window;
00070 this->top_level = parent_window->top_level;
00071 this->w = w;
00072 this->h = h;
00073 this->color_model = color_model;
00074 this->use_shm = use_shm ? parent_window->get_resources()->use_shm : 0;
00075 this->bg_color = parent_window->bg_color;
00076 ximage[0] = 0;
00077 xv_image[0] = 0;
00078 data[0] = 0;
00079 last_pixmap_used = 0;
00080 last_pixmap = 0;
00081 current_ringbuffer = 0;
00082
00083
00084
00085 int pixelsize = cmodel_calculate_pixelsize(color_model);
00086 int buffer_size = w * h * pixelsize;
00087
00088 if(buffer_size < 0x40000)
00089 ring_buffers = 4;
00090 else
00091 ring_buffers = 1;
00092
00093 allocate_data();
00094 return 0;
00095 }
00096
00097 int BC_Bitmap::match_params(int w, int h, int color_model, int use_shm)
00098 {
00099 if(this->w < w ||
00100 this->h < h ||
00101 this->color_model != color_model ||
00102 this->use_shm != use_shm)
00103 {
00104 delete_data();
00105 initialize(parent_window, w, h, color_model, use_shm);
00106 }
00107
00108 return 0;
00109 }
00110
00111 int BC_Bitmap::params_match(int w, int h, int color_model, int use_shm)
00112 {
00113 int result = 0;
00114 if(this->w == w &&
00115 this->h == h &&
00116 this->color_model == color_model)
00117 {
00118 if(use_shm == this->use_shm || use_shm == BC_INFINITY)
00119 result = 1;
00120 }
00121
00122 return result;
00123 }
00124
00125
00126 int BC_Bitmap::allocate_data()
00127 {
00128 int want_row_pointers = 1;
00129
00130
00131 if(use_shm)
00132 {
00133 switch(color_model)
00134 {
00135
00136 case BC_YUV420P:
00137 case BC_YUV422P:
00138
00139 case BC_YUV422:
00140 ring_buffers = BITMAP_RING;
00141 xv_portid = top_level->xvideo_port_id;
00142
00143 xv_image[0] = XvShmCreateImage(top_level->display,
00144 xv_portid,
00145 cmodel_bc_to_x(color_model),
00146 0,
00147 w,
00148 h,
00149 &shm_info);
00150
00151 shm_info.shmid = shmget(IPC_PRIVATE,
00152 xv_image[0]->data_size * ring_buffers + 4,
00153 IPC_CREAT | 0777);
00154 if(shm_info.shmid < 0) perror("BC_Bitmap::allocate_data shmget");
00155 data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
00156
00157 xv_image[0]->data = shm_info.shmaddr = (char*)data[0];
00158 shm_info.readOnly = 0;
00159
00160
00161 w = xv_image[0]->width;
00162 h = xv_image[0]->height;
00163
00164
00165 for(int i = 1; i < ring_buffers; i++)
00166 {
00167 data[i] = data[0] + xv_image[0]->data_size * i;
00168 xv_image[i] = XvShmCreateImage(top_level->display,
00169 xv_portid,
00170 cmodel_bc_to_x(color_model),
00171 (char*)data[i],
00172 w,
00173 h,
00174 &shm_info);
00175 xv_image[i]->data = (char*)data[i];
00176 }
00177
00178 if(color_model == BC_YUV422)
00179 {
00180 bytes_per_line = w * 2;
00181 bits_per_pixel = 2;
00182 want_row_pointers = 1;
00183 }
00184 else
00185 {
00186 bytes_per_line = 0;
00187 bits_per_pixel = 0;
00188 want_row_pointers = 0;
00189 }
00190 break;
00191
00192 default:
00193
00194 ring_buffers = BITMAP_RING;
00195
00196 ximage[0] = XShmCreateImage(top_level->display,
00197 top_level->vis,
00198 get_default_depth(),
00199 get_default_depth() == 1 ? XYBitmap : ZPixmap,
00200 (char*)NULL,
00201 &shm_info,
00202 w,
00203 h);
00204
00205
00206 shm_info.shmid = shmget(IPC_PRIVATE,
00207 h * ximage[0]->bytes_per_line * ring_buffers + 4,
00208 IPC_CREAT | 0777);
00209 if(shm_info.shmid < 0)
00210 perror("BC_Bitmap::allocate_data shmget");
00211 data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
00212 ximage[0]->data = shm_info.shmaddr = (char*)data[0];
00213 shm_info.readOnly = 0;
00214
00215
00216 bits_per_pixel = ximage[0]->bits_per_pixel;
00217 bytes_per_line = ximage[0]->bytes_per_line;
00218
00219
00220 for(int i = 1; i < ring_buffers; i++)
00221 {
00222 data[i] = data[0] + h * ximage[0]->bytes_per_line * i;
00223 ximage[i] = XShmCreateImage(top_level->display,
00224 top_level->vis,
00225 get_default_depth(),
00226 get_default_depth() == 1 ? XYBitmap : ZPixmap,
00227 (char*)data[i],
00228 &shm_info,
00229 w,
00230 h);
00231 ximage[i]->data = (char*)data[i];
00232
00233 }
00234 break;
00235 }
00236
00237 if(!XShmAttach(top_level->display, &shm_info))
00238 {
00239 perror("BC_Bitmap::allocate_data XShmAttach");
00240 }
00241
00242
00243 shmctl(shm_info.shmid, IPC_RMID, 0);
00244 }
00245 else
00246
00247 {
00248 ring_buffers = 1;
00249
00250 data[0] = 0;
00251
00252
00253
00254 ximage[0] = XCreateImage(top_level->display,
00255 top_level->vis,
00256 get_default_depth(),
00257 get_default_depth() == 1 ? XYBitmap : ZPixmap,
00258 0,
00259 (char*)data[0],
00260 w,
00261 h,
00262 8,
00263 0);
00264
00265
00266 data[0] = (unsigned char*)malloc(h * ximage[0]->bytes_per_line + 4);
00267
00268
00269 XDestroyImage(ximage[0]);
00270
00271
00272 ximage[0] = XCreateImage(top_level->display,
00273 top_level->vis,
00274 get_default_depth(),
00275 get_default_depth() == 1 ? XYBitmap : ZPixmap,
00276 0,
00277 (char*)data[0],
00278 w,
00279 h,
00280 8,
00281 0);
00282
00283
00284 bits_per_pixel = ximage[0]->bits_per_pixel;
00285 bytes_per_line = ximage[0]->bytes_per_line;
00286
00287 }
00288
00289
00290 if(want_row_pointers)
00291 {
00292
00293 for(int j = 0; j < ring_buffers; j++)
00294 {
00295 row_data[j] = new unsigned char*[h];
00296 for(int i = 0; i < h; i++)
00297 {
00298 row_data[j][i] = &data[j][i * bytes_per_line];
00299 }
00300 }
00301 }
00302 return 0;
00303 }
00304
00305 int BC_Bitmap::delete_data()
00306 {
00307 if(data[0])
00308 {
00309 if(use_shm)
00310 {
00311 switch(color_model)
00312 {
00313 case BC_YUV420P:
00314 case BC_YUV422P:
00315 case BC_YUV422:
00316
00317 if(last_pixmap_used) XvStopVideo(top_level->display, xv_portid, last_pixmap);
00318 for(int i = 0; i < ring_buffers; i++)
00319 {
00320 XFree(xv_image[i]);
00321 }
00322 XShmDetach(top_level->display, &shm_info);
00323 XvUngrabPort(top_level->display, xv_portid, CurrentTime);
00324
00325 shmdt(shm_info.shmaddr);
00326 shmctl(shm_info.shmid, IPC_RMID, 0);
00327 break;
00328
00329 default:
00330 for(int i = 0; i < ring_buffers; i++)
00331 {
00332 XDestroyImage(ximage[i]);
00333 delete [] row_data[i];
00334 }
00335 XShmDetach(top_level->display, &shm_info);
00336
00337 shmdt(shm_info.shmaddr);
00338 shmctl(shm_info.shmid, IPC_RMID, 0);
00339 break;
00340 }
00341 }
00342 else
00343 {
00344 XDestroyImage(ximage[0]);
00345 delete [] row_data[0];
00346 }
00347
00348
00349 data[0] = 0;
00350 last_pixmap_used = 0;
00351 }
00352 return 0;
00353 }
00354
00355 int BC_Bitmap::get_default_depth()
00356 {
00357 if(color_model == BC_TRANSPARENCY)
00358 return 1;
00359 else
00360 return top_level->default_depth;
00361 }
00362
00363
00364 int BC_Bitmap::set_bg_color(int color)
00365 {
00366 this->bg_color = color;
00367 return 0;
00368 }
00369
00370 int BC_Bitmap::invert()
00371 {
00372 for(int j = 0; j < ring_buffers; j++)
00373 for(int k = 0; k < h; k++)
00374 for(int i = 0; i < bytes_per_line; i++)
00375 {
00376 row_data[j][k][i] ^= 0xff;
00377 }
00378 return 0;
00379 }
00380
00381 int BC_Bitmap::write_drawable(Drawable &pixmap,
00382 GC &gc,
00383 int dest_x,
00384 int dest_y,
00385 int source_x,
00386 int source_y,
00387 int dest_w,
00388 int dest_h,
00389 int dont_wait)
00390 {
00391 return write_drawable(pixmap,
00392 gc,
00393 source_x,
00394 source_y,
00395 get_w() - source_x,
00396 get_h() - source_y,
00397 dest_x,
00398 dest_y,
00399 dest_w,
00400 dest_h,
00401 dont_wait);
00402 }
00403
00404 void BC_Bitmap::rewind_ring()
00405 {
00406 current_ringbuffer--;
00407 if(current_ringbuffer < 0) current_ringbuffer = ring_buffers - 1;
00408 }
00409
00410 int BC_Bitmap::write_drawable(Drawable &pixmap,
00411 GC &gc,
00412 int source_x,
00413 int source_y,
00414 int source_w,
00415 int source_h,
00416 int dest_x,
00417 int dest_y,
00418 int dest_w,
00419 int dest_h,
00420 int dont_wait)
00421 {
00422
00423 if(use_shm)
00424 {
00425 if(dont_wait) XSync(top_level->display, False);
00426
00427 if(hardware_scaling())
00428 {
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 XvShmPutImage(top_level->display,
00443 xv_portid,
00444 pixmap,
00445 gc,
00446 xv_image[current_ringbuffer],
00447 source_x,
00448 source_y,
00449 source_w,
00450 source_h,
00451 dest_x,
00452 dest_y,
00453 dest_w,
00454 dest_h,
00455 False);
00456
00457 last_pixmap = pixmap;
00458 last_pixmap_used = 1;
00459 }
00460 else
00461 {
00462
00463
00464
00465
00466
00467
00468
00469
00470 XShmPutImage(top_level->display,
00471 pixmap,
00472 gc,
00473 ximage[current_ringbuffer],
00474 source_x,
00475 source_y,
00476 dest_x,
00477 dest_y,
00478 dest_w,
00479 dest_h,
00480 False);
00481 }
00482
00483
00484
00485 if(!dont_wait) XSync(top_level->display, False);
00486
00487 }
00488 else
00489 {
00490 XPutImage(top_level->display,
00491 pixmap,
00492 gc,
00493 ximage[current_ringbuffer],
00494 source_x,
00495 source_y,
00496 dest_x,
00497 dest_y,
00498 dest_w,
00499 dest_h);
00500 }
00501
00502
00503 current_ringbuffer++;
00504 if(current_ringbuffer >= ring_buffers) current_ringbuffer = 0;
00505
00506 return 0;
00507 }
00508
00509
00510
00511
00512
00513 int BC_Bitmap::read_drawable(Drawable &pixmap, int source_x, int source_y)
00514 {
00515 if(use_shm)
00516 XShmGetImage(top_level->display, pixmap, ximage[current_ringbuffer], source_x, source_y, 0xffffffff);
00517 else
00518 XGetSubImage(top_level->display, pixmap, source_x, source_y, w, h, 0xffffffff, ZPixmap, ximage[current_ringbuffer], 0, 0);
00519 return 0;
00520 }
00521
00522
00523
00524 int BC_Bitmap::read_frame(VFrame *frame,
00525 int x1,
00526 int y1,
00527 int x2,
00528 int y2)
00529 {
00530 return read_frame(frame,
00531 0, 0, frame->get_w(), frame->get_h(),
00532 x1, y1, x2 - x1, y2 - y1);
00533 }
00534
00535
00536 int BC_Bitmap::read_frame(VFrame *frame,
00537 int in_x,
00538 int in_y,
00539 int in_w,
00540 int in_h,
00541 int out_x,
00542 int out_y,
00543 int out_w,
00544 int out_h)
00545 {
00546 switch(color_model)
00547 {
00548
00549 case BC_YUV420P:
00550 if(frame->get_color_model() == color_model)
00551 {
00552 memcpy(get_y_plane(), frame->get_y(), w * h);
00553 memcpy(get_u_plane(), frame->get_u(), w * h / 4);
00554 memcpy(get_v_plane(), frame->get_v(), w * h / 4);
00555 break;
00556 }
00557
00558 case BC_YUV422P:
00559 if(frame->get_color_model() == color_model)
00560 {
00561 memcpy(get_y_plane(), frame->get_y(), w * h);
00562 memcpy(get_u_plane(), frame->get_u(), w * h / 2);
00563 memcpy(get_v_plane(), frame->get_v(), w * h / 2);
00564 break;
00565 }
00566
00567 case BC_YUV422:
00568 if(frame->get_color_model() == color_model)
00569 {
00570 memcpy(get_data(), frame->get_data(), w * h + w * h);
00571 break;
00572 }
00573
00574
00575 default:
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 cmodel_transfer(row_data[current_ringbuffer],
00590 frame->get_rows(),
00591 get_y_plane(),
00592 get_u_plane(),
00593 get_v_plane(),
00594 frame->get_y(),
00595 frame->get_u(),
00596 frame->get_v(),
00597 in_x,
00598 in_y,
00599 in_w,
00600 in_h,
00601 out_x,
00602 out_y,
00603 out_w,
00604 out_h,
00605 frame->get_color_model(),
00606 color_model,
00607 bg_color,
00608 frame->get_w(),
00609 w);
00610
00611
00612 if ((color_model == BC_TRANSPARENCY) && (!top_level->server_byte_order))
00613 transparency_bitswap();
00614
00615
00616
00617
00618 break;
00619 }
00620
00621
00622 return 0;
00623 }
00624
00625 long BC_Bitmap::get_shm_id()
00626 {
00627 return shm_info.shmid;
00628 }
00629
00630 long BC_Bitmap::get_shm_size()
00631 {
00632 if(xv_image[0])
00633 return xv_image[0]->data_size * ring_buffers;
00634 else
00635 return h * ximage[0]->bytes_per_line;
00636 }
00637
00638 long BC_Bitmap::get_shm_offset()
00639 {
00640 if(xv_image[0])
00641 return xv_image[0]->data_size * current_ringbuffer;
00642 else
00643 if(ximage[0])
00644 return h * ximage[0]->bytes_per_line * current_ringbuffer;
00645 else
00646 return 0;
00647 }
00648
00649 long BC_Bitmap::get_y_shm_offset()
00650 {
00651 if(xv_image[0])
00652 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[0];
00653 else
00654 return 0;
00655 }
00656
00657 long BC_Bitmap::get_u_shm_offset()
00658 {
00659 if(xv_image[0])
00660 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[2];
00661 else
00662 return 0;
00663 }
00664
00665 long BC_Bitmap::get_v_shm_offset()
00666 {
00667 if(xv_image[0])
00668 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[1];
00669 else
00670 return 0;
00671 }
00672
00673 long BC_Bitmap::get_y_offset()
00674 {
00675 if(xv_image[0])
00676 return xv_image[current_ringbuffer]->offsets[0];
00677 else
00678 return 0;
00679 }
00680
00681 long BC_Bitmap::get_u_offset()
00682 {
00683 if(xv_image[0] && xv_image[current_ringbuffer]->num_planes > 1)
00684 return xv_image[current_ringbuffer]->offsets[2];
00685 else
00686 return 0;
00687 }
00688
00689 long BC_Bitmap::get_v_offset()
00690 {
00691 if(xv_image[0] && xv_image[current_ringbuffer]->num_planes > 1)
00692 return xv_image[current_ringbuffer]->offsets[1];
00693 else
00694 return 0;
00695 }
00696
00697
00698 unsigned char** BC_Bitmap::get_row_pointers()
00699 {
00700 return row_data[current_ringbuffer];
00701 }
00702
00703 int BC_Bitmap::get_bytes_per_line()
00704 {
00705 return bytes_per_line;
00706 }
00707 unsigned char* BC_Bitmap::get_data()
00708 {
00709
00710 return data[current_ringbuffer];
00711 }
00712
00713 unsigned char* BC_Bitmap::get_y_plane()
00714 {
00715 if(color_model == BC_YUV420P ||
00716 color_model == BC_YUV422P)
00717 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[0];
00718 else
00719 return 0;
00720 }
00721
00722 unsigned char* BC_Bitmap::get_v_plane()
00723 {
00724 if(color_model == BC_YUV420P ||
00725 color_model == BC_YUV422P)
00726 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[1];
00727 else
00728 return 0;
00729 }
00730
00731 unsigned char* BC_Bitmap::get_u_plane()
00732 {
00733 if(color_model == BC_YUV420P ||
00734 color_model == BC_YUV422P)
00735 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[2];
00736 else
00737 return 0;
00738 }
00739
00740 void BC_Bitmap::rewind_ringbuffer()
00741 {
00742 current_ringbuffer--;
00743 if(current_ringbuffer < 0) current_ringbuffer = ring_buffers - 1;
00744 }
00745
00746 int BC_Bitmap::hardware_scaling()
00747 {
00748 return (get_color_model() == BC_YUV420P ||
00749 get_color_model() == BC_YUV422P ||
00750 get_color_model() == BC_YUV422);
00751 }
00752
00753 int BC_Bitmap::get_w() { return w; }
00754
00755 int BC_Bitmap::get_h() { return h; }
00756
00757 char BC_Bitmap::byte_bitswap(char src) {
00758 int i;
00759 char dst;
00760
00761 dst = 0;
00762 if (src & 1) dst |= ((unsigned char)1 << 7);
00763 src = src >> 1;
00764 if (src & 1) dst |= ((unsigned char)1 << 6);
00765 src = src >> 1;
00766 if (src & 1) dst |= ((unsigned char)1 << 5);
00767 src = src >> 1;
00768 if (src & 1) dst |= ((unsigned char)1 << 4);
00769 src = src >> 1;
00770 if (src & 1) dst |= ((unsigned char)1 << 3);
00771 src = src >> 1;
00772 if (src & 1) dst |= ((unsigned char)1 << 2);
00773 src = src >> 1;
00774 if (src & 1) dst |= ((unsigned char)1 << 1);
00775 src = src >> 1;
00776 if (src & 1) dst |= ((unsigned char)1 << 0);
00777
00778 return(dst);
00779 }
00780
00781 void BC_Bitmap::transparency_bitswap() {
00782 unsigned char *buf;
00783 int i, width, height;
00784 int len;
00785
00786 buf = *row_data[current_ringbuffer];
00787
00788 width = w;
00789 height = h;
00790 if (width % 8)
00791 width = width + 8 - (width % 8);
00792 len = width * height / 8;
00793
00794 for(i=0 ; i+8<=len ; i+=8){
00795 buf[i+0] = byte_bitswap(buf[i+0]);
00796 buf[i+1] = byte_bitswap(buf[i+1]);
00797 buf[i+2] = byte_bitswap(buf[i+2]);
00798 buf[i+3] = byte_bitswap(buf[i+3]);
00799 buf[i+4] = byte_bitswap(buf[i+4]);
00800 buf[i+5] = byte_bitswap(buf[i+5]);
00801 buf[i+6] = byte_bitswap(buf[i+6]);
00802 buf[i+7] = byte_bitswap(buf[i+7]);
00803 }
00804 for( ; i<len ; i++){
00805 buf[i+0] = byte_bitswap(buf[i+0]);
00806 }
00807 }
00808
00809 int BC_Bitmap::get_color_model() { return color_model; }
00810
00811
00812