From 089475041fe26964d72cb2ebc3559a36ba89a2f2 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 8 Jul 2008 05:56:10 +0000 Subject: trying to import gridflow 0.9.4 svn path=/trunk/; revision=10148 --- externals/gridflow/format/videodev.c | 792 +++++++++++++++++++++++++++++++++++ 1 file changed, 792 insertions(+) create mode 100644 externals/gridflow/format/videodev.c (limited to 'externals/gridflow/format/videodev.c') 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 +#include +#include +#include +#include +#include +#include +#include +#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) { + 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; iframes; 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 bit_packing; + P 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>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>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; yunpack(sx,buf+y*sx*bit_packing->bytes,rgb); + for (int x=0,xx=0; x>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; yunpack(sx,buf+y*sx*bit_packing->bytes,rgb); + out.send(bs,rgb); + } + } else if (cs=="yuv") { + for(int y=0; yunpack(sx,buf+y*sx*bit_packing->bytes,rgb); + for (int x=0,xx=0; x>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 100) gfpost("VIDIOCSYNC delay: %d us",t1-t0); + frame_finished(image+vmbuf.offsets[queue[0]]); + queuesize--; + for (int i=0; i3) 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<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