4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bccapture.h"
23 #include "bcresources.h"
24 #include "bcwindowbase.h"
25 #include "bccmodels.h"
32 #include <X11/Xutil.h>
33 #include <X11/extensions/Xfixes.h>
37 // 24 bpp unpacked: 0bgr
40 BC_Capture::BC_Capture(int w, int h, const char *display_path)
47 init_window(display_path);
52 BC_Capture::~BC_Capture()
55 XCloseDisplay(display);
58 int BC_Capture::init_window(const char *display_path)
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"));
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;
78 ximage = XCreateImage(display,
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);
93 // This doesn't ensure the X Server is on the local host
94 if( use_shm && !XShmQueryExtension(display) ) {
101 int BC_Capture::allocate_data()
104 if( !display ) return 1;
106 ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
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");
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;
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);
130 // need to use bytes_per_line for some X servers
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);
136 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
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];
143 // This differs from the depth parameter of the top_level.
144 bits_per_pixel = ximage->bits_per_pixel;
148 int BC_Capture::delete_data()
150 if( !display ) return 1;
153 XShmDetach(display, &shm_info);
154 XDestroyImage(ximage);
155 shmdt(shm_info.shmaddr);
158 XDestroyImage(ximage);
161 // data is automatically freed by XDestroyImage
169 int BC_Capture::get_w() { return w; }
170 int BC_Capture::get_h() { return h; }
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); }
177 int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1,
178 int do_cursor) // the scale of the cursor if nonzero
180 if( !display ) return 1;
183 if( x1 > get_top_w() - w ) x1 = get_top_w() - w;
184 if( y1 > get_top_h() - h ) y1 = get_top_h() - h;
189 XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff);
191 XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0);
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);
201 XFixesCursorImage *cursor;
202 cursor = XFixesGetCursorImage(display);
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 +
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 ) {
224 int invert_a = 0xff - a;
228 switch( frame->get_color_model() ) {
230 unsigned char *dst = frame->get_rows()[dst_y] +
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;
238 unsigned char *dst_y_ = frame->get_y() +
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);
245 RGB_TO_YUV(y, u, v, r, g, b);
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;
261 // This frees cursor->pixels
269 int BC_Capture::get_top_w()
271 Screen *screen_ptr = XDefaultScreenOfDisplay(display);
272 return WidthOfScreen(screen_ptr);
275 int BC_Capture::get_top_h()
277 Screen *screen_ptr = XDefaultScreenOfDisplay(display);
278 return HeightOfScreen(screen_ptr);