aboutsummaryrefslogtreecommitdiff
path: root/externals/gridflow/format
diff options
context:
space:
mode:
authorN.N. <matju@users.sourceforge.net>2008-07-08 05:56:10 +0000
committerN.N. <matju@users.sourceforge.net>2008-07-08 05:56:10 +0000
commit089475041fe26964d72cb2ebc3559a36ba89a2f2 (patch)
tree4ea7537e82b2ee34748ef7cbfc18c523425d4f7a /externals/gridflow/format
parentd1ad56f1da41e7a88eb9a52d6b0daaf145b54ea7 (diff)
trying to import gridflow 0.9.4
svn path=/trunk/; revision=10148
Diffstat (limited to 'externals/gridflow/format')
-rw-r--r--externals/gridflow/format/aalib.c144
-rw-r--r--externals/gridflow/format/dc1394.c287
-rw-r--r--externals/gridflow/format/ieee1394-ioctl.h111
-rw-r--r--externals/gridflow/format/jpeg.c122
-rw-r--r--externals/gridflow/format/main.c249
-rw-r--r--externals/gridflow/format/mpeg3.c83
-rw-r--r--externals/gridflow/format/netpbm.c119
-rw-r--r--externals/gridflow/format/opengl.c174
-rw-r--r--externals/gridflow/format/png.c116
-rw-r--r--externals/gridflow/format/pwc-ioctl.h292
-rw-r--r--externals/gridflow/format/quartz.m224
-rw-r--r--externals/gridflow/format/quicktimeapple.c456
-rw-r--r--externals/gridflow/format/quicktimehw.c243
-rw-r--r--externals/gridflow/format/sdl.c209
-rw-r--r--externals/gridflow/format/videodev.c792
-rw-r--r--externals/gridflow/format/x11.c656
16 files changed, 4277 insertions, 0 deletions
diff --git a/externals/gridflow/format/aalib.c b/externals/gridflow/format/aalib.c
new file mode 100644
index 00000000..f33d8d83
--- /dev/null
+++ b/externals/gridflow/format/aalib.c
@@ -0,0 +1,144 @@
+/*
+ $Id: aalib.c 3624 2008-04-19 02:07:36Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#define aa_hardwareparams aa_hardware_params
+#include <aalib.h>
+#include <map>
+
+/* MINNOR is a typo in aalib.h, sorry */
+typedef
+#if AA_LIB_MINNOR == 2
+ int
+#else
+ enum aa_attribute
+#endif
+AAAttr;
+
+static std::map<string,const aa_driver *> drivers;
+
+\class FormatAALib : Format {
+ aa_context *context;
+ aa_renderparams *rparams;
+ \attr bool autodraw;
+ bool raw_mode;
+ /* !@#$ varargs missing here */
+ \constructor (t_symbol *mode, string target) {
+ context=0; autodraw=1;
+ argc-=2; argv+=2;
+ char *argv2[argc];
+ for (int i=0; i<argc; i++) argv2[i] = strdup(string(argv[i]).data());
+ if (mode!=gensym("out")) RAISE("write-only, sorry");
+ aa_parseoptions(0,0,&argc,argv2);
+ for (int i=0; i<argc; i++) free(argv2[i]);
+ if (drivers.find(target)==drivers.end()) RAISE("unknown aalib driver '%s'",target.data());
+ const aa_driver *driver = drivers[target];
+ context = aa_init(driver,&aa_defparams,0);
+ rparams = aa_getrenderparams();
+ if (!context) RAISE("opening aalib didn't work");
+ int32 v[]={context->imgheight,context->imgwidth,1};
+ post("aalib image size: %s",(new Dim(3,v))->to_s());
+ }
+ ~FormatAALib () {if (context) aa_close(context);}
+ \decl 0 hidecursor ();
+ \decl 0 print (int y, int x, int a, string text);
+ \decl 0 draw ();
+ \decl 0 dump ();
+ \grin 0 int
+};
+
+GRID_INLET(FormatAALib,0) {
+ if (!context) RAISE("boo");
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ switch (in->dim->get(2)) {
+ case 1: raw_mode = false; break;
+ case 2: raw_mode = true; break;
+ default:
+ RAISE("expecting 1 greyscale channel (got %d)",in->dim->get(2));
+ }
+ in->set_chunk(1);
+} GRID_FLOW {
+ int f = in->factor();
+ if (raw_mode) {
+ int sx = min(f,aa_scrwidth(context));
+ int y = in->dex/f;
+ while (n) {
+ if (y>=aa_scrheight(context)) return;
+ for (int x=0; x<sx; x++) {
+ context->textbuffer[y*aa_scrwidth(context)+x]=data[x*2+0];
+ context->attrbuffer[y*aa_scrwidth(context)+x]=data[x*2+1];
+ }
+ y++;
+ n-=f;
+ data+=f;
+ }
+ } else {
+ int sx = min(f,context->imgwidth);
+ int y = in->dex/f;
+ while (n) {
+ if (y>=context->imgheight) return;
+ for (int x=0; x<sx; x++) aa_putpixel(context,x,y,data[x]);
+ y++;
+ n-=f;
+ data+=f;
+ }
+ }
+} GRID_FINISH {
+ if (!raw_mode) {
+ aa_palette pal;
+ for (int i=0; i<256; i++) aa_setpalette(pal,i,i,i,i);
+ aa_renderpalette(context,pal,rparams,0,0,
+ aa_scrwidth(context),aa_scrheight(context));
+ }
+ if (autodraw==1) aa_flush(context);
+} GRID_END
+
+\def 0 hidecursor () { aa_hidemouse(context); }
+\def 0 draw () { aa_flush(context); }
+\def 0 print (int y, int x, int a, string text) {
+ aa_puts(context,x,y,(AAAttr)a,(char *)text.data());
+ if (autodraw==1) aa_flush(context);
+}
+
+\def 0 dump () {
+ int32 v[] = {aa_scrheight(context), aa_scrwidth(context), 2};
+ GridOutlet out(this,0,new Dim(3,v));
+ for (int y=0; y<aa_scrheight(context); y++) {
+ for (int x=0; x<aa_scrwidth(context); x++) {
+ int32 data[2];
+ data[0] = context->textbuffer[y*aa_scrwidth(context)+x];
+ data[1] = context->attrbuffer[y*aa_scrwidth(context)+x];
+ out.send(2,data);
+ }
+ }
+}
+
+\end class FormatAALib {
+ const aa_driver *const *p = aa_drivers;
+ for (; *p; p++) drivers[(*p)->shortname] = *p;
+ install_format("#io.aalib",2,"");
+}
+void startup_aalib () {
+ \startall
+}
diff --git a/externals/gridflow/format/dc1394.c b/externals/gridflow/format/dc1394.c
new file mode 100644
index 00000000..7f107b49
--- /dev/null
+++ b/externals/gridflow/format/dc1394.c
@@ -0,0 +1,287 @@
+/*
+ $Id: dc1394.c 3978 2008-07-04 20:18:01Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <libraw1394/raw1394.h>
+#include <libdc1394/dc1394_control.h>
+#include "../gridflow.h.fcs"
+
+/* speeds are numbered 0 to 5, worth 100<<speednum */
+/* framerates are numbers 32 to 39, worth 1.875<<(frameratenum-32) */
+
+#define MODE(x,y,palette) /* nothing for now */
+
+static std::map<int,string> feature_names;
+
+static void setup_modes () {
+ int i=64; // format 0
+ MODE(160,120,YUV444);
+ MODE(320,240,YUV422);
+ MODE(640,480,YUV411);
+ MODE(640,480,YUV422);
+ MODE(640,480,RGB);
+ MODE(640,480,MONO);
+ MODE(640,480,MONO16);
+ i=96; // format 1
+ MODE(800,600,YUV422);
+ MODE(800,600,RGB);
+ MODE(800,600,MONO);
+ MODE(1024,768,YUV422);
+ MODE(1024,768,RGB);
+ MODE(1024,768,MONO);
+ MODE(800,600,MONO16);
+ MODE(1024,768,MONO16);
+ i=128; // format 2
+ MODE(1280,960,YUV422);
+ MODE(1280,960,RGB);
+ MODE(1280,960,MONO);
+ MODE(1600,1200,YUV422);
+ MODE(1600,1200,RGB);
+ MODE(1600,1200,MONO);
+ MODE(1280,960,MONO16);
+ MODE(1600,1200,MONO16);
+ i=256; // format 6
+ // MODE_EXIF= 256
+ i=288; // format 7
+ //MODE_FORMAT7_0,
+ //MODE_FORMAT7_1,
+ //MODE_FORMAT7_2,
+ //MODE_FORMAT7_3,
+ //MODE_FORMAT7_4,
+ //MODE_FORMAT7_5,
+ //MODE_FORMAT7_6,
+ //MODE_FORMAT7_7
+
+// format7 color modes start at #320 and are MONO8 YUV411 YUV422 YUV444 RGB8 MONO16 RGB16 MONO16S RGB16S RAW8 RAW16
+// trigger modes start at #352 and are 0 1 2 3
+// image formats start at #384 and are VGA_NONCOMPRESSED SVGA_NONCOMPRESSED_1 SVGA_NONCOMPRESSED_2
+// and continue at #390 and are STILL_IMAGE FORMAT_SCALABLE_IMAGE_SIZE
+
+#define FEATURE(foo) feature_names[i++] = #foo;
+
+ i=416;
+ FEATURE(BRIGHTNESS);
+ FEATURE(EXPOSURE);
+ FEATURE(SHARPNESS);
+ FEATURE(WHITE_BALANCE);
+ FEATURE(HUE);
+ FEATURE(SATURATION);
+ FEATURE(GAMMA);
+ FEATURE(SHUTTER);
+ FEATURE(GAIN);
+ FEATURE(IRIS);
+ FEATURE(FOCUS);
+ FEATURE(TEMPERATURE);
+ FEATURE(TRIGGER);
+ FEATURE(TRIGGER_DELAY);
+ FEATURE(WHITE_SHADING);
+ FEATURE(FRAME_RATE);
+ i+=16;/* 16 reserved features */
+ FEATURE(ZOOM);
+ FEATURE(PAN);
+ FEATURE(TILT);
+ FEATURE(OPTICAL_FILTER);
+ i+=12;/* 12 reserved features */
+ FEATURE(CAPTURE_SIZE);
+ FEATURE(CAPTURE_QUALITY);
+ i+=14;/* 14 reserved features */
+
+ i=480; // operation modes
+ //OPERATION_MODE_LEGACY
+ //OPERATION_MODE_1394B
+
+ i=512; // sensor layouts
+ //RGGB
+ //GBRG,
+ //GRBG,
+ //BGGR
+
+ i=544; // IIDC_VERSION
+#if 0
+ IIDC_VERSION(1_04);
+ IIDC_VERSION(1_20);
+ IIDC_VERSION(PTGREY);
+ IIDC_VERSION(1_30);
+ IIDC_VERSION(1_31);
+ IIDC_VERSION(1_32);
+ IIDC_VERSION(1_33);
+ IIDC_VERSION(1_34);
+ IIDC_VERSION(1_35);
+ IIDC_VERSION(1_36);
+ IIDC_VERSION(1_37);
+ IIDC_VERSION(1_38);
+ IIDC_VERSION(1_39);
+#endif
+
+// Return values are SUCCESS FAILURE NO_FRAME NO_CAMERA
+
+// Parameter flags for dc1394_setup_format7_capture()
+//#define QUERY_FROM_CAMERA -1
+//#define USE_MAX_AVAIL -2
+//#define USE_RECOMMENDED -3
+
+// The video1394 policy: blocking (wait for a frame forever) or polling (returns if no frames in buffer
+// WAIT=0 POLL=1
+};
+
+typedef raw1394handle_t RH;
+typedef nodeid_t NID;
+
+#define IO(func,args...) if (func(rh,usenode,args)!=DC1394_SUCCESS) RAISE(#func " failed");
+
+\class FormatDC1394 : Format {
+ RH rh;
+ int useport;
+ int usenode;
+ int framerate_e;
+ int height;
+ int width;
+ dc1394_cameracapture camera;
+ dc1394_feature_set features;
+ std::map<int,int> feature_index;
+ \constructor (t_symbol *mode) {
+ bool gotone=false;
+ post("DC1394: hello world");
+ rh = raw1394_new_handle();
+ if (!rh) RAISE("could not get a handle for /dev/raw1394 and /dev/video1394");
+ int numPorts = raw1394_get_port_info(rh,0,0);
+ raw1394_destroy_handle(rh);
+ post("there are %d Feuerweuer ports",numPorts);
+ if (mode!=gensym("in")) RAISE("sorry, read-only");
+ for(int port=0; port<numPorts; port++) {
+ post("trying port #%d...",port);
+ RH rh = dc1394_create_handle(port);
+ int numCameras=0xDEADBEEF;
+ NID *nodes = dc1394_get_camera_nodes(rh,&numCameras,0);
+ post("port #%d has %d cameras",port,numCameras);
+ for (int i=0; i<numCameras; i++) {
+ post("camera at node #%d",nodes[i]);
+ if (!gotone) {gotone=true; useport=port; usenode=nodes[i];}
+ }
+ dc1394_destroy_handle(rh);
+ }
+ if (!gotone) RAISE("no cameras available");
+ this->rh = dc1394_create_handle(useport);
+ IO(dc1394_get_camera_feature_set,&features);
+ dc1394_print_feature_set(&features);
+ post("NUM_FEATURES=%d",NUM_FEATURES);
+ for (int i=0; i<NUM_FEATURES; i++) {
+ dc1394_feature_info &f = features.feature[i];
+ int id = f.feature_id;
+ string name = feature_names.find(id)==feature_names.end() ? "(unknown)" : feature_names[id];
+ bool is_there = f.available;
+ post(" feature %d '%s' is %s",id,name.data(),is_there?"present":"absent");
+ if (!is_there) continue;
+ post(" min=%u max=%u abs_min=%u abs_max=%u",f.min,f.max,f.abs_min,f.abs_max);
+ }
+ framerate_e = FRAMERATE_30;
+ height = 480;
+ width = 640;
+ setup();
+ }
+ \decl 0 bang ();
+ \attr float framerate();
+ \attr unsigned brightness();
+ \attr unsigned hue();
+ \attr unsigned colour();
+ //\attr uint16 contrast();
+ //\attr uint16 whiteness();
+ void setup ();
+ \decl 0 get (t_symbol *s=0);
+ \decl 0 size (int height, int width);
+};
+
+\def 0 get (t_symbol *s=0) {
+ FObject::_0_get(argc,argv,s);
+ t_atom a[2];
+ if (!s) {
+ SETFLOAT(a+0,camera.frame_height);
+ SETFLOAT(a+1,camera.frame_width);
+ outlet_anything(bself->outlets[0],gensym("size"),2,a); // abnormal (does not use nested list)
+ unsigned int width,height;
+ IO(dc1394_query_format7_max_image_size,MODE_FORMAT7_0,&width,&height);
+ SETFLOAT(a+0,height);
+ SETFLOAT(a+1,width);
+ outlet_anything(bself->outlets[0],gensym("maxsize"),2,a); // abnormal (does not use nested list)
+ }
+}
+\def 0 size (int height, int width) {
+ IO(dc1394_set_format7_image_size,MODE_FORMAT7_0,width,height);
+ this->height = height;
+ this->width = width;
+ setup();
+}
+
+\def unsigned brightness () {unsigned value; dc1394_get_brightness(rh,usenode,&value); return value;}
+\def 0 brightness (unsigned value) {dc1394_set_brightness(rh,usenode, value);}
+\def unsigned hue () {unsigned value; dc1394_get_hue( rh,usenode,&value); return value;}
+\def 0 hue (unsigned value) {dc1394_set_hue( rh,usenode, value);}
+\def unsigned colour () {unsigned value; dc1394_get_saturation(rh,usenode,&value); return value;}
+\def 0 colour (unsigned value) {dc1394_set_saturation(rh,usenode, value);}
+
+void FormatDC1394::setup () {
+ //dc1394_set_format7_image_size(rh,usenode,0,width,height);
+ IO(dc1394_setup_capture,0,FORMAT_VGA_NONCOMPRESSED,MODE_640x480_MONO,SPEED_400,framerate_e,&camera);
+ //IO(dc1394_setup_format7_capture,0,MODE_FORMAT7_0,SPEED_400,QUERY_FROM_CAMERA,0,0,width,height,&camera);
+ if (dc1394_set_trigger_mode(rh,usenode,TRIGGER_MODE_0) != DC1394_SUCCESS) RAISE("dc1394_set_trigger_mode error");
+ if (dc1394_start_iso_transmission(rh,usenode)!=DC1394_SUCCESS) RAISE("dc1394_start_iso_transmission error");
+}
+
+\def float framerate() {
+ return 1.875 * (1<<(framerate_e-FRAMERATE_1_875));
+}
+
+\def 0 framerate(float framerate) {
+ framerate_e = FRAMERATE_1_875;
+ while (framerate>=1.875 && framerate_e <= FRAMERATE_240) {framerate/=2; framerate_e++;}
+ setup();
+}
+
+static volatile int timeout=0;
+static void rien (int) {timeout=1; post("timeout2");}
+
+\def 0 bang () {
+ //struct itimerval tval;
+ //tval.it_interval.tv_sec = 1;
+ //tval.it_interval.tv_usec = 0;
+ //tval.it_value = tval.it_interval;
+ //setitimer(ITIMER_REAL,&tval,0);
+ //signal(SIGALRM,rien);
+ if (dc1394_single_capture(rh,&camera)!=DC1394_SUCCESS) RAISE("dc1394_single_capture error");
+ //setitimer(ITIMER_REAL,0,0);
+ out=new GridOutlet(this,0,new Dim(height,width,1));
+ //out->send(out->dim->prod(),(uint8 *)camera.capture_buffer);
+ for (int i=0; i<height; i++) out->send(out->dim->prod(1),(uint8 *)camera.capture_buffer+640*i);
+ //if (dc1394_stop_iso_transmission(rh,usenode)!=DC1394_SUCCESS) RAISE("dc1394_stop_iso_transmission error");
+ //post("frame_height=%d",camera.frame_height);
+ //post("frame_width=%d" ,camera.frame_width);
+ //post("quadlets_per_frame=%d" ,camera.quadlets_per_frame);
+ //post("quadlets_per_packet=%d" ,camera.quadlets_per_packet);
+}
+
+\end class FormatDC1394 {
+ install_format("#io.dc1394",4,"");
+ setup_modes();
+}
+void startup_dc1394 () {
+ \startall
+}
diff --git a/externals/gridflow/format/ieee1394-ioctl.h b/externals/gridflow/format/ieee1394-ioctl.h
new file mode 100644
index 00000000..f92b5663
--- /dev/null
+++ b/externals/gridflow/format/ieee1394-ioctl.h
@@ -0,0 +1,111 @@
+/* Base file for all ieee1394 ioctl's. Linux-1394 has allocated base '#'
+ * with a range of 0x00-0x3f. */
+
+#ifndef __IEEE1394_IOCTL_H
+#define __IEEE1394_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+
+/* AMDTP Gets 6 */
+#define AMDTP_IOC_CHANNEL _IOW('#', 0x00, struct amdtp_ioctl)
+#define AMDTP_IOC_PLUG _IOW('#', 0x01, struct amdtp_ioctl)
+#define AMDTP_IOC_PING _IOW('#', 0x02, struct amdtp_ioctl)
+#define AMDTP_IOC_ZAP _IO ('#', 0x03)
+
+
+/* DV1394 Gets 10 */
+
+/* Get the driver ready to transmit video. pass a struct dv1394_init* as
+ * the parameter (see below), or NULL to get default parameters */
+#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init)
+
+/* Stop transmitting video and free the ringbuffer */
+#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07)
+
+/* Submit N new frames to be transmitted, where the index of the first new
+ * frame is first_clear_buffer, and the index of the last new frame is
+ * (first_clear_buffer + N) % n_frames */
+#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08)
+
+/* Block until N buffers are clear (pass N as the parameter) Because we
+ * re-transmit the last frame on underrun, there will at most be n_frames
+ * - 1 clear frames at any time */
+#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09)
+
+/* Capture new frames that have been received, where the index of the
+ * first new frame is first_clear_buffer, and the index of the last new
+ * frame is (first_clear_buffer + N) % n_frames */
+#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a)
+
+/* Tell card to start receiving DMA */
+#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b)
+
+/* Pass a struct dv1394_status* as the parameter */
+#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status)
+
+
+/* Video1394 Gets 10 */
+
+#define VIDEO1394_IOC_LISTEN_CHANNEL \
+ _IOWR('#', 0x10, struct video1394_mmap)
+#define VIDEO1394_IOC_UNLISTEN_CHANNEL \
+ _IOW ('#', 0x11, int)
+#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \
+ _IOW ('#', 0x12, struct video1394_wait)
+#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \
+ _IOWR('#', 0x13, struct video1394_wait)
+#define VIDEO1394_IOC_TALK_CHANNEL \
+ _IOWR('#', 0x14, struct video1394_mmap)
+#define VIDEO1394_IOC_UNTALK_CHANNEL \
+ _IOW ('#', 0x15, int)
+/*
+ * This one is broken: it really wanted
+ * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
+ * but got just a "size_t"
+ */
+#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \
+ _IOW ('#', 0x16, size_t)
+#define VIDEO1394_IOC_TALK_WAIT_BUFFER \
+ _IOW ('#', 0x17, struct video1394_wait)
+#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \
+ _IOWR('#', 0x18, struct video1394_wait)
+
+
+/* Raw1394's ISO interface */
+#define RAW1394_IOC_ISO_XMIT_INIT \
+ _IOW ('#', 0x1a, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_RECV_INIT \
+ _IOWR('#', 0x1b, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_RECV_START \
+ _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
+#define RAW1394_IOC_ISO_XMIT_START \
+ _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
+#define RAW1394_IOC_ISO_XMIT_RECV_STOP \
+ _IO ('#', 0x1e)
+#define RAW1394_IOC_ISO_GET_STATUS \
+ _IOR ('#', 0x1f, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_SHUTDOWN \
+ _IO ('#', 0x20)
+#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \
+ _IO ('#', 0x21)
+#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \
+ _IOW ('#', 0x22, unsigned char)
+#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
+ _IOW ('#', 0x23, unsigned char)
+#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
+ _IOW ('#', 0x24, __u64)
+#define RAW1394_IOC_ISO_RECV_PACKETS \
+ _IOW ('#', 0x25, struct raw1394_iso_packets)
+#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
+ _IOW ('#', 0x26, unsigned int)
+#define RAW1394_IOC_ISO_XMIT_PACKETS \
+ _IOW ('#', 0x27, struct raw1394_iso_packets)
+#define RAW1394_IOC_ISO_XMIT_SYNC \
+ _IO ('#', 0x28)
+#define RAW1394_IOC_ISO_RECV_FLUSH \
+ _IO ('#', 0x29)
+
+
+#endif /* __IEEE1394_IOCTL_H */
diff --git a/externals/gridflow/format/jpeg.c b/externals/gridflow/format/jpeg.c
new file mode 100644
index 00000000..80e5e717
--- /dev/null
+++ b/externals/gridflow/format/jpeg.c
@@ -0,0 +1,122 @@
+/*
+ $Id: jpeg.c 3624 2008-04-19 02:07:36Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+//!@#$ not handling abort on compress
+//!@#$ not handling abort on decompress
+
+#include "../gridflow.h.fcs"
+/* removing macros (removing warnings) */
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDLIB_H
+#undef EXTERN
+extern "C" {
+#include <jpeglib.h>
+};
+
+\class FormatJPEG < Format {
+ P<BitPacking> bit_packing;
+ struct jpeg_compress_struct cjpeg;
+ struct jpeg_decompress_struct djpeg;
+ struct jpeg_error_mgr jerr;
+ \constructor (t_symbol *mode, string filename) {
+ Format::_0_open(0,0,mode,filename);
+ uint32 mask[3] = {0x0000ff,0x00ff00,0xff0000};
+ bit_packing = new BitPacking(is_le(),3,3,mask);
+ }
+ \decl 0 bang ();
+ \decl 0 quality (short quality);
+ \grin 0 int
+};
+
+GRID_INLET(FormatJPEG,0) {
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3)
+ RAISE("expecting 3 channels (got %d)",in->dim->get(2));
+ in->set_chunk(1);
+ cjpeg.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cjpeg);
+ jpeg_stdio_dest(&cjpeg,f);
+ cjpeg.image_width = in->dim->get(1);
+ cjpeg.image_height = in->dim->get(0);
+ cjpeg.input_components = 3;
+ cjpeg.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cjpeg);
+ jpeg_start_compress(&cjpeg,TRUE);
+} GRID_FLOW {
+ int rowsize = in->dim->get(1)*in->dim->get(2);
+ int rowsize2 = in->dim->get(1)*3;
+ uint8 row[rowsize2];
+ uint8 *rows[1] = { row };
+ while (n) {
+ bit_packing->pack(in->dim->get(1),data,row);
+ jpeg_write_scanlines(&cjpeg,rows,1);
+ n-=rowsize; data+=rowsize;
+ }
+} GRID_FINISH {
+ jpeg_finish_compress(&cjpeg);
+ jpeg_destroy_compress(&cjpeg);
+} GRID_END
+
+static bool gfeof(FILE *f) {
+ off_t cur,end;
+ cur = ftell(f);
+ fseek(f,0,SEEK_END);
+ end = ftell(f);
+ fseek(f,cur,SEEK_SET);
+ return cur==end;
+}
+
+\def 0 bang () {
+ //off_t off = ftell(f);
+ //fseek(f,off,SEEK_SET);
+ if (gfeof(f)) {outlet_bang(bself->te_outlet); return;}
+ djpeg.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&djpeg);
+ jpeg_stdio_src(&djpeg,f);
+ jpeg_read_header(&djpeg,TRUE);
+ int sx=djpeg.image_width, sy=djpeg.image_height, chans=djpeg.num_components;
+ GridOutlet out(this,0,new Dim(sy,sx,chans),cast);
+ jpeg_start_decompress(&djpeg);
+ uint8 row[sx*chans];
+ uint8 *rows[1] = { row };
+ for (int n=0; n<sy; n++) {
+ jpeg_read_scanlines(&djpeg,rows,1);
+ out.send(sx*chans,row);
+ }
+ jpeg_finish_decompress(&djpeg);
+ jpeg_destroy_decompress(&djpeg);
+}
+
+\def 0 quality (short quality) {
+ quality = min(max((int)quality,0),100);
+ // should the last arg ("baseline") be set to true ?
+ // and what is it for? is it for accuracy of the DC component?
+ jpeg_set_quality(&cjpeg,quality,false);
+}
+
+\classinfo {install_format("#io.jpeg",6,"jpeg jpg");}
+\end class FormatJPEG
+void startup_jpeg () {
+ \startall
+}
diff --git a/externals/gridflow/format/main.c b/externals/gridflow/format/main.c
new file mode 100644
index 00000000..caf90672
--- /dev/null
+++ b/externals/gridflow/format/main.c
@@ -0,0 +1,249 @@
+/*
+ $Id$
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include <string>
+#include <map>
+#include <errno.h>
+#define L _L_
+
+/* API (version 0.9.3)
+ mode is :in or :out
+ def initialize(mode,*args) :
+ open a file handler (do it via .new of class)
+ attr_reader :description :
+ a _literal_ (constant) string describing the format handler
+ def self.info() optional :
+ return a string describing the format handler differently
+ than self.description(). in particular, it can list
+ compile-time options and similar things. for example,
+ quicktime returns a list of codecs.
+ def 0 bang() :
+ read one frame, send through outlet 0
+ return values :
+ Integer >= 0 : frame number of frame read.
+ false : no frame was read : end of sequence.
+ nil : a frame was read, but can't say its number.
+ note that trying to read a nonexistent frame should no longer
+ rewind automatically (@in handles that part), nor re-read the
+ last frame (mpeg/quicktime used to do this)
+ def 0 seek(Integer i) : select one frame to be read next (by number)
+ def 0 grid() : frame to write
+ def 0 get (optional Symbol s) : get one attribute value or all of them
+ def 0 ...() : options
+ outlet 0 grid() frame just read
+ outlet 0 ...() everything else
+ destructor : close a handler
+*/
+
+std::map<std::string,std::string> suffix_table;
+void suffixes_are (const char *name, const char *suffixes) {
+ std::string name2 = name;
+ char *suff2 = strdup(suffixes);
+ char *suff3 = suff2+strlen(suff2);
+ for (char *s=suff2; s<suff3; s++) if (*s==' ' || *s==',') *s=0;
+ for (char *s=suff2; s<suff3; s+=strlen(s)+1) {
+ std::string ss = s;
+ suffix_table[ss]=name2;
+ }
+}
+
+\class SuffixLookup : FObject {
+ \constructor () {}
+ \decl 0 symbol (t_symbol *str);
+};
+\def 0 symbol (t_symbol *str) {
+ char *s = strdup(str->s_name);
+ char *t = strrchr(s,'.');
+ if (!t) outlet_symbol(bself->outlets[2],gensym(s));
+ else {
+ *t = 0;
+ outlet_symbol(bself->outlets[1],gensym(t+1));
+ std::map<std::string,std::string>::iterator u = suffix_table.find(std::string(t+1));
+ if (u==suffix_table.end()) outlet_bang(bself->outlets[0]);
+ else outlet_symbol(bself->outlets[0],gensym((char *)u->second.data()));
+ }
+ free(s);
+}
+\end class SuffixLookup {install("gf.suffix_lookup",1,3);}
+
+\class Format : FObject
+Format::Format (BFObject *bself, MESSAGE) : FObject(bself,MESSAGE2) {
+ mode=0; fd=-1; f=0; cast=int32_e; frame=0;
+ if (argv[0]==gensym("out")) this->mode=2; else
+ if (argv[0]==gensym("in")) this->mode=4; else RAISE("unknown mode");
+// case mode
+// when :in; flags[2]==1
+// when :out; flags[1]==1
+// else raise "Format opening mode is incorrect"
+ //end or raise "Format '#{self.class.instance_eval{@symbol_name}}' does not support mode '#{mode}'"
+}
+
+\def 0 open(t_symbol *mode, string filename) {
+ const char *fmode;
+ if (mode==gensym("in")) fmode="r"; else
+ if (mode==gensym("out")) fmode="w"; else
+ RAISE("bad mode");
+ if (f) _0_close(0,0);
+ if (mode==gensym("in")) {filename = gf_find_file(filename);}
+ f = fopen(filename.data(),fmode);
+ if (!f) RAISE("can't open file '%s': %s",filename.data(),strerror(errno));
+ fd = fileno(f);
+// case gzfile:
+// if (mode==SYM(in)) {filename = GridFlow.find_file(filename);}
+// if (mode==:in) {raw_open_gzip_in filename; else raw_open_gzip_out filename;}
+// def self.rewind() raw_open(*@raw_open_args); @frame = 0 end unless @rewind_redefined
+// @rewind_redefined = true
+}
+\def 0 close() {if (f) {fclose(f); f=0; fd=-1;}}
+\def 0 cast(NumberTypeE nt) {cast = nt;}
+
+\def 0 seek(int frame) {
+ if (!frame) {_0_rewind(0,0); return;}
+ RAISE("don't know how to seek for frame other than # 0");
+}
+
+// this is what you should use to rewind
+// different file-sources may redefine this as something else
+// (eg: gzip)
+\def 0 rewind () {
+ if (!f) RAISE("Nothing to rewind about...");
+ fseek(f,0,SEEK_SET);
+ frame = 0;
+}
+
+Format::~Format () {if (f) fclose(f); /*if (fd>=0) close(fd);*/}
+\end class Format {}
+
+/* This is the Grid format I defined: */
+struct GridHeader {
+ char magic[5]; // = "\7fgrid" on little endian, "\x7fGRID" on big endian
+ uint8 type; // number of bits.
+ // the original doc said: "plus one of: 1:unsigned 2:float" but i don't recall what this means.
+ uint8 reserved; // set this to 0 all of the time.
+ uint8 dimn; // number of dimensions supported: at least 0..4)
+ // int32 dimv[dimn]; // number of elements in each dimension. (in the file's endianness!)
+ // raw data goes after that
+};
+
+\class FormatGrid : Format {
+ GridHeader head;
+ int endian;
+ NumberTypeE nt;
+ P<Dim> headerless_dim; // if null: headerful; if Dim: it is the assumed dimensions of received grids
+ \grin 0
+ \constructor (t_symbol *mode, string filename) {
+ strncpy(head.magic,is_le()?"\7fgrid":"\7fGRID",5);
+ head.type = 32;
+ _0_open(0,0,mode,filename);
+ }
+ \decl 0 bang ();
+ \decl 0 headerless (...);
+ \decl 0 headerful ();
+ \decl 0 type (NumberTypeE nt);
+ ~FormatGrid() {
+ //@stream.close if @stream
+ //GridFlow.hunt_zombies
+ }
+// \decl void raw_open_gzip_in(string filename);
+// \decl void raw_open_gzip_out(string filename);
+};
+\def 0 bang () {
+ P<Dim> dim;
+ if (feof(f)) {outlet_bang(bself->te_outlet); return;}
+ if (headerless_dim) {
+ dim = headerless_dim;
+ } else {
+ fread(&head,1,8,f);
+ uint8 *m = (uint8 *)head.magic;
+ if (strncmp((char *)m,"\7fgrid",5)==0) endian=1; else
+ if (strncmp((char *)m,"\7fGRID",5)==0) endian=1; else
+ RAISE("unknown header, can't read grid from file: "
+ "%02x %02x %02x %02x %02x %02x %02x %02x",
+ m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7]);
+ if (head.type!=32) RAISE("unsupported grid type %d in file",head.type);
+ // apparently, head.type 8 and 16 worked too.
+ if (head.reserved!=0) RAISE("unsupported grid reserved field %d in file",head.reserved);
+ if (head.dimn>16) RAISE("unsupported grid number of dimensions %d in file",head.dimn);
+ int32 dimv[head.dimn];
+ fread(dimv,head.dimn,4,f);
+ if (endian != is_le()) swap32(head.dimn,(uint32 *)dimv);
+ dim = new Dim(head.dimn,dimv);
+ }
+ GridOutlet out(this,0,dim,nt);
+ long nn = dim->prod();
+#define FOO(T) {T data[nn]; fread(data,nn,sizeof(T),f); out.send(nn,(T *)data);}
+TYPESWITCH(nt,FOO,)
+#undef FOO
+ SUPER;
+}
+
+GRID_INLET(FormatGrid,0) {
+ if (!headerless_dim) {
+ fwrite(&head,1,8,f);
+ fwrite(in->dim->v,in->dim->n,4,f); // forgot the endian here
+ }
+} GRID_FLOW {
+#define FOO(T) {T data2[n]; for(int i=0; i<n; i++) data2[i]=(T)data[i]; \
+ if (endian!=is_le()) swap_endian(n,data2); \
+ fwrite(data2,n,sizeof(T),f);}
+TYPESWITCH(nt,FOO,)
+#undef FOO
+} GRID_FINISH {
+ fflush(f);
+} GRID_END
+
+\def 0 headerless (...) {
+ if (argc>=0 && argv[0].a_type==A_LIST) {
+ t_binbuf *b = (t_binbuf *)argv[0]; argc = binbuf_getnatom(b); argv = (t_atom2 *)binbuf_getvec(b);}
+ int v[argc];
+ for (int i=0; i<argc; i++) v[i] = argv[i];
+ headerless_dim = new Dim(argc,v);
+}
+\def 0 headerful () { headerless_dim = 0; }
+//#!@#$ method name conflict ?
+\def 0 type (NumberTypeE nt) {
+ //!@#$ bug: should not be able to modify this _during_ a transfer
+ switch (nt) {
+ case uint8_e: head.type= 8; break;
+ case int16_e: head.type=16; break;
+ case int32_e: head.type=32; break;
+ default: RAISE("unsupported type");
+ }
+ this->nt = nt;
+}
+
+//\def void raw_open_gzip_in(string filename) {
+ //r,w = IO.pipe
+ //if (pid=fork) {GridFlow.subprocesses[pid]=true; w.close; @stream = r;}
+ //else {r.close; STDOUT.reopen w; STDIN.reopen filename, "r"; exec "gzip", "-dc";}
+//\def void raw_open_gzip_out(string filename) {
+ //r,w = IO.pipe
+ //if (pid=fork) {GridFlow.subprocesses[pid]=true; r.close; @stream = w;}
+ //else {w.close; STDIN.reopen r; STDOUT.reopen filename, "w"; exec "gzip", "-c";}
+
+\end class FormatGrid {install_format("#io.grid",6,"grid");}
+
+void startup_format () {
+ \startall
+}
diff --git a/externals/gridflow/format/mpeg3.c b/externals/gridflow/format/mpeg3.c
new file mode 100644
index 00000000..c034f4dc
--- /dev/null
+++ b/externals/gridflow/format/mpeg3.c
@@ -0,0 +1,83 @@
+/*
+ $Id: mpeg3.c 3815 2008-06-06 03:50:40Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define LIBMPEG_INCLUDE_HERE
+#include "../gridflow.h.fcs"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+\class FormatMPEG3 : Format {
+ mpeg3_t *mpeg;
+ int track;
+ ~FormatMPEG3 () {if (mpeg) {mpeg3_close(mpeg); mpeg=0;}}
+ \constructor (t_symbol *mode, string filename) {
+ track=0;
+ // libmpeg3 may be nice, but it won't take a filehandle, only filename
+ if (mode!=gensym("in")) RAISE("read-only, sorry");
+ filename = gf_find_file(filename);
+ #ifdef MPEG3_UNDEFINED_ERROR
+ int err;
+ mpeg = mpeg3_open((char *)filename.data(),&err);
+ post("mpeg error code = %d",err);
+ #else
+ mpeg = mpeg3_open((char *)filename.data());
+ #endif
+ if (!mpeg) RAISE("IO Error: can't open file `%s': %s", filename.data(), strerror(errno));
+ }
+ \decl 0 seek (long frame);
+ \decl 0 rewind ();
+ \decl 0 bang ();
+};
+
+\def 0 seek (long frame) {
+ mpeg3_set_frame(mpeg,clip(frame,0L,mpeg3_video_frames(mpeg,track)-1),track);
+}
+\def 0 rewind () {_0_seek(0,0,0);}
+
+\def 0 bang () {
+ int nframe = mpeg3_get_frame(mpeg,track);
+ int nframes = mpeg3_video_frames(mpeg,track);
+ //post("track=%d; nframe=%d; nframes=%d",track,nframe,nframes);
+ if (nframe >= nframes) {outlet_bang(bself->te_outlet); return;}
+ int sx = mpeg3_video_width(mpeg,track);
+ int sy = mpeg3_video_height(mpeg,track);
+ int channels = 3;
+ /* !@#$ the doc says "You must allocate 4 extra bytes in the
+ last output_row. This is scratch area for the MMX routines." */
+ uint8 *buf = NEWBUF(uint8,sy*sx*channels+16);
+ uint8 *rows[sy];
+ for (int i=0; i<sy; i++) rows[i]=buf+i*sx*channels;
+ mpeg3_read_frame(mpeg,rows,0,0,sx,sy,sx,sy,MPEG3_RGB888,track);
+ GridOutlet out(this,0,new Dim(sy,sx,channels),cast);
+ int bs = out.dim->prod(1);
+ for(int y=0; y<sy; y++) out.send(bs,buf+channels*sx*y);
+ DELBUF(buf);
+// return INT2NUM(nframe);
+}
+
+\classinfo {install_format("#io.mpeg",4,"mpg mpeg");}
+\end class FormatMPEG3
+void startup_mpeg3 () {
+ \startall
+}
diff --git a/externals/gridflow/format/netpbm.c b/externals/gridflow/format/netpbm.c
new file mode 100644
index 00000000..159903bd
--- /dev/null
+++ b/externals/gridflow/format/netpbm.c
@@ -0,0 +1,119 @@
+/*
+ $Id$
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+extern "C" {
+#include <pam.h>
+};
+
+\class FormatNetPBM : Format {
+ struct pam inpam, outpam;
+ \grin 0
+ \constructor (t_symbol *mode, string filename) {
+ Format::_0_open(0,0,mode,filename);
+ memset(& inpam,sizeof(pam),0);
+ memset(&outpam,sizeof(pam),0);
+ }
+ \decl 0 bang ();
+};
+\def 0 bang () {
+ //inpam.allocation_depth = 3;
+ pnm_readpaminit(f, &inpam, /*PAM_STRUCT_SIZE(tuple_type)*/ sizeof(struct pam));
+ tuple *tuplerow = pnm_allocpamrow(&inpam);
+ if (inpam.depth!=3) RAISE("image has %d channels instead of 3 channels",inpam.depth);
+ GridOutlet out(this,0,new Dim(inpam.height,inpam.width,inpam.depth),cast);
+ uint8 buf[inpam.width*3];
+ for (int i=0; i<inpam.height; i++) {
+ pnm_readpamrow(&inpam, tuplerow);
+ for (int j=0; j<inpam.width; j++) {
+ buf[j*3+0] = tuplerow[j][0];
+ buf[j*3+1] = tuplerow[j][1];
+ buf[j*3+2] = tuplerow[j][2];
+ }
+ out.send(inpam.width*inpam.depth,buf);
+ }
+ pnm_freepamrow(tuplerow);
+}
+GRID_INLET(FormatNetPBM,0) {
+ if (in->dim->n!=3) RAISE("need 3 dimensions");
+ if (in->dim->v[2]!=3) RAISE("need 3 channels");
+ outpam.size = sizeof(struct pam);
+ outpam.len = sizeof(struct pam);
+ outpam.file = f;
+ outpam.format = PPM_FORMAT;
+ outpam.height = in->dim->v[0];
+ outpam.width = in->dim->v[1];
+ outpam.depth = in->dim->v[2];
+ outpam.plainformat = false;
+ outpam.maxval = 255;
+ //outpam.allocation_depth = 3;
+ strcpy(outpam.tuple_type,PAM_PPM_TUPLETYPE);
+ pnm_writepaminit(&outpam);
+ in->set_chunk(1);
+} GRID_FLOW {
+ tuple *tuplerow = pnm_allocpamrow(&outpam);
+ int m = in->dim->v[1];
+ for (int i=0; i<n; i+=in->dim->prod(1)) {
+ for (int j=0; j<m; j++, data+=3) {
+ tuplerow[j][0] = int(data[0]);
+ tuplerow[j][1] = int(data[1]);
+ tuplerow[j][2] = int(data[2]);
+ }
+ pnm_writepamrow(&outpam, tuplerow);
+ }
+ pnm_freepamrow(tuplerow);
+} GRID_FINISH {
+ fflush(f);
+} GRID_END
+/* was supposed to be "#io.netpbm" but there's backwards compat. */
+\classinfo {install_format("#io.ppm",6,"ppm pgm pnm pam");}
+\end class FormatNetPBM
+
+/*FormatPPM.subclass("#io:tk",1,1) {
+ install_rgrid 0
+ def initialize(mode)
+ @id = sprintf("x%08x",object_id)
+ @filename = "/tmp/tk-#{$$}-#{@id}.ppm"
+ if mode!=:out then raise "only #out" end
+ super(mode,:file,@filename)
+ GridFlow.gui "toplevel .#{@id}\n"
+ GridFlow.gui "wm title . GridFlow/Tk\n"
+ GridFlow.gui "image create photo gf#{@id} -width 320 -height 240\n"
+ GridFlow.gui "pack [label .#{@id}.im -image #{@id}]\n"
+ end
+ def _0_rgrid_end
+ super
+ @stream.seek 0,IO::SEEK_SET
+ GridFlow.gui "image create photo #{@id} -file #{@filename}\n"
+ end
+ def delete
+ GridFlow.gui "destroy .#{@id}\n"
+ GridFlow.gui "image delete #{@id}\n"
+ end
+ alias close delete
+}*/
+
+void startup_netpbm () {
+ pm_init(0,0);
+ \startall
+}
diff --git a/externals/gridflow/format/opengl.c b/externals/gridflow/format/opengl.c
new file mode 100644
index 00000000..e4606d4e
--- /dev/null
+++ b/externals/gridflow/format/opengl.c
@@ -0,0 +1,174 @@
+/*
+ $Id: opengl.c 3650 2008-04-25 15:55:52Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <GLUT/glut.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#endif
+#include <setjmp.h>
+
+static bool in_use = false;
+
+\class FormatOpenGL : Format {
+ int window;
+ GLuint gltex;
+ P<BitPacking> bit_packing;
+ P<Dim> dim;
+ uint8 *buf;
+ t_clock *clock;
+ void call ();
+ \decl 0 resize_window (int sx, int sy);
+ \grin 0
+ \constructor (t_symbol *mode) {
+ if (in_use) RAISE("only one #io:opengl object at a time; sorry");
+ in_use=true;
+ if (mode!=gensym("out")) RAISE("write-only, sorry");
+ int dummy = 0;
+ glutInit(&dummy,0);
+ glutInitDisplayMode(GLUT_RGBA);
+ resize_window(0,0,320,240);
+ gltex = 0;
+ glEnable(GL_TEXTURE_2D);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DITHER);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ window = 0xDeadBeef;
+ uint32 mask[3] = {0xff000000,0x00ff0000,0x0000ff00};
+ bit_packing = new BitPacking(4,4,3,mask);
+ clock = clock_new(this,(t_method)FormatOpenGL_call);
+ clock_delay(clock,0);
+ }
+
+ ~FormatOpenGL () {
+ clock_unset(clock);
+ if (gltex) glDeleteTextures(1, (GLuint*)&gltex);
+ if (buf) delete buf;
+ in_use=false;
+ if ((unsigned)window!=0xDeadBeef) {
+ glutDestroyWindow(window);
+ window=0xDeadBeef;
+ }
+ }
+};
+
+static jmp_buf hack;
+static void my_idle () { longjmp(hack,1); }
+
+\def void call () {
+ int32 sy = dim->get(0);
+ int32 sx = dim->get(1);
+ glEnable(GL_TEXTURE_2D);
+ if (!gltex) {
+ }
+ glTexSubImage2D(GL_TEXTURE_2D,0,0,0,sx,sy,GL_RGBA,GL_UNSIGNED_BYTE,buf);
+ glBindTexture(GL_TEXTURE_2D, gltex);
+ glBegin(GL_QUADS);
+ glColor3f(1.f,1.f,1.f);
+ glTexCoord2f(0.f,0.f); glVertex2f(0.f,0.f);
+ glTexCoord2f(1.f,0.f); glVertex2f( sx,0.f);
+ glTexCoord2f(1.f,1.f); glVertex2f( sx, sy);
+ glTexCoord2f(0.f,1.f); glVertex2f(0.f, sy);
+ glEnd();
+
+ //Here comes some (un)fair amount of arm-twisting
+ //This is for processing queued events and then "returning".
+ glutIdleFunc(my_idle);
+ if(!setjmp(hack)) glutMainLoop();
+ //done
+
+ clock_delay(clock,100);
+}
+void FormatOpenGL_call (FormatOpenGL *self) {self->call();}
+
+\def 0 resize_window (int sx, int sy) {
+ dim = new Dim(sy,sx,3);
+ char foo[666];
+ sprintf(foo,"GridFlow/GL (%d,%d,3)",sy,sx);
+ if ((unsigned)window==0xDeadBeef) {
+ glutInitWindowSize(sx,sy);
+ window = glutCreateWindow(foo);
+ } else {
+ glutReshapeWindow(sx,sy);
+ }
+ if (buf) delete buf;
+ buf = new uint8[sy*sx*4];
+ glViewport(0,0,sx,sy);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0,sx,sy,0,-99999,99999);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (gltex) glDeleteTextures(1, (GLuint*)&gltex);
+ glGenTextures(1, (GLuint*)&gltex);
+ glBindTexture(GL_TEXTURE_2D,gltex);
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+ glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,sx,sy,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
+
+}
+
+GRID_INLET(FormatOpenGL,0) {
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3)
+ RAISE("expecting 3 channels: red,green,blue (got %d)",in->dim->get(2));
+ int sx = in->dim->get(1), osx = dim->get(1);
+ int sy = in->dim->get(0), osy = dim->get(0);
+ in->set_chunk(1);
+ if (sx!=osx || sy!=osy) resize_window(0,0,sx,sy);
+} GRID_FLOW {
+ int sxc = in->dim->prod(1);
+ int sx = in->dim->get(1);
+ int bypl = 4*sx;
+ int y = in->dex / sxc;
+ for (; n>0; y++, data+=sxc, n-=sxc) bit_packing->pack(sx, data, buf+y*bypl);
+ } GRID_FINISH {
+} GRID_END
+
+\classinfo {install_format("#io.opengl",2,"");}
+\end class FormatOpenGL
+void startup_opengl () {
+ \startall
+}
diff --git a/externals/gridflow/format/png.c b/externals/gridflow/format/png.c
new file mode 100644
index 00000000..a55ca648
--- /dev/null
+++ b/externals/gridflow/format/png.c
@@ -0,0 +1,116 @@
+/*
+ $Id: png.c 3624 2008-04-19 02:07:36Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* !@#$ not handling abort on compress */
+/* !@#$ not handling abort on decompress */
+
+#include "../gridflow.h.fcs"
+extern "C" {
+#include <libpng12/png.h>
+};
+
+\class FormatPNG : Format {
+ P<BitPacking> bit_packing;
+ png_structp png;
+ png_infop info;
+ \constructor (t_symbol *mode, string filename) {
+ Format::_0_open(0,0,mode,filename);
+ uint32 mask[3] = {0x0000ff,0x00ff00,0xff0000};
+ bit_packing = new BitPacking(is_le(),3,3,mask);
+ }
+ \decl 0 bang ();
+ \grin 0 int
+};
+
+GRID_INLET(FormatPNG,0) {
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3)
+ RAISE("expecting 3 channels (got %d)",in->dim->get(2));
+ in->set_chunk(1);
+ RAISE("bother, said pooh, as the PNG encoding was found unimplemented");
+} GRID_FLOW {
+ int rowsize = in->dim->get(1)*in->dim->get(2);
+ int rowsize2 = in->dim->get(1)*3;
+ uint8 row[rowsize2];
+ while (n) {
+ bit_packing->pack(in->dim->get(1),data,row);
+ n-=rowsize; data+=rowsize;
+ }
+} GRID_FINISH {
+} GRID_END
+
+\def 0 bang () {
+ uint8 sig[8];
+ if (!fread(sig, 1, 8, f)) {outlet_bang(bself->te_outlet); return;}
+ if (!png_check_sig(sig, 8)) RAISE("bad signature");
+ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png) RAISE("!png");
+ info = png_create_info_struct(png);
+ if (!info) {png_destroy_read_struct(&png, NULL, NULL); RAISE("!info");}
+ if (setjmp(png_jmpbuf(png))) {png_destroy_read_struct(&png, &info, NULL); RAISE("png read error");}
+ png_init_io(png, f);
+ png_set_sig_bytes(png, 8); // we already read the 8 signature bytes
+ png_read_info(png, info); // read all PNG info up to image data
+ png_uint_32 width, height;
+ int bit_depth, color_type;
+ png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, 0,0,0);
+
+ png_bytepp row_pointers = 0;
+ if (color_type == PNG_COLOR_TYPE_PALETTE
+ || (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ || png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_expand(png);
+ // 16bpp y, 32bpp ya, 48bpp rgb, 64bpp rgba...
+ if (bit_depth == 16) png_set_strip_16(png);
+
+ double display_gamma = 2.2;
+ double gamma;
+ if (png_get_gAMA(png, info, &gamma))
+ png_set_gamma(png, display_gamma, gamma);
+ png_read_update_info(png, info);
+
+ int rowbytes = png_get_rowbytes(png, info);
+ int channels = (int)png_get_channels(png, info);
+ uint8 *image_data = new uint8[rowbytes*height];
+ row_pointers = new png_bytep[height];
+ //gfpost("png: color_type=%d channels=%d, width=%d, rowbytes=%ld, height=%ld, gamma=%f",
+ // color_type, channels, width, rowbytes, height, gamma);
+ for (int i=0; i<(int)height; i++) row_pointers[i] = image_data + i*rowbytes;
+ if ((uint32)rowbytes != width*channels)
+ RAISE("rowbytes mismatch: %d is not %d*%d=%d", rowbytes, width, channels, width*channels);
+ png_read_image(png, row_pointers);
+ delete[] row_pointers;
+ row_pointers = 0;
+ png_read_end(png, 0);
+ GridOutlet out(this,0,new Dim(height, width, channels), cast);
+ out.send(rowbytes*height,image_data);
+ delete[] image_data;
+ png_destroy_read_struct(&png, &info, NULL);
+}
+
+\classinfo {install_format("#io.png",4,"png");}
+\end class FormatPNG
+void startup_png () {
+ \startall
+}
diff --git a/externals/gridflow/format/pwc-ioctl.h b/externals/gridflow/format/pwc-ioctl.h
new file mode 100644
index 00000000..65805eaa
--- /dev/null
+++ b/externals/gridflow/format/pwc-ioctl.h
@@ -0,0 +1,292 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+ (C) 2004 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 8.12.1
+ It contains structures and defines to communicate from user space
+ directly to the driver.
+ */
+
+/*
+ Changes
+ 2001/08/03 Alvarado Added ioctl constants to access methods for
+ changing white balance and red/blue gains
+ 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE
+ 2003/12/13 Nemosft Unv. Some modifications to make interfacing to
+ PWCX easier
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+ They contain functions not found in other webcams, and settings not
+ specified in the Video4Linux API.
+
+ The #define names are built up like follows:
+ VIDIOC VIDeo IOCtl prefix
+ PWC Philps WebCam
+ G optional: Get
+ S optional: Set
+ ... the function
+ */
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF 0x00
+#define PSZ_QSIF 0x01
+#define PSZ_QCIF 0x02
+#define PSZ_SIF 0x03
+#define PSZ_CIF 0x04
+#define PSZ_VGA 0x05
+#define PSZ_MAX 6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+ the upper 16 bits, since some flags are defined nowadays. The following
+ defines provide a mask and shift to filter out this value.
+
+ In 'Snapshot' mode the camera freezes its automatic exposure and colour
+ balance controls.
+ */
+#define PWC_FPS_SHIFT 16
+#define PWC_FPS_MASK 0x00FF0000
+#define PWC_FPS_FRMASK 0x003F0000
+#define PWC_FPS_SNAPSHOT 0x00400000
+
+
+/* structure for transfering x & y coordinates */
+struct pwc_coord
+{
+ int x, y; /* guess what */
+ int size; /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+ char name[32];
+ int type;
+};
+
+struct pwc_serial
+{
+ char serial[30]; /* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR 0
+#define PWC_WB_OUTDOOR 1
+#define PWC_WB_FL 2
+#define PWC_WB_MANUAL 3
+#define PWC_WB_AUTO 4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+ Set mode to one of the PWC_WB_* values above.
+ *red and *blue are the respective gains of these colour components inside
+ the camera; range 0..65535
+ When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+ otherwise undefined.
+ 'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+ int mode;
+ int manual_red, manual_blue; /* R/W */
+ int read_red, read_blue; /* R/O */
+};
+
+/*
+ 'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+ and tell the camera how fast it should react to changes in lighting, and
+ with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+ int control_speed;
+ int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+ int led_on; /* Led on-time; range = 0..25000 */
+ int led_off; /* Led off-time; range = 0..25000 */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+ int width;
+ int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN 0x01
+#define PWC_MPT_TILT 0x02
+#define PWC_MPT_TIMEOUT 0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+ driver calculates the relative offset for you. This can only
+ be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+ absolute angles.
+ */
+struct pwc_mpt_angles
+{
+ int absolute; /* write-only */
+ int pan; /* degrees * 100 */
+ int tilt; /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+ int pan_min, pan_max; /* degrees * 100 */
+ int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+ int status;
+ int time_pan;
+ int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+ all the necessary information to initialize and use the decompressor
+ routines in standalone applications.
+ */
+struct pwc_video_command
+{
+ int type; /* camera type (645, 675, 730, etc.) */
+ int release; /* release number */
+
+ int size; /* one of PSZ_* */
+ int alternate;
+ int command_len; /* length of USB video command */
+ unsigned char command_buf[13]; /* Actual USB video command */
+ int bandlength; /* >0 = compressed */
+ int frame_size; /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR 0x0001
+#define PWCX_FLAG_BAYER 0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+ means use uncompressed modes when available; 1 is low compression, 2 is
+ medium and 3 is high compression preferred. Of course, the higher the
+ compression, the lower the bandwidth used but more chance of artefacts
+ in the image. The driver automatically chooses a higher compression when
+ the preferred mode is not available.
+ */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+ becomes difficult to include all the names in programs that want to
+ check for the enhanced Philips stuff. So in stead, try this PROBE;
+ it returns a structure with the original name, and the corresponding
+ Philips type.
+ To use, fill the structure with zeroes, call PROBE and if that succeeds,
+ compare the name with that returned from VIDIOCGCAP; they should be the
+ same. If so, you can be assured it is a Philips (OEM) cam and the type
+ is valid.
+ */
+#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds)
+
+ /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR _IOR('v', 206, int)
+
+ /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int)
+
+ /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER _IOR('v', 208, int)
+
+ /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+ int len;
+ char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer)
+
+#endif
diff --git a/externals/gridflow/format/quartz.m b/externals/gridflow/format/quartz.m
new file mode 100644
index 00000000..8ff389a8
--- /dev/null
+++ b/externals/gridflow/format/quartz.m
@@ -0,0 +1,224 @@
+/*
+ $Id: quartz.m 3709 2008-05-21 18:53:54Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+ This is written in Objective C++, which is the union of C++ and Objective C;
+ Their intersection is C or almost. They add quite different sets of features.
+ I need Objective C here because the Cocoa API is for Objective C and Java only,
+ and the Objective C one was the easiest to integrate in GridFlow.
+
+ The next best possibility may be using RubyCocoa, a port of the Cocoa API to Ruby;
+ However I haven't checked whether Quartz is wrapped, and how easy it is to
+ process images.
+*/
+
+#include <stdio.h>
+#include <objc/Object.h>
+#include <Cocoa/Cocoa.h>
+
+#include "../gridflow.h.fcs"
+
+@interface GFView: NSView {
+ uint8 *imdata;
+ int imwidth;
+ int imheight;
+}
+- (id) drawRect: (NSRect)rect;
+- (id) imageHeight: (int)w width: (int)h;
+- (int) imageHeight;
+- (int) imageWidth;
+- (uint8 *) imageData;
+- (int) imageDataSize;
+@end
+
+@implementation GFView
+
+- (uint8 *) imageData {return imdata;}
+- (int) imageDataSize {return imwidth*imheight*4;}
+- (int) imageHeight {return imheight;}
+- (int) imageWidth {return imwidth;}
+
+- (id) imageHeight: (int)h width: (int)w {
+ if (imheight==h && imwidth==w) return self;
+ post("new size: y=%d x=%d",h,w);
+ imheight=h;
+ imwidth=w;
+ if (imdata) delete imdata;
+ int size = [self imageDataSize];
+ imdata = new uint8[size];
+ CLEAR(imdata,size);
+ NSSize s = {w,h};
+ [[self window] setContentSize: s];
+ return self;
+}
+
+- (id) initWithFrame: (NSRect)r {
+ [super initWithFrame: r];
+ imdata=0; imwidth=-1; imheight=-1;
+ [self imageHeight: 240 width: 320];
+ return self;
+}
+
+- (id) drawRect: (NSRect)rect {
+ [super drawRect: rect];
+ if (![self lockFocusIfCanDraw]) return self;
+ CGContextRef g = (CGContextRef)
+ [[NSGraphicsContext graphicsContextWithWindow: [self window]]
+ graphicsPort];
+ CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
+ CGDataProviderRef dp = CGDataProviderCreateWithData(
+ NULL, imdata, imheight*imwidth*4, NULL);
+ CGImageRef image = CGImageCreate(imwidth, imheight, 8, 32, imwidth*4,
+ cs, kCGImageAlphaFirst, dp, NULL, 0, kCGRenderingIntentDefault);
+ CGDataProviderRelease(dp);
+ CGColorSpaceRelease(cs);
+ CGRect rectangle = CGRectMake(0,0,imwidth,imheight);
+ CGContextDrawImage(g,rectangle,image);
+ CGImageRelease(image);
+ [self unlockFocus];
+ return self;
+}
+@end
+
+/* workaround: bus error in gcc */
+uint8 *GFView_imageData(GFView *self) {return (uint8 *)[self imageData];}
+
+void GFView_imageHeight_width(GFView *self, int height, int width) {
+ [self imageHeight: height width: width];
+}
+
+void GFView_display(GFView *self) {
+ NSRect r = {{0,0},{[self imageHeight],[self imageWidth]}};
+ [self displayRect: r];
+ [self setNeedsDisplay: YES];
+ [self display];
+}
+
+struct FormatQuartz;
+void FormatQuartz_call(FormatQuartz *self);
+
+\class FormatQuartz : Format {
+ NSWindow *window;
+ NSWindowController *wc;
+ GFView *widget; /* GridFlow's Cocoa widget */
+ t_clock *clock;
+ \constructor (t_symbol *mode) {
+ NSRect r = {{0,0}, {320,240}};
+ window = [[NSWindow alloc]
+ initWithContentRect: r
+ styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask
+ backing: NSBackingStoreBuffered
+ defer: YES];
+ widget = [[GFView alloc] initWithFrame: r];
+ [window setContentView: widget];
+ [window setTitle: @"GridFlow"];
+ [window makeKeyAndOrderFront: NSApp];
+ [window orderFrontRegardless];
+ wc = [[NSWindowController alloc] initWithWindow: window];
+ clock = clock_new(this,(t_method)FormatQuartz_call);
+ [window makeFirstResponder: widget];
+ post("mainWindow = %08lx",(long)[NSApp mainWindow]);
+ post(" keyWindow = %08lx",(long)[NSApp keyWindow]);
+ NSColor *color = [NSColor clearColor];
+ [window setBackgroundColor: color];
+ }
+ ~FormatQuartz () {
+ clock_unset(clock);
+ clock_free(clock);
+ clock = 0;
+ [window autorelease];
+ [window setReleasedWhenClosed: YES];
+ [window close];
+ }
+ void call ();
+ \grin 0
+};
+
+static NSDate *distantFuture, *distantPast;
+
+void FormatQuartz::call() {
+ NSEvent *e = [NSApp nextEventMatchingMask: NSAnyEventMask
+ // untilDate: distantFuture // blocking
+ untilDate: distantPast // nonblocking
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ if (e) {
+ NSLog(@"%@", e);
+ [NSApp sendEvent: e];
+ }
+ [NSApp updateWindows];
+ [this->window flushWindowIfNeeded];
+ clock_delay(clock,20);
+}
+void FormatQuartz_call(FormatQuartz *self) {self->call();}
+
+template <class T, class S>
+static void convert_number_type(int n, T *out, S *in) {
+ for (int i=0; i<n; i++) out[i]=(T)in[i];
+}
+
+GRID_INLET(FormatQuartz,0) {
+ if (in->dim->n!=3) RAISE("expecting 3 dims, not %d", in->dim->n);
+ int c=in->dim->get(2);
+ if (c!=3&&c!=4) RAISE("expecting 3 or 4 channels, not %d", in->dim->get(2));
+// [widget imageHeight: in->dim->get(0) width: in->dim->get(1) ];
+ GFView_imageHeight_width(widget,in->dim->get(0),in->dim->get(1));
+ in->set_factor(in->dim->prod(1));
+} GRID_FLOW {
+ int off = in->dex/in->dim->prod(2);
+ int c=in->dim->get(2);
+ NSView *w = widget;
+ uint8 *data2 = GFView_imageData(w)+off*4;
+// convert_number_type(n,data2,data);
+ if (c==3) {
+ while(n) {
+ data2[0]=255;
+ data2[1]=(uint8)data[0];
+ data2[2]=(uint8)data[1];
+ data2[3]=(uint8)data[2];
+ data+=3; data2+=4; n-=3;
+ }
+ } else {
+ while(n) {
+ data2[0]=255;
+ data2[1]=(uint8)data[0];
+ data2[2]=(uint8)data[1];
+ data2[3]=(uint8)data[2];
+ data+=4; data2+=4; n-=4;
+ }
+ }
+} GRID_FINISH {
+ GFView_display(widget);
+} GRID_END
+
+\end class FormatQuartz {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ distantFuture = [NSDate distantFuture];
+ distantPast = [NSDate distantPast];
+ [NSApplication sharedApplication];
+ install_format("#io.quartz",2,"");
+}
+void startup_quartz () {
+ \startall
+}
+
diff --git a/externals/gridflow/format/quicktimeapple.c b/externals/gridflow/format/quicktimeapple.c
new file mode 100644
index 00000000..2882168e
--- /dev/null
+++ b/externals/gridflow/format/quicktimeapple.c
@@ -0,0 +1,456 @@
+/*
+ $Id: quicktimeapple.c 3904 2008-06-18 20:32:46Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <QuickTime/QuickTime.h>
+#include <QuickTime/Movies.h>
+#include <QuickTime/QuickTimeComponents.h>
+#include "../gridflow.h.fcs"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <CoreServices/CoreServices.h>
+
+typedef ComponentInstance VideoDigitizerComponent, VDC;
+typedef ComponentResult VideoDigitizerError, VDE;
+
+#if 0
+//enum {VDCType='vdig', vdigInterfaceRev=2 };
+//enum {ntscIn=0, currentIn=0, palIn, secamIn, ntscReallyIn };
+//enum {compositeIn, sVideoIn, rgbComponentIn, rgbComponentSyncIn, yuvComponentIn, yuvComponentSyncIn, tvTunerIn, sdiIn};
+//enum {vdPlayThruOff, vdPlayThruOn};
+//enum {vdDigitizerBW, vdDigitizerRGB};
+//enum {vdBroadcastMode, vdVTRMode};
+//enum {vdUseAnyField, vdUseOddField, vdUseEvenField};
+//enum {vdTypeBasic, vdTypeAlpha, vdTypeMask, vdTypeKey};
+/*enum {digiInDoesNTSC, digiInDoesPAL, digiInDoesSECAM, skip 4,
+ digiInDoesGenLock, digiInDoesComposite, digiInDoesSVideo, digiInDoesComponent,
+ digiInVTR_Broadcast, digiInDoesColor, digiInDoesBW, skip 17,
+ digiInSignalLock};*/
+/*bitset {digiOutDoes1, digiOutDoes2, digiOutDoes4,
+ digiOutDoes8, digiOutDoes16, digiOutDoes32,
+ digiOutDoesDither, digiOutDoesStretch, digiOutDoesShrink,
+ digiOutDoesMask, skip 1,
+ digiOutDoesDouble, digiOutDoesQuad, digiOutDoesQuarter, digiOutDoesSixteenth,
+ digiOutDoesRotate, digiOutDoesHorizFlip, digiOutDoesVertFlip, digiOutDoesSkew,
+ digiOutDoesBlend, digiOutDoesWarp, digiOutDoesHW_DMA,
+ digiOutDoesHWPlayThru, digiOutDoesILUT, digiOutDoesKeyColor,
+ digiOutDoesAsyncGrabs, digiOutDoesUnreadableScreenBits,
+ digiOutDoesCompress, digiOutDoesCompressOnly,
+ digiOutDoesPlayThruDuringCompress, digiOutDoesCompressPartiallyVisible,
+ digiOutDoesNotNeedCopyOfCompressData};*/
+/*struct DigitizerInfo {
+ short vdigType;
+ long inputCapabilityFlags, outputCapabilityFlags;
+ long inputCurrentFlags, outputCurrentFlags;
+ short slot;
+ GDHandle gdh, maskgdh;
+ short minDestHeight, minDestWidth;
+ short maxDestHeight, maxDestWidth;
+ short blendLevels;
+ long reserved;};*/
+/*struct VdigType { long digType, reserved;};*/
+/*struct VdigTypeList { short count; VdigType list[1];};*/
+/*struct VdigBufferRec { PixMapHandle dest; Point location; long reserved;};*/
+/*struct VdigBufferRecList {
+ short count; MatrixRecordPtr matrix; RgnHandle mask; VdigBufferRec list[1];};*/
+//typedef VdigBufferRecList *VdigBufferRecListPtr;
+//typedef VdigBufferRecListPtr *VdigBufferRecListHandle;
+//typedef CALLBACK_API(void,VdigIntProcPtr)(long flags, long refcon);
+//typedef STACK_UPP_TYPE(VdigIntProcPtr);
+/*struct VDCompressionList {
+ CodecComponent codec; CodecType cType; Str63 typeName, name;
+ long formatFlags, compressFlags, reserved;};*/
+//typedef VDCompressionList * VDCompressionListPtr;
+//typedef VDCompressionListPtr *VDCompressionListHandle;
+/*bitset {
+ dmaDepth1, dmaDepth2, dmaDepth4, dmaDepth8, dmaDepth16, dmaDepth32,
+ dmaDepth2Gray, dmaDepth4Gray, dmaDepth8Gray};*/
+//enum {kVDIGControlledFrameRate=-1};
+//bitset {vdDeviceFlagShowInputsAsDevices, vdDeviceFlagHideDevice};
+/*bitset {
+ vdFlagCaptureStarting, vdFlagCaptureStopping,
+ vdFlagCaptureIsForPreview, vdFlagCaptureIsForRecord,
+ vdFlagCaptureLowLatency, vdFlagCaptureAlwaysUseTimeBase,
+ vdFlagCaptureSetSettingsBegin, vdFlagCaptureSetSettingsEnd};*/
+/*\class VDC
+VDE VDGetMaxSrcRect (short inputStd, Rect *maxSrcRect)
+VDE VDGetActiveSrcRect(short inputStd, Rect *activeSrcRect)
+VDE VD[GS]etDigitizerRect(Rect *digitizerRect)
+VDE VDGetVBlankRect(short inputStd, Rect *vBlankRect)
+VDE VDGetMaskPixMap(PixMapHandlemaskPixMap)
+VDE VDGetPlayThruDestination(PixMapHandle * dest, Rect *destRect, MatrixRecord * m, RgnHandle *mask)
+VDE VDUseThisCLUT(CTabHandle colorTableHandle)
+VDE VD[SG*]etInputGammaValue(Fixed channel1, Fixed channel2, Fixed channel3)
+VDE VD[GS]etBrightness(uint16 *)
+VDE VD[GS]etContrast(uint16 *)
+VDE VD[GS]etHue(uint16 *)
+VDE VD[GS]etSharpness(uint16 *)
+VDE VD[GS]etSaturation(uint16 *)
+VDE VDGrabOneFrame(VDC ci)
+VDE VDGetMaxAuxBuffer(PixMapHandle *pm, Rect *r)
+VDE VDGetDigitizerInfo(DigitizerInfo *info)
+VDE VDGetCurrentFlags(long *inputCurrentFlag, long *outputCurrentFlag)
+VDE VD[SG*]etKeyColor(long index)
+VDE VDAddKeyColor(long *index)
+VDE VDGetNextKeyColor(long index)
+VDE VD[GS]etKeyColorRange(RGBColor minRGB, RGBColor maxRGB)
+VDE VDSetDigitizerUserInterrupt(long flags, VdigIntUPP userInterruptProc, long refcon)
+VDE VD[SG*]etInputColorSpaceMode(short colorSpaceMode)
+VDE VD[SG*]etClipState(short clipEnable)
+VDE VDSetClipRgn(RgnHandle clipRegion)
+VDE VDClearClipRgn(RgnHandle clipRegion)
+VDE VDGetCLUTInUse(CTabHandle *colorTableHandle)
+VDE VD[SG*]etPLLFilterType(short pllType)
+VDE VDGetMaskandValue(uint16 blendLevel, long *mask, long *value)
+VDE VDSetMasterBlendLevel(uint16 *blendLevel)
+VDE VDSetPlayThruDestination(PixMapHandledest, RectPtr destRect, MatrixRecordPtr m, RgnHandle mask)
+VDE VDSetPlayThruOnOff(short state)
+VDE VD[SG*]etFieldPreference(short fieldFlag)
+VDE VDPreflightDestination(Rect *digitizerRect, PixMap **dest, RectPtr destRect, MatrixRecordPtr m)
+VDE VDPreflightGlobalRect(GrafPtr theWindow, Rect *globalRect)
+VDE VDSetPlayThruGlobalRect(GrafPtr theWindow, Rect *globalRect)
+VDE VDSetInputGammaRecord(VDGamRecPtrinputGammaPtr)
+VDE VDGetInputGammaRecord(VDGamRecPtr *inputGammaPtr)
+VDE VD[SG]etBlackLevelValue(uint16 *)
+VDE VD[SG]etWhiteLevelValue(uint16 *)
+VDE VDGetVideoDefaults(uint16 *blackLevel, uint16 *whiteLevel, uint16 *brightness, uint16 *hue, uint16 *saturation, uint16 *contrast, uint16 *sharpness)
+VDE VDGetNumberOfInputs(short *inputs)
+VDE VDGetInputFormat(short input, short *format)
+VDE VD[SG*]etInput(short input)
+VDE VDSetInputStandard(short inputStandard)
+VDE VDSetupBuffers(VdigBufferRecListHandle bufferList)
+VDE VDGrabOneFrameAsync(short buffer)
+VDE VDDone(short buffer)
+VDE VDSetCompression(OSTypecompressType, short depth, Rect *bounds, CodecQspatialQuality, CodecQtemporalQuality, long keyFrameRate)
+VDE VDCompressOneFrameAsync(VDC ci)
+VDE VDCompressDone(UInt8 *queuedFrameCount, Ptr *theData, long *dataSize, UInt8 *similarity, TimeRecord *t)
+VDE VDReleaseCompressBuffer(Ptr bufferAddr)
+VDE VDGetImageDescription(ImageDescriptionHandle desc)
+VDE VDResetCompressSequence(VDC ci)
+VDE VDSetCompressionOnOff(Boolean)
+VDE VDGetCompressionTypes(VDCompressionListHandle h)
+VDE VDSetTimeBase(TimeBase t)
+VDE VDSetFrameRate(Fixed framesPerSecond)
+VDE VDGetDataRate(long *milliSecPerFrame, Fixed *framesPerSecond, long *bytesPerSecond)
+VDE VDGetSoundInputDriver(Str255 soundDriverName)
+VDE VDGetDMADepths(long *depthArray, long *preferredDepth)
+VDE VDGetPreferredTimeScale(TimeScale *preferred)
+VDE VDReleaseAsyncBuffers(VDC ci)
+VDE VDSetDataRate(long bytesPerSecond)
+VDE VDGetTimeCode(TimeRecord *atTime, void *timeCodeFormat, void *timeCodeTime)
+VDE VDUseSafeBuffers(Boolean useSafeBuffers)
+VDE VDGetSoundInputSource(long videoInput, long *soundInput)
+VDE VDGetCompressionTime(OSTypecompressionType, short depth, Rect *srcRect, CodecQ *spatialQuality, CodecQ *temporalQuality, ulong *compressTime)
+VDE VDSetPreferredPacketSize(long preferredPacketSizeInBytes)
+VDE VD[SG*]etPreferredImageDimensions(long width, long height)
+VDE VDGetInputName(long videoInput, Str255 name)
+VDE VDSetDestinationPort(CGrafPtr destPort)
+VDE VDGetDeviceNameAndFlags(Str255 outName, UInt32 *outNameFlags)
+VDE VDCaptureStateChanging(UInt32inStateFlags)
+VDE VDGetUniqueIDs(UInt64 *outDeviceID, UInt64 *outInputID)
+VDE VDSelectUniqueIDs(const UInt64 *inDeviceID, const UInt64 *inInputID)
+*/
+#endif
+
+static OSErr callback(ComponentInstanceRecord*, char*, long int, long int*, long int, TimeValue, short int, long int) {
+ post("FormatQuickTimeCamera callback");
+ return noErr;
+}
+
+\class FormatQuickTimeCamera : Format {
+ P<Dim> dim;
+ uint8 *buf;
+ uint8 *buf2;
+ VDC vdc;
+ int m_newFrame;
+ SeqGrabComponent m_sg;
+ SGChannel m_vc;
+ short m_pixelDepth;
+ Rect rect;
+ GWorldPtr m_srcGWorld;
+ PixMapHandle m_pixMap;
+ Ptr m_baseAddr;
+ long m_rowBytes;
+ int m_quality;
+//int m_colorspace;
+ \constructor (t_symbol *mode) {
+ //vdc = SGGetVideoDigitizerComponent(c);
+ dim = new Dim(240,320,4);
+ OSErr e;
+ rect.top=rect.left=0;
+ rect.bottom=dim->v[0]; rect.right=dim->v[1];
+ int n=0;
+ Component c = 0;
+ ComponentDescription cd;
+ cd.componentType = SeqGrabComponentType;
+ cd.componentSubType = 0;
+ cd.componentManufacturer = 0;
+ cd.componentFlags = 0;
+ cd.componentFlagsMask = 0;
+ for(;;) {
+ c = FindNextComponent(c, &cd);
+ if (!c) break;
+ ComponentDescription cd2;
+ Ptr name=0,info=0,icon=0;
+ GetComponentInfo(c,&cd2,&name,&info,&icon);
+ post("Component #%d",n);
+ char *t = (char *)&cd.componentType;
+ post(" type='%c%c%c%c'",t[3],t[2],t[1],t[0]);
+ t = (char *)&cd.componentSubType;
+ post(" subtype='%c%c%c%c'",t[3],t[2],t[1],t[0]);
+ post(" name=%08x, *name='%*s'",name, *name, name+1);
+ post(" info=%08x, *info='%*s'",info, *name, info+1);
+ n++;
+ }
+ post("number of components: %d",n);
+ m_sg = OpenDefaultComponent(SeqGrabComponentType, 0);
+ if(!m_sg) RAISE("could not open default component");
+ e=SGInitialize(m_sg);
+ if(e!=noErr) RAISE("could not initialize SG");
+ e=SGSetDataRef(m_sg, 0, 0, seqGrabDontMakeMovie);
+ if (e!=noErr) RAISE("dataref failed");
+ e=SGNewChannel(m_sg, VideoMediaType, &m_vc);
+ if(e!=noErr) post("could not make new SG channel");
+ e=SGSetChannelBounds(m_vc, &rect);
+ if(e!=noErr) post("could not set SG ChannelBounds");
+ e=SGSetChannelUsage(m_vc, seqGrabPreview);
+ if(e!=noErr) post("could not set SG ChannelUsage");
+ e=SGSetDataProc(m_sg,NewSGDataUPP(callback),0);
+ if (e!=noErr) post("could not set SG DataProc");
+ // m_rowBytes = m_vidXSize*4;
+ switch (3) {
+ case 0: e=SGSetChannelPlayFlags(m_vc, channelPlayNormal); break;
+ case 1: e=SGSetChannelPlayFlags(m_vc, channelPlayHighQuality); break;
+ case 2: e=SGSetChannelPlayFlags(m_vc, channelPlayFast); break;
+ case 3: e=SGSetChannelPlayFlags(m_vc, channelPlayAllData); break;
+ }
+ int dataSize = dim->prod();
+ buf = new uint8[dataSize];
+ buf2 = new uint8[dataSize];
+ m_rowBytes = dim->prod(1);
+ e=QTNewGWorldFromPtr (&m_srcGWorld,k32ARGBPixelFormat,&rect,NULL,NULL,0,buf,m_rowBytes);
+ if (0/*yuv*/) {
+ int dataSize = dim->prod()*2/4;
+ buf = new uint8[dataSize];
+ m_rowBytes = dim->prod(1)*2/4;
+ e=QTNewGWorldFromPtr (&m_srcGWorld,k422YpCbCr8CodecType,&rect,NULL,NULL,0,buf,m_rowBytes);
+ }
+ if (e!=noErr) RAISE("error #%d at QTNewGWorldFromPtr",e);
+ if (!m_srcGWorld) RAISE("Could not allocate off screen");
+ SGSetGWorld(m_sg,(CGrafPtr)m_srcGWorld, NULL);
+ //SGStartPreview(m_sg);
+ e=SGStartRecord(m_sg);
+ if (e!=noErr) RAISE("error #%d at SGStartRecord",e);
+ }
+ ~FormatQuickTimeCamera() {
+ if (m_vc) if (::SGDisposeChannel(m_sg, m_vc)) RAISE("SGDisposeChannel");
+ if (m_sg) {
+ if (::CloseComponent(m_sg)) RAISE("CloseComponent");
+ if (m_srcGWorld) ::DisposeGWorld(m_srcGWorld);
+ }
+ }
+ \decl 0 bang ();
+ \grin 0 int
+};
+
+// /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Components.h
+
+static int nn(int c) {return c?c:' ';}
+
+/*
+pascal Boolean pix_videoDarwin :: SeqGrabberModalFilterProc (DialogPtr theDialog, const EventRecord *theEvent, short *itemHit, long refCon){
+ Boolean handled = false;
+ if ((theEvent->what == updateEvt) &&
+ ((WindowPtr) theEvent->message == (WindowPtr) refCon)) {
+ BeginUpdate ((WindowPtr) refCon);
+ EndUpdate ((WindowPtr) refCon);
+ handled = true;
+ }
+ WindowRef awin = GetDialogWindow(theDialog);
+ ShowWindow (awin);
+ SetWindowClass(awin,kUtilityWindowClass);
+ //ChangeWindowAttributes(awin,kWindowStandardHandlerAttribute,0);
+ //SGPanelEvent(m_sg,m_vc,theDialog,0,theEvent,itemHit,&handled);
+ //AEProcessAppleEvent (theEvent);
+ return handled;
+}
+void pix_videoDarwin :: DoVideoSettings() {
+ Rect newActiveVideoRect;
+ Rect curBounds, curVideoRect, newVideoRect;
+ ComponentResult err;
+ SGModalFilterUPP seqGragModalFilterUPP;
+ err = SGGetChannelBounds (m_vc, &curBounds);
+ err = SGGetVideoRect (m_vc, &curVideoRect);
+ err = SGPause (m_sg, true);
+ seqGragModalFilterUPP = (SGModalFilterUPP)NewSGModalFilterUPP(SeqGrabberModalFilterProc);
+ err = SGSettingsDialog(m_sg, m_vc, 0, NULL, seqGrabSettingsPreviewOnly, seqGragModalFilterUPP, (long)m_srcGWorld);
+ DisposeSGModalFilterUPP(seqGragModalFilterUPP);
+ err = SGGetVideoRect (m_vc, &newVideoRect);
+ err = SGGetSrcVideoBounds (m_vc, &newActiveVideoRect);
+ err = SGPause (m_sg, false);
+}
+*/
+
+\def 0 bang () {
+ GridOutlet out(this,0,dim);
+ int n = dim->prod()/4;
+ for (int i=0; i<n; i++) ((uint32 *)buf2)[i] = ((uint32 *)buf)[i] >> 8;
+ out.send(dim->prod(),buf2);
+ SGIdle(m_sg);
+}
+
+GRID_INLET(FormatQuickTimeCamera,0) {
+ RAISE("Unimplemented. Sorry.");
+//!@#$
+ if (in->dim->n != 3) RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3) RAISE("expecting 3 channels (got %d)",in->dim->get(2));
+ in->set_chunk(0);
+} GRID_FLOW {
+} GRID_FINISH {
+} GRID_END
+\end class FormatQuickTimeCamera {install_format("#io.quicktimecamera",4,"");}
+
+\class FormatQuickTimeApple : Format {
+ Movie movie;
+ TimeValue time;
+ short movie_file;
+ GWorldPtr gw; /* just like an X11 Image or Pixmap, maybe. */
+ uint8 *buffer;
+ P<Dim> dim;
+ int nframe, nframes;
+ \constructor (t_symbol *mode, string filename) {
+ /*vdc=0;*/ movie=0; time=0; movie_file=0; gw=0; buffer=0; dim=0; nframe=0; nframes=0;
+ int err;
+ filename = gf_find_file(filename);
+ FSSpec fss;
+ FSRef fsr;
+ err = FSPathMakeRef((const UInt8 *)filename.data(), &fsr, NULL); if (err) goto err;
+ err = FSGetCatalogInfo(&fsr, kFSCatInfoNone, NULL, NULL, &fss, NULL); if (err) goto err;
+ err = OpenMovieFile(&fss,&movie_file,fsRdPerm); if (err) goto err;
+ NewMovieFromFile(&movie, movie_file, NULL, NULL, newMovieActive, NULL);
+ Rect r;
+ GetMovieBox(movie, &r);
+ post("handle=%d movie=%d tracks=%d", movie_file, movie, GetMovieTrackCount(movie));
+ post("duration=%d; timescale=%d cHz", (long)GetMovieDuration(movie), (long)GetMovieTimeScale(movie));
+ nframes = GetMovieDuration(movie); /* i don't think so */
+ post("rect=((%d..%d),(%d..%d))", r.top, r.bottom, r.left, r.right);
+ OffsetRect(&r, -r.left, -r.top);
+ SetMovieBox(movie, &r);
+ dim = new Dim(r.bottom-r.top, r.right-r.left, 4);
+ SetMoviePlayHints(movie, hintsHighQuality, hintsHighQuality);
+ buffer = new uint8[dim->prod()];
+ err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &r, NULL, NULL, 0, buffer, dim->prod(1));
+ if (err) goto err;
+ return;
+ err:
+ // RAISE("can't open file `%s': error #%d (%s)", filename.data(), err, rb_str_ptr(rb_funcall(mGridFlow,SI(macerr),1,INT2NUM(err))));
+ RAISE("can't open file `%s': error #%d (0x%08x)", filename.data(), err, err);
+ }
+ ~FormatQuickTimeApple() {
+ if (movie) {
+ DisposeMovie(movie);
+ DisposeGWorld(gw);
+ CloseMovieFile(movie_file);
+ }
+ }
+ \decl 0 codec (string c);
+ \decl 0 colorspace (string c);
+ \decl 0 bang ();
+ \decl 0 seek (int frame);
+ \decl 0 rewind ();
+ \grin 0
+};
+
+\def 0 seek (int frame) {nframe=frame;}
+\def 0 rewind () {_0_seek(0,0,0);}
+
+\def 0 bang () {
+ CGrafPtr savedPort;
+ GDHandle savedDevice;
+ SetMovieGWorld(movie,gw,GetGWorldDevice(gw));
+ Rect r;
+ GetMovieBox(movie,&r);
+ PixMapHandle pixmap = GetGWorldPixMap(gw);
+ short flags = nextTimeStep;
+ if (nframe>=nframes) {outlet_bang(bself->te_outlet); return;}
+ if (nframe==0) flags |= nextTimeEdgeOK;
+ TimeValue duration;
+ OSType mediaType = VisualMediaCharacteristic;
+ GetMovieNextInterestingTime(movie,
+ flags,1,&mediaType,time,0,&time,&duration);
+ if (time<0) {
+ time=0;
+ outlet_bang(bself->te_outlet);
+ return;
+ }
+// post("quicktime frame #%d; time=%d duration=%d", nframe, (long)time, (long)duration);
+ SetMovieTimeValue(movie,nframe*duration);
+ MoviesTask(movie,0);
+ GridOutlet out(this,0,dim);
+ uint32 *bufu32 = (uint32 *)buffer;
+ int n = dim->prod()/4;
+ int i;
+ if (is_le()) {
+ for (; i<n; i++) {
+ bufu32[i+0]=bufu32[i+0]>>8;
+ }
+ } else {
+ for (i=0; i<n&-4; i+=4) {
+ bufu32[i+0]=(bufu32[i+0]<<8)+(bufu32[i+0]>>24);
+ bufu32[i+1]=(bufu32[i+1]<<8)+(bufu32[i+1]>>24);
+ bufu32[i+2]=(bufu32[i+2]<<8)+(bufu32[i+2]>>24);
+ bufu32[i+3]=(bufu32[i+3]<<8)+(bufu32[i+3]>>24);
+ }
+ for (; i<n; i++) {
+ bufu32[i+0]=(bufu32[i+0]<<8)+(bufu32[i+0]>>24);
+ }
+ }
+ out.send(dim->prod(),buffer);
+ int nf=nframe;
+ nframe++;
+ //return INT2NUM(nf);
+}
+
+GRID_INLET(FormatQuickTimeApple,0) {
+ RAISE("Unimplemented. Sorry.");
+//!@#$
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3)
+ RAISE("expecting 3 channels (got %d)",in->dim->get(2));
+ in->set_chunk(0);
+} GRID_FLOW {
+} GRID_FINISH {
+} GRID_END
+
+\def 0 codec (string c) { RAISE("Unimplemented. Sorry."); }
+\def 0 colorspace (string c) { RAISE("Unimplemented. Sorry."); }
+
+\classinfo {
+ EnterMovies();
+ install_format("#io.quicktime",4,"mov");
+}
+\end class FormatQuickTimeApple
+void startup_quicktimeapple () {
+ \startall
+}
diff --git a/externals/gridflow/format/quicktimehw.c b/externals/gridflow/format/quicktimehw.c
new file mode 100644
index 00000000..363c4641
--- /dev/null
+++ b/externals/gridflow/format/quicktimehw.c
@@ -0,0 +1,243 @@
+/*
+ $Id: quicktimehw.c 3878 2008-06-15 04:37:33Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define QUICKTIMEHW_INCLUDE_HERE
+#include "../gridflow.h.fcs"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <map>
+#include <vector>
+
+static std::map<string,std::vector<string> *> codecs;
+static std::map<string,string> fourccs;
+
+\class FormatQuickTimeHW : Format {
+ quicktime_t *anim;
+ int track;
+ P<Dim> dim;
+ char *codec;
+ int colorspace;
+ int channels;
+ bool started;
+ P<Dim> force;
+ int length; // in frames
+ float64 framerate;
+ P<BitPacking> bit_packing;
+ int jpeg_quality; // in theory we shouldn't need this, but...
+ ~FormatQuickTimeHW() {if (anim) quicktime_close(anim);}
+ \constructor (t_symbol *mode, string filename) {
+ track=0; dim=0; codec=QUICKTIME_RAW; started=false; force=0; framerate=29.97; bit_packing=0; jpeg_quality=75;
+// libquicktime may be nice, but it won't take a filehandle, only filename
+ filename = gf_find_file(filename);
+ anim = quicktime_open((char *)filename.data(),mode==gensym("in"),mode==gensym("out"));
+ if (!anim) RAISE("can't open file `%s': %s (or some other reason that libquicktime won't tell us)",
+ filename.data(), strerror(errno));
+ if (mode==gensym("in")) {
+ length = quicktime_video_length(anim,track);
+ post("quicktime: codec=%s height=%d width=%d depth=%d framerate=%f",
+ quicktime_video_compressor(anim,track),
+ quicktime_video_height(anim,track),
+ quicktime_video_width(anim,track),
+ quicktime_video_depth(anim,track),
+ quicktime_frame_rate(anim,track));
+ /* This doesn't really work: (is it just for encoding?)
+ if (!quicktime_supported_video(anim,track))
+ RAISE("quicktime: unsupported codec: %s",
+ quicktime_video_compressor(anim,track));
+ */
+ }
+ _0_colorspace(0,0,string("rgb"));
+ quicktime_set_cpus(anim,1);
+ uint32 mask[3] = {0x0000ff,0x00ff00,0xff0000};
+ bit_packing = new BitPacking(is_le(),3,3,mask);
+ }
+ \decl 0 bang ();
+ \decl 0 seek (long frame);
+ \decl 0 rewind ();
+ \decl 0 force_size (int32 height, int32 width);
+ \decl 0 codec (string c);
+ \decl 0 colorspace (string c);
+ \decl 0 parameter (string name, int32 value);
+ \decl 0 framerate (float64 f);
+ \decl 0 size (int32 height, int32 width);
+ \decl 0 get ();
+ \grin 0 int
+};
+
+\def 0 force_size (int32 height, int32 width) { force = new Dim(height, width); }
+\def 0 seek (long frame) {
+ quicktime_set_video_position(anim,clip(frame,0L,quicktime_video_length(anim,track)-1),track);
+}
+\def 0 rewind () {_0_seek(0,0,0);}
+
+\def 0 bang () {
+ long length = quicktime_video_length(anim,track);
+ long nframe = quicktime_video_position(anim,track);
+ if (nframe >= length) {outlet_bang(bself->te_outlet); return;}
+ /* if it works, only do it once, to avoid silly stderr messages forgotten in LQT */
+ if (!quicktime_reads_cmodel(anim,colorspace,0) && !started) {
+ RAISE("LQT says this video cannot be decoded into the chosen colorspace");
+ }
+ int sx = quicktime_video_width(anim,track);
+ int sy = quicktime_video_height(anim,track);
+ int sz = quicktime_video_depth(anim,track);
+ channels = sz/8; // hack. how do i get the video's native colormodel ?
+ switch (sz) {
+ case 24: colorspace=BC_RGB888; break;
+ case 32: colorspace=BC_RGBA8888; break;
+ default: post("strange quicktime. ask matju."); break;
+ }
+ if (force) {
+ sy = force->get(0);
+ sx = force->get(1);
+ }
+ uint8 *buf = new uint8[sy*sx*channels];
+ uint8 *rows[sy]; for (int i=0; i<sy; i++) rows[i]=buf+i*sx*channels;
+ quicktime_decode_scaled(anim,0,0,sx,sy,sx,sy,colorspace,rows,track);
+ GridOutlet out(this,0,new Dim(sy,sx,channels),cast);
+ out.give(sy*sx*channels,buf);
+ started=true;
+// return INT2NUM(nframe);
+}
+
+//!@#$ should also support symbol values (how?)
+\def 0 parameter (string name, int32 value) {
+ int val = value;
+ //post("quicktime_set_parameter %s %d",name.data(), val);
+ quicktime_set_parameter(anim, const_cast<char *>(name.data()), &val);
+ if (name=="jpeg_quality") jpeg_quality=value;
+}
+
+\def 0 framerate (float64 f) {
+ framerate=f;
+ quicktime_set_framerate(anim, f);
+}
+
+\def 0 size (int32 height, int32 width) {
+ if (dim) RAISE("video size already set!");
+ // first frame: have to do setup
+ dim = new Dim(height, width, 3);
+ quicktime_set_video(anim,1,dim->get(1),dim->get(0),framerate,codec);
+ quicktime_set_cmodel(anim,colorspace);
+}
+
+GRID_INLET(FormatQuickTimeHW,0) {
+ if (in->dim->n != 3) RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2)!=channels) RAISE("expecting %d channels (got %d)",channels,in->dim->get(2));
+ in->set_chunk(0);
+ if (dim) {
+ if (!dim->equal(in->dim)) RAISE("all frames should be same size");
+ } else {
+ // first frame: have to do setup
+ dim = in->dim;
+ quicktime_set_video(anim,1,dim->get(1),dim->get(0),framerate,codec);
+ quicktime_set_cmodel(anim,colorspace);
+ quicktime_set_depth(anim,8*channels,track);
+ }
+ //post("quicktime jpeg_quality %d", jpeg_quality);
+ quicktime_set_parameter(anim, (char*)"jpeg_quality", &jpeg_quality);
+} GRID_FLOW {
+ int sx = quicktime_video_width(anim,track);
+ int sy = quicktime_video_height(anim,track);
+ uint8 *rows[sy];
+ if (sizeof(T)>1) {
+ uint8 data2[n];
+ bit_packing->pack(sx*sy,data,(uint8 *)data2);
+ for (int i=0; i<sy; i++) rows[i]=data2+i*sx*channels;
+ quicktime_encode_video(anim,rows,track);
+ } else {
+ for (int i=0; i<sy; i++) rows[i]=(uint8 *)data+i*sx*channels;
+ quicktime_encode_video(anim,rows,track);
+ }
+} GRID_FINISH {
+} GRID_END
+
+\def 0 codec (string c) {
+#ifdef LQT_VERSION
+ char buf[5];
+ strncpy(buf,c.data(),4);
+ for (int i=c.length(); i<4; i++) buf[i]=' ';
+ buf[4]=0;
+ if (fourccs.find(string(buf))==fourccs.end())
+ RAISE("warning: unknown fourcc '%s'" /*" (%s)"*/, buf /*, rb_str_ptr(rb_inspect(rb_funcall(fourccs,SI(keys),0)))*/);
+#endif
+ codec = strdup(buf);
+}
+
+\def 0 colorspace (string c) {
+ if (0) {
+ } else if (c=="rgb") { channels=3; colorspace=BC_RGB888;
+ } else if (c=="rgba") { channels=4; colorspace=BC_RGBA8888;
+ } else if (c=="bgr") { channels=3; colorspace=BC_BGR888;
+ } else if (c=="bgrn") { channels=4; colorspace=BC_BGR8888;
+// } else if (c=="yuv") { channels=3; colorspace=BC_YUV888;
+ } else if (c=="yuva") { channels=4; colorspace=BC_YUVA8888;
+ } else if (c=="YUV420P") { channels=3; colorspace=BC_YUV420P;
+ } else RAISE("unknown colorspace '%s' (supported: rgb, rgba, bgr, bgrn, yuv, yuva)",c.data());
+}
+
+\def 0 get () {
+/* t_atom a[1];
+ SETFLOAT(a,(float)length);
+ outlet_anything(bself->te_outlet,gensym("frames"),1,a);
+*/
+ t_atom a[1];
+ SETFLOAT(a,length);
+ outlet_anything(bself->outlets[0],gensym("frames"),1,a);
+ //SUPER;
+}
+
+\classinfo {install_format("#io.quicktime",6,"mov avi");
+// def self.info; %[codecs: #{@codecs.keys.join' '}] end
+//#define L fprintf(stderr,"%s:%d in %s\n",__FILE__,__LINE__,__PRETTY_FUNCTION__);
+#ifdef LQT_VERSION
+ lqt_registry_init();
+ int n = lqt_get_num_video_codecs();
+ for (int i=0; i<n; i++) {
+ const lqt_codec_info_t *s = lqt_get_video_codec_info(i);
+ if (!s->name) {
+ fprintf(stderr,"[#in quicktime]: skipping codec with null name!\n");
+ continue;
+ }
+ string name = string(s->name);
+ std::vector<string> *f = new std::vector<string>(s->num_fourccs);
+ if (!s->fourccs) {
+ post("WARNING: no fourccs (quicktime library is broken?)");
+ goto hell;
+ }
+ //fprintf(stderr,"num_fourccs=%d fourccs=%p\n",s->num_fourccs,s->fourccs);
+ for (int j=0; j<s->num_fourccs; j++) {
+ string fn = string(s->fourccs[j]);
+ f->push_back(fn);
+ fourccs[fn]=name;
+ }
+ codecs[name]=f;
+ hell:;
+ }
+#endif
+}
+\end class FormatQuickTimeHW
+void startup_quicktimehw () {
+ \startall
+}
diff --git a/externals/gridflow/format/sdl.c b/externals/gridflow/format/sdl.c
new file mode 100644
index 00000000..e87d65c9
--- /dev/null
+++ b/externals/gridflow/format/sdl.c
@@ -0,0 +1,209 @@
+/*
+ $Id: sdl.c 3809 2008-06-05 17:17:54Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../gridflow.h.fcs"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <SDL/SDL.h>
+
+struct FormatSDL;
+void FormatSDL_call(FormatSDL *self);
+static bool in_use = false;
+static bool full_screen = false;
+static int mousex,mousey,mousem;
+SDL_Surface *screen;
+FObject *instance;
+
+static t_symbol *keyboard[SDLK_LAST];
+
+static void KEYS_ARE (int i, const char *s__) {
+ char *s_ = strdup(s__);
+ char *s = s_;
+ while (*s) {
+ char *t = strchr(s,' ');
+ if (t) *t=0;
+ keyboard[i] = gensym(s);
+ if (!t) break;
+ s=t+1; i++;
+ }
+ free(s_);
+}
+
+static void build_keyboard () {
+ KEYS_ARE(8,"BackSpace Tab");
+ KEYS_ARE(13,"Return");
+ KEYS_ARE(27,"Escape");
+ KEYS_ARE(32,"space exclam quotedbl numbersign dollar percent ampersand apostrophe");
+ KEYS_ARE(40,"parenleft parenright asterisk plus comma minus period slash");
+ KEYS_ARE(48,"D0 D1 D2 D3 D4 D5 D6 D7 D8 D9");
+ KEYS_ARE(58,"colon semicolon less equal greater question at");
+ //KEYS_ARE(65,"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
+ KEYS_ARE(91,"bracketleft backslash bracketright asciicircum underscore grave quoteleft");
+ KEYS_ARE(97,"a b c d e f g h i j k l m n o p q r s t u v w x y z");
+ //SDLK_DELETE = 127
+ KEYS_ARE(256,"KP_0 KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9");
+ KEYS_ARE(266,"KP_Decimal KP_Divide KP_Multiply KP_Subtract KP_Add KP_Enter KP_Equal");
+ KEYS_ARE(273,"KP_Up KP_Down KP_Right KP_Left KP_Insert KP_Home KP_End KP_Prior KP_Next");
+ KEYS_ARE(282,"F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15");
+ KEYS_ARE(300,"Num_Lock Caps_Lock Scroll_Lock");
+ KEYS_ARE(303,"Shift_R Shift_L Control_R Control_L Alt_R Alt_L Meta_L Meta_R");
+ KEYS_ARE(311,"Super_L Super_R Mode_switch Multi_key");
+}
+
+static void report_pointer () {
+ t_atom a[3];
+ SETFLOAT(a+0,mousey);
+ SETFLOAT(a+1,mousex);
+ SETFLOAT(a+2,mousem);
+ outlet_anything(instance->bself->outlets[0],gensym("position"),COUNT(a),a);
+}
+
+static void HandleEvent () {
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_KEYDOWN: case SDL_KEYUP: {
+ int key = event.key.keysym.sym;
+ int mod = event.key.keysym.mod;
+ if (event.type==SDL_KEYDOWN && (key==SDLK_F11 || key==SDLK_ESCAPE || key=='f')) {
+ full_screen = !full_screen;
+ SDL_WM_ToggleFullScreen(screen);
+ break;
+ }
+ t_symbol *sel = gensym(const_cast<char *>(event.type==SDL_KEYDOWN ? "keypress" : "keyrelease"));
+ t_atom at[4];
+ mousem &= ~0xFF;
+ mousem |= mod;
+ SETFLOAT(at+0,mousey);
+ SETFLOAT(at+1,mousex);
+ SETFLOAT(at+2,mousem);
+ SETSYMBOL(at+3,keyboard[event.key.keysym.sym]);
+ outlet_anything(instance->bself->outlets[0],sel,4,at);
+ } break;
+ case SDL_MOUSEBUTTONDOWN: SDL_MOUSEBUTTONUP: {
+ if (SDL_MOUSEBUTTONDOWN) mousem |= (128<<event.button.button);
+ else mousem &= ~(128<<event.button.button);
+ //post("mousem=%d",mousem);
+ report_pointer();
+ } break;
+ case SDL_MOUSEMOTION: {
+ mousey = event.motion.y;
+ mousex = event.motion.x;
+ report_pointer();
+ } break;
+ case SDL_VIDEORESIZE: {
+ } break;
+ }
+ }
+}
+
+\class FormatSDL : Format {
+ P<BitPacking> bit_packing;
+ P<Dim> dim;
+ t_clock *clock;
+ void resize_window (int sx, int sy);
+ void call ();
+ \decl 0 setcursor (int shape);
+ \decl 0 hidecursor ();
+ \decl 0 title (string title);
+ \constructor (t_symbol *mode) {
+ dim=0;screen=0;
+ if (in_use) RAISE("only one FormatSDL object at a time; sorry");
+ in_use=true;
+ if (SDL_Init(SDL_INIT_VIDEO)<0) RAISE("SDL_Init() error: %s",SDL_GetError());
+ atexit(SDL_Quit);
+ resize_window(320,240);
+ SDL_PixelFormat *f = screen->format;
+ uint32 mask[3] = {f->Rmask,f->Gmask,f->Bmask};
+ switch (f->BytesPerPixel) {
+ case 1: RAISE("8 bpp not supported"); break;
+ case 2: case 3: case 4:
+ bit_packing = new BitPacking(is_le(),f->BytesPerPixel,3,mask);
+ break;
+ default: RAISE("%d bytes/pixel: how do I deal with that?",f->BytesPerPixel); break;
+ }
+ instance=this;
+ clock = clock_new(this,(t_method)FormatSDL_call);
+ clock_delay(clock,0);
+ _0_title(0,0,string("GridFlow SDL"));
+ }
+ \grin 0 int
+ ~FormatSDL () {
+ clock_unset(clock);
+ clock_free(clock);
+ SDL_Quit();
+ instance=0;
+ in_use=false;
+ }
+};
+
+\def 0 title (string title) {
+ SDL_WM_SetCaption(title.data(),title.data());
+}
+
+void FormatSDL::call() {HandleEvent(); clock_delay(clock,20);}
+void FormatSDL_call(FormatSDL *self) {self->call();}
+
+void FormatSDL::resize_window (int sx, int sy) {
+ dim = new Dim(sy,sx,3);
+ screen = SDL_SetVideoMode(sx,sy,0,SDL_SWSURFACE);
+ if (!screen)
+ RAISE("Can't switch to (%d,%d,%dbpp): %s", sy,sx,24, SDL_GetError());
+}
+
+GRID_INLET(FormatSDL,0) {
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2) != 3)
+ RAISE("expecting 3 channels: red,green,blue (got %d)",in->dim->get(2));
+ int sx = in->dim->get(1), osx = dim->get(1);
+ int sy = in->dim->get(0), osy = dim->get(0);
+ in->set_chunk(1);
+ if (sx!=osx || sy!=osy) resize_window(sx,sy);
+} GRID_FLOW {
+ int bypl = screen->pitch;
+ int sxc = in->dim->prod(1);
+ int sx = in->dim->get(1);
+ int y = in->dex / sxc;
+ if (SDL_MUSTLOCK(screen)) if (SDL_LockSurface(screen) < 0) return; //???
+ for (; n>0; y++, data+=sxc, n-=sxc) {
+ /* convert line */
+ bit_packing->pack(sx, data, (uint8 *)screen->pixels+y*bypl);
+ }
+ if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
+} GRID_FINISH {
+ SDL_UpdateRect(screen,0,0,in->dim->get(1),in->dim->get(0));
+} GRID_END
+
+\def 0 setcursor (int shape) {SDL_ShowCursor(SDL_ENABLE);}
+\def 0 hidecursor () {SDL_ShowCursor(SDL_DISABLE);}
+
+\end class FormatSDL {install_format("#io.sdl",2,"");}
+void startup_sdl () {
+ \startall
+ build_keyboard();
+}
diff --git a/externals/gridflow/format/videodev.c b/externals/gridflow/format/videodev.c
new file mode 100644
index 00000000..eb508fbd
--- /dev/null
+++ b/externals/gridflow/format/videodev.c
@@ -0,0 +1,792 @@
+/*
+ $Id: videodev.c 3871 2008-06-12 14:41:53Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* bt878 on matju's comp supports only palette 4 */
+/* bt878 on heri's comp supports palettes 3, 6, 7, 8, 9, 13 */
+/* pwc supports palettes 12 and 15 */
+
+#include "../gridflow.h.fcs"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/videodev.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "pwc-ioctl.h"
+
+//#define error post
+static bool debug=0;
+
+/* **************************************************************** */
+
+typedef video_capability VideoCapability;
+typedef video_channel VideoChannel ;
+typedef video_tuner VideoTuner ;
+typedef video_window VideoWindow ;
+typedef video_picture VideoPicture ;
+typedef video_mbuf VideoMbuf ;
+typedef video_mmap VideoMmap ;
+
+#define FLAG(_num_,_name_,_desc_) #_name_,
+#define OPT(_num_,_name_,_desc_) #_name_,
+
+/*
+static const char *video_type_flags[] = {
+ FLAG( 0,CAPTURE, "Can capture")
+ FLAG( 1,TUNER, "Can tune")
+ FLAG( 2,TELETEXT, "Does teletext")
+ FLAG( 3,OVERLAY, "Overlay onto frame buffer")
+ FLAG( 4,CHROMAKEY, "Overlay by chromakey")
+ FLAG( 5,CLIPPING, "Can clip")
+ FLAG( 6,FRAMERAM, "Uses the frame buffer memory")
+ FLAG( 7,SCALES, "Scalable")
+ FLAG( 8,MONOCHROME, "Monochrome only")
+ FLAG( 9,SUBCAPTURE, "Can capture subareas of the image")
+ FLAG(10,MPEG_DECODER, "Can decode MPEG streams")
+ FLAG(11,MPEG_ENCODER, "Can encode MPEG streams")
+ FLAG(12,MJPEG_DECODER, "Can decode MJPEG streams")
+ FLAG(13,MJPEG_ENCODER, "Can encode MJPEG streams")
+};
+*/
+
+static const char *tuner_flags[] = {
+ FLAG(0,PAL, "")
+ FLAG(1,NTSC, "")
+ FLAG(2,SECAM, "")
+ FLAG(3,LOW, "Uses KHz not MHz")
+ FLAG(4,NORM, "Tuner can set norm")
+ FLAG(5,DUMMY5, "")
+ FLAG(6,DUMMY6, "")
+ FLAG(7,STEREO_ON,"Tuner is seeing stereo")
+ FLAG(8,RDS_ON, "Tuner is seeing an RDS datastream")
+ FLAG(9,MBS_ON, "Tuner is seeing an MBS datastream")
+};
+
+static const char *channel_flags[] = {
+ FLAG(0,TUNER,"")
+ FLAG(1,AUDIO,"")
+ FLAG(2,NORM ,"")
+};
+
+static const char *video_palette_choice[] = {
+ OPT( 0,NIL, "(nil)")
+ OPT( 1,GREY, "Linear greyscale")
+ OPT( 2,HI240, "High 240 cube (BT848)")
+ OPT( 3,RGB565, "565 16 bit RGB")
+ OPT( 4,RGB24, "24bit RGB")
+ OPT( 5,RGB32, "32bit RGB")
+ OPT( 6,RGB555, "555 15bit RGB")
+ OPT( 7,YUV422, "YUV422 capture")
+ OPT( 8,YUYV, "")
+ OPT( 9,UYVY, "The great thing about standards is ...")
+ OPT(10,YUV420, "")
+ OPT(11,YUV411, "YUV411 capture")
+ OPT(12,RAW, "RAW capture (BT848)")
+ OPT(13,YUV422P, "YUV 4:2:2 Planar")
+ OPT(14,YUV411P, "YUV 4:1:1 Planar")
+ OPT(15,YUV420P, "YUV 4:2:0 Planar")
+ OPT(16,YUV410P, "YUV 4:1:0 Planar")
+};
+
+static const char *video_mode_choice[] = {
+ OPT( 0,PAL, "pal")
+ OPT( 1,NTSC, "ntsc")
+ OPT( 2,SECAM,"secam")
+ OPT( 3,AUTO, "auto")
+};
+
+#define WH(_field_,_spec_) \
+ sprintf(buf+strlen(buf), "%s=" _spec_ " ", #_field_, self->_field_);
+#define WHYX(_name_,_fieldy_,_fieldx_) \
+ sprintf(buf+strlen(buf), "%s=(%d %d) ", #_name_, self->_fieldy_, self->_fieldx_);
+#define WHFLAGS(_field_,_table_) { \
+ char *foo; \
+ sprintf(buf+strlen(buf), "%s:%s ", #_field_, \
+ foo=flags_to_s(self->_field_,COUNT(_table_),_table_)); \
+ free(foo);}
+#define WHCHOICE(_field_,_table_) { \
+ char *foo; \
+ sprintf(buf+strlen(buf), "%s=%s; ", #_field_, \
+ foo=choice_to_s(self->_field_,COUNT(_table_),_table_));\
+ free(foo);}
+
+static char *flags_to_s(int value, int n, const char **table) {
+ char foo[256];
+ *foo = 0;
+ for(int i=0; i<n; i++) {
+ if ((value & (1<<i)) == 0) continue;
+ if (*foo) strcat(foo," | ");
+ strcat(foo,table[i]);
+ }
+ if (!*foo) strcat(foo,"0");
+ return strdup(foo);
+}
+static char *choice_to_s(int value, int n, const char **table) {
+ if (value < 0 || value >= n) {
+ char foo[64];
+ sprintf(foo,"(Unknown #%d)",value);
+ return strdup(foo);
+ } else {
+ return strdup(table[value]);
+ }
+}
+static void gfpost(VideoChannel *self) {
+ char buf[256] = "[VideoChannel] ";
+ WH(channel,"%d");
+ WH(name,"\"%.32s\"");
+ WH(tuners,"%d");
+ WHFLAGS(flags,channel_flags);
+ WH(type,"0x%04x");
+ WH(norm,"%d");
+ post("%s",buf);
+}
+static void gfpost(VideoTuner *self) {
+ char buf[256] = "[VideoTuner] ";
+ WH(tuner,"%d");
+ WH(name,"\"%.32s\"");
+ WH(rangelow,"%lu");
+ WH(rangehigh,"%lu");
+ WHFLAGS(flags,tuner_flags);
+ WHCHOICE(mode,video_mode_choice);
+ WH(signal,"%d");
+ post("%s",buf);
+}
+static void gfpost(VideoWindow *self) {
+ char buf[256] = "[VideoWindow] ";
+ WHYX(pos,y,x);
+ WHYX(size,height,width);
+ WH(chromakey,"0x%08x");
+ WH(flags,"0x%08x");
+ WH(clipcount,"%d");
+ post("%s",buf);
+}
+static void gfpost(VideoMbuf *self) {
+ char buf[256] = "[VideoMBuf] ";
+ WH(size,"%d");
+ WH(frames,"%d");
+ sprintf(buf+strlen(buf), "offsets=[");
+ for (int i=0; i<self->frames; i++) {
+ /* WH(offsets[i],"%d"); */
+ sprintf(buf+strlen(buf), "%d%s", self->offsets[i],
+ i+1==self->frames?"]":", ");
+ }
+ post("%s",buf);
+}
+static void gfpost(VideoMmap *self) {
+ char buf[256] = "[VideoMMap] ";
+ WH(frame,"%u");
+ WHYX(size,height,width);
+ WHCHOICE(format,video_palette_choice);
+ post("%s",buf);
+};
+
+/* **************************************************************** */
+
+\class FormatVideoDev : Format {
+ VideoCapability vcaps;
+ VideoPicture vp;
+ VideoMbuf vmbuf;
+ VideoMmap vmmap;
+ uint8 *image;
+ int queue[8], queuesize, queuemax, next_frame;
+ int current_channel, current_tuner;
+ bool use_mmap, use_pwc;
+ P<BitPacking> bit_packing;
+ P<Dim> dim;
+ bool has_frequency, has_tuner, has_norm;
+ int fd;
+ int palettes; /* bitfield */
+
+ \constructor (string mode, string filename) {
+ queuesize=0; queuemax=2; next_frame=0; use_mmap=true; use_pwc=false; bit_packing=0; dim=0;
+ has_frequency=false;
+ has_tuner=false;
+ has_norm=false;
+ image=0;
+ f = fopen(filename.data(),"r+");
+ if (!f) RAISE("can't open device '%s': %s",filename.data(),strerror(errno));
+ fd = fileno(f);
+ initialize2();
+ }
+ void frame_finished (uint8 *buf);
+
+ void alloc_image ();
+ void dealloc_image ();
+ void frame_ask ();
+ void initialize2 ();
+ ~FormatVideoDev () {if (image) dealloc_image();}
+
+ \decl 0 bang ();
+ \grin 0 int
+
+ \attr int channel();
+ \attr int tuner();
+ \attr int norm();
+ \decl 0 size (int sy, int sx);
+ \decl 0 transfer (string sym, int queuemax=2);
+
+ \attr t_symbol *colorspace;
+ \attr long frequency();
+ \attr uint16 brightness();
+ \attr uint16 hue();
+ \attr uint16 colour();
+ \attr uint16 contrast();
+ \attr uint16 whiteness();
+
+ \attr bool pwc(); /* 0..1 */
+ \attr uint16 framerate();
+ \attr uint16 white_mode(); /* 0..1 */
+ \attr uint16 white_red();
+ \attr uint16 white_blue();
+ \attr uint16 white_speed();
+ \attr uint16 white_delay();
+ \attr int auto_gain();
+ \attr int noise_reduction(); /* 0..3 */
+ \attr int compression(); /* 0..3 */
+ \attr t_symbol *name;
+
+ \decl 0 get (t_symbol *s=0);
+};
+
+#define DEBUG(args...) 42
+//#define DEBUG(args...) post(args)
+
+#define IOCTL( F,NAME,ARG) \
+ (DEBUG("fd%d.ioctl(0x%08x,0x%08x)",F,NAME,ARG), ioctl(F,NAME,ARG))
+#define WIOCTL( F,NAME,ARG) \
+ (IOCTL(F,NAME,ARG)<0 && (error("ioctl %s: %s",#NAME,strerror(errno)),1))
+#define WIOCTL2(F,NAME,ARG) \
+ (IOCTL(F,NAME,ARG)<0 && (error("ioctl %s: %s",#NAME,strerror(errno)), RAISE("ioctl error"), 0))
+
+\def 0 get (t_symbol *s=0) {
+ // this is abnormal for a get-function
+ if (s==gensym("frequency") && !has_frequency ) return;
+ if (s==gensym("tuner") && !has_tuner ) return;
+ if (s==gensym("norm") && !has_norm ) return;
+ if (s==gensym("channel") && vcaps.channels<2) return;
+ if (!use_pwc && (s==gensym("white_mode") || s==gensym("white_red") || s==gensym("white_blue") ||
+ s==gensym("white_speed") || s==gensym("white_delay") || s==gensym("auto_gain") ||
+ s==gensym("noise_reduction") || s==gensym("compression") || s==gensym("framerate"))) return;
+ FObject::_0_get(argc,argv,s);
+ if (!s) {
+ t_atom a[2];
+ SETFLOAT(a+0,vcaps.minheight);
+ SETFLOAT(a+1,vcaps.minwidth);
+ outlet_anything(bself->outlets[0],gensym("minsize"),2,a);
+ SETFLOAT(a+0,vcaps.maxheight);
+ SETFLOAT(a+1,vcaps.maxwidth);
+ outlet_anything(bself->outlets[0],gensym("maxsize"),2,a);
+ char *foo = choice_to_s(vp.palette,COUNT(video_palette_choice),video_palette_choice);
+ SETSYMBOL(a,gensym(foo));
+ free(foo);
+ outlet_anything(bself->outlets[0],gensym("palette"),1,a);
+ SETSYMBOL(a,use_mmap ? gensym("mmap") : gensym("read"));
+ outlet_anything(bself->outlets[0],gensym("transfer"),1,a);
+ SETFLOAT(a+0,dim->v[0]);
+ SETFLOAT(a+1,dim->v[1]);
+ outlet_anything(bself->outlets[0],gensym("size"),2,a); // abnormal (does not use nested list)
+ }
+}
+
+\def 0 size (int sy, int sx) {
+ VideoWindow grab_win;
+ // !@#$ bug here: won't flush the frame queue
+ dim = new Dim(sy,sx,3);
+ WIOCTL(fd, VIDIOCGWIN, &grab_win);
+ if (debug) gfpost(&grab_win);
+ grab_win.clipcount = 0;
+ grab_win.flags = 0;
+ if (sy && sx) {
+ grab_win.height = sy;
+ grab_win.width = sx;
+ }
+ if (debug) gfpost(&grab_win);
+ WIOCTL(fd, VIDIOCSWIN, &grab_win);
+ WIOCTL(fd, VIDIOCGWIN, &grab_win);
+ if (debug) gfpost(&grab_win);
+}
+
+void FormatVideoDev::dealloc_image () {
+ if (!image) return;
+ if (use_mmap) {
+ munmap(image, vmbuf.size);
+ image=0;
+ } else {
+ delete[] (uint8 *)image;
+ }
+}
+
+void FormatVideoDev::alloc_image () {
+ if (use_mmap) {
+ WIOCTL2(fd, VIDIOCGMBUF, &vmbuf);
+ //gfpost(&vmbuf);
+ //size_t size = vmbuf.frames > 4 ? vmbuf.offsets[4] : vmbuf.size;
+ image = (uint8 *)mmap(0,vmbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
+ if (((long)image)==-1) {image=0; RAISE("mmap: %s", strerror(errno));}
+ } else {
+ image = new uint8[dim->prod(0,1)*bit_packing->bytes];
+ }
+}
+
+void FormatVideoDev::frame_ask () {
+ if (queuesize>=queuemax) RAISE("queue is full (queuemax=%d)",queuemax);
+ if (queuesize>=vmbuf.frames) RAISE("queue is full (vmbuf.frames=%d)",vmbuf.frames);
+ vmmap.frame = queue[queuesize++] = next_frame;
+ vmmap.format = vp.palette;
+ vmmap.width = dim->get(1);
+ vmmap.height = dim->get(0);
+ WIOCTL2(fd, VIDIOCMCAPTURE, &vmmap);
+ //gfpost(&vmmap);
+ next_frame = (next_frame+1) % vmbuf.frames;
+}
+
+static uint8 clip(int x) {return x<0?0 : x>255?255 : x;}
+
+void FormatVideoDev::frame_finished (uint8 *buf) {
+ string cs = colorspace->s_name;
+ int downscale = cs=="magic";
+ /* picture is converted here. */
+ int sy = dim->get(0)>>downscale;
+ int sx = dim->get(1)>>downscale;
+ int bs = dim->prod(1)>>downscale;
+ uint8 b2[bs];
+ //post("sy=%d sx=%d bs=%d",sy,sx,bs);
+ //post("frame_finished, vp.palette = %d; colorspace = %s",vp.palette,cs.data());
+ if (vp.palette==VIDEO_PALETTE_YUV420P) {
+ GridOutlet out(this,0,cs=="magic"?new Dim(sy,sx,3):(Dim *)dim,cast);
+ if (cs=="y") {
+ out.send(sy*sx,buf);
+ } else if (cs=="rgb") {
+ for(int y=0; y<sy; y++) {
+ uint8 *bufy = buf+sx* y;
+ uint8 *bufu = buf+sx*sy +(sx/2)*(y/2);
+ uint8 *bufv = buf+sx*sy*5/4+(sx/2)*(y/2);
+ int Y1,Y2,U,V;
+ for (int x=0,xx=0; x<sx; x+=2,xx+=6) {
+ Y1=bufy[x] - 16;
+ Y2=bufy[x+1] - 16;
+ U=bufu[x/2] - 128;
+ V=bufv[x/2] - 128;
+ b2[xx+0]=clip((298*Y1 + 409*V)>>8);
+ b2[xx+1]=clip((298*Y1 - 100*U - 208*V)>>8);
+ b2[xx+2]=clip((298*Y1 + 516*U )>>8);
+ b2[xx+3]=clip((298*Y2 + 409*V)>>8);
+ b2[xx+4]=clip((298*Y2 - 100*U - 208*V)>>8);
+ b2[xx+5]=clip((298*Y2 + 516*U )>>8);
+ }
+ out.send(bs,b2);
+ }
+ } else if (cs=="yuv") {
+ for(int y=0; y<sy; y++) {
+ uint8 *bufy = buf+sx* y;
+ uint8 *bufu = buf+sx*sy +(sx/2)*(y/2);
+ uint8 *bufv = buf+sx*sy*5/4+(sx/2)*(y/2);
+ int U,V;
+ for (int x=0,xx=0; x<sx; x+=2,xx+=6) {
+ U=bufu[x/2];
+ V=bufv[x/2];
+ b2[xx+0]=clip(((bufy[x+0]-16)*298)>>8);
+ b2[xx+1]=clip(128+(((U-128)*293)>>8));
+ b2[xx+2]=clip(128+(((V-128)*293)>>8));
+ b2[xx+3]=clip(((bufy[x+1]-16)*298)>>8);
+ b2[xx+4]=clip(128+(((U-128)*293)>>8));
+ b2[xx+5]=clip(128+(((V-128)*293)>>8));
+ }
+ out.send(bs,b2);
+ }
+ } else if (cs=="magic") {
+ for(int y=0; y<sy; y++) {
+ uint8 *bufy = buf +4*sx*y;
+ uint8 *bufu = buf+4*sx*sy+ sx*y;
+ uint8 *bufv = buf+5*sx*sy+ sx*y;
+ for (int x=0,xx=0; x<sx; x++,xx+=3) {
+ b2[xx+0]=bufy[x+x];
+ b2[xx+1]=bufu[x];
+ b2[xx+2]=bufv[x];
+ }
+ out.send(bs,b2);
+ }
+ }
+ } else if (vp.palette==VIDEO_PALETTE_RGB32 || vp.palette==VIDEO_PALETTE_RGB24 || vp.palette==VIDEO_PALETTE_RGB565) {
+ GridOutlet out(this,0,dim,cast);
+ uint8 rgb[sx*3];
+ uint8 b2[sx*3];
+ if (cs=="y") {
+ for(int y=0; y<sy; y++) {
+ bit_packing->unpack(sx,buf+y*sx*bit_packing->bytes,rgb);
+ for (int x=0,xx=0; x<sx; x+=2,xx+=6) {
+ b2[x+0] = (76*rgb[xx+0]+150*rgb[xx+1]+29*rgb[xx+2])>>8;
+ b2[x+1] = (76*rgb[xx+3]+150*rgb[xx+4]+29*rgb[xx+5])>>8;
+ }
+ out.send(bs,b2);
+ }
+ } else if (cs=="rgb") {
+ for(int y=0; y<sy; y++) {
+ bit_packing->unpack(sx,buf+y*sx*bit_packing->bytes,rgb);
+ out.send(bs,rgb);
+ }
+ } else if (cs=="yuv") {
+ for(int y=0; y<sy; y++) {
+ bit_packing->unpack(sx,buf+y*sx*bit_packing->bytes,rgb);
+ for (int x=0,xx=0; x<sx; x+=2,xx+=6) {
+ b2[xx+0] = clip( (( 76*rgb[xx+0] + 150*rgb[xx+1] + 29*rgb[xx+2])>>8));
+ b2[xx+1] = clip(128+((- 44*rgb[xx+0] - 85*rgb[xx+1] + 108*rgb[xx+2])>>8));
+ b2[xx+2] = clip(128+(( 128*rgb[xx+0] - 108*rgb[xx+1] - 21*rgb[xx+2])>>8));
+ b2[xx+3] = clip( (( 76*rgb[xx+3] + 150*rgb[xx+4] + 29*rgb[xx+5])>>8));
+ b2[xx+4] = clip(128+((- 44*rgb[xx+3] - 85*rgb[xx+4] + 108*rgb[xx+5])>>8));
+ b2[xx+5] = clip(128+(( 128*rgb[xx+3] - 108*rgb[xx+4] - 21*rgb[xx+5])>>8));
+ }
+ out.send(bs,b2);
+ }
+ } else if (cs=="magic") {
+ RAISE("magic colorspace not supported with a RGB palette");
+ }
+ } else {
+ RAISE("unsupported palette %d",vp.palette);
+ }
+}
+
+/* these are factors for RGB to analog YUV */
+// Y = 66*R + 129*G + 25*B
+// U = - 38*R - 74*G + 112*B
+// V = 112*R - 94*G - 18*B
+
+// strange that read2 is not used and read3 is used instead
+static int read2(int fd, uint8 *image, int n) {
+ int r=0;
+ while (n>0) {
+ int rr=read(fd,image,n);
+ if (rr<0) return rr; else {r+=rr; image+=rr; n-=rr;}
+ }
+ return r;
+}
+
+static int read3(int fd, uint8 *image, int n) {
+ int r=read(fd,image,n);
+ if (r<0) return r;
+ return n;
+}
+
+\def 0 bang () {
+ if (!image) alloc_image();
+ if (!use_mmap) {
+ /* picture is read at once by frame() to facilitate debugging. */
+ int tot = dim->prod(0,1) * bit_packing->bytes;
+ int n = (int) read3(fd,image,tot);
+ if (n==tot) frame_finished(image);
+ if (0> n) RAISE("error reading: %s", strerror(errno));
+ if (n < tot) RAISE("unexpectedly short picture: %d of %d",n,tot);
+ return;
+ }
+ while(queuesize<queuemax) frame_ask();
+ vmmap.frame = queue[0];
+ //uint64 t0 = gf_timeofday();
+ WIOCTL2(fd, VIDIOCSYNC, &vmmap);
+ //uint64 t1 = gf_timeofday();
+ //if (t1-t0 > 100) gfpost("VIDIOCSYNC delay: %d us",t1-t0);
+ frame_finished(image+vmbuf.offsets[queue[0]]);
+ queuesize--;
+ for (int i=0; i<queuesize; i++) queue[i]=queue[i+1];
+ frame_ask();
+}
+
+GRID_INLET(FormatVideoDev,0) {
+ RAISE("can't write.");
+} GRID_FLOW {
+} GRID_FINISH {
+} GRID_END
+
+\def 0 norm (int value) {
+ VideoTuner vtuner;
+ vtuner.tuner = current_tuner;
+ if (value<0 || value>3) RAISE("norm must be in range 0..3");
+ if (0> IOCTL(fd, VIDIOCGTUNER, &vtuner)) {
+ post("no tuner #%d", value);
+ } else {
+ vtuner.mode = value;
+ gfpost(&vtuner);
+ WIOCTL(fd, VIDIOCSTUNER, &vtuner);
+ }
+}
+
+\def int norm () {
+ VideoTuner vtuner;
+ vtuner.tuner = current_tuner;
+ if (0> IOCTL(fd, VIDIOCGTUNER, &vtuner)) {post("no tuner #%d", current_tuner); return -1;}
+ return vtuner.mode;
+}
+
+\def 0 tuner (int value) {
+ VideoTuner vtuner;
+ vtuner.tuner = current_tuner = value;
+ if (0> IOCTL(fd, VIDIOCGTUNER, &vtuner)) RAISE("no tuner #%d", value);
+ vtuner.mode = VIDEO_MODE_NTSC; //???
+ gfpost(&vtuner);
+ WIOCTL(fd, VIDIOCSTUNER, &vtuner);
+ has_norm = (vtuner.mode<=3);
+ int meuh;
+ has_frequency = (ioctl(fd, VIDIOCGFREQ, &meuh)>=0);
+}
+\def int tuner () {return current_tuner;}
+
+#define warn(fmt,stuff...) post("warning: " fmt,stuff)
+
+\def 0 channel (int value) {
+ VideoChannel vchan;
+ vchan.channel = value;
+ current_channel = value;
+ if (0> IOCTL(fd, VIDIOCGCHAN, &vchan)) warn("no channel #%d", value);
+ //gfpost(&vchan);
+ WIOCTL(fd, VIDIOCSCHAN, &vchan);
+ if (vcaps.type & VID_TYPE_TUNER) _0_tuner(0,0,0);
+ has_tuner = (vcaps.type & VID_TYPE_TUNER && vchan.tuners > 1);
+}
+\def int channel () {return current_channel;}
+
+\def 0 transfer (string sym, int queuemax=2) {
+ if (sym=="read") {
+ dealloc_image();
+ use_mmap = false;
+ post("transfer read");
+ } else if (sym=="mmap") {
+ dealloc_image();
+ use_mmap = true;
+ alloc_image();
+ queuemax=min(queuemax,vmbuf.frames);
+ post("transfer mmap with queuemax=%d (max max is vmbuf.frames=%d)", queuemax,vmbuf.frames);
+ this->queuemax=queuemax;
+ } else RAISE("don't know that transfer mode");
+}
+
+#define PICTURE_ATTR(_name_) {\
+ WIOCTL(fd, VIDIOCGPICT, &vp); \
+ vp._name_ = _name_; \
+ WIOCTL(fd, VIDIOCSPICT, &vp);}
+
+#define PICTURE_ATTRGET(_name_) { \
+ WIOCTL(fd, VIDIOCGPICT, &vp); \
+ /*gfpost("getting %s=%d",#_name_,vp._name_);*/ \
+ return vp._name_;}
+
+\def uint16 brightness () {PICTURE_ATTRGET(brightness)}
+\def 0 brightness (uint16 brightness){PICTURE_ATTR( brightness)}
+\def uint16 hue () {PICTURE_ATTRGET(hue)}
+\def 0 hue (uint16 hue) {PICTURE_ATTR( hue)}
+\def uint16 colour () {PICTURE_ATTRGET(colour)}
+\def 0 colour (uint16 colour) {PICTURE_ATTR( colour)}
+\def uint16 contrast () {PICTURE_ATTRGET(contrast)}
+\def 0 contrast (uint16 contrast) {PICTURE_ATTR( contrast)}
+\def uint16 whiteness () {PICTURE_ATTRGET(whiteness)}
+\def 0 whiteness (uint16 whiteness) {PICTURE_ATTR( whiteness)}
+\def long frequency () {
+ long value;
+ //if (ioctl(fd, VIDIOCGFREQ, &value)<0) {has_frequency=false; return 0;}
+ WIOCTL(fd, VIDIOCGFREQ, &value);
+ return value;
+}
+\def 0 frequency (long frequency) {
+ WIOCTL(fd, VIDIOCSFREQ, &frequency);
+}
+
+\def 0 colorspace (t_symbol *colorspace) { /* y yuv rgb magic */
+ string c = colorspace->s_name;
+ if (c=="y") {}
+ else if (c=="yuv") {}
+ else if (c=="rgb") {}
+ else if (c=="magic") {}
+ else RAISE("got '%s' but supported colorspaces are: y yuv rgb magic",c.data());
+ WIOCTL(fd, VIDIOCGPICT, &vp);
+ int palette = (palettes&(1<<VIDEO_PALETTE_RGB24)) ? VIDEO_PALETTE_RGB24 :
+ (palettes&(1<<VIDEO_PALETTE_RGB32)) ? VIDEO_PALETTE_RGB32 :
+ (palettes&(1<<VIDEO_PALETTE_RGB565)) ? VIDEO_PALETTE_RGB565 :
+ VIDEO_PALETTE_YUV420P;
+ vp.palette = palette;
+ WIOCTL(fd, VIDIOCSPICT, &vp);
+ WIOCTL(fd, VIDIOCGPICT, &vp);
+ if (vp.palette != palette) {
+ post("this driver is unsupported: it wants palette %d instead of %d",vp.palette,palette);
+ return;
+ }
+ if (palette == VIDEO_PALETTE_RGB565) {
+ //uint32 masks[3] = { 0x00fc00,0x003e00,0x00001f };
+ uint32 masks[3] = { 0x00f800,0x007e0,0x00001f };
+ bit_packing = new BitPacking(is_le(),2,3,masks);
+ } else if (palette == VIDEO_PALETTE_RGB32) {
+ uint32 masks[3] = { 0xff0000,0x00ff00,0x0000ff };
+ bit_packing = new BitPacking(is_le(),4,3,masks);
+ } else {
+ uint32 masks[3] = { 0xff0000,0x00ff00,0x0000ff };
+ bit_packing = new BitPacking(is_le(),3,3,masks);
+ }
+ this->colorspace=gensym(c.data());
+ dim = new Dim(dim->v[0],dim->v[1],c=="y"?1:3);
+}
+
+\def bool pwc () {return use_pwc;}
+\def 0 pwc (bool pwc) {use_pwc=pwc;}
+
+void set_pan_and_tilt(int fd, char what, int pan, int tilt) { /*unused*/
+ // if (!use_pwc) return;
+ struct pwc_mpt_angles pma;
+ pma.absolute=1;
+ WIOCTL(fd, VIDIOCPWCMPTGANGLE, &pma);
+ pma.pan = pan;
+ pma.tilt = tilt;
+ WIOCTL(fd, VIDIOCPWCMPTSANGLE, &pma);
+}
+
+\def uint16 framerate() {
+ if (!use_pwc) return 0;
+ struct video_window vwin;
+ WIOCTL(fd, VIDIOCGWIN, &vwin);
+ return (vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT;
+}
+
+\def 0 framerate(uint16 framerate) {
+ if (!use_pwc) return;
+ struct video_window vwin;
+ WIOCTL(fd, VIDIOCGWIN, &vwin);
+ vwin.flags &= ~PWC_FPS_FRMASK;
+ vwin.flags |= (framerate << PWC_FPS_SHIFT) & PWC_FPS_FRMASK;
+ WIOCTL(fd, VIDIOCSWIN, &vwin);
+}
+
+/* those functions are still mostly unused */
+//void set_compression_preference(int fd, int pref) {if (use_pwc) WIOCTL(fd, VIDIOCPWCSCQUAL, &pref);}
+
+\def int auto_gain() {int auto_gain=0; if (use_pwc) WIOCTL(fd, VIDIOCPWCGAGC, &auto_gain); return auto_gain;}
+\def 0 auto_gain (int auto_gain) {if (use_pwc) WIOCTL(fd, VIDIOCPWCSAGC, &auto_gain);}
+
+//void set_shutter_speed(int fd, int pref) {if (use_pwc) WIOCTL(fd, VIDIOCPWCSSHUTTER, &pref);}
+
+\def uint16 white_mode () {
+ if (!use_pwc) return 0;
+ struct pwc_whitebalance pwcwb;
+ WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb);
+ if (pwcwb.mode==PWC_WB_AUTO) return 0;
+ if (pwcwb.mode==PWC_WB_MANUAL) return 1;
+ return 2;
+}
+
+\def 0 white_mode (uint16 white_mode) {
+ if (!use_pwc) return;
+ struct pwc_whitebalance pwcwb;
+ WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb);
+ if (white_mode==0) pwcwb.mode = PWC_WB_AUTO;
+ else if (white_mode==1) pwcwb.mode = PWC_WB_MANUAL;
+ /*else if (strcasecmp(mode, "indoor") == 0) pwcwb.mode = PWC_WB_INDOOR;*/
+ /*else if (strcasecmp(mode, "outdoor") == 0) pwcwb.mode = PWC_WB_OUTDOOR;*/
+ /*else if (strcasecmp(mode, "fl") == 0) pwcwb.mode = PWC_WB_FL;*/
+ else {error("unknown mode number %d", white_mode); return;}
+ WIOCTL(fd, VIDIOCPWCSAWB, &pwcwb);}
+
+\def uint16 white_red() {if (!use_pwc) return 0;
+ struct pwc_whitebalance pwcwb; WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb); return pwcwb.manual_red;}
+\def uint16 white_blue() {if (!use_pwc) return 0;
+ struct pwc_whitebalance pwcwb; WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb); return pwcwb.manual_blue;}
+\def 0 white_red(uint16 white_red) {if (!use_pwc) return;
+ struct pwc_whitebalance pwcwb; WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb);
+ pwcwb.manual_red = white_red; WIOCTL(fd, VIDIOCPWCSAWB, &pwcwb);}
+\def 0 white_blue(uint16 white_blue) {if (!use_pwc) return;
+ struct pwc_whitebalance pwcwb; WIOCTL(fd, VIDIOCPWCGAWB, &pwcwb);
+ pwcwb.manual_blue = white_blue;WIOCTL(fd, VIDIOCPWCSAWB, &pwcwb);}
+
+\def uint16 white_speed() {if (!use_pwc) return 0;
+ struct pwc_wb_speed pwcwbs; WIOCTL(fd, VIDIOCPWCGAWBSPEED, &pwcwbs); return pwcwbs.control_speed;}
+\def uint16 white_delay() {if (!use_pwc) return 0;
+ struct pwc_wb_speed pwcwbs; WIOCTL(fd, VIDIOCPWCGAWBSPEED, &pwcwbs); return pwcwbs.control_delay;}
+\def 0 white_speed(uint16 white_speed) {if (!use_pwc) return;
+ struct pwc_wb_speed pwcwbs; WIOCTL(fd, VIDIOCPWCGAWBSPEED, &pwcwbs);
+ pwcwbs.control_speed = white_speed; WIOCTL(fd, VIDIOCPWCSAWBSPEED, &pwcwbs);}
+\def 0 white_delay(uint16 white_delay) {if (!use_pwc) return;
+ struct pwc_wb_speed pwcwbs; WIOCTL(fd, VIDIOCPWCGAWBSPEED, &pwcwbs);
+ pwcwbs.control_delay = white_delay; WIOCTL(fd, VIDIOCPWCSAWBSPEED, &pwcwbs);}
+
+void set_led_on_time(int fd, int val) {
+ struct pwc_leds pwcl; WIOCTL(fd, VIDIOCPWCGLED, &pwcl);
+ pwcl.led_on = val; WIOCTL(fd, VIDIOCPWCSLED, &pwcl);}
+void set_led_off_time(int fd, int val) {
+ struct pwc_leds pwcl; WIOCTL(fd, VIDIOCPWCGLED, &pwcl);
+ pwcl.led_off = val; WIOCTL(fd, VIDIOCPWCSLED, &pwcl);}
+void set_sharpness(int fd, int val) {WIOCTL(fd, VIDIOCPWCSCONTOUR, &val);}
+void set_backlight_compensation(int fd, int val) {WIOCTL(fd, VIDIOCPWCSBACKLIGHT, &val);}
+void set_antiflicker_mode(int fd, int val) {WIOCTL(fd, VIDIOCPWCSFLICKER, &val);}
+
+\def int noise_reduction() {
+ if (!use_pwc) return 0;
+ int noise_reduction;
+ WIOCTL(fd, VIDIOCPWCGDYNNOISE, &noise_reduction);
+ return noise_reduction;
+}
+\def 0 noise_reduction(int noise_reduction) {
+ if (!use_pwc) return;
+ WIOCTL(fd, VIDIOCPWCSDYNNOISE, &noise_reduction);
+}
+\def int compression() {
+ if (!use_pwc) return 0;
+ int compression;
+ WIOCTL(fd, VIDIOCPWCSCQUAL, &compression);
+ return compression;
+}
+\def 0 compression(int compression) {
+ if (!use_pwc) return;
+ WIOCTL(fd, VIDIOCPWCGCQUAL, &compression);
+}
+
+void FormatVideoDev::initialize2 () {
+ WIOCTL(fd, VIDIOCGCAP, &vcaps);
+ _0_size(0,0,vcaps.maxheight,vcaps.maxwidth);
+ char namebuf[33];
+ memcpy(namebuf,vcaps.name,sizeof(vcaps.name));
+ int i;
+ for (i=32; i>=1; i--) if (!namebuf[i] || !isspace(namebuf[i])) break;
+ namebuf[i]=0;
+ while (--i>=0) if (isspace(namebuf[i])) namebuf[i]='_';
+ name = gensym(namebuf);
+ WIOCTL(fd, VIDIOCGPICT,&vp);
+ palettes=0;
+ int checklist[] = {VIDEO_PALETTE_RGB565,VIDEO_PALETTE_RGB24,VIDEO_PALETTE_RGB32,VIDEO_PALETTE_YUV420P};
+#if 1
+ for (size_t i=0; i<sizeof(checklist)/sizeof(*checklist); i++) {
+ int p = checklist[i];
+#else
+ for (size_t p=0; p<17; p++) {
+#endif
+ vp.palette = p;
+ ioctl(fd, VIDIOCSPICT,&vp);
+ ioctl(fd, VIDIOCGPICT,&vp);
+ if (vp.palette == p) {
+ palettes |= 1<<p;
+ post("palette %d supported",p);
+ }
+ }
+ _0_colorspace(0,0,gensym("rgb"));
+ _0_channel(0,0,0);
+}
+
+\end class FormatVideoDev {install_format("#io.videodev",4,"");}
+void startup_videodev () {
+ \startall
+}
diff --git a/externals/gridflow/format/x11.c b/externals/gridflow/format/x11.c
new file mode 100644
index 00000000..91beb0bc
--- /dev/null
+++ b/externals/gridflow/format/x11.c
@@ -0,0 +1,656 @@
+/*
+ $Id: x11.c 3982 2008-07-04 20:49:12Z matju $
+
+ GridFlow
+ Copyright (c) 2001-2008 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Note: some of the code was adapted from PDP's (the XVideo stuff).
+*/
+#include "../gridflow.h.fcs"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/StringDefs.h>
+#ifdef HAVE_X11_SHARED_MEMORY
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#endif
+#ifdef HAVE_X11_XVIDEO
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+#endif
+
+/* X11 Error Handler type */
+typedef int (*XEH)(Display *, XErrorEvent *);
+
+struct FormatX11;
+void FormatX11_call(FormatX11 *p);
+
+\class FormatX11 : Format {
+/* at the Display/Screen level */
+ Display *display; /* connection to xserver */
+ Visual *visual; /* screen properties */
+ Window root_window;
+ Colormap colormap;/* for 256-color mode */
+ short depth;
+ bool use_stripes; /* use alternate conversion in 256-color mode */
+ bool shared_memory;
+ bool xvideo;
+/* at the Window level */
+ Window window; /* X11 window number */
+ Window parent; /* X11 window number of the parent */
+ GC imagegc; /* X11 graphics context (like java.awt.Graphics) */
+ XImage *ximage; /* X11 image descriptor */
+ uint8 *image; /* the real data (that XImage binds to) */
+ bool is_owner;
+ int32 pos[2];
+ P<BitPacking> bit_packing;
+ P<Dim> dim;
+ bool lock_size;
+ bool override_redirect;
+ t_clock *clock;
+ std::string title;
+#ifdef HAVE_X11_SHARED_MEMORY
+ XShmSegmentInfo *shm_info; /* to share memory with X11/Unix */
+#endif
+#ifdef HAVE_X11_XVIDEO
+ int xv_format;
+ int xv_port;
+ XvImage *xvi; /* ils sont fous ces romains */
+ unsigned char *data;
+ int last_encoding;
+#endif
+ ~FormatX11 () {
+ clock_unset(clock);
+ if (is_owner) XDestroyWindow(display,window);
+ XSync(display,0);
+ dealloc_image();
+ if (imagegc) XFreeGC(display,imagegc);
+ XCloseDisplay(display);
+ }
+ template <class T> void frame_by_type (T bogus);
+ void show_section(int x, int y, int sx, int sy);
+ void set_wm_hints ();
+ void dealloc_image ();
+ bool alloc_image (int sx, int sy);
+ void resize_window (int sx, int sy);
+ void open_display(const char *disp_string);
+ void report_pointer(int y, int x, int state);
+ void prepare_colormap();
+ Window search_window_tree (Window xid, Atom key, const char *value, int level=0);
+ \constructor (...) {
+ shared_memory=false; xvideo=false; use_stripes=false; window=0; ximage=0; image=0; is_owner=true;
+ dim=0; lock_size=false; override_redirect=false; clock=0; imagegc=0;
+#ifdef HAVE_X11_SHARED_MEMORY
+ shm_info=0;
+#endif
+ int sy=240, sx=320; // defaults
+ argv++, argc--;
+ t_symbol *domain = argc<1 ? gensym("here") : argv[0];
+ int i;
+ char host[256];
+ if (domain==gensym("here")) {
+ open_display(0);
+ i=1;
+ } else if (domain==gensym("local")) {
+ if (argc<2) RAISE("open x11 local: not enough args");
+ sprintf(host,":%ld",long(argv[1]));
+ open_display(host);
+ i=2;
+ } else if (domain==gensym("remote")) {
+ if (argc<3) RAISE("open x11 remote: not enough args");
+ sprintf(host,"%s:%ld",string(argv[1]).data(),long(argv[2]));
+ open_display(host);
+ i=3;
+ } else if (domain==gensym("display")) {
+ if (argc<2) RAISE("open x11 display: not enough args");
+ strcpy(host,string(argv[1]).data());
+ for (int k=0; host[k]; k++) if (host[k]=='%') host[k]==':';
+ post("mode `display', DISPLAY=`%s'",host);
+ open_display(host);
+ i=2;
+ } else RAISE("x11 destination syntax error");
+ for(;i<argc;i++) {
+ if (argv[i]==gensym("override_redirect")) override_redirect = true;
+ else if (argv[i]==gensym("use_stripes")) use_stripes = true;
+ else RAISE("argument '%s' not recognized",string(argv[i]).data());
+ }
+ pos[1]=pos[0]=0;
+ parent = root_window;
+ if (i>=argc) {
+ } else {
+ const t_atom2 &winspec = argv[i];
+ if (winspec==gensym("root")) {
+ window = root_window;
+ is_owner = false;
+ } else if (winspec==gensym("embed")) {
+ string title = argv[i+1];
+ sy = sx = pos[0] = pos[1] = 0;
+ parent = search_window_tree(root_window,XInternAtom(display,"WM_NAME",0),title.data());
+ if (parent == 0xDeadBeef) RAISE("Window not found.");
+ } else if (winspec==gensym("embed_by_id")) {
+ const char *winspec2 = string(argv[i+1]).data();
+ if (strncmp(winspec2,"0x",2)==0) {
+ parent = strtol(winspec2+2,0,16);
+ } else {
+ parent = atoi(winspec2);
+ }
+ } else {
+ if (winspec.a_type==A_SYMBOL) {
+ const char *winspec2 = string(winspec).data();
+ if (strncmp(winspec2,"0x",2)==0) {
+ window = strtol(winspec2+2,0,16);
+ } else {
+ window = atoi(winspec2); // huh?
+ }
+ } else {
+ window = INT(winspec);
+ }
+ is_owner = false;
+ sy = sx = pos[0] = pos[1] = 0;
+ }
+ }
+ resize_window(sx,sy); // "resize" also takes care of creation
+ if (is_owner) {
+ Atom wmDeleteAtom = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display,window,&wmDeleteAtom,1);
+ }
+ Visual *v = visual;
+ int disp_is_le = !ImageByteOrder(display);
+ int bpp = ximage->bits_per_pixel;
+ switch(visual->c_class) {
+ case TrueColor: case DirectColor: {
+ uint32 masks[3] = { v->red_mask, v->green_mask, v->blue_mask };
+ bit_packing = new BitPacking(disp_is_le, bpp/8, 3, masks);
+ } break;
+ case PseudoColor: {
+ uint32 masks[3] = { 0x07, 0x38, 0xC0 };
+ bit_packing = new BitPacking(disp_is_le, bpp/8, 3, masks);
+ } break;
+ default: RAISE("huh?");
+ }
+ clock = clock_new(this,(t_method)FormatX11_call);
+ clock_delay(clock,0);
+ show_section(0,0,sx,sy);
+ }
+
+ \decl 0 bang ();
+ void call ();
+ \decl 0 out_size (int sy, int sx);
+ \decl 0 setcursor (int shape);
+ \decl 0 hidecursor ();
+ \decl 0 set_geometry (int y, int x, int sy, int sx);
+ \decl 0 move (int y, int x);
+ \decl 0 shared_memory (bool toggle);
+ \decl 0 xvideo (bool toggle);
+ \decl 0 title (string title="");
+ \decl 0 warp (int y, int x);
+ \grin 0 int
+};
+
+/* ---------------------------------------------------------------- */
+
+void FormatX11::show_section(int x, int y, int sx, int sy) {
+ int zy=dim->get(0), zx=dim->get(1);
+ if (y>zy||x>zx) return;
+ if (y+sy>zy) sy=zy-y;
+ if (x+sx>zx) sx=zx-x;
+#ifndef HAVE_X11_XVIDEO
+ if (xvideo) RAISE("xvideo not available (recompile)");
+#endif
+#ifndef HAVE_X11_SHARED_MEMORY
+ if (shared_memory) RAISE("xshm not available (recompile)");
+#endif
+ if (xvideo) {
+#ifdef HAVE_X11_XVIDEO
+ if (shared_memory) {
+#ifdef HAVE_X11_SHARED_MEMORY
+
+#endif // shm
+ } else {
+ XvPutImage(display,port,window,imagegc,ximage,
+ xvi, 0, 0, image_width, image_height,
+ drwX - (vo_panscan_x >> 1), drwY - (vo_panscan_y >> 1),
+ vo_dwidth + vo_panscan_x,
+ vo_dheight + vo_panscan_y);
+
+ }
+#endif // xvideo
+ } else {
+ if (shared_memory) {
+#ifdef HAVE_X11_SHARED_MEMORY
+ XSync(display,False);
+ XShmPutImage(display,window,imagegc,ximage,x,y,x,y,sx,sy,False);
+ XFlush(display);
+ //XPutImage( display,window,imagegc,ximage,x,y,x,y,sx,sy);
+ // should completion events be waited for? looks like a bug
+#endif // xshm
+ } else {
+ XPutImage(display,window,imagegc,ximage,x,y,x,y,sx,sy);
+ XFlush(display);
+ }
+ }
+}
+
+/* window manager hints, defines the window as non-resizable */
+void FormatX11::set_wm_hints () {
+ if (!is_owner) return;
+ XWMHints wmh;
+ char buf[256],*bufp=buf;
+ if (title=="") {
+ sprintf(buf,"GridFlow (%d,%d,%d)",dim->get(0),dim->get(1),dim->get(2));
+ } else {
+ sprintf(buf,"%.255s",title.data());
+ }
+ XTextProperty wtitle; XStringListToTextProperty((char **)&bufp, 1, &wtitle);
+ XSizeHints sh;
+ sh.flags=PSize|PMaxSize|PMinSize;
+ sh.min_width = sh.max_width = sh.width = dim->get(1);
+ sh.min_height = sh.max_height = sh.height = dim->get(0);
+ wmh.input = True;
+ wmh.flags = InputHint;
+ XSetWMProperties(display,window,&wtitle,&wtitle,0,0,&sh,&wmh,0);
+}
+
+void FormatX11::report_pointer(int y, int x, int state) {
+ t_atom a[3];
+ SETFLOAT(a+0,y);
+ SETFLOAT(a+1,x);
+ SETFLOAT(a+2,state);
+ outlet_anything(bself->outlets[0],gensym("position"),COUNT(a),a);
+}
+
+void FormatX11::call() {
+ XEvent e;
+ for (;;) {
+ int xpending = XEventsQueued(display, QueuedAfterFlush);
+ if (!xpending) break;
+ XNextEvent(display,&e);
+ switch (e.type) {
+ case Expose:{
+ XExposeEvent *ex = (XExposeEvent *)&e;
+ if (mode==2) show_section(ex->x,ex->y,ex->width,ex->height);
+ }break;
+ case ButtonPress:{
+ XButtonEvent *eb = (XButtonEvent *)&e;
+ eb->state |= 128<<eb->button;
+ report_pointer(eb->y,eb->x,eb->state);
+ }break;
+ case ButtonRelease:{
+ XButtonEvent *eb = (XButtonEvent *)&e;
+ eb->state &= ~(128<<eb->button);
+ report_pointer(eb->y,eb->x,eb->state);
+ }break;
+ case KeyPress:
+ case KeyRelease:{
+ XKeyEvent *ek = (XKeyEvent *)&e;
+ //XLookupString(ek, buf, 63, 0, 0);
+ char *kss = XKeysymToString(XLookupKeysym(ek, 0));
+ char buf[64];
+ if (!kss) return; /* unknown keys ignored */
+ if (isdigit(*kss)) sprintf(buf,"D%s",kss); else strcpy(buf,kss);
+ t_atom at[4];
+ t_symbol *sel = gensym(const_cast<char *>(e.type==KeyPress ? "keypress" : "keyrelease"));
+ SETFLOAT(at+0,ek->y);
+ SETFLOAT(at+1,ek->x);
+ SETFLOAT(at+2,ek->state);
+ SETSYMBOL(at+3,gensym(buf));
+ outlet_anything(bself->outlets[0],sel,4,at);
+ //XFree(kss);
+ }break;
+ case MotionNotify:{
+ XMotionEvent *em = (XMotionEvent *)&e;
+ report_pointer(em->y,em->x,em->state);
+ }break;
+ case DestroyNotify:{
+ post("This window is being closed, so this handler will close too!");
+ delete this; /* really! what else could i do here anyway? */
+ return;
+ }break;
+ case ConfigureNotify:break; // as if we cared
+ }
+ }
+ clock_delay(clock,20);
+}
+void FormatX11_call(FormatX11 *p) {p->call();}
+
+\def 0 bang () {
+ XGetSubImage(display, window, 0, 0, dim->get(1), dim->get(0), (unsigned)-1, ZPixmap, ximage, 0, 0);
+ GridOutlet out(this,0,dim,cast);
+ int sy=dim->get(0), sx=dim->get(1), bs=dim->prod(1);
+ uint8 b2[bs];
+ for(int y=0; y<sy; y++) {
+ uint8 *b1 = image + ximage->bytes_per_line * y;
+ bit_packing->unpack(sx,b1,b2);
+ out.send(bs,b2);
+ }
+}
+
+/* loathe Xlib's error handlers */
+static FormatX11 *current_x11;
+static int FormatX11_error_handler (Display *d, XErrorEvent *xee) {
+ post("XErrorEvent: type=0x%08x display=0x%08x xid=0x%08x",
+ xee->type, xee->display, xee->resourceid);
+ post("... serial=0x%08x error=0x%08x request=0x%08lx minor=0x%08x",
+ xee->serial, xee->error_code, xee->request_code, xee->minor_code);
+ if (current_x11->shared_memory==1) {
+ post("(note: turning shm off)");
+ current_x11->shared_memory = 0;
+ }
+ return 42; /* it seems that the return value is ignored. */
+}
+
+bool FormatX11::alloc_image (int sx, int sy) {
+ dim = new Dim(sy,sx,3);
+ dealloc_image();
+ if (sx==0 || sy==0) return false;
+ current_x11 = this;
+ if (!shared_memory) {
+ ximage = XCreateImage(display,visual,depth,ZPixmap,0,0,sx,sy,8,0);
+ int size = ximage->bytes_per_line*ximage->height;
+ if (!ximage) RAISE("can't create image");
+ image = new uint8[size];
+ ximage->data = (int8 *)image;
+ } else {
+#ifdef HAVE_X11_SHARED_MEMORY
+ shm_info = new XShmSegmentInfo;
+ ximage = XShmCreateImage(display,visual,depth,ZPixmap,0,shm_info,sx,sy);
+ if (!ximage) {post("x11: will retry without shared memory"); shared_memory=false;}
+ XSync(display,0);
+ if (!shared_memory) return alloc_image(sx,sy);
+ int size = ximage->bytes_per_line*ximage->height;
+ shm_info->shmid = shmget(IPC_PRIVATE,size,IPC_CREAT|0777);
+ if(shm_info->shmid < 0) RAISE("shmget() failed: %s",strerror(errno));
+ ximage->data = shm_info->shmaddr = (char *)shmat(shm_info->shmid,0,0);
+ if ((long)(shm_info->shmaddr) == -1) RAISE("shmat() failed: %s",strerror(errno));
+ image = (uint8 *)ximage->data;
+ shm_info->readOnly = False;
+ if (!XShmAttach(display, shm_info)) RAISE("ERROR: XShmAttach: big problem");
+ XSync(display,0); // make sure the server picks it up
+ // yes, this can be done now. should cause auto-cleanup.
+ shmctl(shm_info->shmid,IPC_RMID,0);
+ if (!shared_memory) return alloc_image(sx,sy);
+#endif
+ }
+#ifdef HAVE_X11_XVIDEO
+ if (xvideo) {
+ unsigned int ver, rel, req, ev, err, i, j, adaptors, formats;
+ XvAdaptorInfo *ai;
+ if (Success != XvQueryExtension(display,&ver,&rel,&req,&ev,&err)) RAISE("XvQueryExtension problem");
+ /* find + lock port */
+ if (Success != XvQueryAdaptors(display,DefaultRootWindow(display),&adaptors,&ai)) RAISE("XvQueryAdaptors problem");
+ for (i = 0; i < adaptors; i++) {
+ if (ai[i].type&XvInputMask && ai[i].type&XvImageMask) {
+ for (j=0; j<ai[i].num_ports; j++) {
+ if (Success != XvGrabPort(display,ai[i].base_id+j,CurrentTime)) RAISE("XvGrabPort problem");
+ xv_port = ai[i].base_id + j;
+ goto breakout;
+ }
+ }
+ }
+ breakout:
+ XFree(ai);
+ if (!xv_port) RAISE("no xv_port");
+/*
+ unsigned int encn;
+ XvEncodingInfo *enc;
+ XvQueryEncodings(display,xv_port,&encn,&enc);
+ for (i=0; i<encn; i++) post("XvEncodingInfo: name='%s' encoding_id=0x%08x",enc[i].name,enc[i].encoding_id);
+ post("pdp_xvideo: grabbed port %d on adaptor %d",xv_port,i);
+ size_t size = sx*sy*4;
+ data = new uint8[size];
+ for (i=0; i<size; i++) data[i]=0;
+ xvi = XvCreateImage(display,xv_port,0x51525762,(char *)data,sx,sy);
+ last_encoding=-1;
+ if (!xvi) RAISE("XvCreateImage problem");
+*/
+ }
+#endif
+ int status = XInitImage(ximage);
+ if (status!=1) post("XInitImage returned: %d", status);
+ return true;
+retry:
+ post("couldn't allocate image buffer for output... retrying...");
+ return alloc_image(sx,sy);
+}
+
+void FormatX11::dealloc_image () {
+ if (!ximage) return;
+ if (!shared_memory) {
+ XFree(ximage); ximage=0; image=0;
+ } else {
+#ifdef HAVE_X11_SHARED_MEMORY
+ shmdt(ximage->data);
+ XShmDetach(display,shm_info);
+ if (shm_info) {delete shm_info; shm_info=0;}
+ XFree(ximage);
+ ximage = 0;
+ image = 0;
+#endif
+ }
+ if (xvideo) {
+#ifdef HAVE_X11_XVIDEO
+ //if (data) delete[] data;
+ if (xvi) XFree(xvi);
+ xvi=0;
+ //data=0;
+#endif
+ }
+}
+
+void FormatX11::resize_window (int sx, int sy) {
+ if (sy<16) sy=16; if (sy>4096) RAISE("height too big");
+ if (sx<16) sx=16; if (sx>4096) RAISE("width too big");
+ alloc_image(sx,sy);
+ if (window) {
+ if (is_owner && !lock_size) {
+ set_wm_hints();
+ XResizeWindow(display,window,sx,sy);
+ }
+ } else {
+ XSetWindowAttributes xswa;
+ xswa.do_not_propagate_mask = 0; //?
+ xswa.override_redirect = override_redirect; //#!@#$
+ window = XCreateWindow(display,
+ parent, pos[1], pos[0], sx, sy, 0,
+ CopyFromParent, InputOutput, CopyFromParent,
+ CWOverrideRedirect|CWDontPropagate, &xswa);
+ if(!window) RAISE("can't create window");
+ set_wm_hints();
+
+ XSelectInput(display, window,
+ ExposureMask|StructureNotifyMask|PointerMotionMask|
+ ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
+ KeyPressMask|KeyReleaseMask);
+
+ if (is_owner) XMapRaised(display, window);
+ imagegc = XCreateGC(display, window, 0, NULL);
+ if (visual->c_class == PseudoColor) prepare_colormap();
+ }
+ XSync(display,0);
+}
+
+GRID_INLET(FormatX11,0) {
+ if (in->dim->n != 3)
+ RAISE("expecting 3 dimensions: rows,columns,channels");
+ if (in->dim->get(2)!=3 && in->dim->get(2)!=4)
+ RAISE("expecting 3 or 4 channels: red,green,blue,ignored (got %d)",in->dim->get(2));
+ int sx = in->dim->get(1), osx = dim->get(1);
+ int sy = in->dim->get(0), osy = dim->get(0);
+ in->set_chunk(1);
+ if (sx!=osx || sy!=osy) resize_window(sx,sy);
+ if (in->dim->get(2)!=bit_packing->size) {
+ bit_packing->mask[3]=0;
+ bit_packing = new BitPacking(bit_packing->endian,
+ bit_packing->bytes, in->dim->get(2), bit_packing->mask);
+ }
+} GRID_FLOW {
+ int bypl = ximage->bytes_per_line;
+ int sxc = in->dim->prod(1);
+ int sx = in->dim->get(1);
+ int y = in->dex/sxc;
+ for (; n>0; y++, data+=sxc, n-=sxc) {
+ // convert line
+ if (use_stripes) {
+ int o=y*bypl;
+ for (int x=0, i=0, k=y%3; x<sx; x++, i+=3, k=(k+1)%3) {
+ image[o+x] = (k<<6) | data[i+k]>>2;
+ }
+ } else {
+ bit_packing->pack(sx, data, image+y*bypl);
+ }
+ }
+} GRID_FINISH {
+ show_section(0,0,in->dim->get(1),in->dim->get(0));
+} GRID_END
+
+\def 0 out_size (int sy, int sx) { resize_window(sx,sy); }
+
+\def 0 setcursor (int shape) {
+ shape = 2*(shape&63);
+ Cursor c = XCreateFontCursor(display,shape);
+ XDefineCursor(display,window,c);
+ XFlush(display);
+}
+
+\def 0 hidecursor () {
+ Font font = XLoadFont(display,"fixed");
+ XColor color; /* bogus */
+ Cursor c = XCreateGlyphCursor(display,font,font,' ',' ',&color,&color);
+ XDefineCursor(display,window,c);
+ XFlush(display);
+}
+
+void FormatX11::prepare_colormap() {
+ Colormap colormap = XCreateColormap(display,window,visual,AllocAll);
+ XColor colors[256];
+ if (use_stripes) {
+ for (int i=0; i<192; i++) {
+ int k=(i&63)*0xffff/63;
+ colors[i].pixel = i;
+ colors[i].red = (i>>6)==0 ? k : 0;
+ colors[i].green = (i>>6)==1 ? k : 0;
+ colors[i].blue = (i>>6)==2 ? k : 0;
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+ XStoreColors(display,colormap,colors,192);
+ } else {
+ for (int i=0; i<256; i++) {
+ colors[i].pixel = i;
+ colors[i].red = ((i>>0)&7)*0xffff/7;
+ colors[i].green = ((i>>3)&7)*0xffff/7;
+ colors[i].blue = ((i>>6)&3)*0xffff/3;
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+ XStoreColors(display,colormap,colors,256);
+ }
+ XSetWindowColormap(display,window,colormap);
+}
+
+void FormatX11::open_display(const char *disp_string) {
+ display = XOpenDisplay(disp_string);
+ if(!display) RAISE("ERROR: opening X11 display: %s",strerror(errno));
+ // btw don't expect too much from Xlib error handling.
+ // Xlib, you are so free of the ravages of intelligence...
+ XSetErrorHandler(FormatX11_error_handler);
+ Screen *screen = DefaultScreenOfDisplay(display);
+ int screen_num = DefaultScreen(display);
+ visual = DefaultVisual(display, screen_num);
+ root_window = DefaultRootWindow(display);
+ depth = DefaultDepthOfScreen(screen);
+ colormap = 0;
+
+ switch(visual->c_class) {
+ // without colormap
+ case TrueColor: case DirectColor: break;
+ // with colormap
+ case PseudoColor: if (depth!=8) RAISE("ERROR: with colormap, only supported depth is 8 (got %d)", depth); break;
+ default: RAISE("ERROR: visual type not supported (got %d)", visual->c_class);
+ }
+
+#if defined(HAVE_X11_XVIDEO)
+ xvideo = true;
+#elif defined(HAVE_X11_SHARED_MEMORY)
+ shared_memory = !! XShmQueryExtension(display);
+#else
+ shared_memory = false;
+#endif
+}
+
+Window FormatX11::search_window_tree (Window xid, Atom key, const char *value, int level) {
+ if (level>2) return 0xDeadBeef;
+ Window root_r, parent_r;
+ Window *children_r;
+ unsigned int nchildren_r;
+ XQueryTree(display,xid,&root_r,&parent_r,&children_r,&nchildren_r);
+ Window target = 0xDeadBeef;
+ for (int i=0; i<(int)nchildren_r; i++) {
+ Atom actual_type_r;
+ int actual_format_r;
+ unsigned long nitems_r, bytes_after_r;
+ unsigned char *prop_r;
+ XGetWindowProperty(display,children_r[i],key,0,666,0,AnyPropertyType,
+ &actual_type_r,&actual_format_r,&nitems_r,&bytes_after_r,&prop_r);
+ uint32 value_l = strlen(value);
+ bool match = prop_r && nitems_r>=value_l &&
+ strncmp((char *)prop_r+nitems_r-value_l,value,value_l)==0;
+ XFree(prop_r);
+ if (match) {target=children_r[i]; break;}
+ target = search_window_tree(children_r[i],key,value,level+1);
+ if (target != 0xDeadBeef) break;
+ }
+ if (children_r) XFree(children_r);
+ return target;
+}
+
+\def 0 move (int y, int x) {
+ pos[0]=y; pos[1]=x;
+ XMoveWindow(display,window,x,y);
+ XFlush(display);
+}
+
+\def 0 set_geometry (int y, int x, int sy, int sx) {
+ pos[0]=y; pos[1]=x;
+ XMoveWindow(display,window,x,y);
+ resize_window(sx,sy);
+ XFlush(display);
+}
+
+\def 0 shared_memory (bool toggle) {shared_memory = toggle;}
+\def 0 xvideo (bool toggle) {xvideo = toggle;}
+
+\def 0 warp (int y, int x) {
+ XWarpPointer(display,None,None,0,0,0,0,x,y);
+ XFlush(display);
+}
+
+\def 0 title (string title="") {this->title = title; set_wm_hints();}
+
+\end class FormatX11 {install_format("#io.x11",6,"");}
+void startup_x11 () {
+ \startall
+}
+