add binfolder path relative filters, fix gbrp color model, vwdw timebar tweaks, title...
[goodguy/history.git] / cinelerra-5.1 / guicast / bccapture.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bccapture.h"
23 #include "bcresources.h"
24 #include "bcwindowbase.h"
25 #include "bccmodels.h"
26 #include "bccolors.h"
27 #include "clip.h"
28 #include "language.h"
29 #include "vframe.h"
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <X11/Xutil.h>
33 #include <X11/extensions/Xfixes.h>
34
35 // Byte orders:
36 // 24 bpp packed:         bgr
37 // 24 bpp unpacked:       0bgr
38
39
40 BC_Capture::BC_Capture(int w, int h, const char *display_path)
41 {
42         this->w = w;
43         this->h = h;
44
45         data = 0;
46         use_shm = 1;
47         init_window(display_path);
48         allocate_data();
49 }
50
51
52 BC_Capture::~BC_Capture()
53 {
54         delete_data();
55         XCloseDisplay(display);
56 }
57
58 int BC_Capture::init_window(const char *display_path)
59 {
60         int bits_per_pixel;
61         if( display_path && display_path[0] == 0 ) display_path = NULL;
62         if( (display = XOpenDisplay(display_path)) == NULL ) {
63                 printf(_("cannot connect to X server.\n"));
64                 if( getenv("DISPLAY") == NULL )
65                 printf(_("'DISPLAY' environment variable not set.\n"));
66                 exit(-1);
67                 return 1;
68         }
69
70         screen = DefaultScreen(display);
71         rootwin = RootWindow(display, screen);
72         vis = DefaultVisual(display, screen);
73         default_depth = DefaultDepth(display, screen);
74         client_byte_order = (*(const u_int32_t*)"a   ") & 0x00000001;
75         server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
76         char *data = 0;
77         XImage *ximage;
78         ximage = XCreateImage(display,
79                                         vis,
80                                         default_depth,
81                                         ZPixmap,
82                                         0,
83                                         data,
84                                         16,
85                                         16,
86                                         8,
87                                         0);
88         bits_per_pixel = ximage->bits_per_pixel;
89         XDestroyImage(ximage);
90         bitmap_color_model = BC_WindowBase::evaluate_color_model(client_byte_order, server_byte_order, bits_per_pixel);
91
92 // test shared memory
93 // This doesn't ensure the X Server is on the local host
94     if( use_shm && !XShmQueryExtension(display) ) {
95         use_shm = 0;
96     }
97         return 0;
98 }
99
100
101 int BC_Capture::allocate_data()
102 {
103 // try shared memory
104         if( !display ) return 1;
105     if( use_shm ) {
106             ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
107
108                 shm_info.shmid = shmget(IPC_PRIVATE, h * ximage->bytes_per_line, IPC_CREAT | 0600);
109                 if( shm_info.shmid == -1 ) {
110                         perror("BC_Capture::allocate_data shmget");
111                         abort();
112                 }
113                 data = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
114                 shmctl(shm_info.shmid, IPC_RMID, 0);
115                 ximage->data = shm_info.shmaddr = (char*)data;  // setting ximage->data stops BadValue
116                 shm_info.readOnly = 0;
117
118 // Crashes here if remote server.
119                 BC_Resources::error = 0;
120                 XShmAttach(display, &shm_info);
121         XSync(display, False);
122                 if( BC_Resources::error ) {
123                         XDestroyImage(ximage);
124                         shmdt(shm_info.shmaddr);
125                         use_shm = 0;
126                 }
127         }
128
129         if( !use_shm ) {
130 // need to use bytes_per_line for some X servers
131                 data = 0;
132                 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
133                 data = (unsigned char*)malloc(h * ximage->bytes_per_line);
134                 XDestroyImage(ximage);
135
136                 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
137         }
138
139         row_data = new unsigned char*[h];
140         for( int i = 0; i < h; i++ ) {
141                 row_data[i] = &data[i * ximage->bytes_per_line];
142         }
143 // This differs from the depth parameter of the top_level.
144         bits_per_pixel = ximage->bits_per_pixel;
145         return 0;
146 }
147
148 int BC_Capture::delete_data()
149 {
150         if( !display ) return 1;
151         if( data ) {
152                 if( use_shm ) {
153                         XShmDetach(display, &shm_info);
154                         XDestroyImage(ximage);
155                         shmdt(shm_info.shmaddr);
156                 }
157                 else {
158                         XDestroyImage(ximage);
159                 }
160
161 // data is automatically freed by XDestroyImage
162                 data = 0;
163                 delete [] row_data;
164         }
165         return 0;
166 }
167
168
169 int BC_Capture::get_w() { return w; }
170 int BC_Capture::get_h() { return h; }
171
172 // Capture a frame from the screen
173 #define RGB_TO_YUV(y, u, v, r, g, b) { \
174  YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \
175  bclamp(y, 0,0xff); bclamp(u, 0,0xff); bclamp(v, 0,0xff); }
176
177 int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1, 
178         int do_cursor) // the scale of the cursor if nonzero
179 {
180         if( !display ) return 1;
181         if( x1 < 0 ) x1 = 0;
182         if( y1 < 0 ) y1 = 0;
183         if( x1 > get_top_w() - w ) x1 = get_top_w() - w;
184         if( y1 > get_top_h() - h ) y1 = get_top_h() - h;
185
186
187 // Read the raw data
188         if( use_shm )
189                 XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff);
190         else
191                 XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0);
192
193         BC_CModels::transfer(frame->get_rows(), row_data,
194                 frame->get_y(), frame->get_u(), frame->get_v(), 0,
195                 0, 0, 0, 0, w, h, 0, 0,
196                 frame->get_w(), frame->get_h(),
197                 bitmap_color_model, frame->get_color_model(),
198                 0, frame->get_w(), w);
199         
200         if( do_cursor ) {
201                 XFixesCursorImage *cursor;
202                 cursor = XFixesGetCursorImage(display);
203                 if( cursor ) {
204 //printf("BC_Capture::capture_frame %d cursor=%p colormodel=%d\n", 
205 // __LINE__, cursor, frame->get_color_model());
206                         int scale = do_cursor;
207                         int cursor_x = cursor->x - x1 - cursor->xhot * scale;
208                         int cursor_y = cursor->y - y1 - cursor->yhot * scale;
209                         int w = frame->get_w();
210                         int h = frame->get_h();
211                         for( int i = 0; i < cursor->height; i++ ) {
212                                 for( int yscale = 0; yscale < scale; yscale++ ) {
213                                         if( cursor_y + i * scale + yscale >= 0 && 
214                                                 cursor_y + i * scale + yscale < h ) {
215                                                 unsigned char *src = (unsigned char*)(cursor->pixels + 
216                                                         i * cursor->width);
217                                                 int dst_y = cursor_y + i * scale + yscale;
218                                                 int dst_x = cursor_x;
219                                                 for( int j = 0; j < cursor->width; j++ ) {
220                                                         for( int xscale = 0; xscale < scale ; xscale++ ) {
221                                                                 if( cursor_x + j * scale + xscale >= 0 && 
222                                                                         cursor_x + j * scale + xscale < w ) {
223                                                                         int a = src[3];
224                                                                         int invert_a = 0xff - a;
225                                                                         int r = src[2];
226                                                                         int g = src[1];
227                                                                         int b = src[0];
228                                                                         switch( frame->get_color_model() ) {
229                                                                         case BC_RGB888: {
230                                                                                 unsigned char *dst = frame->get_rows()[dst_y] +
231                                                                                         dst_x * 3;
232                                                                                 dst[0] = (r * a + dst[0] * invert_a) / 0xff;
233                                                                                 dst[1] = (g * a + dst[1] * invert_a) / 0xff;
234                                                                                 dst[2] = (b * a + dst[2] * invert_a) / 0xff;
235                                                                                 break; }
236
237                                                                         case BC_YUV420P: {
238                                                                                 unsigned char *dst_y_ = frame->get_y() + 
239                                                                                         dst_y * w + dst_x;
240                                                                                 unsigned char *dst_u = frame->get_u() + 
241                                                                                         (dst_y / 2) * (w / 2) + (dst_x / 2);
242                                                                                 unsigned char *dst_v = frame->get_v() + 
243                                                                                         (dst_y / 2) * (w / 2) + (dst_x / 2);
244                                                                                 int y, u, v;
245                                                                                 RGB_TO_YUV(y, u, v, r, g, b);
246                                                                                         
247                                                                                 *dst_y_ = (y * a + *dst_y_ * invert_a) / 0xff;
248                                                                                 *dst_u = (u * a + *dst_u * invert_a) / 0xff;
249                                                                                 *dst_v = (v * a + *dst_v * invert_a) / 0xff;
250                                                                                 break; }
251                                                                         }
252                                                                 }
253                                                                 dst_x++;
254                                                         }
255                                                         src += sizeof(long);
256                                                 }
257                                         }
258                                 }
259                         }
260
261 // This frees cursor->pixels
262                         XFree(cursor);
263                 }
264         }
265
266         return 0;
267 }
268
269 int BC_Capture::get_top_w()
270 {
271         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
272         return WidthOfScreen(screen_ptr);
273 }
274
275 int BC_Capture::get_top_h()
276 {
277         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
278         return HeightOfScreen(screen_ptr);
279 }