#include "bcresources.h"
#include "bcwindowbase.h"
#include "bccmodels.h"
+#include "bccolors.h"
+#include "clip.h"
#include "language.h"
#include "vframe.h"
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xutil.h>
-
-
-
-
+#include <X11/extensions/Xfixes.h>
// Byte orders:
// 24 bpp packed: bgr
int BC_Capture::init_window(const char *display_path)
{
int bits_per_pixel;
- if(display_path && display_path[0] == 0) display_path = NULL;
- if((display = XOpenDisplay(display_path)) == NULL)
- {
+ if( display_path && display_path[0] == 0 ) display_path = NULL;
+ if( (display = XOpenDisplay(display_path)) == NULL ) {
printf(_("cannot connect to X server.\n"));
- if(getenv("DISPLAY") == NULL)
+ if( getenv("DISPLAY") == NULL )
printf(_("'DISPLAY' environment variable not set.\n"));
exit(-1);
return 1;
// test shared memory
// This doesn't ensure the X Server is on the local host
- if(use_shm && !XShmQueryExtension(display))
- {
+ if( use_shm && !XShmQueryExtension(display) ) {
use_shm = 0;
}
return 0;
int BC_Capture::allocate_data()
{
// try shared memory
- if(!display) return 1;
- if(use_shm)
- {
+ if( !display ) return 1;
+ if( use_shm ) {
ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
shm_info.shmid = shmget(IPC_PRIVATE, h * ximage->bytes_per_line, IPC_CREAT | 0600);
- if(shm_info.shmid == -1)
- {
+ if( shm_info.shmid == -1 ) {
perror("BC_Capture::allocate_data shmget");
abort();
}
BC_Resources::error = 0;
XShmAttach(display, &shm_info);
XSync(display, False);
- if(BC_Resources::error)
- {
+ if( BC_Resources::error ) {
XDestroyImage(ximage);
shmdt(shm_info.shmaddr);
use_shm = 0;
}
}
- if(!use_shm)
- {
+ if( !use_shm ) {
// need to use bytes_per_line for some X servers
data = 0;
ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
}
row_data = new unsigned char*[h];
- for(int i = 0; i < h; i++)
- {
+ for( int i = 0; i < h; i++ ) {
row_data[i] = &data[i * ximage->bytes_per_line];
}
// This differs from the depth parameter of the top_level.
int BC_Capture::delete_data()
{
- if(!display) return 1;
- if(data)
- {
- if(use_shm)
- {
+ if( !display ) return 1;
+ if( data ) {
+ if( use_shm ) {
XShmDetach(display, &shm_info);
XDestroyImage(ximage);
shmdt(shm_info.shmaddr);
}
- else
- {
+ else {
XDestroyImage(ximage);
}
int BC_Capture::get_h() { return h; }
// Capture a frame from the screen
-#define CAPTURE_FRAME_HEAD \
- for(int i = 0; i < h; i++) \
- { \
- unsigned char *input_row = row_data[i]; \
- unsigned char *output_row = (unsigned char*)frame->get_rows()[i]; \
- for(int j = 0; j < w; j++) \
- {
-
-#define CAPTURE_FRAME_TAIL \
- } \
- }
+#define RGB_TO_YUV(y, u, v, r, g, b) { \
+ YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \
+ bclamp(y, 0,0xff); bclamp(u, 0,0xff); bclamp(v, 0,0xff); }
-
-
-int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1)
+int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1,
+ int do_cursor) // the scale of the cursor if nonzero
{
- if(!display) return 1;
- if(x1 < 0) x1 = 0;
- if(y1 < 0) y1 = 0;
- if(x1 > get_top_w() - w) x1 = get_top_w() - w;
- if(y1 > get_top_h() - h) y1 = get_top_h() - h;
+ if( !display ) return 1;
+ if( x1 < 0 ) x1 = 0;
+ if( y1 < 0 ) y1 = 0;
+ if( x1 > get_top_w() - w ) x1 = get_top_w() - w;
+ if( y1 > get_top_h() - h ) y1 = get_top_h() - h;
// Read the raw data
- if(use_shm)
+ if( use_shm )
XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff);
else
XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0);
frame->get_w(), frame->get_h(),
bitmap_color_model, frame->get_color_model(),
0, frame->get_w(), w);
+
+ if( do_cursor ) {
+ XFixesCursorImage *cursor;
+ cursor = XFixesGetCursorImage(display);
+ if( cursor ) {
+//printf("BC_Capture::capture_frame %d cursor=%p colormodel=%d\n",
+// __LINE__, cursor, frame->get_color_model());
+ int scale = do_cursor;
+ int cursor_x = cursor->x - x1 - cursor->xhot * scale;
+ int cursor_y = cursor->y - y1 - cursor->yhot * scale;
+ int w = frame->get_w();
+ int h = frame->get_h();
+ for( int i = 0; i < cursor->height; i++ ) {
+ for( int yscale = 0; yscale < scale; yscale++ ) {
+ if( cursor_y + i * scale + yscale >= 0 &&
+ cursor_y + i * scale + yscale < h ) {
+ unsigned char *src = (unsigned char*)(cursor->pixels +
+ i * cursor->width);
+ int dst_y = cursor_y + i * scale + yscale;
+ int dst_x = cursor_x;
+ for( int j = 0; j < cursor->width; j++ ) {
+ for( int xscale = 0; xscale < scale ; xscale++ ) {
+ if( cursor_x + j * scale + xscale >= 0 &&
+ cursor_x + j * scale + xscale < w ) {
+ int a = src[3];
+ int invert_a = 0xff - a;
+ int r = src[2];
+ int g = src[1];
+ int b = src[0];
+ switch( frame->get_color_model() ) {
+ case BC_RGB888: {
+ unsigned char *dst = frame->get_rows()[dst_y] +
+ dst_x * 3;
+ dst[0] = (r * a + dst[0] * invert_a) / 0xff;
+ dst[1] = (g * a + dst[1] * invert_a) / 0xff;
+ dst[2] = (b * a + dst[2] * invert_a) / 0xff;
+ break; }
+
+ case BC_YUV420P: {
+ unsigned char *dst_y_ = frame->get_y() +
+ dst_y * w + dst_x;
+ unsigned char *dst_u = frame->get_u() +
+ (dst_y / 2) * (w / 2) + (dst_x / 2);
+ unsigned char *dst_v = frame->get_v() +
+ (dst_y / 2) * (w / 2) + (dst_x / 2);
+ int y, u, v;
+ RGB_TO_YUV(y, u, v, r, g, b);
+
+ *dst_y_ = (y * a + *dst_y_ * invert_a) / 0xff;
+ *dst_u = (u * a + *dst_u * invert_a) / 0xff;
+ *dst_v = (v * a + *dst_v * invert_a) / 0xff;
+ break; }
+ }
+ }
+ dst_x++;
+ }
+ src += sizeof(long);
+ }
+ }
+ }
+ }
+
+// This frees cursor->pixels
+ XFree(cursor);
+ }
+ }
return 0;
}