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