From b39ac6d642143a74bf5bb26fac58f657db08b199 Mon Sep 17 00:00:00 2001 From: "Jordan K. Hubbard" Date: Wed, 24 Jun 1998 07:54:40 +0000 Subject: 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 --- mbone/vic/files/patch-al | 706 ++++++++++++++++++++++++ mbone/vic/files/patch-am | 1335 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2041 insertions(+) create mode 100644 mbone/vic/files/patch-al create mode 100644 mbone/vic/files/patch-am (limited to 'mbone/vic') 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 ++#include + + /*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 "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 "x11cmd.update.geo $w" ++ bind $w.row.y "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 "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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "grabber.h" ++#include "Tcl.h" ++#include "device-input.h" ++#include "module.h" ++ ++#include ++#include ++#include ++#include ++#include ++/*** #include "sized_types.h" ***/ ++ ++/* ++ Netvideo version 3.3 ++ Written by Ron Frederick ++ ++ 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> 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>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>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>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>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> 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> 2) ; ++ uint16 *data=(uint16 *)ximage_->image->data, p0, p1, p2, p3; ++ ++ for (y=0; y> 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> 2) ; ++ uint16 p0, p1 ; ++ uint32 *data=(uint32 *)ximage_->image->data, d ; ++ ++ for (y=0; y>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>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 ++#ifdef USE_SHM ++#include ++#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 ++#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 */ -- cgit v1.2.3