From 9f44c4f923324dfcf094d2781ad3806ee9db7d8e Mon Sep 17 00:00:00 2001 From: Sebastien Vincent Date: Wed, 16 Dec 2009 07:55:05 +0000 Subject: [PATCH] Add native X11 screen capture. --- lib/native/linux-64/libscreencapture.so | Bin 0 -> 9248 bytes lib/native/linux/libscreencapture.so | Bin 0 -> 6405 bytes src/native/linux/screencapture/Makefile | 21 ++ ..._neomedia_imgstreaming_UnixScreenCapture.c | 218 ++++++++++++++++++ ..._neomedia_imgstreaming_UnixScreenCapture.h | 21 ++ ...ractImpl.java => DesktopInteractImpl.java} | 61 +++-- .../imgstreaming/UnixScreenCapture.java | 70 ++++++ .../protocol/imgstreaming/ImageStream.java | 127 +++++----- 8 files changed, 417 insertions(+), 101 deletions(-) create mode 100755 lib/native/linux-64/libscreencapture.so create mode 100755 lib/native/linux/libscreencapture.so create mode 100644 src/native/linux/screencapture/Makefile create mode 100644 src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c create mode 100644 src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h rename src/net/java/sip/communicator/impl/neomedia/imgstreaming/{RobotDesktopInteractImpl.java => DesktopInteractImpl.java} (71%) create mode 100644 src/net/java/sip/communicator/impl/neomedia/imgstreaming/UnixScreenCapture.java diff --git a/lib/native/linux-64/libscreencapture.so b/lib/native/linux-64/libscreencapture.so new file mode 100755 index 0000000000000000000000000000000000000000..8cbebc740036d108bde885b86deb7accf4e1e5b2 GIT binary patch literal 9248 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 literal 0 HcmV?d00001 diff --git a/lib/native/linux/libscreencapture.so b/lib/native/linux/libscreencapture.so new file mode 100755 index 0000000000000000000000000000000000000000..5ca0f239016c767f0bd155c34fbb1babe2880c9c GIT binary patch literal 6405 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 IjO8W&-+s*pZU6uP literal 0 HcmV?d00001 diff --git a/src/native/linux/screencapture/Makefile b/src/native/linux/screencapture/Makefile new file mode 100644 index 000000000..bddbb7ec3 --- /dev/null +++ b/src/native/linux/screencapture/Makefile @@ -0,0 +1,21 @@ +## +# \file Makefile +# \brief libscreencapture makefile. +# \author Sebastien Vincent + +CC = gcc +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) + +all: libscreencapture + +libscreencapture: net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c + $(CC) -shared -fPIC $(CFLAGS) -o libscreencapture.so -O $< + +# 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 $< + +clean: + rm -f *.o *.so + diff --git a/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c b/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c new file mode 100644 index 000000000..088632960 --- /dev/null +++ b/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c @@ -0,0 +1,218 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +/** + * \file net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.c + * \brief X11 screen capture. + * \author Sebastien Vincent + * \date 2009 + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h" + +/** + * \brief Grab X11 screen. + * \param x11display display string (i.e. :0.0), if NULL getenv("DISPLAY") is used + * \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 integers which will contains screen capture + * (ARGB format) or NULL if failure. This parameter needs to be freed by caller + */ +static int32_t* grab_screen(const char* x11display, int32_t x, int32_t y, int32_t w, int32_t h) +{ + const char* display_str; /* display string */ + Display* display = NULL; /* X11 display */ + Visual* visual = NULL; + int screen = 0; /* X11 screen */ + Window root_window = 0; /* X11 root window of a screen */ + int width = 0; + int height = 0; + int depth = 0; + int shm_support = 0; + XImage* img = NULL; + XShmSegmentInfo shm_info; + int32_t* data = NULL; + size_t off = 0; + int i = 0; + int j = 0; + size_t size = 0; + + display_str = x11display ? x11display : getenv("DISPLAY"); + + if(!display_str) + { + /* fprintf(stderr, "No display!\n"); */ + return NULL; + } + + /* open current X11 display */ + display = XOpenDisplay(display_str); + + if(!display) + { + /* fprintf(stderr, "Cannot open X11 display!\n"); */ + return NULL; + } + + screen = DefaultScreen(display); + root_window = RootWindow(display, screen); + visual = DefaultVisual(display, screen); + width = DisplayWidth(display, screen); + height = DisplayHeight(display, screen); + depth = DefaultDepth(display, screen); + + /* check that user-defined parameters are in image */ + if((w + x) > width || (h + y) > height) + { + XCloseDisplay(display); + return NULL; + } + + size = w * h; + + /* test is XServer support SHM */ + shm_support = XShmQueryExtension(display); + + /* fprintf(stdout, "Display=%s width=%d height=%d depth=%d SHM=%s\n", display_str, width, height, depth, shm_support ? "true" : "false"); */ + + if(shm_support) + { + /* fprintf(stdout, "Use XShmGetImage\n"); */ + + /* create image for SHM use */ + img = XShmCreateImage(display, visual, depth, ZPixmap, NULL, &shm_info, w, h); + + if(!img) + { + /* fprintf(stderr, "Image cannot be created!\n"); */ + XCloseDisplay(display); + return NULL; + } + + /* setup SHM stuff */ + shm_info.shmid = shmget(IPC_PRIVATE, img->bytes_per_line * img->height, IPC_CREAT | 0777); + shm_info.shmaddr = (char*)shmat(shm_info.shmid, NULL, 0); + img->data = shm_info.shmaddr; + shmctl(shm_info.shmid, IPC_RMID, NULL); + shm_info.readOnly = 0; + + if((shm_info.shmaddr == (void*)-1) || !XShmAttach(display, &shm_info)) + { + /* fprintf(stderr, "Cannot use shared memory!\n"); */ + XCloseDisplay(display); + return NULL; + } + + /* grab screen */ + if(!XShmGetImage(display, root_window, img, x, y, 0xffffffff)) + { + /* fprintf(stderr, "Cannot grab image!\n"); */ + XShmDetach(display, &shm_info); + shmdt(shm_info.shmaddr); + XCloseDisplay(display); + return NULL; + } + } + else + { + /* fprintf(stdout, "Use XGetImage\n"); */ + /* no SHM */ + img = XGetImage(display, root_window, x, y, w, h, 0xffffffff, ZPixmap); + + if(!img) + { + /* fprintf(stderr, "Cannot grab image!\n"); */ + XCloseDisplay(display); + return NULL; + } + } + + data = malloc(sizeof(int32_t) * size); + + if(!data) + { + XDestroyImage(img); + + if(shm_support) + { + XShmDetach(display, &shm_info); + shmdt(shm_info.shmaddr); + } + + XCloseDisplay(display); + return NULL; + } + + /* convert to Java ARGB */ + for(j = 0 ; j < h ; j++) + { + for(i = 0 ; i < w ; i++) + { + /* do not care about hight 32-bit for 64 bit host + * (sizeof(long) = 8 on 64 bit Linux host) + */ + unsigned int pixel = (unsigned int)XGetPixel(img, i, j); + + pixel |= 0xff000000; /* ARGB */ + data[off++] = pixel; + } + } + + /* free X11 resources and close display */ + XDestroyImage(img); + + if(shm_support) + { + XShmDetach(display, &shm_info); + shmdt(shm_info.shmaddr); + } + + XCloseDisplay(display); + + /* return array */ + return data; +} + +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) +{ + int32_t* data = NULL; /* jint is always four-bytes signed integer */ + size_t size = width * height; + jintArray ret = NULL; + + obj = obj; /* not used */ + + data = grab_screen(NULL, x, y, width, height); + + if(!data) + { + return 0; + } + + ret = (*env)->NewIntArray(env, size); + + /* updates array with data's content */ + (*env)->SetIntArrayRegion(env, ret, 0, size, data); + free(data); + + return ret; +} + diff --git a/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h b/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h new file mode 100644 index 000000000..7f6cce8cf --- /dev/null +++ b/src/native/linux/screencapture/net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture */ + +#ifndef _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture +#define _Included_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture + * Method: grabScreen + * Signature: (IIII)[I + */ +JNIEXPORT jintArray JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_UnixScreenCapture_grabScreen + (JNIEnv *, jclass, jint, jint, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/RobotDesktopInteractImpl.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java similarity index 71% rename from src/net/java/sip/communicator/impl/neomedia/imgstreaming/RobotDesktopInteractImpl.java rename to src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java index f9513bbd5..67e427d32 100644 --- a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/RobotDesktopInteractImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/DesktopInteractImpl.java @@ -13,18 +13,18 @@ /** * This singleton class provide screen capture and key/mouse - * events generation by wrapping java.awt.Robot - * to interact with desktop. + * events generation by wrapping partial or all java.awt.Robot + * methods to interact with desktop. * * @see java.awt.Robot * @author Sebastien Vincent */ -public class RobotDesktopInteractImpl implements DesktopInteract +public class DesktopInteractImpl implements DesktopInteract { /** * The Logger. */ - private static final Logger logger = Logger.getLogger(RobotDesktopInteractImpl.class); + private static final Logger logger = Logger.getLogger(DesktopInteractImpl.class); /** * Screen capture robot. @@ -34,31 +34,17 @@ public class RobotDesktopInteractImpl implements DesktopInteract /** * The unique instance of this class (singleton). */ - private static RobotDesktopInteractImpl instance = null; + private static DesktopInteractImpl instance = null; /** * Constructor. - */ - private RobotDesktopInteractImpl() - { - } - - /** - * Get the unique instance of RobotDesktopInteractImpl. - * - * @return instance + * * @throws AWTException if platform configuration does not allow low-level input control * @throws SecurityException if Robot creation is not permitted */ - public static RobotDesktopInteractImpl getInstance() throws AWTException, SecurityException + public DesktopInteractImpl() throws AWTException, SecurityException { - if(instance == null) - { - instance = new RobotDesktopInteractImpl(); - instance.robot = new Robot(); - } - - return instance; + robot = new Robot(); } /** @@ -76,6 +62,10 @@ public BufferedImage captureScreen() /** * Capture a part of the desktop screen. * + * @param x x position to start capture + * @param y y position to start capture + * @param width capture width + * @param height capture height * @return BufferedImage of a part of the desktop screen * or null if Robot problem */ @@ -83,18 +73,25 @@ public BufferedImage captureScreen(int x, int y, int width, int height) { BufferedImage img = null; Rectangle rect = null; - - /* Robot has not been created so abort */ - if(robot == null) + + if(OSUtils.IS_LINUX) { - return null; + return UnixScreenCapture.captureScreen(x, y, width, height); + } + else + { + /* Robot has not been created so abort */ + if(robot == null) + { + return null; + } + + logger.info("Begin capture: " + System.nanoTime()); + rect = new Rectangle(x, y, width, height); + img = robot.createScreenCapture(rect); + logger.info("End capture: " + System.nanoTime()); + return img; } - - logger.info("Begin capture: " + System.nanoTime()); - rect = new Rectangle(x, y, width, height); - img = robot.createScreenCapture(rect); - logger.info("End capture: " + System.nanoTime()); - return img; } /** diff --git a/src/net/java/sip/communicator/impl/neomedia/imgstreaming/UnixScreenCapture.java b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/UnixScreenCapture.java new file mode 100644 index 000000000..c4c9611c9 --- /dev/null +++ b/src/net/java/sip/communicator/impl/neomedia/imgstreaming/UnixScreenCapture.java @@ -0,0 +1,70 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.neomedia.imgstreaming; + +import java.awt.*; +import java.awt.image.*; + +/** + * This class uses native code to capture + * desktop screen. + * + * It should work on all OS with underlying X11. + * + * @author Sebastien Vincent + */ +public class UnixScreenCapture +{ + static + { + System.loadLibrary("screencapture"); + } + + /** + * Capture desktop screen. + * + * @param x x position to start capture + * @param y y position to start capture + * @param width capture width + * @param height capture height + * @return BufferedImage of the desktop screen + */ + public static BufferedImage captureScreen(int x, int y, int width, int height) + { + DirectColorModel model = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0xFF); + int masks[] = {0xFF0000, 0xFF00, 0xFF}; + WritableRaster raster = null; + DataBufferInt buffer = null; + BufferedImage image = null; + int data[] = null; + + data = grabScreen(x, y, width, height); + + if(data == null) + { + return null; + } + + buffer = new DataBufferInt(data, data.length); + raster = Raster.createPackedRaster(buffer, width, height, width, masks, null); + image = new BufferedImage(model, raster, false, null); + + return image; + } + + /** + * Grab desktop screen and get ARGB pixels. + * + * @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 + */ + private static native int[] grabScreen(int x, int y, int width, int height); +} + diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java index 245bdc7d2..978b59595 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/imgstreaming/ImageStream.java @@ -78,6 +78,11 @@ public class ImageStream implements PushBufferStream, Runnable */ private RingBuffer ringBuffer = null; + /** + * Destkop interaction (screen capture, key press, ...). + */ + private DesktopInteract desktopInteract = null; + /** * Constructor. */ @@ -276,91 +281,75 @@ public void run() final RGBFormat format = (RGBFormat)currentFormat; final int width = (int)format.getSize().getWidth(); final int height = (int)format.getSize().getHeight(); - BufferedImage scaledScreen = null; - BufferedImage screen = null; Buffer buffer = new Buffer(); - byte data[] = null; - - /* capture first full desktop screen - try - { - screen = RobotDesktopInteractImpl.getInstance().captureScreen(); - scaledScreen = ImageStreamingUtils.getScaledImage(screen, - width, height, BufferedImage.TYPE_INT_ARGB); - } - catch(Exception e) - { - } - screen = null; - */ -/* - synchronized(this) + if(desktopInteract == null) { - while(transferHandler == null && started) + try { - try - { - wait(1000); - } - catch (InterruptedException e) - { - } + desktopInteract = new DesktopInteractImpl(); + } + catch(Exception e) + { + logger.warn("Cannot create DesktopInteract object!"); + started = false; + return; } } -*/ + while(started) { - try - { - long t = System.nanoTime(); + byte data[] = null; + BufferedImage scaledScreen = null; + BufferedImage screen = null; + + long t = System.nanoTime(); - /* get desktop screen and resize it */ - screen = RobotDesktopInteractImpl.getInstance().captureScreen(); - scaledScreen = ImageStreamingUtils.getScaledImage(screen, + /* get desktop screen and resize it */ + screen = desktopInteract.captureScreen(); + scaledScreen = ImageStreamingUtils.getScaledImage(screen, width, height, BufferedImage.TYPE_INT_ARGB); - /* get raw bytes */ - data = ImageStreamingUtils.getImageByte(scaledScreen); - - /* add it to a RingBuffer and notify JMF that new data - * is available - */ - buffer.setData(data); - buffer.setOffset(0); - buffer.setLength(data.length); - buffer.setFormat(currentFormat); - buffer.setHeader(null); - buffer.setTimeStamp(System.nanoTime()); - buffer.setSequenceNumber(seqNo); - buffer.setFlags(Buffer.FLAG_LIVE_DATA | Buffer.FLAG_SYSTEM_TIME); - seqNo++; - - ringBuffer.put(buffer); - - /* pass to JMF handler */ - if(transferHandler != null) - { - transferHandler.transferData(this); - } - - t = System.nanoTime() - t; - logger.info("Desktop capture processing time: " + t); - - /* cleanup */ - screen = null; - scaledScreen = null; - data = null; + /* get raw bytes */ + data = ImageStreamingUtils.getImageByte(scaledScreen); + + /* add it to a RingBuffer and notify JMF that new data + * is available + */ + buffer.setData(data); + buffer.setOffset(0); + buffer.setLength(data.length); + buffer.setFormat(currentFormat); + buffer.setHeader(null); + buffer.setTimeStamp(System.nanoTime()); + buffer.setSequenceNumber(seqNo); + buffer.setFlags(Buffer.FLAG_LIVE_DATA | Buffer.FLAG_SYSTEM_TIME); + seqNo++; + ringBuffer.put(buffer); + + /* pass to JMF handler */ + if(transferHandler != null) + { + transferHandler.transferData(this); + } + + t = System.nanoTime() - t; + logger.info("Desktop capture processing time: " + t); + + /* cleanup */ + screen = null; + scaledScreen = null; + data = null; + + try + { /* 500 ms */ Thread.sleep(500); - } - catch(AWTException ae) - { - logger.warn("Desktop capture failed!"); } - catch (InterruptedException e) + catch(InterruptedException e) { + /* do nothing */ } }