summaryrefslogtreecommitdiff
path: root/mbone
diff options
context:
space:
mode:
authorJordan K. Hubbard <jkh@FreeBSD.org>1998-06-24 07:54:40 +0000
committerJordan K. Hubbard <jkh@FreeBSD.org>1998-06-24 07:54:40 +0000
commitb39ac6d642143a74bf5bb26fac58f657db08b199 (patch)
tree1523ca6cffccae4139a05ac293033f80578138ed /mbone
parentThis patch contains an update to the audio-voxware.cc module in vat (diff)
These patches implement the following features in vic:
* 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
Notes
Notes: svn path=/head/; revision=11502
Diffstat (limited to 'mbone')
-rw-r--r--mbone/vic/files/patch-al706
-rw-r--r--mbone/vic/files/patch-am1335
2 files changed, 2041 insertions, 0 deletions
diff --git a/mbone/vic/files/patch-al b/mbone/vic/files/patch-al
new file mode 100644
index 000000000000..668fefff59e4
--- /dev/null
+++ b/mbone/vic/files/patch-al
@@ -0,0 +1,706 @@
+diff -ubwr ./grabber-meteor.cc /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber-meteor.cc
+--- ./grabber-meteor.cc Fri May 29 17:06:00 1998
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber-meteor.cc Mon Apr 13 20:47:54 1998
+@@ -59,6 +59,7 @@
+ #include "bsd-endian.h"
+
+ #include <machine/ioctl_meteor.h>
++#include <machine/ioctl_bt848.h>
+
+ /*XXX*/
+ #define NTSC_WIDTH 320
+@@ -92,6 +93,7 @@
+ u_int baseheight_; /* Width of frame to be captured */
+ u_int decimate_; /* division of base sizes */
+ volatile u_int* pyuv_; /* pointer to yuv data */
++ int tuner_ ; /* tuner device... */
+ };
+
+ class Meteor422Grabber : public MeteorGrabber {
+@@ -131,24 +133,16 @@
+
+ MeteorScanner::MeteorScanner(const int n)
+ {
+- char* devname_template = "/dev/meteor%d";
+- char* nickname_template = "Matrox Meteor %d";
+- char* devname_template1 = "/dev/bktr%d";
+- char* nickname_template1 = "BrookTree848 %d";
+-
+-
++ static char *d[] = { "/dev/bktr%d", "/dev/meteor%d", NULL };
++ char *nickname_template = "meteor-%d";
+
+ for(int i = 0; i < n; i++) {
+- char *devname = new char[strlen(devname_template) + 3];
++ for (int j = 0 ; d[j] != NULL ; j++) {
++ char *devname = new char[strlen(d[j]) + 3];
+ char *nickname = new char[strlen(nickname_template) + 3];
+- char *devname1 = new char[strlen(devname_template1) + 3];
+- char *nickname1 = new char[strlen(nickname_template1) + 3];
+
++ sprintf(devname, d[j], i);
+ sprintf(nickname, nickname_template, i + 1);
+- sprintf(devname, devname_template, i);
+-
+- sprintf(nickname1, nickname_template1, i + 1);
+- sprintf(devname1, devname_template1, i);
+ if(access(devname, R_OK) == 0) {
+ int fd = open(devname, O_RDONLY);
+ if(fd < 0) {
+@@ -161,29 +155,17 @@
+ delete nickname;
+ delete devname;
+ }
+-
+- if(access(devname1, R_OK) == 0) {
+- int fd = open(devname1, O_RDONLY);
+- if(fd < 0) {
+- new MeteorDevice(nickname1, devname1, 0);
+- } else {
+- (void)close(fd);
+- new MeteorDevice(nickname1, devname1, 1);
+ }
+- } else {
+- delete nickname1;
+- delete devname1;
+ }
+ }
+
+-}
+-
+ MeteorDevice::MeteorDevice(const char* nickname, const char *devname, int free):
+ InputDevice(nickname), name_(devname)
+ {
+ if(free)
+ attributes_ = "\
+ format {422 411} \
++type {pal ntsc secam auto} \
+ size {large normal small cif} \
+ port {RCA Port-1 Port-2 Port-3 S-Video RGB}";
+ else
+@@ -208,6 +190,7 @@
+
+ MeteorGrabber::MeteorGrabber(const char* name)
+ {
++ tuner_ = open("/dev/tuner", O_RDONLY);
+ dev_ = open(name, O_RDONLY);
+ if (dev_ == -1) {
+ status_ = -1;
+@@ -230,6 +213,8 @@
+ if (dev_ != -1) {
+ close(dev_);
+ }
++ if (tuner_ != -1)
++ close(tuner_);
+ }
+
+ void MeteorGrabber::set_size_meteor(int w, int h)
+@@ -245,23 +230,14 @@
+ * means do so.
+ */
+ unsigned short status;
+- ioctl(dev_, METEORSTATUS, &status);
+- if(status & METEOR_STATUS_HCLK) {
+- /* No source, assume ntsc */
++ // ioctl(dev_, METEORSTATUS, &status);
++ if ( video_format_ == METEOR_FMT_NTSC ) {
+ if(geom.rows <= NTSC_HEIGHT && geom.columns <= NTSC_WIDTH)
+ geom.oformat |= METEOR_GEO_EVEN_ONLY;
+ } else {
+- /* is it pal or ntsc? */
+- if(status & METEOR_STATUS_FIDT) {
+- /* 60 hz */
+- if(geom.rows<=NTSC_HEIGHT && geom.columns<=NTSC_WIDTH)
+- geom.oformat |= METEOR_GEO_EVEN_ONLY;
+- } else { /* 50 hz */
+ if(geom.rows<=PAL_HEIGHT && geom.columns<=PAL_WIDTH)
+ geom.oformat |= METEOR_GEO_EVEN_ONLY;
+ }
+- }
+-
+ if(ioctl(dev_, METEORSETGEO, &geom) < 0)
+ perror("vic: METERSETGEO: ");
+ }
+@@ -326,7 +302,7 @@
+ void MeteorGrabber::fps(int f)
+ {
+ u_short met_fps = (u_short)f;
+- (void)ioctl(dev_, METEORSFPS, &met_fps);
++ // (void)ioctl(dev_, METEORSFPS, &met_fps);
+
+ Grabber::fps(f);
+ }
+@@ -367,6 +343,28 @@
+ }
+ return (TCL_OK);
+ }
++ if (strcmp(argv[1], "freeze") == 0) {
++ int cmd = METEOR_CAP_CONTINOUS ;
++ if ( atoi(argv[2]) != 0 )
++ cmd = METEOR_CAP_STOP_CONT;
++ ioctl(dev_, METEORCAPTUR, (char*)&cmd);
++ return (TCL_OK);
++ }
++ if (strcmp(argv[1], "chan") == 0) {
++ int p = port_;
++ int c = atoi(argv[2]);
++ if (c > 0 && c < 199)
++ p = METEOR_INPUT_DEV1 ;
++ else
++ p = METEOR_INPUT_DEV0 ;
++ if (p != port_) {
++ port_ = p;
++ ioctl(dev_, METEORSINPUT, &port_);
++ }
++ if (p == METEOR_INPUT_DEV1)
++ ioctl(dev_, TVTUNER_SETCHNL, &c);
++ return (TCL_OK);
++ }
+ if (strcmp(argv[1], "format") == 0 ||
+ strcmp(argv[1], "type") == 0) {
+ if (strcmp(argv[2], "auto") == 0)
+@@ -437,7 +435,7 @@
+ if (strcmp(argv[1], "brightness") == 0) {
+ u_char val;
+ ioctl(dev_, METEORGBRIG, &val);
+- tcl.resultf("%d", (int)val);
++ tcl.resultf("%d", (unsigned int)val);
+ return (TCL_OK);
+ }
+ if (strcmp(argv[1], "contrast") == 0) {
+@@ -507,10 +505,10 @@
+ return 0;
+
+ int istride = inw_ * 2;
+- suppress((u_char*)pyuv_, istride);
+- saveblks((u_char*)pyuv_, istride);
++ suppress((u_char*)pyuv_, istride); // compute which ones to send
++ saveblks((u_char*)pyuv_, istride); // save copied blocks
+ u_int32_t ts = media_ts();
+- YuvFrame f(ts, frame_, crvec_, outw_, outh_);
++ YuvFrame f(ts, frame_, crvec_, outw_, outh_); // new obj.
+ return (target_->consume(&f));
+ }
+
+@@ -724,6 +722,7 @@
+ u_char* chm = lum + off;
+ off >>= 2;
+
++int to_send = 0 ;
+ crv += vstart_ * blkw_ + hstart_;
+ lum += vstart_ * outw_ * 16 + hstart_ * 16;
+ chm += vstart_ * (outw_ >> 1) * 8 + hstart_ * 8;
+@@ -734,9 +733,10 @@
+ const u_char* nin = in;
+ for (int x = hstart_; x < hstop_; ++x) {
+ int s = *crv++;
+- if ((s & CR_SEND) != 0)
++ if ((s & CR_SEND) != 0) {
+ saveblk(in, lum, chm, chm + off, outw_, is);
+-
++ to_send++ ;
++ }
+ in += 32;
+ lum += 16;
+ chm += 8;
+@@ -746,4 +746,5 @@
+ chm += 7 * (outw_ >> 1) + skip * 8;
+ in = nin + 16 * is;
+ }
++ // fprintf(stderr, "this time send %d\n", to_send);
+ }
+diff -ubwr ./grabber.cc /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber.cc
+--- ./grabber.cc Tue Feb 6 00:02:00 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber.cc Fri Apr 10 15:36:42 1998
+@@ -69,6 +69,7 @@
+ hstart_(0), hstop_(0),
+ framebase_(0), frame_(0),
+ inw_(0), inh_(0), outw_(0), outh_(0),
++ threshold_(48),
+ target_(0), tx_(0)
+ {
+ bps(128);
+@@ -122,6 +123,10 @@
+ }
+ return (TCL_OK);
+ }
++ if (strcmp(argv[1], "threshold") == 0) {
++ threshold_ = 8*atoi(argv[2]);
++ return (TCL_OK);
++ }
+ if (strcmp(argv[1], "fps") == 0) {
+ /*XXX assume value in range */
+ fps(atoi(argv[2]));
+@@ -194,11 +199,14 @@
+ * favoring the more restrictive metric. If we're more than
+ * 200ms behind (e.g., the cpu is saturated or we've been
+ * suspended), give up and reset the frame clock.
++ * The argument passed is the number of bytes transmitted.
+ */
+ double Grabber::tick(int n)
+ {
++ // how much it took to send the data (microseconds)
+ double frametime = 8e6 * double(n) / double(bps_);
+ if (frametime < frametime_) {
++ // took less than one frame...
+ if (frametime * 2. < frametime_)
+ delta_ += (frametime - delta_) * .25;
+ else
+@@ -207,6 +215,7 @@
+ } else
+ delta_ = frametime;
+
++ // when to get next frame (not earlier than now!
+ frameclock_ += frametime;
+ double now = gettimeofday();
+ double delta = frameclock_ - now;
+diff -ubwr ./grabber.h /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber.h
+--- ./grabber.h Tue Feb 6 00:02:00 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/grabber.h Fri Apr 10 15:37:28 1998
+@@ -87,6 +87,7 @@
+ int vstop_;
+ int hstart_;
+ int hstop_;
++ int threshold_ ; // when a block is changed ? (was constant 48)
+
+ u_int framesize_;
+ u_char* framebase_;
+@@ -160,19 +161,19 @@
+ rb -= _rs << 3; \
+ \
+ int center = 0; \
+- if (left >= 48 && x > 0) { \
++ if (left >= threshold_ && x > 0) { \
+ crv[-1] = CR_MOTION|CR_SEND; \
+ center = 1; \
+ } \
+- if (right >= 48 && x < w - 1) { \
++ if (right >= threshold_ && x < w - 1) { \
+ crv[1] = CR_MOTION|CR_SEND; \
+ center = 1; \
+ } \
+- if (bottom >= 48 && y < blkh_ - 1) { \
++ if (bottom >= threshold_ && y < blkh_ - 1) { \
+ crv[w] = CR_MOTION|CR_SEND; \
+ center = 1; \
+ } \
+- if (top >= 48 && y > 0) { \
++ if (top >= threshold_ && y > 0) { \
+ crv[-w] = CR_MOTION|CR_SEND; \
+ center = 1; \
+ } \
+diff -ubwr ./ui-ctrlmenu.tcl /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-ctrlmenu.tcl
+--- ./ui-ctrlmenu.tcl Thu Jun 27 01:27:48 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-ctrlmenu.tcl Fri Apr 10 16:39:04 1998
+@@ -124,6 +124,7 @@
+ catch "wm resizable $w false false"
+
+ frame $w.session
++ # luigi - move next 2 lines to ui-main
+ frame $w.cb
+ build.xmit $w.cb
+ frame $w.encoder
+@@ -139,9 +140,12 @@
+ -relief raised -anchor c \
+ -command "toggle_window $w" -font [mediumfont]
+
++ # luigi $w.cb goes into main menu
+ pack $w.cb $w.encoder $w.decoder $w.session -padx 6 -fill x
++ # pack $w.encoder $w.decoder $w.session -padx 6 -fill x
+ pack $w.dismiss -anchor c -pady 4
+
++ # luigi - move next 3 lines to ui-main (must check something)
+ if [have_transmit_permission] {
+ selectInitialDevice
+ }
+@@ -390,11 +394,15 @@
+ -relief raised -command transmit \
+ -anchor w -variable transmitButtonState -font $f \
+ -state disabled -highlightthickness 0
++ checkbutton $w.freeze -text "Freeze" \
++ -relief raised -command "grabber freeze \$freeze" \
++ -anchor w -variable freeze -font $f \
++ -highlightthickness 0
+ button $w.release -text "Release" \
+ -relief raised -command release_device \
+ -font $f -highlightthickness 0
+
+- pack $w.send $w.release -fill both
++ pack $w.send $w.release $w.freeze -fill both
+ }
+
+ proc doNothing { args } {
+@@ -434,8 +442,9 @@
+
+ frame $w.bps
+ scale $w.bps.scale -orient horizontal -font $f \
+- -showvalue 0 -from 10 -to [option get . maxbw Vic] \
++ -showvalue 0 -from 1 -to [option get . maxbw Vic] \
+ -command "set_bps $w.bps.value" -width 12 \
++ -sliderlength 20 \
+ -relief groove
+ label $w.bps.value -font $f -width 8 -anchor w
+
+@@ -443,6 +452,7 @@
+ scale $w.fps.scale -font $f -orient horizontal \
+ -showvalue 0 -from 1 -to 30 \
+ -command "set_fps $w.fps.value" -width 12 \
++ -sliderlength 20 \
+ -relief groove
+ label $w.fps.value -font $f -width 8 -anchor w
+
+@@ -564,7 +574,7 @@
+ proc select_device device {
+ global transmitButton sizeButtons portButton formatButtons \
+ videoFormat defaultFormat lastDevice defaultPort inputPort \
+- transmitButtonState
++ transmitButtonState typeButton
+
+ #
+ # Remember settings of various controls for previous device
+@@ -607,6 +617,11 @@
+ } else {
+ $portButton configure -state disabled
+ }
++ if [device_supports $device type *] {
++ $typeButton configure -state normal
++ } else {
++ $typeButton configure -state disabled
++ }
+
+ insert_grabber_panel [$device nickname]
+
+@@ -765,7 +780,7 @@
+ -value secam -variable inputType -font $f
+
+ global inputType typeButton
+- set inputType auto
++ set inputType pal ; # auto
+ set typeButton $w
+ }
+
+@@ -774,7 +789,8 @@
+ build.encoder_options $w.options
+ build.device $w.device
+ build.port $w.port
+- pack $w.device $w.port $w.options -fill x
++ build.type $w.type
++ pack $w.device $w.port $w.type $w.options -fill x
+ }
+
+ proc build.encoder_options w {
+@@ -1172,6 +1188,9 @@
+ global inputPort inputType portButton typeButton
+ if { [$portButton cget -state] == "normal" } {
+ $grabber port $inputPort
++ }
++ if { [$typeButton cget -state] == "normal" } {
++ $grabber type $inputType
+ }
+ setFillRate
+ update
+diff -ubwr ./ui-grabber.tcl /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-grabber.tcl
+--- ./ui-grabber.tcl Fri Jun 21 04:39:35 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-grabber.tcl Fri Apr 10 13:54:42 1998
+@@ -39,65 +39,93 @@
+ # called foo-1, foo-2, etc. and you'll only need build.foo
+ #
+
++proc build.meteor w {
++#
++# The meteor has the same controls as the slicvideo, so just call that
++# routine to build the controls.
++
++ build.slicvideo $w
++}
++
++proc build.bktr w {
++ build.slicvideo $w
++}
++
+ proc build.slicvideo w {
+ set f [smallfont]
++# set f "-*-helvetica-medium-r-normal--*-100-75-75-*-*-*-*"
+ label $w.title -text "Grabber"
+ frame $w.f -relief sunken -borderwidth 2
+
+ frame $w.f.h -relief flat
+
+- label $w.f.h.label -font $f -anchor e -text "Hue"
+-
+- scale $w.f.h.scale -orient horizontal -width 12 -length 20 \
+- -relief groove -showvalue 0 -from -128 -to 127 \
+- -command "grabber set HUE"
+- pack $w.f.h.label $w.f.h.scale -side left -fill x -expand 1
+-
+- frame $w.f.ll -relief flat
+-
+- label $w.f.ll.label -font $f -text "Luma" -anchor s
+-
+- label $w.f.ll.clabel -font $f -text "Contrast" -anchor s
+-
+- label $w.f.ll.blabel -font $f -text "Brightness" -anchor s
+- pack $w.f.ll.clabel $w.f.ll.label $w.f.ll.blabel \
++ frame $w.f.h.c
++ label $w.f.h.c.l1 -font $f -anchor e -text "Chan:"
++ mk.entry $w.f.h.c do_chan "20"
++ $w.f.h.c.entry configure -relief sunken -width 5
++ bind $w.f.h.c.entry <Return> "grabber chan \[$w.f.h.c.entry get\]"
++ pack $w.f.h.c.l1 $w.f.h.c.entry -side top
++
++ global ths
++ scale $w.f.h.ths \
++-orient horizontal -width 12 -length 60 -relief groove -sliderlength 6 \
++ -showvalue 0 -from 1 -to 10 \
++ -command "grabber threshold" -label Thre
++ $w.f.h.ths set 6
++ # the actual scale is multiplied by 8
++ scale $w.f.h.scale \
++-orient horizontal -width 12 -length 100 -relief groove \
++ -showvalue 0 -from -128 -to 127 \
++ -command "grabber hue" -label Hue
++ pack $w.f.h.c \
++ $w.f.h.ths \
++ $w.f.h.scale \
+ -side left -fill x -expand 1
+
++# frame $w.f.ll -relief flat
++# label $w.f.ll.label -font $f -text "Luma" -anchor s
++# label $w.f.ll.clabel -font $f -text "Contrast" -anchor s
++# label $w.f.ll.blabel -font $f -text "Brightness" -anchor s
++# pack $w.f.ll.clabel $w.f.ll.label $w.f.ll.blabel \
++# -side left -fill x -expand 1
++
+ frame $w.f.l -relief flat
+
+- scale $w.f.l.cscale -orient horizontal -width 12 -relief groove \
++ scale $w.f.l.cscale \
++-orient horizontal -width 12 -length 100 -relief groove \
+ -showvalue 0 -from 0 -to 127 \
+- -command "grabber set LUMA_CONTRAST"
++ -label "Contrast" \
++ -command "grabber contrast"
+
+- scale $w.f.l.bscale -orient horizontal -width 12 -relief groove \
++ scale $w.f.l.bscale \
++-orient horizontal -width 12 -length 100 -relief groove \
+ -showvalue 0 -from 0 -to 255 \
+- -command "grabber set LUMA_BRIGHTNESS"
++ -command "grabber brightness" -label "Brightness"
+ pack $w.f.l.cscale $w.f.l.bscale -side left -fill x -expand 1
+
+- frame $w.f.cl -relief flat
+-
+- label $w.f.cl.label -font $f -text "Chroma" -anchor n
+-
+- label $w.f.cl.glabel -font $f -text "Gain" -anchor n
+-
+- label $w.f.cl.slabel -font $f -text "Saturation" -anchor n
+- pack $w.f.cl.glabel $w.f.cl.label $w.f.cl.slabel \
+- -side left -fill x -expand 1
++# frame $w.f.cl -relief flat
++# label $w.f.cl.label -font $f -text "Chroma" -anchor n
++# label $w.f.cl.glabel -font $f -text "Gain" -anchor n
++# label $w.f.cl.slabel -font $f -text "Saturation" -anchor n
++# pack $w.f.cl.glabel $w.f.cl.label $w.f.cl.slabel \
++# -side left -fill x -expand 1
+
+ frame $w.f.c -relief flat
+
+- scale $w.f.c.gscale -orient horizontal -width 12 -relief groove \
++ scale $w.f.c.gscale \
++-orient horizontal -width 12 -length 100 -relief groove \
+ -showvalue 0 -from 0 -to 255 \
+- -command "grabber set CHROMA_GAIN"
++ -command "grabber uvgain" -label "Chr. Gain"
+
+- scale $w.f.c.sscale -orient horizontal -width 12 -relief groove \
++ scale $w.f.c.sscale \
++-orient horizontal -width 12 -length 100 -relief groove \
+ -showvalue 0 -from 0 -to 127 \
+- -command "grabber set CHROMA_SATURATION"
++ -command "grabber saturation" -label "Saturation"
+ pack $w.f.c.gscale $w.f.c.sscale -side left -fill x -expand 1
+
+
+- pack $w.f.h $w.f.ll $w.f.l $w.f.c $w.f.cl \
+- -fill x -expand 1 -padx 1m
++ # pack $w.f.h $w.f.ll $w.f.l $w.f.c $w.f.cl
++ pack $w.f.h $w.f.l $w.f.c -fill x -expand 1 -padx 1m
+
+
+ pack $w.title $w.f -fill x -expand 1
+@@ -109,6 +137,10 @@
+ $w.f.c.sscale set 64
+ }
+
++#
++# STILL image-grabber (?)
++#
++
+ proc build.still w {
+
+ set f [smallfont]
+@@ -131,6 +163,10 @@
+ $lastDevice file $s
+ }
+
++#
++# quickcam grabber
++#
++
+ proc build.qcam {w} {
+ global qcamwindow
+
+@@ -190,3 +226,118 @@
+ set qcamwindow(setwbal) "$w.f.s.s.wbal.scale set"
+ set qcamwindow(setbpp) "set qcambpp"
+ }
++
++#
++# X11 Grabber controls
++#
++proc x11grabUpdatePos {x y w h} {
++
++ global x11grabcontrols
++ set w $x11grabcontrols
++
++ if {[string compare $x [$w.x11grab.row1.pos.x.e get]] != 0} {
++ $w.x11grab.row1.pos.x.e delete 0 end
++ $w.x11grab.row1.pos.x.e insert 0 $x
++ }
++ if {[string compare $y [$w.x11grab.row1.pos.y.e get]] != 0} {
++ $w.x11grab.row1.pos.y.e delete 0 end
++ $w.x11grab.row1.pos.y.e insert 0 $y
++ }
++ if {[string compare $w [$w.x11grab.row1.pos.w.e get]] != 0} {
++ $w.x11grab.row1.pos.w.e delete 0 end
++ $w.x11grab.row1.pos.w.e insert 0 $w
++ }
++ if {[string compare $h [$w.x11grab.row1.pos.h.e get]] != 0} {
++ $w.x11grab.row1.pos.h.e delete 0 end
++ $w.x11grab.row1.pos.h.e insert 0 $h
++ }
++}
++
++proc x11cmd.update.geo w {
++ grabber fixed [$w.row.x get] [$w.row.y get]
++}
++
++proc x11cmd.fixed {} {
++ global x11Source x11grabcontrols
++ set w $x11grabcontrols
++ $w.label configure -text "$x11Source"
++ if [winfo exists $w.row] {
++ destroy $w.row
++ }
++ frame $w.row
++ pack append $w.row \
++ [label $w.row.xl -text "X:" -width 2 -anchor e] {left filly} \
++ [entry $w.row.x -relief flat -width 4] {left filly} \
++ [label $w.row.yl -text "Y:" -width 2 -anchor e] {left filly} \
++ [entry $w.row.y -relief flat -width 4] {left filly}
++ bind $w.row.x <Return> "x11cmd.update.geo $w"
++ bind $w.row.y <Return> "x11cmd.update.geo $w"
++
++ pack $w.row -after $w.label
++}
++
++proc x11cmd.pointer {} {
++ global x11Source x11grabcontrols
++ set w $x11grabcontrols
++ $w.label configure -text "$x11Source"
++ if [winfo exists $w.row] {
++ destroy $w.row
++ }
++ frame $w.row
++ pack append $w.row \
++ [button $w.row.s -text "Follow pointer" ] { left filly }
++ pack $w.row -after $w.label
++}
++
++proc x11cmd.window {} {
++ global x11Source x11grabcontrols
++ puts "x11cmd -- x11Source $x11Source"
++ set w $x11grabcontrols
++ $w.label configure -text "$x11Source"
++ if [winfo exists $w.row] {
++ destroy $w.row
++ }
++ frame $w.row
++ pack append $w.row \
++ [button $w.row.s -text "Select window" ] { left filly }
++ pack $w.row -after $w.label
++}
++
++proc build.x11 w {
++ global x11grabcontrols x11Source
++ set f [smallfont]
++
++ label $w.title -text "X11 Grabber controls"
++ frame $w.x11grab -relief sunken -borderwidth 2
++ set x11grabcontrols $w.x11grab
++ set x11Source "Fixed"
++ set w1 $w.x11grab
++
++
++ # luigi
++ set m $w1.menu
++ set m1 $m.m1
++ menubutton $w1.menu -menu $m1 -text "Source:" \
++ -relief raised -width 7 -font $f
++ label $w1.label -width 6 -font $f
++ frame $w1.row
++ menu $m1
++ $m1 add radiobutton -label Fixed \
++ -state active \
++ -command "x11cmd.fixed" -font $f -variable x11Source
++# $m1 add radiobutton -label Pointer \
++# -command "x11cmd.pointer" -font $f -variable x11Source
++# $m1 add radiobutton -label Window \
++# -command "x11cmd.window" -font $f -variable x11Source
++
++ pack append $w1 \
++ $w1.menu {left} \
++ $w1.label {left} \
++ $w1.row {left}
++
++ pack $w $w.title $w1 -fill x -expand 1
++
++ x11cmd.fixed
++}
++
++### end of file ###
+diff -ubwr ./ui-resource.tcl /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-resource.tcl
+--- ./ui-resource.tcl Wed Apr 3 02:33:56 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-resource.tcl Fri Apr 10 21:11:56 1998
+@@ -140,7 +140,7 @@
+ option add Vic.useHardwareDecode false startupFile
+ option add Vic.infoHighlightColor LightYellow2 startupFile
+ option add Vic.useJPEGforH261 false startupFile
+- option add Vic.stillGrabber false startupFile
++ option add Vic.stillGrabber true startupFile ; # XXX was false
+ option add Vic.siteDropTime "300" startupFile
+
+ #
+diff -ubwr ./ui-util.tcl /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-util.tcl
+--- ./ui-util.tcl Tue Feb 6 00:02:20 1996
++++ /home/old_wd0f/ports/mbone/vic/work.luigi/vic-2.8-luigi/ui-util.tcl Fri Apr 10 20:49:56 1998
+@@ -64,7 +64,7 @@
+ global created$w
+ if { ! [info exists created$w] } {
+ set created$w 1
+- wm transient $w .
++ # wm transient $w .
+ update idletasks
+ set x [winfo rootx .]
+ set y [winfo rooty .]
+@@ -103,7 +103,7 @@
+ }
+ set title [resource iconPrefix]$title
+ wm withdraw $w
+- wm transient $w .
++ # wm transient $w .
+ wm title $w $title
+ wm iconname $w $title
+ bind $w <Enter> "focus $w"
diff --git a/mbone/vic/files/patch-am b/mbone/vic/files/patch-am
new file mode 100644
index 000000000000..a29a780aa006
--- /dev/null
+++ b/mbone/vic/files/patch-am
@@ -0,0 +1,1335 @@
+--- 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 */