Add Windows native screen grabber, change UnixScreenCapture to NativeScreenCapture as file will be used for Linux, Windows and soon Mac OS X. Add the compiled JNI libraries for Linux (32 and 64-bit), FreeBSD (32 and 64-bit) and Windows (32 and 64-bit).

cusax-fix
Sebastien Vincent 17 years ago
parent 5b1ed4c3a8
commit 6d81880fcb

@ -4,17 +4,37 @@
# \author Sebastien Vincent
CC = gcc
CFLAGS = -std=c99 -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600 -Wall -Wextra -pedantic -Wstrict-prototypes -Wredundant-decls
# uncomment to compile on Linux
LDFLAGS =
CFLAGS += -fPIC
JNI_HEADERS = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
CFLAGS = -std=c99 -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600 -Wall -Wextra -pedantic -Wstrict-prototypes -Wredundant-decls $(JNI_HEADERS)
TARGET = libscreencapture.so
# uncomment to compile on Windows
#LDFLAGS = -lgdi32
#JNI_HEADERS = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/win32
#CFLAGS += -Wl,--kill-at
#TARGET = screencapture.dll
# uncomment to compile on FreeBSD
#CFLAGS += -fPIC -I/usr/local/include
#LDFLAGS =
#JNI_HEADERS = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/freebsd
#TARGET = libscreencapture.so
CFLAGS += $(JNI_HEADERS)
all: libscreencapture
libscreencapture: net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c
$(CC) -shared -fPIC $(CFLAGS) -o libscreencapture.so -O $<
libscreencapture: net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.c
$(CC) -shared $(CFLAGS) -o $(TARGET) -O $< $(LDFLAGS)
# To compile 32 bit library under 64 bit system
libscreencapture-32: net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c
$(CC) -shared -m32 $(CFLAGS) -o libscreencapture.so -O $<
# Note: On Windows, cross-compilation is supported from gcc-4.5
libscreencapture-32: net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.c
$(CC) -shared -m32 $(CFLAGS) -o $(TARGET) -O $< $(LDFLAGS)
clean:
rm -f *.o *.so
rm -f *.o *.so *.dll

@ -6,7 +6,7 @@
*/
/**
* \file net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c
* \file net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.c
* \brief X11 screen capture.
* \author Sebastien Vincent
* \date 2009
@ -14,6 +14,17 @@
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wingdi.h>
typedef __int32 int32_t;
#else /* Unix */
#include <stdint.h>
#include <sys/types.h>
@ -24,7 +35,166 @@
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include "net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h"
#endif
#include "net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture.h"
#if defined(_WIN32) || defined (_WIN64)
/**
* \brief Grab Windows screen.
* \param data array that will contain screen capture
* \param x x position to start capture
* \param y y position to start capture
* \param w capture width
* \param h capture height
* \return 0 if success, -1 otherwise
*/
static int windows_grab_screen(int32_t* data, int32_t x, int32_t y, int32_t w, int32_t h)
{
static const RGBQUAD redColor = {0x00, 0x00, 0xFF, 0x00};
static const RGBQUAD greenColor = {0x00, 0xFF, 0x00, 0x00};
static const RGBQUAD blueColor = {0xFF, 0x00, 0x00, 0x00};
HDC desktop = NULL;
HDC dest = NULL;
HBITMAP bitmap;
HBITMAP oldBitmap;
int width = 0;
int height = 0;
size_t size = 0;
BITMAPINFO* bitmap_info = NULL;
BITMAPINFOHEADER* bitmap_hdr = NULL;
RGBQUAD *pixels = NULL;
size_t i = 0;
/* get handle to the entire screen of Windows */
desktop = GetDC(NULL);
if(!desktop)
{
fprintf(stderr, "GetDC failed!\n");
return -1;
}
/* get resolution */
width = GetDeviceCaps(desktop, HORZRES);
height = GetDeviceCaps(desktop, VERTRES);
/* check that user-defined parameters are in image */
if((w + x) > width || (h + y) > height)
{
ReleaseDC(NULL, desktop);
return -1;
}
size = w * h;
/* fprintf(stderr, "Resolution: %dx%d\n", width, height); */
dest = CreateCompatibleDC(desktop);
if(!dest)
{
fprintf(stderr, "CreateCompatibleDC failed!\n");
ReleaseDC(NULL, desktop);
return -1;
}
bitmap = CreateCompatibleBitmap(desktop, width, height);
if(!bitmap)
{
fprintf(stderr, "CreateCompatibleBitmap failed!\n");
ReleaseDC(NULL, desktop);
return -1;
}
/* select bitmap to be used by DC */
oldBitmap = SelectObject(dest, bitmap);
if(BitBlt(dest, 0, 0, w, h, desktop, x, y, SRCCOPY | CAPTUREBLT) == FALSE)
{
fprintf(stderr, "BitBlt failed\n");
SelectObject(dest, oldBitmap); /* restore old state before delete */
DeleteDC(dest);
DeleteObject(bitmap);
ReleaseDC(NULL, desktop);
return -1;
}
/* allocate memory for bitmap header, it consists
* of header size and the uncompressed pixels
* GetDiBits with BI_BITFIELDS requires array of 3 RBGQUAD
* structures and BITMAPINFO structure has just one allocated
* RGBQUAD array
*/
bitmap_info = malloc(sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD) + (size * 4));
if(!bitmap_info)
{
fprintf(stderr, "malloc failed\n");
SelectObject(dest, oldBitmap); /* restore old state before delete */
DeleteDC(dest);
DeleteObject(bitmap);
ReleaseDC(NULL, desktop);
return -1;
}
bitmap_hdr = &bitmap_info->bmiHeader;
bitmap_hdr->biSize = sizeof(BITMAPINFOHEADER);
bitmap_hdr->biWidth = w;
bitmap_hdr->biHeight = -h; /* otherwise inverse screen */
bitmap_hdr->biPlanes = 1;
bitmap_hdr->biCompression = BI_BITFIELDS;
bitmap_hdr->biBitCount = 32;
bitmap_hdr->biSizeImage = 0;
bitmap_hdr->biXPelsPerMeter = 0;
bitmap_hdr->biYPelsPerMeter = 0;
bitmap_hdr->biClrImportant = 0;
bitmap_hdr->biClrUsed = 0;
/* set up color */
/* red */
bitmap_info->bmiColors[0] = redColor;
/* green */
bitmap_info->bmiColors[1] = greenColor;
/* blue */
bitmap_info->bmiColors[2] = blueColor;
/* first data pixel begins after the array of color mask */
pixels = &bitmap_info->bmiColors[2];
pixels++;
/* get raw bytes */
if(GetDIBits(dest, bitmap, 0, height, pixels, bitmap_info, DIB_RGB_COLORS) == 0)
{
fprintf(stderr, "GetDIBits failed!\n");
free(bitmap_info);
SelectObject(dest, oldBitmap); /* restore old state before delete */
DeleteDC(dest);
DeleteObject(bitmap);
ReleaseDC(NULL, desktop);
return -1;
}
for(i = 0 ; i < size ; i++)
{
RGBQUAD* pixel = &pixels[i];
data[i] = 0xFF000000 | pixel->rgbRed << 16 | pixel->rgbGreen << 8 | pixel->rgbBlue;
}
/* cleanup */
free(bitmap_info);
SelectObject(dest, oldBitmap); /* restore old state before delete */
DeleteDC(dest);
DeleteObject(bitmap);
ReleaseDC(NULL, desktop);
return 0;
}
#else /* Unix */
/**
* \brief Grab X11 screen.
@ -190,18 +360,20 @@ static int x11_grab_screen(const char* x11display, int32_t* data, int32_t x, int
return 0;
}
#endif
/**
* \brief JNI native method to grab desktop screen and retrieve ARGB pixels.
* \param env JVM environment
* \param obj UnixScreenCapture Java object
* \param obj NativeScreenCapture Java class
* \param x x position to start capture
* \param y y position to start capture
* \param width capture width
* \param height capture height
* \return array of ARGB pixels (jint)
*/
JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture_grabScreen
(JNIEnv* env, jobject obj, jint x, jint y, jint width, jint height)
JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen
(JNIEnv* env, jclass obj, jint x, jint y, jint width, jint height)
{
int32_t* data = NULL; /* jint is always four-bytes signed integer */
size_t size = width * height;
@ -223,7 +395,11 @@ JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstre
return NULL;
}
#if defined (_WIN32) || defined(_WIN64)
if(windows_grab_screen(data, x, y, width, height) == -1)
#else /* Unix */
if(x11_grab_screen(NULL, data, x, y, width, height) == -1)
#endif
{
(*env)->ReleaseIntArrayElements(env, ret, data, 0);
return NULL;

@ -1,18 +1,18 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture */
/* Header for class net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture */
#ifndef _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture
#define _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture
#ifndef _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture
#define _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture
* Class: net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture
* Method: grabScreen
* Signature: (IIII)[I
*/
JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture_grabScreen
JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen
(JNIEnv *, jclass, jint, jint, jint, jint);
#ifdef __cplusplus

@ -74,9 +74,9 @@ public BufferedImage captureScreen(int x, int y, int width, int height)
BufferedImage img = null;
Rectangle rect = null;
if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD)
if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS)
{
return UnixScreenCapture.captureScreen(x, y, width, height);
return NativeScreenCapture.captureScreen(x, y, width, height);
}
else
{

@ -10,13 +10,12 @@
/**
* This class uses native code to capture
* desktop screen.
*
* It should work on all OS with underlying X11.
* desktop screen. It should work for Windows and
* X11-based Unix such as Linux and FreeBSD.
*
* @author Sebastien Vincent
*/
public class UnixScreenCapture
public class NativeScreenCapture
{
static
{
@ -38,8 +37,8 @@ public static BufferedImage captureScreen(int x,
int height)
{
DirectColorModel model
= new DirectColorModel(24, 0xFF0000, 0x00FF00, 0xFF);
int masks[] = {0xFF0000, 0xFF00, 0xFF};
= new DirectColorModel(32, 0xFF0000, 0x00FF00, 0xFF, 0xFF000000);
int masks[] = {0xFF0000, 0xFF00, 0xFF, 0xFF000000};
WritableRaster raster = null;
DataBufferInt buffer = null;
BufferedImage image = null;

@ -180,13 +180,26 @@ public void run()
/* get desktop screen and resize it */
screen = desktopInteract.captureScreen();
scaledScreen
= ImageStreamingUtils
.getScaledImage(
screen,
width,
height,
BufferedImage.TYPE_INT_ARGB);
if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS)
{
/* with our native screencapture we
* automatically create BufferedImage in
* ARGB format so no need to rescale/convert
* to ARGB
*/
scaledScreen = screen;
}
else
{
scaledScreen
= ImageStreamingUtils
.getScaledImage(
screen,
width,
height,
BufferedImage.TYPE_INT_ARGB);
}
/* get raw bytes */
data = ImageStreamingUtils.getImageBytes(scaledScreen);

Loading…
Cancel
Save