mirror of
https://git.FreeBSD.org/ports.git
synced 2024-11-04 22:33:27 +00:00
de0b643f57
-current machine. Also I fixed the code for grabbing from the X11 desktop in 24 bit colour modes. Previously it gave us a blurred yellow image. Now it can capture the X11 desktop in full 24 bit colour for both XRGB and XBGR Truecolour.
1402 lines
38 KiB
Plaintext
1402 lines
38 KiB
Plaintext
--- grabber-x11.cc.orig Thu Sep 9 06:57:14 1999
|
|
+++ grabber-x11.cc Wed Sep 8 21:31:27 1999
|
|
@@ -0,0 +1,1398 @@
|
|
+/*
|
|
+ * Copyright (c) 1998 Luigi Rizzo
|
|
+ * grabber-x11.cc for vic
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Jim Lowe
|
|
+ * 4. The name of the author may not be used to endorse or promote products
|
|
+ * derived from this software without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
+ * POSSIBILITY OF SUCH DAMAGE.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/mman.h>
|
|
+
|
|
+#include "grabber.h"
|
|
+#include "Tcl.h"
|
|
+#include "device-input.h"
|
|
+#include "module.h"
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+#include <X11/Xutil.h>
|
|
+#include <X11/Xatom.h>
|
|
+#include <X11/cursorfont.h>
|
|
+#include <tk.h>
|
|
+/*** #include "sized_types.h" ***/
|
|
+
|
|
+/*
|
|
+ Netvideo version 3.3
|
|
+ Written by Ron Frederick <frederick@parc.xerox.com>
|
|
+
|
|
+ Machine-specific sized integer type definitions
|
|
+ Video utility definitions
|
|
+*/
|
|
+
|
|
+/*
|
|
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
|
|
+ *
|
|
+ * License is granted to copy, to use, and to make and to use derivative
|
|
+ * works for research and evaluation purposes, provided that Xerox is
|
|
+ * acknowledged in all documentation pertaining to any such copy or derivative
|
|
+ * work. Xerox grants no other licenses expressed or implied. The Xerox trade
|
|
+ * name should not be used in any advertising without its written permission.
|
|
+ *
|
|
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
|
|
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
|
|
+ * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
|
|
+ * express or implied warranty of any kind.
|
|
+ *
|
|
+ * These notices must be retained in any copies of any part of this software.
|
|
+ */
|
|
+
|
|
+typedef signed char int8; /* 8 bit signed int */
|
|
+typedef short int16; /* 16 bit signed int */
|
|
+typedef int int32; /* 32 bit signed int */
|
|
+#if defined(__alpha)
|
|
+typedef long int64; /* 64 bit signed int */
|
|
+#endif
|
|
+
|
|
+typedef unsigned char uint8; /* 8 bit unsigned int */
|
|
+typedef unsigned short uint16; /* 16 bit unsigned int */
|
|
+typedef unsigned int uint32; /* 32 bit unsigned int */
|
|
+#if defined(__alpha)
|
|
+typedef unsigned long uint64; /* 64 bit unsigned int */
|
|
+#endif
|
|
+
|
|
+/* Mildly gross but moderately portable test for littleendian machines */
|
|
+#define LITTLEENDIAN (ntohl(0x12345678) != 0x12345678)
|
|
+
|
|
+typedef struct {
|
|
+ XImage *image;
|
|
+ void *shminfo;
|
|
+} ximage_t;
|
|
+
|
|
+/*************************/
|
|
+
|
|
+#define VID_SMALL 0x01
|
|
+#define VID_MEDIUM 0x02
|
|
+#define VID_LARGE 0x04
|
|
+#define VID_SIZEMASK 0x07
|
|
+
|
|
+#define VID_GREYSCALE 0x08
|
|
+#define VID_COLOR 0x10
|
|
+
|
|
+#define X11GRAB_FIXED 0
|
|
+#define X11GRAB_POINTER 1
|
|
+#define X11GRAB_WINDOW 2
|
|
+
|
|
+
|
|
+/*XXX*/
|
|
+#define NTSC_WIDTH 320
|
|
+#define NTSC_HEIGHT 240
|
|
+#define PAL_WIDTH 384
|
|
+#define PAL_HEIGHT 288
|
|
+#define CIF_WIDTH 352
|
|
+#define CIF_HEIGHT 288
|
|
+
|
|
+
|
|
+class X11Grabber : public Grabber {
|
|
+ public:
|
|
+ X11Grabber(const char* name, const char* format);
|
|
+ virtual ~X11Grabber();
|
|
+ virtual void start();
|
|
+ virtual void stop();
|
|
+ protected:
|
|
+ virtual int command(int argc, const char*const* argv);
|
|
+ virtual int capture();
|
|
+ virtual int grab();
|
|
+ void format();
|
|
+ void setsize();
|
|
+
|
|
+ void X11Grab_ComputeYUVTable(void) ;
|
|
+ int X11Grab_MSBWhite1(void);
|
|
+ int X11Grab_LSBWhite1(void);
|
|
+ int X11Grab_MSBBlack1(void);
|
|
+ int X11Grab_LSBBlack1(void);
|
|
+ int X11Grab_Pseudo8(void);
|
|
+ int X11Grab_RGB16(void);
|
|
+ int X11Grab_TrueXBGR24(void);
|
|
+ int X11Grab_TrueXRGB24(void);
|
|
+
|
|
+ int X11Grab_Initialize(Window rw, int w, int h);
|
|
+ typedef enum {
|
|
+ grab_none,
|
|
+ grab_X11Grab_LSBWhite1,
|
|
+ grab_X11Grab_MSBWhite1,
|
|
+ grab_X11Grab_LSBBlack1,
|
|
+ grab_X11Grab_MSBBlack1,
|
|
+ grab_X11Grab_Pseudo8,
|
|
+ grab_X11Grab_RGB16,
|
|
+ grab_X11Grab_TrueXBGR24,
|
|
+ grab_X11Grab_TrueXRGB24
|
|
+ } c_grab_type;
|
|
+ c_grab_type c_grab;
|
|
+
|
|
+
|
|
+ uint8 *rgb2y_ ;
|
|
+ int8 *rgb2u_ ;
|
|
+ int8 *rgb2v_ ;
|
|
+
|
|
+ ximage_t *ximage_ ;
|
|
+
|
|
+ Display *dpy_ ;
|
|
+ int mode_; /* input mode */
|
|
+ Window theroot_ ;
|
|
+
|
|
+// Tcl_Interp *interp_=NULL;
|
|
+
|
|
+ int screen, xerror ;
|
|
+ Window vRoot_ ;
|
|
+ Window rootwin_ ;
|
|
+ Colormap colormap;
|
|
+ Visual *root_vis;
|
|
+ XVisualInfo root_visinfo;
|
|
+
|
|
+ int ncolors_ ;
|
|
+ int black, white;
|
|
+ XColor *color ;
|
|
+ uint8 *col2y_ ;
|
|
+ uint16 *col2rgb16_ ;
|
|
+
|
|
+ u_int basewidth_; /* Height of frame to be captured */
|
|
+ u_int baseheight_; /* Width of frame to be captured */
|
|
+ u_int decimate_; /* division of base sizes */
|
|
+
|
|
+ int x_origin_, y_origin_, width_, height_;
|
|
+ int root_depth_, root_width, root_height;
|
|
+};
|
|
+
|
|
+class X11Device : public InputDevice {
|
|
+ public:
|
|
+ X11Device(const char* nickname);
|
|
+ virtual int command(int argc, const char*const* argv);
|
|
+ protected:
|
|
+ const char* name_;
|
|
+};
|
|
+
|
|
+static X11Device find_x11_devices("x11");
|
|
+
|
|
+X11Device::X11Device(const char* nickname):
|
|
+ InputDevice(nickname), name_(nickname)
|
|
+{
|
|
+ if (free)
|
|
+ attributes_ = "\
|
|
+size {large normal small cif} \
|
|
+format {422}" ;
|
|
+ else
|
|
+ attributes_ = "disabled";
|
|
+}
|
|
+
|
|
+extern "C" {
|
|
+/*** most of this taken from nv:x11-grab.c ***/
|
|
+extern ximage_t *VidUtil_AllocXImage(Display *dpy, Visual *vis, int depth,
|
|
+ int width, int height, int readonly);
|
|
+
|
|
+#if 0 /* debugging stuff */
|
|
+static int my_Tcl_Eval(Tcl_Interp *interp, char *cmd)
|
|
+{
|
|
+ fprintf(stderr,"Tcl_Eval <%s>\n", cmd);
|
|
+ Tcl_Eval(interp, cmd);
|
|
+}
|
|
+#define Tcl_Eval my_Tcl_Eval
|
|
+#endif
|
|
+
|
|
+static Window
|
|
+VirtualRootWindow(Display *dpy, int screen)
|
|
+{
|
|
+ static Display *last_dpy=(Display *)NULL;
|
|
+ static int last_screen = -1;
|
|
+ static Window vRoot=None;
|
|
+
|
|
+ Atom __SWM_VROOT=None;
|
|
+ Window rw, p, *child;
|
|
+ unsigned int i, nChildren;
|
|
+
|
|
+ if ((dpy != last_dpy) || (screen != last_screen)) {
|
|
+ vRoot = RootWindow(dpy, screen);
|
|
+
|
|
+ /* go look for a virtual root */
|
|
+ __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
|
|
+ XQueryTree(dpy, vRoot, &rw, &p, &child, &nChildren);
|
|
+ for (i=0; i<nChildren; i++) {
|
|
+ Atom actual_type;
|
|
+ int actual_format;
|
|
+ unsigned long nitems, bytesafter;
|
|
+ Window *newRoot=NULL;
|
|
+
|
|
+ if ((XGetWindowProperty(dpy, child[i], __SWM_VROOT, 0, 1, False,
|
|
+ XA_WINDOW, &actual_type, &actual_format,
|
|
+ &nitems, &bytesafter,
|
|
+ (unsigned char **)&newRoot) == Success)
|
|
+ && (newRoot != NULL)) {
|
|
+ vRoot = *newRoot;
|
|
+ XFree((void *)newRoot);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ XFree((void *)child);
|
|
+
|
|
+ last_dpy = dpy;
|
|
+ last_screen = screen;
|
|
+ }
|
|
+
|
|
+ return vRoot;
|
|
+}
|
|
+
|
|
+} /* end extern C */
|
|
+
|
|
+void
|
|
+X11Grabber::X11Grab_ComputeYUVTable(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ switch (root_visinfo.c_class) {
|
|
+ case StaticColor:
|
|
+ case PseudoColor:
|
|
+ case StaticGray:
|
|
+ case GrayScale:
|
|
+ for (i=0; i<ncolors_; i++) color[i].pixel = i;
|
|
+ XQueryColors(dpy_, colormap, color, ncolors_);
|
|
+ for (i=0; i<ncolors_; i++) {
|
|
+ color[i].red = (color[i].red & 0xf800) ;
|
|
+ color[i].green = (color[i].green & 0xfc00) >> 5 ;
|
|
+ color[i].blue = (color[i].blue & 0xf800) >> 11 ;
|
|
+ col2rgb16_[i] = color[i].red + color[i].green + color[i].blue;
|
|
+ col2y_[i] = rgb2y_[col2rgb16_[i]];
|
|
+ }
|
|
+ break;
|
|
+ case TrueColor:
|
|
+ fprintf(stderr, "TrueColor...\n");
|
|
+ break;
|
|
+ case DirectColor:
|
|
+ fprintf(stderr, "DirectColor...\n");
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * these are the grabbing functions for the various video formats
|
|
+ */
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_MSBWhite1()
|
|
+{
|
|
+ int x, y, row;
|
|
+ uint8 *data=(uint8 *)ximage_->image->data, *yp= frame_;
|
|
+
|
|
+ for (y=0; y<height_; y++) {
|
|
+ for (x=0; x<width_; x+=8) {
|
|
+ row = *data++;
|
|
+
|
|
+ yp[0] = 255 * ((row & 0x80)>>7);
|
|
+ yp[1] = 255 * ((row & 0x40)>>6);
|
|
+ yp[2] = 255 * ((row & 0x20)>>5);
|
|
+ yp[3] = 255 * ((row & 0x10)>>4);
|
|
+ yp[4] = 255 * ((row & 0x08)>>3);
|
|
+ yp[5] = 255 * ((row & 0x04)>>2);
|
|
+ yp[6] = 255 * ((row & 0x02)>>1);
|
|
+ yp[7] = 255 * (row & 0x01);
|
|
+ yp += 8;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_MSBBlack1()
|
|
+{
|
|
+ int x, y, row;
|
|
+ uint8 *data=(uint8 *)ximage_->image->data, *yp= frame_;
|
|
+
|
|
+ for (y=0; y<height_; y++) {
|
|
+ for (x=0; x<width_; x+=8) {
|
|
+ row = *data++;
|
|
+
|
|
+ yp[0] = 255 - 255 * ((row & 0x80)>>7);
|
|
+ yp[1] = 255 - 255 * ((row & 0x40)>>6);
|
|
+ yp[2] = 255 - 255 * ((row & 0x20)>>5);
|
|
+ yp[3] = 255 - 255 * ((row & 0x10)>>4);
|
|
+ yp[4] = 255 - 255 * ((row & 0x08)>>3);
|
|
+ yp[5] = 255 - 255 * ((row & 0x04)>>2);
|
|
+ yp[6] = 255 - 255 * ((row & 0x02)>>1);
|
|
+ yp[7] = 255 - 255 * (row & 0x01);
|
|
+ yp += 8;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_LSBWhite1()
|
|
+{
|
|
+ int x, y, row;
|
|
+ uint8 *data=(uint8 *)ximage_->image->data, *yp= frame_ ;
|
|
+
|
|
+ for (y=0; y<height_; y++) {
|
|
+ for (x=0; x<width_; x+=8) {
|
|
+ row = *data++;
|
|
+
|
|
+ yp[7] = 255 * ((row & 0x80)>>7);
|
|
+ yp[6] = 255 * ((row & 0x40)>>6);
|
|
+ yp[5] = 255 * ((row & 0x20)>>5);
|
|
+ yp[4] = 255 * ((row & 0x10)>>4);
|
|
+ yp[3] = 255 * ((row & 0x08)>>3);
|
|
+ yp[2] = 255 * ((row & 0x04)>>2);
|
|
+ yp[1] = 255 * ((row & 0x02)>>1);
|
|
+ yp[0] = 255 * (row & 0x01);
|
|
+ yp += 8;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_LSBBlack1()
|
|
+{
|
|
+ int x, y, row;
|
|
+ uint8 *data=(uint8 *)ximage_->image->data, *yp= frame_;
|
|
+
|
|
+ for (y=0; y<height_; y++) {
|
|
+ for (x=0; x<width_; x+=8) {
|
|
+ row = *data++;
|
|
+
|
|
+ yp[7] = 255 - 255 * ((row & 0x80)>>7);
|
|
+ yp[6] = 255 - 255 * ((row & 0x40)>>6);
|
|
+ yp[5] = 255 - 255 * ((row & 0x20)>>5);
|
|
+ yp[4] = 255 - 255 * ((row & 0x10)>>4);
|
|
+ yp[3] = 255 - 255 * ((row & 0x08)>>3);
|
|
+ yp[2] = 255 - 255 * ((row & 0x04)>>2);
|
|
+ yp[1] = 255 - 255 * ((row & 0x02)>>1);
|
|
+ yp[0] = 255 - 255 * (row & 0x01);
|
|
+ yp += 8;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_Pseudo8()
|
|
+{
|
|
+ int x, y, p0, p1, p2, p3 ;
|
|
+ uint8 *data=(uint8 *)ximage_->image->data, *yp=frame_ ;
|
|
+ uint8 *up= (uint8 *)yp + framesize_ ;
|
|
+ uint8 *vp= up + (framesize_ >> 2) ;
|
|
+
|
|
+ X11Grab_ComputeYUVTable();
|
|
+
|
|
+ for (y=0; y<height_; y += 2) {
|
|
+ for (x=0; x<width_ ; x += 2) {
|
|
+ yp[0] = col2y_[data[0]];
|
|
+ p0 = col2rgb16_[data[0]];
|
|
+ yp[1] = col2y_[data[1]];
|
|
+ p1 = col2rgb16_[data[1]];
|
|
+
|
|
+ p2 = col2rgb16_[data[width_]];
|
|
+ p3 = col2rgb16_[data[width_ + 1]];
|
|
+#if 0 /* average */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ p2 = ( (p2 >> 1) & 0x7bef ) + ( (p3 >> 1) & 0x7bef ) ;
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p2 >> 1) & 0x7bef ) ;
|
|
+#else /* take the darkest... */
|
|
+ if (yp[1] < yp[0]) p0 = p1 ;
|
|
+ if (rgb2y_[p2] < rgb2y_[p0]) p0 = p2 ;
|
|
+ if (rgb2y_[p3] < rgb2y_[p0]) p0 = p3 ;
|
|
+#endif
|
|
+ *up++ = rgb2u_[ p0 ];
|
|
+ *vp++ = rgb2v_[ p0 ];
|
|
+
|
|
+ data += 2;
|
|
+ yp += 2 ;
|
|
+ }
|
|
+ for (x=0; x<width_; x += 8) {
|
|
+ yp[0] = col2y_[data[0]];
|
|
+ yp[1] = col2y_[data[1]];
|
|
+ yp[2] = col2y_[data[2]];
|
|
+ yp[3] = col2y_[data[3]];
|
|
+ yp[4] = col2y_[data[4]];
|
|
+ yp[5] = col2y_[data[5]];
|
|
+ yp[6] = col2y_[data[6]];
|
|
+ yp[7] = col2y_[data[7]];
|
|
+ data += 8;
|
|
+ yp += 8 ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_RGB16(void)
|
|
+{
|
|
+ int x, y;
|
|
+ uint8 *yp= (uint8 *)frame_ ;
|
|
+ uint8 *up= (uint8 *)yp + framesize_ ;
|
|
+ uint8 *vp= up + (framesize_ >> 2) ;
|
|
+ uint16 *data=(uint16 *)ximage_->image->data, p0, p1, p2, p3;
|
|
+
|
|
+ for (y=0; y<height_; y+=2) {
|
|
+ for (x=0; x<width_; x += 2) {
|
|
+ p0 = data[0] ;
|
|
+ p1 = data[1] ;
|
|
+ p2 = data[ width_] ;
|
|
+ p3 = data[ width_ + 1] ;
|
|
+ data += 2 ;
|
|
+ yp[0] = rgb2y_[ p0 ] ; /* in 565 format */
|
|
+ yp[1] = rgb2y_[ p1 ] ; /* in 565 format */
|
|
+#if 0
|
|
+ /* average the four pixels... */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ p2 = ( (p2 >> 1) & 0x7bef ) + ( (p3 >> 1) & 0x7bef ) ;
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p2 >> 1) & 0x7bef ) ;
|
|
+#else /* take the darkest... */
|
|
+ if (yp[1] < yp[0]) p0 = p1 ;
|
|
+ if (rgb2y_[p2] < rgb2y_[p0]) p0 = p2 ;
|
|
+ if (rgb2y_[p3] < rgb2y_[p0]) p0 = p3 ;
|
|
+#endif
|
|
+ *up++ = rgb2u_[ p0 ];
|
|
+ *vp++ = rgb2v_[ p0 ];
|
|
+ yp += 2 ;
|
|
+ }
|
|
+ for (x=0; x<width_; x += 8) {
|
|
+ yp[0] = rgb2y_[data[0] ];
|
|
+ yp[1] = rgb2y_[data[1] ];
|
|
+ yp[2] = rgb2y_[data[2] ];
|
|
+ yp[3] = rgb2y_[data[3] ];
|
|
+ yp[4] = rgb2y_[data[4] ];
|
|
+ yp[5] = rgb2y_[data[5] ];
|
|
+ yp[6] = rgb2y_[data[6] ];
|
|
+ yp[7] = rgb2y_[data[7] ];
|
|
+ yp += 8 ;
|
|
+ data += 8 ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_TrueXBGR24()
|
|
+{
|
|
+ int x, y;
|
|
+ uint8 *yp= (uint8 *)frame_ ;
|
|
+ uint8 *up= (uint8 *)yp + framesize_ ;
|
|
+ uint8 *vp= up + (framesize_ >> 2) ;
|
|
+ uint16 p0, p1 ;
|
|
+ uint32 *data=(uint32 *)ximage_->image->data, d ;
|
|
+
|
|
+ for (y=0; y<height_; y += 2) {
|
|
+ for (x=0; x<width_; x+=2) {
|
|
+ d = *data++ ;
|
|
+ p0 = ((d<<8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d<<8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p1 ];
|
|
+
|
|
+ /* average the two pixels... */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ *up++ = rgb2u_[ p0 ];
|
|
+ }
|
|
+ for (x=0; x<width_; x+=2) {
|
|
+ d = *data++ ;
|
|
+ p0 = ((d<<8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d<<8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p1 ];
|
|
+
|
|
+ /* average the two pixels... */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ *vp++ = rgb2v_[ p0 ];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::X11Grab_TrueXRGB24()
|
|
+{
|
|
+ int x, y;
|
|
+ uint8 *yp= (uint8 *)frame_ ;
|
|
+ uint8 *up= (uint8 *)yp + framesize_ ;
|
|
+ uint8 *vp= up + (framesize_ >> 2) ;
|
|
+ uint16 p0, p1 ;
|
|
+ uint32 *data=(uint32 *)ximage_->image->data, d ;
|
|
+
|
|
+ for (y=0; y<height_; y += 2) {
|
|
+ for (x=0; x<width_; x+=2) {
|
|
+ d = *data++ ;
|
|
+ /* -- RED -- -- GREEN -- -- BLUE -- */
|
|
+ p0 = ((d>>8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>3) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d>>8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>3) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p1 ];
|
|
+
|
|
+ /* average the two pixels... */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ *up++ = rgb2u_[ p0 ];
|
|
+ }
|
|
+ for (x=0; x<width_; x+=2) {
|
|
+ d = *data++ ;
|
|
+ p0 = ((d>>8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>3) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d>>8) & 0xf100) | ((d>>5) & 0x7e0) | ((d>>3) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p1 ];
|
|
+
|
|
+ /* average the two pixels... */
|
|
+ p0 = ( (p0 >> 1) & 0x7bef ) + ( (p1 >> 1) & 0x7bef ) ;
|
|
+ *vp++ = rgb2v_[ p0 ];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * initialization of frame grabber...
|
|
+ */
|
|
+int
|
|
+X11Grabber::X11Grab_Initialize(Window rw, int w, int h)
|
|
+{
|
|
+ int config = 0 ;
|
|
+ XWindowAttributes wattr;
|
|
+
|
|
+ if (theroot_ != rw) {
|
|
+ theroot_ = rw;
|
|
+ XGetWindowAttributes(dpy_, theroot_, &wattr);
|
|
+ screen = XScreenNumberOfScreen(wattr.screen);
|
|
+ colormap = DefaultColormapOfScreen(wattr.screen);
|
|
+ ncolors_ = CellsOfScreen(wattr.screen);
|
|
+ black = BlackPixelOfScreen(wattr.screen);
|
|
+ white = WhitePixelOfScreen(wattr.screen);
|
|
+ root_depth_ = wattr.depth;
|
|
+ root_width = wattr.width;
|
|
+ root_height = wattr.height;
|
|
+ root_vis = wattr.visual;
|
|
+ vRoot_ = VirtualRootWindow(dpy_, screen);
|
|
+
|
|
+ if (color != NULL) {
|
|
+ free(color);
|
|
+ free(col2y_);
|
|
+ free(col2rgb16_);
|
|
+ }
|
|
+ color = (XColor *) malloc(ncolors_*sizeof(XColor));
|
|
+ col2y_ = (uint8 *) malloc(ncolors_*sizeof(uint8));
|
|
+ col2rgb16_ = (uint16 *) malloc(ncolors_*sizeof(uint16));
|
|
+
|
|
+ XMatchVisualInfo(dpy_, screen, root_depth_, root_vis->c_class,
|
|
+ &root_visinfo);
|
|
+ switch (root_depth_) {
|
|
+ case 1:
|
|
+ if (white == 1) {
|
|
+ c_grab = (LITTLEENDIAN) ? grab_X11Grab_LSBWhite1 : grab_X11Grab_MSBWhite1;
|
|
+ } else {
|
|
+ c_grab = (LITTLEENDIAN) ? grab_X11Grab_LSBBlack1 : grab_X11Grab_MSBBlack1;
|
|
+ }
|
|
+ config = VID_GREYSCALE;
|
|
+ break;
|
|
+
|
|
+ case 8:
|
|
+ switch (root_visinfo.c_class) {
|
|
+ case PseudoColor:
|
|
+ case GrayScale:
|
|
+ case StaticColor:
|
|
+ case StaticGray:
|
|
+ c_grab = grab_X11Grab_Pseudo8;
|
|
+ break;
|
|
+ default:
|
|
+ c_grab = grab_none;
|
|
+ break;
|
|
+ }
|
|
+ config = VID_GREYSCALE|VID_COLOR;
|
|
+ break;
|
|
+
|
|
+ case 16:
|
|
+ c_grab = grab_X11Grab_RGB16;
|
|
+ break ;
|
|
+
|
|
+ case 24:
|
|
+ if ((root_visinfo.c_class == TrueColor) &&
|
|
+ (root_visinfo.green_mask = 0xff00) &&
|
|
+ (root_visinfo.red_mask == 0xff) &&
|
|
+ (root_visinfo.blue_mask == 0xff0000)) {
|
|
+ c_grab = grab_X11Grab_TrueXBGR24;
|
|
+
|
|
+ } else if ((root_visinfo.c_class == TrueColor) &&
|
|
+ (root_visinfo.green_mask = 0xff00) &&
|
|
+ (root_visinfo.red_mask == 0xff0000) &&
|
|
+ (root_visinfo.blue_mask == 0xff)) {
|
|
+ c_grab = grab_X11Grab_TrueXRGB24;
|
|
+ } else
|
|
+ c_grab = grab_none;
|
|
+ config = VID_GREYSCALE|VID_COLOR;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ fprintf(stderr, "don't know how to grab %d bits\n",
|
|
+ root_depth_);
|
|
+ c_grab = grab_none;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((ximage_ == NULL) || (width_ != w) || (height_ != h)) {
|
|
+ width_ = w;
|
|
+ height_ = h;
|
|
+ if (ximage_ != NULL)
|
|
+ VidUtil_DestroyXImage(dpy_, ximage_);
|
|
+ ximage_ = VidUtil_AllocXImage(dpy_, root_vis, root_depth_, w, h, False);
|
|
+ }
|
|
+ return (c_grab == grab_none) ? 0 : config|VID_SMALL|VID_MEDIUM|VID_LARGE;
|
|
+}
|
|
+
|
|
+extern "C" {
|
|
+extern void VidUtil_Init(Display *dpy);
|
|
+extern void VidUtil_DestroyXImage(Display *dpy, ximage_t *ximage);
|
|
+
|
|
+#ifdef UNUSED /* not yet... */
|
|
+static int
|
|
+ErrHandler1(ClientData clientData, XErrorEvent *errevp)
|
|
+{
|
|
+ xerror = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+X11Grab_MakeBox(unsigned int x1, unsigned int y1,
|
|
+ unsigned int x2, unsigned int y2,
|
|
+ int *xp, int *yp, int *wp, int *hp)
|
|
+{
|
|
+ int w, h;
|
|
+
|
|
+ w = x2-x1;
|
|
+ if (w < 0) {
|
|
+ *xp = x2;
|
|
+ *wp = -w;
|
|
+ } else {
|
|
+ *xp = x1;
|
|
+ *wp = w;
|
|
+ }
|
|
+
|
|
+ h = y2-y1;
|
|
+ if (h < 0) {
|
|
+ *yp = y2;
|
|
+ *hp = -h;
|
|
+ } else {
|
|
+ *yp = y1;
|
|
+ *hp = h;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+X11Grab_UpdatePos(Window rw, int x, int y, int w, int h)
|
|
+{
|
|
+ static char cmd[256];
|
|
+
|
|
+ if (w < 8) w = 8;
|
|
+ if (h < 8) h = 8;
|
|
+
|
|
+ if (w > root_width/8*8) w = root_width/8*8;
|
|
+ if (h > root_height/8*8) h = root_height/8*8;
|
|
+
|
|
+ w = (w+7)/8*8;
|
|
+ h = (h+7)/8*8;
|
|
+
|
|
+ if (x < 0) x = 0;
|
|
+ if (y < 0) y = 0;
|
|
+
|
|
+ if (x > root_width-w) x = root_width-w;
|
|
+ if (y > root_height-h) y = root_height-h;
|
|
+
|
|
+ sprintf(cmd, "x11grabUpdatePos %d %d %d %d", x, y, w, h);
|
|
+ (void) Tcl_Eval(interp, cmd);
|
|
+
|
|
+ x_origin = x;
|
|
+ y_origin = y;
|
|
+
|
|
+ if ((root != rw) || (width != w) || (height != h)) {
|
|
+ X11Grab_Initialize(rw, w, h);
|
|
+ return 0;
|
|
+ } else
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int
|
|
+X11Grab_FollowPointer(void)
|
|
+{
|
|
+ Window rw, cw;
|
|
+ int x, y, wx, wy;
|
|
+ unsigned int mask;
|
|
+
|
|
+ XQueryPointer(dpy, root, &rw, &cw, &x, &y, &wx, &wy, &mask);
|
|
+
|
|
+ if (x < x_origin+width/4)
|
|
+ x = x-width/4;
|
|
+ else if (x >= x_origin+3*width/4)
|
|
+ x = x-3*width/4;
|
|
+ else
|
|
+ x = x_origin;
|
|
+
|
|
+ if (y < y_origin+height/4)
|
|
+ y = y-height/4;
|
|
+ else if (y >= y_origin+3*height/4)
|
|
+ y = y-3*height/4;
|
|
+ else
|
|
+ y = y_origin;
|
|
+
|
|
+ return X11Grab_UpdatePos(rw, x, y, width, height);
|
|
+}
|
|
+
|
|
+static int
|
|
+X11Grab_FollowWindow(void)
|
|
+{
|
|
+ int x, y, w, h;
|
|
+ XWindowAttributes wattr, vRoot_wattr;
|
|
+ Tk_ErrorHandler handler;
|
|
+
|
|
+ handler = Tk_CreateErrorHandler(dpy, -1, -1, -1, ErrHandler1, NULL);
|
|
+ xerror = 0;
|
|
+ XGetWindowAttributes(dpy, target, &wattr);
|
|
+ XSync(dpy, False);
|
|
+ Tk_DeleteErrorHandler(handler);
|
|
+ if ((target == None) || xerror) {
|
|
+ target = None;
|
|
+ (void) Tcl_Eval(interp,
|
|
+ ".grabControls.x11grab.row1.mode.window config -state disabled");
|
|
+ (void) Tcl_Eval(interp, "set x11grabMode fixed");
|
|
+ return 1;
|
|
+ } else {
|
|
+ XGetWindowAttributes(dpy, vRoot, &vRoot_wattr);
|
|
+ x = wattr.x+vRoot_wattr.x;
|
|
+ y = wattr.y+vRoot_wattr.y;
|
|
+ w = wattr.width+2*wattr.border_width;
|
|
+ h = wattr.height+2*wattr.border_width;
|
|
+
|
|
+ return X11Grab_UpdatePos(root, x, y, w, h);
|
|
+ }
|
|
+}
|
|
+#endif /* UNUSED ... */
|
|
+
|
|
+
|
|
+#ifdef UNUSED
|
|
+/*ARGSUSED*/
|
|
+static int
|
|
+X11Grab_SetXCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ int x;
|
|
+
|
|
+ if (argc != 2) {
|
|
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
|
+ " x\"", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ x = atoi(argv[1]);
|
|
+ (void) X11Grab_UpdatePos(root, x, y_origin, width, height);
|
|
+
|
|
+ return TCL_OK;
|
|
+}
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int
|
|
+X11Grab_SetYCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ int y;
|
|
+
|
|
+ if (argc != 2) {
|
|
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
|
+ " y\"", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ y = atoi(argv[1]);
|
|
+ (void) X11Grab_UpdatePos(root, x_origin, y, width, height);
|
|
+
|
|
+ return TCL_OK;
|
|
+}
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int X11Grab_SetWCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ int w;
|
|
+
|
|
+ if (argc != 2) {
|
|
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
|
+ " width\"", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ w = atoi(argv[1]);
|
|
+ (void) X11Grab_UpdatePos(root, x_origin, y_origin, w, height);
|
|
+
|
|
+ return TCL_OK;
|
|
+}
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int
|
|
+X11Grab_SetHCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ int h;
|
|
+
|
|
+ if (argc != 2) {
|
|
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
|
+ " height\"", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ h = atoi(argv[1]);
|
|
+ (void) X11Grab_UpdatePos(root, x_origin, y_origin, width, h);
|
|
+
|
|
+ return TCL_OK;
|
|
+}
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int
|
|
+X11Grab_SetRegionCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ unsigned int rootx, rooty;
|
|
+ int x, y, w, h, boxDrawn=0;
|
|
+ GC xorGC;
|
|
+ Cursor cursor;
|
|
+ XEvent event;
|
|
+
|
|
+ cursor = XCreateFontCursor(dpy, XC_cross);
|
|
+
|
|
+ if (XGrabPointer(dpy, root, False, ButtonPressMask, GrabModeAsync,
|
|
+ GrabModeAsync, root, cursor, CurrentTime)!=GrabSuccess) {
|
|
+ Tcl_AppendResult(interp, argv[0], ": can't grab mouse", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ xorGC = XCreateGC(dpy, root, 0, NULL);
|
|
+ XSetSubwindowMode(dpy, xorGC, IncludeInferiors);
|
|
+ XSetForeground(dpy, xorGC, -1);
|
|
+ XSetFunction(dpy, xorGC, GXxor);
|
|
+
|
|
+ XMaskEvent(dpy, ButtonPressMask, &event);
|
|
+ rootx = event.xbutton.x_root;
|
|
+ rooty = event.xbutton.y_root;
|
|
+
|
|
+ XChangeActivePointerGrab(dpy, ButtonMotionMask|ButtonReleaseMask, cursor,
|
|
+ CurrentTime);
|
|
+
|
|
+ while (1) {
|
|
+ XNextEvent(dpy, &event);
|
|
+ switch (event.type) {
|
|
+ case MotionNotify:
|
|
+ if (boxDrawn) {
|
|
+ XDrawRectangle(dpy, root, xorGC, x, y, w, h);
|
|
+ boxDrawn = 0;
|
|
+ }
|
|
+ while (XCheckTypedEvent(dpy, MotionNotify, &event)) ;
|
|
+ X11Grab_MakeBox(rootx, rooty, event.xbutton.x_root,
|
|
+ event.xbutton.y_root, &x, &y, &w, &h);
|
|
+ XDrawRectangle(dpy, root, xorGC, x, y, w, h);
|
|
+ boxDrawn = 1;
|
|
+ break;
|
|
+ case ButtonRelease:
|
|
+ if (boxDrawn) {
|
|
+ XDrawRectangle(dpy, root, xorGC, x, y, w, h);
|
|
+ boxDrawn = 0;
|
|
+ }
|
|
+ XFlush(dpy);
|
|
+ X11Grab_MakeBox(rootx, rooty, event.xmotion.x_root,
|
|
+ event.xmotion.y_root, &x, &y, &w, &h);
|
|
+ XUngrabPointer(dpy, CurrentTime);
|
|
+ XFreeGC(dpy, xorGC);
|
|
+ XFreeCursor(dpy, cursor);
|
|
+ (void) Tcl_Eval(interp, "set x11grabMode fixed");
|
|
+ (void) X11Grab_UpdatePos(root, x, y, w, h);
|
|
+ return TCL_OK;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int X11Grab_SetWindowCmd(ClientData clientData, Tcl_Interp *interp,
|
|
+ int argc, char *argv[])
|
|
+{
|
|
+ int buttons=0;
|
|
+ Cursor cursor;
|
|
+ XEvent event;
|
|
+
|
|
+ cursor = XCreateFontCursor(dpy, XC_crosshair);
|
|
+ target = None;
|
|
+
|
|
+ if (XGrabPointer(dpy, vRoot, False, ButtonPressMask|ButtonReleaseMask,
|
|
+ GrabModeSync, GrabModeAsync, root, cursor,
|
|
+ CurrentTime) != GrabSuccess) {
|
|
+ Tcl_AppendResult(interp, argv[0], ": can't grab mouse", NULL);
|
|
+ return TCL_ERROR;
|
|
+ }
|
|
+
|
|
+ while ((target == None) || (buttons != 0)) {
|
|
+ XAllowEvents(dpy, SyncPointer, CurrentTime);
|
|
+ XWindowEvent(dpy, vRoot, ButtonPressMask|ButtonReleaseMask, &event);
|
|
+ switch (event.type) {
|
|
+ case ButtonPress:
|
|
+ if (target == None) target = event.xbutton.subwindow;
|
|
+ buttons++;
|
|
+ break;
|
|
+ case ButtonRelease:
|
|
+ if (buttons > 0) buttons--;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ XUngrabPointer(dpy, CurrentTime);
|
|
+ XFreeCursor(dpy, cursor);
|
|
+
|
|
+ (void) Tcl_Eval(interp,
|
|
+ ".grabControls.x11grab.row1.mode.window config -state normal");
|
|
+ (void) Tcl_Eval(interp, "set x11grabMode window");
|
|
+ (void) X11Grab_FollowWindow();
|
|
+ return TCL_OK;
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grab_Probe(Tk_Window tkMainWin)
|
|
+{
|
|
+ Window rw;
|
|
+ interp = Tcl_CreateInterp();
|
|
+
|
|
+ if (tkMainWin == NULL) return 0;
|
|
+
|
|
+ Tcl_TraceVar(interp, "x11grabMode", TCL_TRACE_WRITES, X11Grab_TraceMode,
|
|
+ NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetX", X11Grab_SetXCmd, 0, NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetY", X11Grab_SetYCmd, 0, NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetW", X11Grab_SetWCmd, 0, NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetH", X11Grab_SetHCmd, 0, NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetRegion", X11Grab_SetRegionCmd, 0,
|
|
+ NULL);
|
|
+ Tcl_CreateCommand(interp, "x11grabSetWindow", X11Grab_SetWindowCmd, 0,
|
|
+ NULL);
|
|
+ dpy = Tk_Display(tkMainWin);
|
|
+ rootwin = rw = RootWindow(dpy, Tk_ScreenNumber(tkMainWin));
|
|
+ VidUtil_Init(dpy);
|
|
+ return X11Grab_Initialize(rw, width, height);
|
|
+}
|
|
+#endif /* UNUSED */
|
|
+
|
|
+} /* end extern "C" block */
|
|
+
|
|
+
|
|
+int
|
|
+X11Device::command(int argc, const char*const* argv)
|
|
+{
|
|
+ Tcl& tcl = Tcl::instance();
|
|
+
|
|
+ if ((argc == 3) && (strcmp(argv[1], "open") == 0)) {
|
|
+ TclObject* o = new X11Grabber(name_, argv[2]);
|
|
+ if (o != 0)
|
|
+ tcl.result(o->name());
|
|
+ return (TCL_OK);
|
|
+ }
|
|
+ return (InputDevice::command(argc, argv));
|
|
+}
|
|
+
|
|
+X11Grabber::X11Grabber(const char* name, const char* format)
|
|
+{
|
|
+ c_grab = grab_none ; /* XXX */
|
|
+ theroot_ = None ; /* XXX */
|
|
+ ximage_ = NULL ;
|
|
+ color = NULL ;
|
|
+ col2y_ = NULL ;
|
|
+ col2rgb16_ = NULL ;
|
|
+
|
|
+ width_ = 320 ;
|
|
+ height_ = 240 ;
|
|
+ x_origin_ = y_origin_ = 0 ; /* XXX */
|
|
+
|
|
+ if (strcmp(format, "422") && strcmp(format, "cif")) {
|
|
+ fprintf(stderr,
|
|
+ "vic: x11Grabber: unsupported format: %s\n",
|
|
+ format);
|
|
+ abort();
|
|
+ }
|
|
+
|
|
+ Tk_Window tkMainWin = Tcl::instance().tkmain() ;
|
|
+ Window rw ;
|
|
+
|
|
+ dpy_ = Tk_Display(tkMainWin);
|
|
+ rootwin_ = rw = RootWindow(dpy_, Tk_ScreenNumber(tkMainWin));
|
|
+
|
|
+ /* Initialize the RGB565 to YUV tables */
|
|
+ int i, r, g, b, y, u, v;
|
|
+
|
|
+ rgb2y_ = new uint8[65536] ;
|
|
+ rgb2u_ = new uint8[65536] ;
|
|
+ rgb2v_ = new uint8[65536] ;
|
|
+
|
|
+ i = 0;
|
|
+ for (r=4; r<256; r+=8) {
|
|
+ for (g=3; g<256; g+=4) { /* XXX */
|
|
+ for (b=4; b<256; b+=8) {
|
|
+ y = (38*r+75*g+15*b+64)/128;
|
|
+ u = 74*(b-y)/128;
|
|
+ if (u > 127) u = 127 ;
|
|
+ else if (u< -128) u = -128 ;
|
|
+ v = (93*(r-y)/128);
|
|
+ if (v > 127) v = 127 ;
|
|
+ else if (v< -128) v = -128 ;
|
|
+ rgb2y_[i] = y ;
|
|
+ rgb2u_[i] = u ^ 0x80 ; /* was u */
|
|
+ rgb2v_[i] = v ^ 0x80 ;
|
|
+ i++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ X11Grab_Initialize(rw, width_, height_);
|
|
+
|
|
+ mode_ = X11GRAB_FIXED; /* XXX */
|
|
+ decimate_ = 1; /* XXX */
|
|
+ basewidth_ = PAL_WIDTH * 2;
|
|
+ baseheight_ = PAL_HEIGHT * 2;
|
|
+
|
|
+}
|
|
+
|
|
+X11Grabber::~X11Grabber()
|
|
+{
|
|
+ if (ximage_ != NULL)
|
|
+ VidUtil_DestroyXImage(dpy_, ximage_);
|
|
+ free(rgb2y_);
|
|
+ free(rgb2u_);
|
|
+ free(rgb2v_);
|
|
+}
|
|
+
|
|
+void
|
|
+X11Grabber::setsize()
|
|
+{
|
|
+ int rows, columns;
|
|
+
|
|
+ rows = (baseheight_ / decimate_) &~0xf; /* 0xf, ugh! */
|
|
+ columns = (basewidth_ / decimate_) &~0xf;
|
|
+
|
|
+ /* XXX set size of captured window ? */
|
|
+
|
|
+ set_size_422(columns, rows); /* was 422... */
|
|
+ X11Grab_Initialize(rootwin_, columns, rows); /* XXX */
|
|
+
|
|
+ allocref(); /* allocate reference frame */
|
|
+}
|
|
+
|
|
+void
|
|
+X11Grabber::format()
|
|
+{
|
|
+
|
|
+ baseheight_ = CIF_HEIGHT * 2;
|
|
+ basewidth_ = CIF_WIDTH * 2;
|
|
+
|
|
+ setsize();
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+X11Grabber::start()
|
|
+{
|
|
+ format();
|
|
+ /* XXX prepare for continuous capture */
|
|
+ Grabber::start();
|
|
+}
|
|
+
|
|
+void
|
|
+X11Grabber::stop()
|
|
+{
|
|
+ /* XXX stop capture */
|
|
+ VidUtil_DestroyXImage(dpy_, ximage_);
|
|
+ ximage_ = NULL ;
|
|
+ Grabber::stop();
|
|
+}
|
|
+
|
|
+int
|
|
+X11Grabber::command(int argc, const char*const* argv)
|
|
+{
|
|
+ if (argc >= 3) {
|
|
+ if (strcmp(argv[1], "decimate") == 0) {
|
|
+ int dec = atoi(argv[2]);
|
|
+ Tcl& tcl = Tcl::instance();
|
|
+ if (dec <= 0) {
|
|
+ tcl.resultf("%s: divide by zero", argv[0]);
|
|
+ return (TCL_ERROR);
|
|
+ }
|
|
+ if (dec != decimate_) {
|
|
+ decimate_ = dec;
|
|
+ if(running_) {
|
|
+ stop();
|
|
+ setsize();
|
|
+ start();
|
|
+ }
|
|
+ }
|
|
+ return (TCL_OK);
|
|
+ } else if (strcmp(argv[1], "fixed") == 0) {
|
|
+ mode_ = X11GRAB_FIXED;
|
|
+
|
|
+ int x = atoi(argv[2]);
|
|
+ int y = atoi(argv[3]);
|
|
+ if (x >= 0 && *argv[2] != '-' && x + width_ <= root_width)
|
|
+ x_origin_ = x ;
|
|
+ else if ( x <= 0 && -x + width_ <= root_width )
|
|
+ x_origin_ = root_width + x - width_ ;
|
|
+ if (y >= 0 && *argv[3] != '-' && y + height_ <= root_height)
|
|
+ y_origin_ = y ;
|
|
+ else if (y <= 0 && -y + height_ <= root_height )
|
|
+ y_origin_ = root_height + y - height_ ;
|
|
+ fprintf(stderr, "x11 fixed %d %d (root %dx%d)\n",
|
|
+ x_origin_, y_origin_, root_width, root_height);
|
|
+ return (TCL_OK);
|
|
+ } else if (!strcmp(argv[2], "pointer")) {
|
|
+ mode_ = X11GRAB_POINTER;
|
|
+ return (TCL_OK);
|
|
+ } else if (!strcmp(argv[2], "window")) {
|
|
+ mode_ = X11GRAB_WINDOW;
|
|
+ return (TCL_OK);
|
|
+ } else if (strcmp(argv[1], "format") == 0 ||
|
|
+ strcmp(argv[1], "type") == 0) {
|
|
+ if (running_)
|
|
+ format();
|
|
+ return (TCL_OK);
|
|
+ } else if (strcmp(argv[1], "contrast") == 0) {
|
|
+ contrast(atof(argv[2]));
|
|
+ return (TCL_OK);
|
|
+ }
|
|
+ } else if (argc == 2) {
|
|
+ if (strcmp(argv[1], "format") == 0 ||
|
|
+ strcmp(argv[1], "type") == 0) {
|
|
+ return (TCL_OK);
|
|
+ }
|
|
+ }
|
|
+ return (Grabber::command(argc, argv));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * captures in CIF or 411 -- color info is half the luma info.
|
|
+ */
|
|
+int
|
|
+X11Grabber::capture()
|
|
+{
|
|
+ int dograb = 0 ;
|
|
+
|
|
+#define MY_T uint8
|
|
+
|
|
+
|
|
+ switch (mode_) {
|
|
+ case X11GRAB_FIXED:
|
|
+ dograb = 1;
|
|
+ break;
|
|
+#if 0 /* not yet... */
|
|
+ case X11GRAB_POINTER:
|
|
+ dograb = X11Grab_FollowPointer();
|
|
+ break;
|
|
+ case X11GRAB_WINDOW:
|
|
+ dograb = X11Grab_FollowWindow();
|
|
+ break;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ if (1 || dograb) {
|
|
+ XImage *image=ximage_->image;
|
|
+
|
|
+#ifdef USE_SHM
|
|
+ if (ximage_->shminfo != NULL)
|
|
+ XShmGetImage(dpy_, theroot_, image, x_origin_, y_origin_,AllPlanes);
|
|
+ else
|
|
+#endif
|
|
+ XGetSubImage(dpy_, theroot_, x_origin_, y_origin_,
|
|
+ image->width, image->height, AllPlanes,
|
|
+ ZPixmap, image, 0, 0);
|
|
+ switch (c_grab) {
|
|
+ case grab_none: break;
|
|
+ case grab_X11Grab_LSBWhite1: X11Grab_LSBWhite1(); break;
|
|
+ case grab_X11Grab_MSBWhite1: X11Grab_MSBWhite1(); break;
|
|
+ case grab_X11Grab_LSBBlack1: X11Grab_LSBBlack1(); break;
|
|
+ case grab_X11Grab_MSBBlack1: X11Grab_MSBBlack1(); break;
|
|
+ case grab_X11Grab_Pseudo8: X11Grab_Pseudo8(); break;
|
|
+ case grab_X11Grab_RGB16: X11Grab_RGB16(); break;
|
|
+ case grab_X11Grab_TrueXBGR24: X11Grab_TrueXBGR24(); break;
|
|
+ case grab_X11Grab_TrueXRGB24: X11Grab_TrueXRGB24(); break;
|
|
+ }
|
|
+ return 1 ;
|
|
+ } else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int X11Grabber::grab()
|
|
+{
|
|
+ if (capture() == 0)
|
|
+ return (0);
|
|
+ suppress(frame_);
|
|
+ saveblks(frame_);
|
|
+ YuvFrame f(media_ts(), frame_, crvec_, outw_, outh_);
|
|
+ return (target_->consume(&f));
|
|
+}
|
|
+
|
|
+extern "C" {
|
|
+
|
|
+#include <sys/ipc.h>
|
|
+#ifdef USE_SHM
|
|
+#include <sys/shm.h>
|
|
+#if defined(sun) && !defined(__svr4__)
|
|
+int shmget(key_t, int, int);
|
|
+char *shmat(int, char*, int);
|
|
+int shmdt(char*);
|
|
+int shmctl(int, int, struct shmid_ds*);
|
|
+#endif
|
|
+#ifdef __osf__
|
|
+int XShmGetEventBase(struct _XDisplay *);
|
|
+#else
|
|
+int XShmGetEventBase(Display *);
|
|
+#endif
|
|
+#ifdef sgi
|
|
+#define XShmAttach __XShmAttach__
|
|
+#define XShmDetach __XShmDetach__
|
|
+#define XShmPutImage __XShmPutImage__
|
|
+#endif
|
|
+#include <X11/extensions/XShm.h>
|
|
+#ifdef sgi
|
|
+#undef XShmAttach
|
|
+#undef XShmDetach
|
|
+#undef XShmPutImage
|
|
+int XShmAttach(Display*, XShmSegmentInfo*);
|
|
+int XShmDetach(Display*, XShmSegmentInfo*);
|
|
+int XShmPutImage(Display*, Drawable, GC, XImage*, int, int, int, int,
|
|
+ int, int, int);
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+
|
|
+/*ARGSUSED*/
|
|
+static int
|
|
+ErrHandler(ClientData clientData, XErrorEvent *errevp)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+ximage_t *
|
|
+VidUtil_AllocXImage(Display *dpy, Visual *vis, int depth, int width,
|
|
+ int height, int readonly)
|
|
+{
|
|
+ ximage_t *ximage;
|
|
+ int ximage_size;
|
|
+ Tk_ErrorHandler handler;
|
|
+
|
|
+ ximage = (ximage_t *) malloc(sizeof(ximage_t));
|
|
+ if (ximage == NULL)
|
|
+ return NULL;
|
|
+
|
|
+#ifdef USE_SHM
|
|
+ if (1) {
|
|
+ XShmSegmentInfo *shminfo;
|
|
+
|
|
+ ximage->shminfo = shminfo =
|
|
+ (XShmSegmentInfo *) malloc(sizeof(XShmSegmentInfo));
|
|
+
|
|
+ ximage->image = XShmCreateImage(dpy, vis, depth, ZPixmap, 0, shminfo,
|
|
+ width, height);
|
|
+ ximage_size = ximage->image->bytes_per_line * ximage->image->height;
|
|
+
|
|
+ shminfo->shmid = shmget(IPC_PRIVATE, ximage_size, IPC_CREAT|0777);
|
|
+ if (shminfo->shmid != -1) {
|
|
+ shminfo->shmaddr = ximage->image->data =
|
|
+ (char *) shmat(shminfo->shmid, 0, 0);
|
|
+ shminfo->readOnly = readonly;
|
|
+
|
|
+ handler = Tk_CreateErrorHandler(dpy, -1, -1, -1, ErrHandler, NULL);
|
|
+ XShmAttach(dpy, shminfo);
|
|
+ XSync(dpy, False);
|
|
+ shmctl(shminfo->shmid, IPC_RMID, 0); /* so it goes away on exit */
|
|
+ Tk_DeleteErrorHandler(handler);
|
|
+ if (0) { /* so it goes away on exit... */
|
|
+ shmdt(shminfo->shmaddr);
|
|
+ shmctl(shminfo->shmid, IPC_RMID, 0);
|
|
+ XDestroyImage(ximage->image);
|
|
+ free(shminfo);
|
|
+ }
|
|
+ return ximage;
|
|
+ } else {
|
|
+ XDestroyImage(ximage->image);
|
|
+ free(shminfo);
|
|
+ ximage->shminfo = NULL ;
|
|
+ /* XXX hmmm... something more ? */
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ {
|
|
+ ximage->image = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, width,
|
|
+ height, (depth == 24) ? 32 : depth, 0);
|
|
+ ximage_size = ximage->image->bytes_per_line * ximage->image->height;
|
|
+ ximage->image->data = (char *) malloc(ximage_size);
|
|
+
|
|
+ ximage->shminfo = NULL;
|
|
+ }
|
|
+
|
|
+ return ximage;
|
|
+}
|
|
+
|
|
+void
|
|
+VidUtil_DestroyXImage(Display *dpy, ximage_t *ximage)
|
|
+{
|
|
+#ifdef USE_SHM
|
|
+ if (ximage->shminfo != NULL) {
|
|
+ XShmSegmentInfo *shminfo=(XShmSegmentInfo *)ximage->shminfo;
|
|
+
|
|
+ XShmDetach(dpy, shminfo);
|
|
+ shmdt(shminfo->shmaddr);
|
|
+ shmctl(shminfo->shmid, IPC_RMID, 0);
|
|
+ free(shminfo);
|
|
+ }
|
|
+ ximage->shminfo = NULL ;
|
|
+#endif
|
|
+
|
|
+ XDestroyImage(ximage->image);
|
|
+ free(ximage);
|
|
+}
|
|
+
|
|
+
|
|
+} /* end extern "C" block */
|