r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / guicast / bcbitmap.C
blob66c0a3a63ba7b161cdfc02e3490a1695ab79db11
1 #include "bcbitmap.h"
2 #include "bcipc.h"
3 #include "bcresources.h"
4 #include "bcsignals.h"
5 #include "bcwindow.h"
6 #include "colormodels.h"
7 #include "vframe.h"
9 #include <string.h>
10 #include <X11/extensions/Xvlib.h>
13 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, unsigned char *png_data)
15 // Decompress data into a temporary vframe
16         VFrame frame;
18         frame.read_png(png_data);
20 // Initialize the bitmap
21         initialize(parent_window, 
22                 frame.get_w(), 
23                 frame.get_h(), 
24                 parent_window->get_color_model(), 
25                 0);
27 // Copy the vframe to the bitmap
28         read_frame(&frame, 0, 0, w, h);
31 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, VFrame *frame)
33 // Initialize the bitmap
34         initialize(parent_window, 
35                 frame->get_w(), 
36                 frame->get_h(), 
37                 parent_window->get_color_model(), 
38                 0);
40 // Copy the vframe to the bitmap
41         read_frame(frame, 0, 0, w, h);
44 BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, 
45         int w, 
46         int h, 
47         int color_model, 
48         int use_shm)
50         initialize(parent_window, 
51                 w, 
52                 h, 
53                 color_model, 
54                 use_shm ? parent_window->get_resources()->use_shm : 0);
57 BC_Bitmap::~BC_Bitmap()
59         delete_data();
62 int BC_Bitmap::initialize(BC_WindowBase *parent_window, 
63         int w, 
64         int h, 
65         int color_model, 
66         int use_shm)
68         this->parent_window = parent_window;
69         this->top_level = parent_window->top_level;
70         this->w = w;
71         this->h = h;
72         this->color_model = color_model;
73         this->use_shm = use_shm ? parent_window->get_resources()->use_shm : 0;
74         this->bg_color = parent_window->bg_color;
75         ximage[0] = 0;
76         xv_image[0] = 0;
77         data[0] = 0;
78         last_pixmap_used = 0;
79         last_pixmap = 0;
80         current_ringbuffer = 0;
81 // Set ring buffers based on total memory used.
82 // The program icon must use multiple buffers but larger bitmaps may not fit
83 // in memory.
84         int pixelsize = cmodel_calculate_pixelsize(color_model);
85         int buffer_size = w * h * pixelsize;
87         if(buffer_size < 0x40000)
88                 ring_buffers = 4;
89         else
90                 ring_buffers = 1;
92         allocate_data();
93         return 0;
96 int BC_Bitmap::match_params(int w, int h, int color_model, int use_shm)
98         if(this->w /* != */ < w ||
99                 this->h /* != */ < h ||
100                 this->color_model != color_model ||
101                 this->use_shm != use_shm)
102         {
103                 delete_data();
104                 initialize(parent_window, w, h, color_model, use_shm);
105         }
107         return 0;
110 int BC_Bitmap::params_match(int w, int h, int color_model, int use_shm)
112         int result = 0;
113         if(this->w == w &&
114                 this->h == h &&
115                 this->color_model == color_model)
116         {
117                 if(use_shm == this->use_shm || use_shm == BC_INFINITY)
118                         result = 1;
119         }
121         return result;
125 int BC_Bitmap::allocate_data()
127         int want_row_pointers = 1;
129 // Shared memory available
130     if(use_shm)
131         {
132                 switch(color_model)
133                 {
134 // Planar YUV.  Must use BC_WindowBase::accel_available before calling this.
135                         case BC_YUV420P:
136                         case BC_YUV422P:
137 // Packed YUV
138                         case BC_YUV422:
139                                 ring_buffers = BITMAP_RING;
140                                 xv_portid = top_level->xvideo_port_id;
141 // Create the X Image
142                                 xv_image[0] = XvShmCreateImage(top_level->display, 
143                                                         xv_portid, 
144                                                         cmodel_bc_to_x(color_model),
145                                                         0, 
146                                                         w,
147                                                         h,
148                                                         &shm_info);
149 // Create the shared memory
150                                 shm_info.shmid = shmget(IPC_PRIVATE, 
151                                         xv_image[0]->data_size * ring_buffers + 4, 
152                                         IPC_CREAT | 0777);
153                                 if(shm_info.shmid < 0) perror("BC_Bitmap::allocate_data shmget");
154                                 data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
155 // setting ximage->data stops BadValue
156                                 xv_image[0]->data = shm_info.shmaddr = (char*)data[0];
157                                 shm_info.readOnly = 0;
159 // Get the real parameters
160                                 w = xv_image[0]->width;
161                                 h = xv_image[0]->height;
163 // Create remaining X Images
164                                 for(int i = 1; i < ring_buffers; i++)
165                                 {
166                                         data[i] = data[0] + xv_image[0]->data_size * i;
167                                         xv_image[i] = XvShmCreateImage(top_level->display, 
168                                                                 xv_portid, 
169                                                                 cmodel_bc_to_x(color_model),
170                                                                 (char*)data[i], 
171                                                                 w,
172                                                                 h,
173                                                                 &shm_info);
174                                         xv_image[i]->data = (char*)data[i];
175                                 }
176                                 
177                                 if(color_model == BC_YUV422)
178                                 {
179                                         bytes_per_line = w * 2;
180                                         bits_per_pixel = 2;
181                                         want_row_pointers = 1;
182                                 }
183                                 else
184                                 {
185                                         bytes_per_line = 0;
186                                         bits_per_pixel = 0;
187                                         want_row_pointers = 0;
188                                 }
189                                 break;
191                         default:
192 // RGB
193                                 ring_buffers = BITMAP_RING;
194 // Create first X Image
195                         ximage[0] = XShmCreateImage(top_level->display, 
196                                         top_level->vis, 
197                                         get_default_depth(), 
198                                         get_default_depth() == 1 ? XYBitmap : ZPixmap, 
199                                         (char*)NULL, 
200                                         &shm_info, 
201                                         w, 
202                                         h);
204 // Create shared memory
205                                 shm_info.shmid = shmget(IPC_PRIVATE, 
206                                         h * ximage[0]->bytes_per_line * ring_buffers + 4, 
207                                         IPC_CREAT | 0777);
208                                 if(shm_info.shmid < 0) 
209                                         perror("BC_Bitmap::allocate_data shmget");
210                                 data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
211                                 ximage[0]->data = shm_info.shmaddr = (char*)data[0];  // setting ximage->data stops BadValue
212                                 shm_info.readOnly = 0;
214 // Get the real parameters
215                                 bits_per_pixel = ximage[0]->bits_per_pixel;
216                                 bytes_per_line = ximage[0]->bytes_per_line;
218 // Create remaining X Images
219                                 for(int i = 1; i < ring_buffers; i++)
220                                 {
221                                         data[i] = data[0] + h * ximage[0]->bytes_per_line * i;
222                                         ximage[i] = XShmCreateImage(top_level->display, 
223                                                                                         top_level->vis, 
224                                                                                         get_default_depth(), 
225                                                                                         get_default_depth() == 1 ? XYBitmap : ZPixmap, 
226                                                                                         (char*)data[i], 
227                                                                                         &shm_info, 
228                                                                                         w, 
229                                                                                         h);
230                                         ximage[i]->data = (char*)data[i];
231 //printf("BC_Bitmap::allocate_data %p\n", ximage[i]);
232                                 }
233                                 break;
234                 }
236                 if(!XShmAttach(top_level->display, &shm_info))
237                 {
238                         perror("BC_Bitmap::allocate_data XShmAttach");
239                 }
241 // This causes it to automatically delete when the program exits.
242                 shmctl(shm_info.shmid, IPC_RMID, 0);
243         }
244         else
245 // Use unshared memory.
246         {
247                 ring_buffers = 1;
248 // need to use bytes_per_line for some X servers
249                 data[0] = 0;
251 // Use RGB frame
252 //printf("BCBitmap::allocate_data 1\n");
253                 ximage[0] = XCreateImage(top_level->display, 
254                                         top_level->vis, 
255                                         get_default_depth(), 
256                                         get_default_depth() == 1 ? XYBitmap : ZPixmap, 
257                                         0, 
258                                         (char*)data[0], 
259                                         w, 
260                                         h, 
261                                         8, 
262                                         0);
263 //printf("BCBitmap::allocate_data 1 %d\n", h * ximage[0]->bytes_per_line + 4);
265                 data[0] = (unsigned char*)malloc(h * ximage[0]->bytes_per_line + 4);
266 //printf("BCBitmap::allocate_data 2\n");
268                 XDestroyImage(ximage[0]);
269 //printf("BCBitmap::allocate_data 1\n");
271                 ximage[0] = XCreateImage(top_level->display, 
272                                         top_level->vis, 
273                                         get_default_depth(), 
274                                         get_default_depth() == 1 ? XYBitmap : ZPixmap, 
275                                         0, 
276                                         (char*)data[0], 
277                                         w, 
278                                         h, 
279                                         8, 
280                                         0);
281 //printf("BCBitmap::allocate_data 1\n");
282 // This differs from the depth parameter of the top_level.
283                 bits_per_pixel = ximage[0]->bits_per_pixel;
284                 bytes_per_line = ximage[0]->bytes_per_line;
285 //printf("BCBitmap::allocate_data 2\n");
286         }
288 // Create row pointers
289         if(want_row_pointers)
290         {
291 //printf("BC_Bitmap::allocate 1 %d %d %d %d\n", w, h, get_default_depth(), bytes_per_line);
292                 for(int j = 0; j < ring_buffers; j++)
293                 {
294                         row_data[j] = new unsigned char*[h];
295                         for(int i = 0; i < h; i++)
296                         {
297                                 row_data[j][i] = &data[j][i * bytes_per_line];
298                         }
299                 }
300         }
301         return 0;
304 int BC_Bitmap::delete_data()
306         if(data[0])
307         {
308                 if(use_shm)
309                 {
310                         switch(color_model)
311                         {
312                                 case BC_YUV420P:
313                                 case BC_YUV422P:
314                                 case BC_YUV422:
315 //printf("BC_Bitmap::delete_data 1\n");
316                                         if(last_pixmap_used) XvStopVideo(top_level->display, xv_portid, last_pixmap);
317                                         for(int i = 0; i < ring_buffers; i++)
318                                         {
319                                                 XFree(xv_image[i]);
320                                         }
321                                         XShmDetach(top_level->display, &shm_info);
322                                         XvUngrabPort(top_level->display, xv_portid, CurrentTime);
324                                         shmdt(shm_info.shmaddr);
325                                         shmctl(shm_info.shmid, IPC_RMID, 0);
326                                         break;
328                                 default:
329                                         for(int i = 0; i < ring_buffers; i++)
330                                         {
331                                                 XDestroyImage(ximage[i]);
332                                                 delete [] row_data[i];
333                                         }
334                                         XShmDetach(top_level->display, &shm_info);
336                                         shmdt(shm_info.shmaddr);
337                                         shmctl(shm_info.shmid, IPC_RMID, 0);
338                                         break;
339                         }
340                 }
341                 else
342                 {
343                         XDestroyImage(ximage[0]);
344                         delete [] row_data[0];
345                 }
347 // data is automatically freed by XDestroyImage
348                 data[0] = 0;
349                 last_pixmap_used = 0;
350         }
351         return 0;
354 int BC_Bitmap::get_default_depth()
356         if(color_model == BC_TRANSPARENCY)
357                 return 1;
358         else
359                 return top_level->default_depth;
363 int BC_Bitmap::set_bg_color(int color)
365         this->bg_color = color;
366         return 0;
369 int BC_Bitmap::invert()
371         for(int j = 0; j < ring_buffers; j++)
372                 for(int k = 0; k < h; k++)
373                         for(int i = 0; i < bytes_per_line; i++)
374                         {
375                                 row_data[j][k][i] ^= 0xff;
376                         }
377         return 0;
380 int BC_Bitmap::write_drawable(Drawable &pixmap, 
381                                                         GC &gc,
382                                                         int dest_x, 
383                                                         int dest_y, 
384                                                         int source_x, 
385                                                         int source_y, 
386                                                         int dest_w, 
387                                                         int dest_h,
388                                                         int dont_wait)
390         return write_drawable(pixmap, 
391                 gc,
392                 source_x, 
393                 source_y, 
394                 get_w() - source_x,
395                 get_h() - source_y,
396                 dest_x, 
397                 dest_y, 
398                 dest_w, 
399                 dest_h, 
400                 dont_wait);
403 void BC_Bitmap::rewind_ring()
405         current_ringbuffer--;
406         if(current_ringbuffer < 0) current_ringbuffer = ring_buffers - 1;
409 int BC_Bitmap::write_drawable(Drawable &pixmap, 
410                 GC &gc,
411                 int source_x, 
412                 int source_y, 
413                 int source_w,
414                 int source_h,
415                 int dest_x, 
416                 int dest_y, 
417                 int dest_w, 
418                 int dest_h, 
419                 int dont_wait)
421 //printf("BC_Bitmap::write_drawable 1 %p %d\n", this, current_ringbuffer);fflush(stdout);
422     if(use_shm)
423         {
424 //TRACE("BC_Bitmap::write_drawable 1");
425                 if(dont_wait) XSync(top_level->display, False);
426 //TRACE("BC_Bitmap::write_drawable 2");
428                 if(hardware_scaling())
429                 {
430 // printf("BC_Bitmap::write_drawable %d %d %d %d -> %d %d %d %d\n", source_x, 
431 //                              source_y, 
432 //                              source_w, 
433 //                              source_h, 
434 //                              dest_x, 
435 //                              dest_y, 
436 //                              dest_w, 
437 //                              dest_h);
438 //for(int i = 0; i < 1000; i++) xv_image[current_ringbuffer]->data[i] = 255;
439 //printf("BC_Bitmap::write_drawable 2 %d %d %p %p\n", xv_portid, 
440 //      pixmap, 
441 //      gc,
442 //      xv_image[current_ringbuffer]);
443 //TRACE("BC_Bitmap::write_drawable 3");
444                         XvShmPutImage(top_level->display, 
445                                 xv_portid, 
446                                 pixmap, 
447                                 gc,
448                                 xv_image[current_ringbuffer], 
449                                 source_x, 
450                                 source_y, 
451                                 source_w, 
452                                 source_h, 
453                                 dest_x, 
454                                 dest_y, 
455                                 dest_w, 
456                                 dest_h, 
457                                 False);
458 //TRACE("BC_Bitmap::write_drawable 4");
459 // Need to pass these to the XvStopVideo
460                         last_pixmap = pixmap;
461                         last_pixmap_used = 1;
462                 }
463                 else
464                 {
465 // printf("BC_Bitmap::write_drawable %d %d %d %d -> %d %d %d %d\n", source_x, 
466 //                              source_y, 
467 //                              source_w, 
468 //                              source_h, 
469 //                              dest_x, 
470 //                              dest_y, 
471 //                              dest_w, 
472 //                              dest_h);
473                 XShmPutImage(top_level->display, 
474                                 pixmap, 
475                                 gc, 
476                                 ximage[current_ringbuffer], 
477                                 source_x, 
478                                 source_y, 
479                                 dest_x, 
480                                 dest_y, 
481                                 dest_w, 
482                                 dest_h, 
483                                 False);
484                 }
486 // Force the X server into processing all requests.
487 // This allows the shared memory to be written to again.
488                 if(!dont_wait) XSync(top_level->display, False);
489 //TRACE("BC_Bitmap::write_drawable 5");
490         }
491     else
492         {
493         XPutImage(top_level->display, 
494                         pixmap, 
495                         gc, 
496                         ximage[current_ringbuffer], 
497                         source_x, 
498                         source_y, 
499                         dest_x, 
500                         dest_y, 
501                         dest_w, 
502                         dest_h);
503         }
505 //printf("BC_Bitmap %d\n", current_ringbuffer);
506         current_ringbuffer++;
507         if(current_ringbuffer >= ring_buffers) current_ringbuffer = 0;
508 //printf("BC_Bitmap::write_drawable 2\n");fflush(stdout);
509         return 0;
515 // the bitmap must be wholly contained in the source during a GetImage
516 int BC_Bitmap::read_drawable(Drawable &pixmap, int source_x, int source_y)
518         if(use_shm)
519                 XShmGetImage(top_level->display, pixmap, ximage[current_ringbuffer], source_x, source_y, 0xffffffff);
520         else
521                 XGetSubImage(top_level->display, pixmap, source_x, source_y, w, h, 0xffffffff, ZPixmap, ximage[current_ringbuffer], 0, 0);
522         return 0;
525 // ============================ Decoding VFrames
527 int BC_Bitmap::read_frame(VFrame *frame, 
528         int x1, 
529         int y1, 
530         int x2, 
531         int y2)
533         return read_frame(frame, 
534                 0, 0, frame->get_w(), frame->get_h(),
535                 x1, y1, x2 - x1, y2 - y1);
539 int BC_Bitmap::read_frame(VFrame *frame, 
540         int in_x, 
541         int in_y, 
542         int in_w, 
543         int in_h,
544         int out_x, 
545         int out_y, 
546         int out_w, 
547         int out_h)
549         switch(color_model)
550         {
551 // Hardware accelerated bitmap
552                 case BC_YUV420P:
553                         if(frame->get_color_model() == color_model)
554                         {
555                                 memcpy(get_y_plane(), frame->get_y(), w * h);
556                                 memcpy(get_u_plane(), frame->get_u(), w * h / 4);
557                                 memcpy(get_v_plane(), frame->get_v(), w * h / 4);
558                                 break;
559                         }
561                 case BC_YUV422P:
562                         if(frame->get_color_model() == color_model)
563                         {
564                                 memcpy(get_y_plane(), frame->get_y(), w * h);
565                                 memcpy(get_u_plane(), frame->get_u(), w * h / 2);
566                                 memcpy(get_v_plane(), frame->get_v(), w * h / 2);
567                                 break;
568                         }
570                 case BC_YUV422:
571                         if(frame->get_color_model() == color_model)
572                         {
573                                 memcpy(get_data(), frame->get_data(), w * h + w * h);
574                                 break;
575                         }
577 // Software only
578                 default:
579 // printf("BC_Bitmap::read_frame %d -> %d %d %d %d %d -> %d %d %d %d\n",
580 //                              frame->get_color_model(), 
581 //                              color_model,
582 //                              in_x, 
583 //                              in_y, 
584 //                              in_w, 
585 //                              in_h,
586 //                              out_x, 
587 //                              out_y, 
588 //                              out_w, 
589 //                              out_h);
590 // printf("BC_Bitmap::read_frame 1 %d %p\n", bits_per_pixel, frame->get_rows());
591                         cmodel_transfer(row_data[current_ringbuffer], 
592                                 frame->get_rows(),
593                                 get_y_plane(),
594                                 get_u_plane(),
595                                 get_v_plane(),
596                                 frame->get_y(),
597                                 frame->get_u(),
598                                 frame->get_v(),
599                                 in_x, 
600                                 in_y, 
601                                 in_w, 
602                                 in_h,
603                                 out_x, 
604                                 out_y, 
605                                 out_w, 
606                                 out_h,
607                                 frame->get_color_model(), 
608                                 color_model,
609                                 bg_color,
610                                 frame->get_w(),
611                                 w);
612 // printf("BC_Bitmap::read_frame 2\n");
613                         break;
614         }
617         return 0;
620 long BC_Bitmap::get_shm_id()
622         return shm_info.shmid;
625 long BC_Bitmap::get_shm_size()
627         if(xv_image[0])
628                 return xv_image[0]->data_size * ring_buffers;
629         else
630                 return h * ximage[0]->bytes_per_line;
633 long BC_Bitmap::get_shm_offset()
635         if(xv_image[0])
636                 return xv_image[0]->data_size * current_ringbuffer;
637         else
638         if(ximage[0])
639                 return h * ximage[0]->bytes_per_line * current_ringbuffer;
640         else
641                 return 0;
644 long BC_Bitmap::get_y_shm_offset()
646         if(xv_image[0])
647                 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[0];
648         else
649                 return 0;
652 long BC_Bitmap::get_u_shm_offset()
654         if(xv_image[0])
655                 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[2];
656         else
657                 return 0;
660 long BC_Bitmap::get_v_shm_offset()
662         if(xv_image[0])
663                 return get_shm_offset() + xv_image[current_ringbuffer]->offsets[1];
664         else
665                 return 0;
668 long BC_Bitmap::get_y_offset()
670         if(xv_image[0])
671                 return xv_image[current_ringbuffer]->offsets[0];
672         else
673                 return 0;
676 long BC_Bitmap::get_u_offset()
678         if(xv_image[0])
679                 return xv_image[current_ringbuffer]->offsets[2];
680         else
681                 return 0;
684 long BC_Bitmap::get_v_offset()
686         if(xv_image[0])
687                 return xv_image[current_ringbuffer]->offsets[1];
688         else
689                 return 0;
693 unsigned char** BC_Bitmap::get_row_pointers()
695         return row_data[current_ringbuffer];
698 int BC_Bitmap::get_bytes_per_line()
700         return bytes_per_line;
702 unsigned char* BC_Bitmap::get_data()
704 //printf("BC_Bitmap::get_data %d %p\n",current_ringbuffer , data[current_ringbuffer]);
705         return data[current_ringbuffer];
708 unsigned char* BC_Bitmap::get_y_plane()
710         if(color_model == BC_YUV420P ||
711                 color_model == BC_YUV422P)
712                 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[0];
713         else
714                 return 0;
717 unsigned char* BC_Bitmap::get_v_plane()
719         if(color_model == BC_YUV420P ||
720                 color_model == BC_YUV422P)
721                 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[1];
722         else
723                 return 0;
726 unsigned char* BC_Bitmap::get_u_plane()
728         if(color_model == BC_YUV420P ||
729                 color_model == BC_YUV422P)
730                 return data[current_ringbuffer] + xv_image[current_ringbuffer]->offsets[2];
731         else
732                 return 0;
735 void BC_Bitmap::rewind_ringbuffer()
737         current_ringbuffer--;
738         if(current_ringbuffer < 0) current_ringbuffer = ring_buffers - 1;
741 int BC_Bitmap::hardware_scaling()
743         return (get_color_model() == BC_YUV420P || 
744                 get_color_model() == BC_YUV422P || 
745                 get_color_model() == BC_YUV422);
748 int BC_Bitmap::get_w() { return w; }
750 int BC_Bitmap::get_h() { return h; }
752 int BC_Bitmap::get_color_model() { return color_model; }