b39ac6d642
* an x11 grabber similar to the one present in nv. Extremely useful for interactive work (i'd say better than a camera in many cases). * add video controls to the meteor grabber (brightness etc.) * add tuner control when used with the meteor grabber (require a small modification to the kernel to let tuner be controlled via the grabber fd); Submitted by: luigi PR: 6814
1336 lines
36 KiB
Plaintext
1336 lines
36 KiB
Plaintext
--- grabber-x11.cc Sat May 30 14:55:30 1998
|
|
+++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber-x11.cc Fri Apr 10 21:32:11 1998
|
|
@@ -0,0 +1,1332 @@
|
|
+/*
|
|
+ * 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_Initialize(Window rw, int w, int h);
|
|
+ int (X11Grabber::*c_grab)(void);
|
|
+
|
|
+ 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) | ((p0>>5) & 0x7e0) | ((p0>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d<<8) & 0xf100) | ((p0>>5) & 0x7e0) | ((p0>>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) | ((p0>>5) & 0x7e0) | ((p0>>19) & 0x1f);
|
|
+ *yp++ = rgb2y_[ p0 ];
|
|
+
|
|
+ d = *data++ ;
|
|
+ p1 = ((d<<8) & 0xf100) | ((p0>>5) & 0x7e0) | ((p0>>19) & 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) ? X11Grab_LSBWhite1 : X11Grab_MSBWhite1;
|
|
+ } else {
|
|
+ c_grab = (LITTLEENDIAN) ? X11Grab_LSBBlack1 : X11Grab_MSBBlack1;
|
|
+ }
|
|
+ config = VID_GREYSCALE;
|
|
+ break;
|
|
+
|
|
+ case 8:
|
|
+ switch (root_visinfo.c_class) {
|
|
+ case PseudoColor:
|
|
+ case GrayScale:
|
|
+ case StaticColor:
|
|
+ case StaticGray:
|
|
+ c_grab = X11Grab_Pseudo8;
|
|
+ break;
|
|
+ default:
|
|
+ c_grab = NULL;
|
|
+ break;
|
|
+ }
|
|
+ config = VID_GREYSCALE|VID_COLOR;
|
|
+ break;
|
|
+
|
|
+ case 16:
|
|
+ c_grab = X11Grab_RGB16;
|
|
+ break ;
|
|
+
|
|
+ case 24:
|
|
+ if ((root_visinfo.c_class == TrueColor) &&
|
|
+ (root_visinfo.green_mask = 0xff00) &&
|
|
+#ifdef __FreeBSD__
|
|
+ (root_visinfo.red_mask == 0xff0000) &&
|
|
+ (root_visinfo.blue_mask == 0xff))
|
|
+#else
|
|
+ (root_visinfo.red_mask == 0xff) &&
|
|
+ (root_visinfo.blue_mask == 0xff0000))
|
|
+#endif
|
|
+ {
|
|
+ c_grab = X11Grab_TrueXBGR24;
|
|
+ } else
|
|
+ c_grab = NULL;
|
|
+ config = VID_GREYSCALE|VID_COLOR;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ fprintf(stderr, "don't know how to grab %d bits\n",
|
|
+ root_depth_);
|
|
+ c_grab = NULL;
|
|
+ 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 == NULL) ? 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 = NULL ; /* 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);
|
|
+ c_grab();
|
|
+ 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 */
|