diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-04-01 11:24:40 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-04-01 11:24:40 +0200 |
commit | 82fbaff22e3e4b1bbdd1e2192cfeff061ce7285c (patch) | |
tree | 308704093028c293b650fcefab4a14ef6f6ca42b | |
parent | e99e58b6d385a8ae806a97b88ec4dbb26c898619 (diff) |
v3.83
45 files changed, 2637 insertions, 378 deletions
@@ -1,4 +1,22 @@ +3.82 => 3.83 +============ + + * compile fixes. + * propwatch updates. + * added config option to disable _NET_WM_STATE_FULLSCREEN support. + * added config option to move the OSD (Alex Ibrado <alex@ibrado.com>). + * minor radio tweaks (DAVID BALAZIC <david.balazic@uni-mb.si>). + + +3.81 => 3.82 +============ + + * compile fixes again ... + * v4l-conf fix (Kyosti Malkki <kmalkki@cc.hut.fi>). + * wmhook fix (Marcin Krzyzanowski <krzak@hakore.com>). + + 3.81 => 3.82 ============ diff --git a/Makefile.in b/Makefile.in index e34fcf3..e487b6b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ OSS_LIBS := @LIBOSS@ ALSA_LIBS := @LIBALSA@ AA_LIBS := @AALIBS@ QT_LIBS := @QTLIBS@ -VBI_LIBS := @LIBZVBI@ -lm -lpng +VBI_LIBS := @LIBZVBI@ GL_LIBS := @LIBGL@ DV_LIBS := @LIBDV@ FS_LIBS := -L@x_libraries@ @FSLIB@ @@ -65,19 +65,23 @@ FOUND_ZVBI := @FOUND_ZVBI@ USE_MMX := @USE_MMX@ # build final cflags -CFLAGS := @CFLAGS@ -CFLAGS += $(WARN_FLAGS) -CFLAGS += $(LFS_FLAGS) -CFLAGS += $(X11_FLAGS) -CFLAGS += $(LIB_FLAGS) -CFLAGS += -DCONFIGFILE='"$(config)"' -CFLAGS += -DLIBDIR='"$(libdir)"' -CFLAGS += -DDATADIR='"$(datadir)"' -CFLAGS += -DVERSION='"$(VERSION)"' -CXXFLAGS = $(CFLAGS) +CFLAGS := @CFLAGS@ +CFLAGS += $(WARN_FLAGS) +CFLAGS += $(LFS_FLAGS) +CFLAGS += $(X11_FLAGS) +CFLAGS += $(LIB_FLAGS) +CFLAGS += -DCONFIGFILE='"$(config)"' +CFLAGS += -DLIBDIR='"$(libdir)"' +CFLAGS += -DDATADIR='"$(datadir)"' +CFLAGS += -DVERSION='"$(VERSION)"' +CXXFLAGS := $(CFLAGS) + +# for gcc3 +#CFLAGS += -std-gnu99 # shared objects need -fPIC -%.so : CFLAGS += -fPIC +%.so : CFLAGS += -fPIC +%.so : CXXFLAGS += -fPIC # libraries LDLIBS := @LDLIBS@ @@ -119,7 +123,7 @@ realclean:: distclean ######################################################### # some rules ... -include $(srcdir)/mk/compile.mk +include $(srcdir)/mk/Compile.mk %.h: %.in perl $(srcdir)/scripts/html.pl < $< > $@ diff --git a/common/Subdir.mk b/common/Subdir.mk index 0b8b5ec..1bb72d2 100644 --- a/common/Subdir.mk +++ b/common/Subdir.mk @@ -16,10 +16,10 @@ OBJS-common-input := \ common/midictrl.o # RegEdit.c is good old K&R ... -common/RegEdit.o : CFLAGS += -Wno-missing-prototypes -Wno-strict-prototypes +common/RegEdit.o: CFLAGS += -Wno-missing-prototypes -Wno-strict-prototypes common/channel-no-x11.o: CFLAGS += -DNO_X11=1 -common/channel-no-x11.o:: common/channel.c +common/channel-no-x11.o: common/channel.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) diff --git a/common/channel.c b/common/channel.c index 0c79355..567f6ae 100644 --- a/common/channel.c +++ b/common/channel.c @@ -75,7 +75,10 @@ int cur_capture = CAPTURE_OFF; int have_config; int keypad_ntsc = 0; int keypad_partial = 1; +int use_wm_fullscreen = 1; int use_osd = 1; +int osd_x = 30; +int osd_y = 20; int fs_width,fs_height,fs_xoff,fs_yoff; int pix_width=128, pix_height=96, pix_cols=1; @@ -468,6 +471,12 @@ read_config(char *conffile, int *argc, char **argv) if (NULL != (val = cfg_get_str("global","osd"))) if (-1 != (i = str_to_int(val,booltab))) use_osd = i; + if (NULL != (val = cfg_get_str("global","osd-position"))) + if (2 != sscanf(val,"%d , %d",&osd_x,&osd_y)) + fprintf(stderr,"invalid values for osd-position: %s\n",val); + if (NULL != (val = cfg_get_str("global","use-wm-fullscreen"))) + if (-1 != (i = str_to_int(val,booltab))) + use_wm_fullscreen = i; if (NULL != (val = cfg_get_str("global","mov-driver"))) mov_driver = val; @@ -580,6 +589,9 @@ save_config() fprintf(fp,"keypad-ntsc = %s\n",int_to_str(keypad_ntsc,booltab)); fprintf(fp,"keypad-partial = %s\n",int_to_str(keypad_partial,booltab)); fprintf(fp,"osd = %s\n",int_to_str(use_osd,booltab)); + fprintf(fp,"osd-position = %d , %d\n",osd_x,osd_y); + fprintf(fp,"use-wm-fullscreen = %s\n", + int_to_str(use_wm_fullscreen,booltab)); if (mixer) fprintf(fp,"mixer = %s\n",mixer); if (midi) diff --git a/common/channel.h b/common/channel.h index 4d92893..fbc44f1 100644 --- a/common/channel.h +++ b/common/channel.h @@ -45,6 +45,8 @@ extern int jpeg_quality; extern int keypad_ntsc; extern int keypad_partial; extern int use_osd; +extern int osd_x, osd_y; +extern int use_wm_fullscreen; extern int fs_width,fs_height,fs_xoff,fs_yoff; extern int pix_width,pix_height,pix_cols; extern int last_sender, cur_sender; @@ -5001,7 +5001,7 @@ if test $ac_cv_lib_zvbi_vbi_capture_fd = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_ZVBI 1 _ACEOF - FOUND_ZVBI="yes"; LIBZVBI="-lzvbi -lpthread" + FOUND_ZVBI="yes"; LIBZVBI="-lzvbi -lpthread -lm -lpng -lz" fi else diff --git a/configure.ac b/configure.ac index e987ce0..eedbb60 100644 --- a/configure.ac +++ b/configure.ac @@ -177,7 +177,7 @@ AC_SUBST(LIBZVBI) LIBZVBI="" if test "$enable_zvbi" != "no"; then AC_CHECK_LIB(zvbi, vbi_capture_fd, - AC_DEFINE(HAVE_ZVBI,1,"have zvbi") FOUND_ZVBI="yes"; LIBZVBI="-lzvbi -lpthread",,) + AC_DEFINE(HAVE_ZVBI,1,"have zvbi") FOUND_ZVBI="yes"; LIBZVBI="-lzvbi -lpthread -lm -lpng -lz",,) else echo "*** zvbi disabled" fi diff --git a/console/fbtools.c b/console/fbtools.c index b7473f0..228589f 100644 --- a/console/fbtools.c +++ b/console/fbtools.c @@ -262,7 +262,7 @@ fb_setvt(int vtno) vtno &= 0xff; sprintf(vtname, devices->ttynr, vtno); chown(vtname, getuid(), getgid()); - if (-1 == access(vtname,R_OK | W_OK)) { + if (-1 == access(vtname, R_OK | W_OK)) { fprintf(stderr,"access %s: %s\n",vtname,strerror(errno)); exit(1); } @@ -349,12 +349,12 @@ fb_init(char *device, char *mode, int vt) struct stat st; char fbdev[16]; + dev_init(); tty = 0; if (vt != 0) fb_setvt(vt); /* FIXME: where are MAJOR() / MINOR() ??? */ - dev_init(); fstat(tty,&st); if (((st.st_rdev >> 8) & 0xff) != TTY_MAJOR) { /* catch that here, give a more user friendly error message that just diff --git a/console/radio.c b/console/radio.c index 010b4a4..fb0e5a6 100644 --- a/console/radio.c +++ b/console/radio.c @@ -56,6 +56,17 @@ radio_setfreq(int fd, float freq) return ioctl(fd, VIDIOCSFREQ, &ifreq); } +static int radio_getfreq(int fd, float *freq) +{ + int ioctl_status; + int ifreq; + ioctl_status = ioctl(fd,VIDIOCGFREQ, &ifreq); + if (ioctl_status == -1) + return ioctl_status; + *freq = (float) ifreq / get_freq_fact(fd); + return 0; +} + static void radio_unmute(int fd) { @@ -521,6 +532,12 @@ main(int argc, char *argv[]) if (!stset) mvwprintw(wstations,1,1,"[none]"); wrefresh(wstations); + + if (ifreq == 0) { + float ffreq; + radio_getfreq(fd,&ffreq); + ifreq = ffreq * 1000000; + } radio_unmute(fd); for (done = 0; done == 0;) { @@ -569,7 +586,11 @@ main(int argc, char *argv[]) noecho(); curs_set(0); wrefresh(wcommand); - ifreq = newfreq * 1000000; + if ( (newfreq >= 87.5) && (newfreq <= 108) ) + ifreq = newfreq * 1000000; + else + mvwprintw(wcommand, 1, 2, + "Frequency out of range (87.5-108 MHz)"); break; case KEY_UP: ifreq += 50000; diff --git a/console/record.c b/console/record.c index 5638fc6..b334a1e 100644 --- a/console/record.c +++ b/console/record.c @@ -535,6 +535,8 @@ usage(FILE *fp) " until stopped by a signal (^C)\n" " -s size set max file size [%s]. You have to give number\n" " and unit without space inbetween, i.e. \"100mb\".\n" + " -n num limit amount of files recorded, quits when\n" + " reached.\n" " -l signal level triggered recording.\n" " -L level same as above + specify trigger level [%d]\n" "\n", @@ -552,6 +554,7 @@ main(int argc, char *argv[]) char *outfile; fd_set s; int sec,maxhour,maxmin,maxsec; + int maxfiles = 0; off_t maxsize; /* init some vars */ @@ -565,7 +568,7 @@ main(int argc, char *argv[]) /* parse options */ for (;;) { - if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:"))) + if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:n:"))) break; switch (c) { case 'v': @@ -612,6 +615,9 @@ main(int argc, char *argv[]) case 's': str_maxsize = optarg; break; + case 'n': + maxfiles = atoi(optarg); + break; case 'h': usage(stdout); exit(0); @@ -649,7 +655,7 @@ main(int argc, char *argv[]) mvprintw(11,0,"'N' next file (same as space twice, but without break)"); mvprintw(12,0,"'Q' quit"); mvprintw(LINES-3,0,"--"); - mvprintw(LINES-2,0,"(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>"); + mvprintw(LINES-2,0,"(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>"); for (;!stop;) { refresh(); @@ -766,6 +772,8 @@ main(int argc, char *argv[]) secr < level_trigger) { record_stop(wav); record=0; + if (maxfiles && nr == maxfiles) + break; } } if (!record) { diff --git a/console/streamer.c b/console/streamer.c index a4e9399..50fd7c8 100644 --- a/console/streamer.c +++ b/console/streamer.c @@ -107,6 +107,7 @@ usage(FILE *out) "general options:\n" " -h print this help text\n" " -q quiet operation\n" + " -d enable debug output\n" " -p n use n compression threads [%d]\n" " -w seconds wait before grabbing [%d]\n" "\n" @@ -203,71 +204,83 @@ find_formats(void) for (w = 0; NULL != ng_writers[w]; w++) { wr = ng_writers[w]; if (debug) - fprintf(stderr,"checking writer %s... ",wr->name); + fprintf(stderr,"checking writer %s [%s] ...\n",wr->name,wr->desc); if ((/*!wr->combined && */mext) || NULL != vfmt_name) { if (NULL == wr->video) { if (debug) - fprintf(stderr,"no video\n"); + fprintf(stderr," no video, skipping\n"); continue; } for (v = 0; NULL != wr->video[v].name; v++) { - if (mext && 0 != strcasecmp(wr->video[v].ext,mext)) + if (debug) + fprintf(stderr," video name=%s ext=%s: ", + wr->video[v].name,wr->video[v].ext); + if (mext && 0 != strcasecmp(wr->video[v].ext,mext)) { + if (debug) + fprintf(stderr,"ext mismatch [need %s]\n",mext); continue; - if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name)) + } + if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name)) { + if (debug) + fprintf(stderr,"name mismatch [need %s]\n",vfmt_name); continue; + } + if (debug) + fprintf(stderr,"OK\n"); break; } - if (NULL == wr->video[v].name) { - if (debug) - fprintf(stderr,"video fmt not found [ext=%s,name=%s]\n", - mext,vfmt_name); + if (NULL == wr->video[v].name) continue; - } } if ((!wr->combined && aext) || NULL != afmt_name) { if (NULL == wr->audio) { if (debug) - fprintf(stderr,"no audio\n"); + fprintf(stderr," no audio, skipping\n"); continue; } for (a = 0; NULL != wr->audio[a].name; a++) { + if (debug) + fprintf(stderr," audio name=%s ext=%s: ", + wr->audio[a].name,wr->audio[a].ext); if (!wr->combined && - aext && 0 != strcasecmp(wr->audio[a].ext,aext)) + aext && 0 != strcasecmp(wr->audio[a].ext,aext)) { + if (debug) + fprintf(stderr,"ext mismatch [need %s]\n",aext); continue; + } if (wr->combined && - mext && 0 != strcasecmp(wr->audio[a].ext,mext)) + mext && 0 != strcasecmp(wr->audio[a].ext,mext)) { + if (debug) + fprintf(stderr,"ext mismatch [need %s]\n",mext); continue; - if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name)) + } + if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name)) { + if (debug) + fprintf(stderr,"name mismatch [need %s]\n",afmt_name); continue; + } + if (debug) + fprintf(stderr,"OK\n"); break; } - if (NULL == wr->audio[a].name) { - if (debug) - fprintf(stderr,"audio fmt not found [ext=%s,name=%s]\n", - wr->combined ? mext : aext, afmt_name); + if (NULL == wr->audio[a].name) continue; - } } - if (debug) - fprintf(stderr,"ok:"); break; } if (NULL != ng_writers[w]) { writer = wr; if (-1 != v) { - if (debug) - fprintf(stderr," video=%s",wr->video[v].name); video.fmtid = wr->video[v].fmtid; video_priv = wr->video[v].priv; } if (-1 != a) { - if (debug) - fprintf(stderr," audio=%s",wr->audio[a].name); audio.fmtid = wr->audio[a].fmtid; audio_priv = wr->audio[a].priv; } + } else { if (debug) - fprintf(stderr,"\n"); + fprintf(stderr,"no match found\n"); } } diff --git a/console/v4l-conf.c b/console/v4l-conf.c index 9d0139f..a17e416 100644 --- a/console/v4l-conf.c +++ b/console/v4l-conf.c @@ -339,7 +339,7 @@ displayinfo_v4l2(int fd, struct DISPLAYINFO *d) /* set values */ fb.fmt.width = d->width; fb.fmt.height = d->height; - switch (d->depth) { + switch (d->bpp) { case 8: fb.fmt.pixelformat = V4L2_PIX_FMT_HI240; break; #if BYTE_ORDER == BIG_ENDIAN case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555X; break; diff --git a/console/webcam.c b/console/webcam.c index a4421a1..4baf12a 100644 --- a/console/webcam.c +++ b/console/webcam.c @@ -686,7 +686,8 @@ main(int argc, char *argv[]) if (-1 != (i = cfg_get_int("grab","trigger"))) grab_trigger = i; if (-1 != (i = cfg_get_int("grab","once"))) - grab_times = 1; + if (i > 0) + grab_times = 1; if (-1 != (i = cfg_get_int("grab","times"))) grab_times = i; if (NULL != (val = cfg_get_str("grab","archive"))) diff --git a/contrib/vdr.config b/contrib/vdr.config new file mode 100644 index 0000000..8d13ec1 --- /dev/null +++ b/contrib/vdr.config @@ -0,0 +1,45 @@ +# eventmap config for using xawtv with vdr +# contributed by Gregoire Favre <greg@ulima.unil.ch> + +[eventmap] +kbd-key-Return = vdr "HITK" "Ok" +kbd-key-Up = vdr "HITK" "Up" +kbd-key-Down = vdr "HITK" "Down" +kbd-key-M = vdr "HITK" "Menu" +kbd-key-Return = vdr "HITK" "Ok" +kbd-key-BackSpace = vdr "HITK" "Back" +kbd-key-Left = vdr "HITK" "Left" +kbd-key-Right = vdr "HITK" "Right" +kbd-key-F1 = vdr "HITK" "Red" +kbd-key-F2 = vdr "HITK" "Green" +kbd-key-F3 = vdr "HITK" "Yellow" +kbd-key-F4 = vdr "HITK" "Blue" +kbd-key-KP_0 = vdr "HITK" "0" +kbd-key-KP_1 = vdr "HITK" "1" +kbd-key-KP_2 = vdr "HITK" "2" +kbd-key-KP_3 = vdr "HITK" "3" +kbd-key-KP_4 = vdr "HITK" "4" +kbd-key-KP_5 = vdr "HITK" "5" +kbd-key-KP_6 = vdr "HITK" "6" +kbd-key-KP_7 = vdr "HITK" "7" +kbd-key-KP_8 = vdr "HITK" "8" +kbd-key-KP_9 = vdr "HITK" "9" +kbd-key-F5 = vdr "HITK" "Play" +kbd-key-F6 = vdr "HITK" "Pause" +kbd-key-F7 = vdr "HITK" "Stop" +kbd-key-R = vdr "HITK" "Record" +kbd-key-F12 = vdr "HITK" "FastFwd" +kbd-key-F11 = vdr "HITK" "FastRew" +kbd-key-P = vdr "HITK" "Power" +kbd-key-F9 = vdr "HITK" "Channel+" +kbd-key-F10 = vdr "HITK" "Channel-" +kbd-key-KP_Add = vdr "HITK" "Volume+" +kbd-key-KP_Subtract = vdr "HITK" "Volume-" +kbd-key-$ = vdr "HITK" "Mute" +kbd-key-S = vdr "HITK" "Schedule" +kbd-key-C = vdr "HITK" "Channels" +kbd-key-T = vdr "HITK" "Timers" +kbd-key-G = vdr "HITK" "Recordings" +kbd-key-X = vdr "HITK" "Setup" +kbd-key-V = vdr "HITK" "Commands" +kbd-key-N = vdr "HITK" "None" diff --git a/debian/changelog b/debian/changelog index 8985ef8..74ecd47 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +xawtv (3.83) unstable; urgency=low + + * new release (closes: #175886, #171884). + * added danish template (closes: #175424). + * fixed radio description text (closes: #175115). + * splitted alsa and quicktime plugins into separate sub-packages. + + -- Gerd Knorr <kraxel@debian.org> Fri, 17 Jan 2003 18:51:34 +0100 + xawtv (3.82) unstable; urgency=low * new release (closes: #173791). diff --git a/debian/control b/debian/control index 6cea323..f704386 100644 --- a/debian/control +++ b/debian/control @@ -9,6 +9,7 @@ Package: xawtv Section: x11 Architecture: any Depends: ${shlibs:Depends}, v4l-conf, xutils, debconf, scantv, xawtv-plugins (=${Source-Version}), tv-fonts, pia +Suggests: xawtv-plugin-qt (=${Source-Version}), xawtv-plugin-alsa (=${Source-Version}) Description: X11 TV application TV application for X11. Supports video4linux devices and the Xvideo extension. @@ -60,7 +61,7 @@ Package: radio Section: sound Architecture: any Depends: ${shlibs:Depends} -Description: ncurses-bases radio application +Description: ncurses-based radio application This is a ncurses-based radio application. It supports the video4linux API. @@ -89,6 +90,19 @@ Description: Miscellaneous tools distributed with xawtv shoot sound problems. * showriff - display the structure of RIFF files (avi, wav). +Package: xawtv-plugin-qt +Architecture: any +Depends: ${shlibs:Depends} +Description: quicktime plugin for xawtv and motv + this plugin is needed to record quicktime movies with + xawtv and motv. + +Package: xawtv-plugin-alsa +Architecture: any +Depends: ${shlibs:Depends} +Description: alsa plugin for xawtv and motv + this plugin adds alsa mixer support to xawtv and motv. + Package: xawtv-plugins Architecture: any Depends: ${shlibs:Depends} diff --git a/debian/xawtv-plugin-alsa.files b/debian/xawtv-plugin-alsa.files new file mode 100644 index 0000000..d70dde6 --- /dev/null +++ b/debian/xawtv-plugin-alsa.files @@ -0,0 +1 @@ +/usr/lib/xawtv/snd-alsa.so diff --git a/debian/xawtv-plugin-qt.files b/debian/xawtv-plugin-qt.files new file mode 100644 index 0000000..1bf958d --- /dev/null +++ b/debian/xawtv-plugin-qt.files @@ -0,0 +1 @@ +/usr/lib/xawtv/*qt.so diff --git a/debian/xawtv.template.da b/debian/xawtv.template.da new file mode 100644 index 0000000..577ad2c --- /dev/null +++ b/debian/xawtv.template.da @@ -0,0 +1,67 @@ +Template: xawtv/channel-scan +Type: boolean +Default: yes +Description: scan for TV stations? + I can do a scan of all channels and put a list of the TV stations I've + found into the config file. + . + This requires a working bttv driver. If bttv isn't configured correctly I + might not find the TV stations. + . + I'll try to pick up the channel names from videotext. This will work with + PAL only. +Description-da: Skan efter TV stationer? + Jeg kan lave en skanning efter alle kanaler og putte dem i en liste af de + TV stationer jeg har fundet, ind i en konfigurations fil. + . + Dette kræver en virkende bttv driver. Hvis bttv ikke er korrekt + konfigureret, vil du måske ikke finde TV stationerne. + . + Jeg vil prøve at finde kanal navne fra videotext. Dette vil kun virke med + PAL. + +Template: xawtv/makedev +Type: boolean +Default: true +Description: Create video4linux (/dev/video*) special files? +Description-da: Opret video4linux (/dev/video*) specielle filer? + +Template: xawtv/tvnorm +Type: select +Choices: PAL, SECAM, NTSC +Choices-da: PAL, SECAM, NTSC +Description: Which TV norm is used in your country? +Description-da: Hvilken TV norm er brugt i dit land? + +Template: xawtv/freqtab +Type: select +Choices: us-bcast, us-cable, us-cable-hrc, japan-bcast, japan-cable, europe-west, europe-east, italy, newzealand, australia, ireland, france, china-bcast +Choices-da: us-bcast, us-cable, us-cable-hrc, japan-bcast, japan-cable, europe-west, europe-east, italy, newzealand, australia, ireland, france, china-bcast +Description: Which frequency table should be used? + A frequency table is just a list of TV channel names/numbers and the + corresponding broadcast frequencies for these channels. Different regions + use different standards here... +Description-da: Hvilken frekvens tabel skal bruges? + En frekvens tabel er bare en liste af kanal navne/tal og de tilsvarende + frekvenser for disse kanaler. Forskellige regioner bruger forskellige + standarder her... + +Template: xawtv/build-config +Type: boolean +Default: false +Description: Create a default configuration for xawtv? + You can create a system-wide configuration file for xawtv with reasonable + default values for the country you live in (which TV norm is used for + example). + . + It is not required to have a global configuration file, but it will be + more comfortable for your users if they find a working default + configuration. +Description-da: Opret en standard konfigurations fil til xawtv? + Du kan oprette en system-bred konfigurations fil til xawtv med fornuftige + standard værdier for landet du lever i (f.eks. hvilken TV norm der bliver + brugt i dit land). + . + Det er ikke krævet at have en global konfigurations fil, men det vil gøre + det mere behageligt for dine brugere, hvis de finder en standard virkende + konfiguration. diff --git a/debian/xawtv.templates b/debian/xawtv.templates index e6d0e80..df24fd0 100644 --- a/debian/xawtv.templates +++ b/debian/xawtv.templates @@ -1,3 +1,11 @@ +Template: xawtv/makedev +Type: boolean +Default: true +Description: Create video4linux (/dev/video*) special files? +Description-da: Opret video4linux (/dev/video*) specielle filer? +Description-de: Sollen Geräte-Dateien (/dev/video*) für video4linux erstellt werden? +Description-es: ¿Crear los ficheros especiales video4linux (/dev/video*)? + Template: xawtv/channel-scan Type: boolean Default: yes @@ -10,6 +18,15 @@ Description: scan for TV stations? . I'll try to pick up the channel names from videotext. This will work with PAL only. +Description-da: Skan efter TV stationer? + Jeg kan lave en skanning efter alle kanaler og putte dem i en liste af de + TV stationer jeg har fundet, ind i en konfigurations fil. + . + Dette kræver en virkende bttv driver. Hvis bttv ikke er korrekt + konfigureret, vil du måske ikke finde TV stationerne. + . + Jeg vil prøve at finde kanal navne fra videotext. Dette vil kun virke med + PAL. Description-de: Soll nach TV-Stationen gesucht werden? Ich kann einen Suche nach Kanälen durchführen und eine Liste der gefundenen TV-Stationen in die Konfigurationsdatei schreiben. @@ -30,36 +47,15 @@ Description-es: ¿Buscar cadenas de televisión? Trataré de obtener los nombres de los canales del teletexto. Esto sólo funcionará con PAL. -Template: xawtv/makedev -Type: boolean -Default: true -Description: Create video4linux (/dev/video*) special files? -Description-de: Sollen Geräte-Dateien (/dev/video*) für video4linux erstellt werden? -Description-es: ¿Crear los ficheros especiales video4linux (/dev/video*)? - Template: xawtv/tvnorm Type: select Choices: PAL, SECAM, NTSC +Choices-da: PAL, SECAM, NTSC Description: Which TV norm is used in your country? +Description-da: Hvilken TV norm er brugt i dit land? Description-de: Welche TV-Norm benutzt man in ihrem Land? Description-es: ¿Qué sistema de televisión se usa en su país? -Template: xawtv/freqtab -Type: select -Choices: us-bcast, us-cable, us-cable-hrc, japan-bcast, japan-cable, europe-west, europe-east, italy, newzealand, australia, ireland, france, china-bcast -Description: Which frequency table should be used? - A frequency table is just a list of TV channel names/numbers and the - corresponding broadcast frequencies for these channels. Different regions - use different standards here... -Description-de: Welche Frequenzen-Tabelle soll benutzt werden? - Eine Frequenzen-Tabelle ist einfach nur eine Liste der TV-Kanäle (Namen - oder Nummern) mit dazugehörigen Frequenzen. Verschiedene Regionen - verwenden unterschiedliche Standards. -Description-es: ¿Que tabla de frecuencias se debería usar? - Una tabla de frecuencias es sólo una lista de nombres/números de canales - de televisión y sus correspondientes frecuencias de emisión. Diferentes - regiones utilizan diferentes estándares para esto... - Template: xawtv/build-config Type: boolean Default: false @@ -71,6 +67,14 @@ Description: Create a default configuration for xawtv? It is not required to have a global configuration file, but it will be more comfortable for your users if they find a working default configuration. +Description-da: Opret en standard konfigurations fil til xawtv? + Du kan oprette en system-bred konfigurations fil til xawtv med fornuftige + standard værdier for landet du lever i (f.eks. hvilken TV norm der bliver + brugt i dit land). + . + Det er ikke krævet at have en global konfigurations fil, men det vil gøre + det mere behageligt for dine brugere, hvis de finder en standard virkende + konfiguration. Description-de: Soll eine Standard-Konfiguration für xawtv erstellt werden? Sie können für xawtv eine systemweite Konfigurationsdatei erstellen, die vernünftige Voreinstellungen für ihr Land enthält (z.B. welche TV-Norm @@ -87,3 +91,24 @@ Description-es: ¿Crear una configuración por defecto para xawtv? No es obligatorio tener un fichero de configuración global, pero será más cómodo para sus usuarios encontrarse una configuración por defecto que funciona. + +Template: xawtv/freqtab +Type: select +Choices: us-bcast, us-cable, us-cable-hrc, japan-bcast, japan-cable, europe-west, europe-east, italy, newzealand, australia, ireland, france, china-bcast +Choices-da: us-bcast, us-cable, us-cable-hrc, japan-bcast, japan-cable, europe-west, europe-east, italy, newzealand, australia, ireland, france, china-bcast +Description: Which frequency table should be used? + A frequency table is just a list of TV channel names/numbers and the + corresponding broadcast frequencies for these channels. Different regions + use different standards here... +Description-da: Hvilken frekvens tabel skal bruges? + En frekvens tabel er bare en liste af kanal navne/tal og de tilsvarende + frekvenser for disse kanaler. Forskellige regioner bruger forskellige + standarder her... +Description-de: Welche Frequenzen-Tabelle soll benutzt werden? + Eine Frequenzen-Tabelle ist einfach nur eine Liste der TV-Kanäle (Namen + oder Nummern) mit dazugehörigen Frequenzen. Verschiedene Regionen + verwenden unterschiedliche Standards. +Description-es: ¿Que tabla de frecuencias se debería usar? + Una tabla de frecuencias es sólo una lista de nombres/números de canales + de televisión y sus correspondientes frecuencias de emisión. Diferentes + regiones utilizan diferentes estándares para esto... diff --git a/libng/color_lut.c b/libng/color_lut.c index b9f857e..ed87e21 100644 --- a/libng/color_lut.c +++ b/libng/color_lut.c @@ -27,9 +27,10 @@ unsigned long ng_lut_blue[256]; /* ------------------------------------------------------------------- */ void -ng_rgb24_to_lut2(unsigned char *dest, unsigned char *src, int p) +ng_rgb24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - uint16_t *d = (uint16_t*)dest; + uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] | @@ -39,9 +40,10 @@ ng_rgb24_to_lut2(unsigned char *dest, unsigned char *src, int p) } static void -bgr24_to_lut2(unsigned char *dest, unsigned char *src, int p) +bgr24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - uint16_t *d = (uint16_t*)dest; + uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | @@ -51,9 +53,10 @@ bgr24_to_lut2(unsigned char *dest, unsigned char *src, int p) } static void -rgb32_to_lut2(unsigned char *dest, unsigned char *src, int p) +rgb32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - uint16_t *d = (uint16_t*)dest; + uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] | @@ -63,9 +66,10 @@ rgb32_to_lut2(unsigned char *dest, unsigned char *src, int p) } static void -bgr32_to_lut2(unsigned char *dest, unsigned char *src, int p) +bgr32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - uint16_t *d = (uint16_t*)dest; + uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | @@ -75,9 +79,10 @@ bgr32_to_lut2(unsigned char *dest, unsigned char *src, int p) } static void -gray_to_lut2(unsigned char *dest, unsigned char *src, int p) +gray_to_lut2(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - uint16_t *d = (uint16_t*)dest; + uint16_t* restrict d = (uint16_t*)dest; while (p-- > 0) { *(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src]; @@ -88,9 +93,10 @@ gray_to_lut2(unsigned char *dest, unsigned char *src, int p) /* ------------------------------------------------------------------- */ void -ng_rgb24_to_lut4(unsigned char *dest, unsigned char *src, int p) +ng_rgb24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] | @@ -100,9 +106,10 @@ ng_rgb24_to_lut4(unsigned char *dest, unsigned char *src, int p) } static void -bgr24_to_lut4(unsigned char *dest, unsigned char *src, int p) +bgr24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | @@ -112,9 +119,10 @@ bgr24_to_lut4(unsigned char *dest, unsigned char *src, int p) } static void -rgb32_to_lut4(unsigned char *dest, unsigned char *src, int p) +rgb32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] | @@ -124,9 +132,10 @@ rgb32_to_lut4(unsigned char *dest, unsigned char *src, int p) } static void -bgr32_to_lut4(unsigned char *dest, unsigned char *src, int p) +bgr32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] | @@ -136,9 +145,10 @@ bgr32_to_lut4(unsigned char *dest, unsigned char *src, int p) } static void -gray_to_lut4(unsigned char *dest, unsigned char *src, int p) +gray_to_lut4(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; while (p-- > 0) { *(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src]; diff --git a/libng/color_packed.c b/libng/color_packed.c index faad23b..7c9aae4 100644 --- a/libng/color_packed.c +++ b/libng/color_packed.c @@ -36,10 +36,11 @@ redblue_swap(unsigned char *dest, unsigned char *src, int p) } static void -bgr24_to_bgr32(unsigned char *dest, unsigned char *src, int p) +bgr24_to_bgr32(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *s = src; - register unsigned char *d = dest; + register unsigned char* restrict s = src; + register unsigned char* restrict d = dest; while (p--) { *(d++) = *(s++); @@ -50,10 +51,11 @@ bgr24_to_bgr32(unsigned char *dest, unsigned char *src, int p) } static void -bgr24_to_rgb32(unsigned char *dest, unsigned char *src, int p) +bgr24_to_rgb32(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *s = src; - register unsigned char *d = dest; + register unsigned char* restrict s = src; + register unsigned char* restrict d = dest; while (p--) { *(d++) = 0; @@ -65,10 +67,11 @@ bgr24_to_rgb32(unsigned char *dest, unsigned char *src, int p) } static void -rgb32_to_rgb24(unsigned char *dest, unsigned char *src, int p) +rgb32_to_rgb24(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *s = src; - register unsigned char *d = dest; + register unsigned char* restrict s = src; + register unsigned char* restrict d = dest; while (p--) { s++; @@ -79,10 +82,11 @@ rgb32_to_rgb24(unsigned char *dest, unsigned char *src, int p) } static void -rgb32_to_bgr24(unsigned char *dest, unsigned char *src, int p) +rgb32_to_bgr24(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *s = src; - register unsigned char *d = dest; + register unsigned char* restrict s = src; + register unsigned char* restrict d = dest; while (p--) { s++; @@ -95,10 +99,11 @@ rgb32_to_bgr24(unsigned char *dest, unsigned char *src, int p) /* 15+16 bpp LE <=> BE */ static void -byteswap_short(unsigned char *dest, unsigned char *src, int p) +byteswap_short(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *s = src; - register unsigned char *d = dest; + register unsigned char* restrict s = src; + register unsigned char* restrict d = dest; while (--p) { *(d++) = s[1]; @@ -111,15 +116,16 @@ byteswap_short(unsigned char *dest, unsigned char *src, int p) /* color => grayscale */ static void -rgb15_native_gray(unsigned char *dest, unsigned char *s, int p) +rgb15_native_gray(unsigned char* restrict dest, unsigned char *s, + int p) { - int r,g,b; - unsigned short *src = (unsigned short*)s; + int r,g,b; + unsigned short* restrict src = (unsigned short*)s; while (p--) { r = (src[0] & 0x7c00) >> 10; g = (src[0] & 0x03e0) >> 5; - b = src[1] & 0x001f; + b = src[0] & 0x001f; *(dest++) = ((3*r + 6*g + b)/10) << 3; src++; @@ -128,14 +134,16 @@ rgb15_native_gray(unsigned char *dest, unsigned char *s, int p) #if BYTE_ORDER == LITTLE_ENDIAN static void -rgb15_be_gray(unsigned char *dest, unsigned char *src, int p) +rgb15_be_gray(unsigned char* restrict dest, unsigned char* restrict src, + int p) { - register unsigned char *d = dest; + int r,g,b; + register unsigned char* restrict d = dest; while (p--) { - unsigned char r = (src[0] & 0x7c) >> 2; - unsigned char g = (src[0] & 0x03) << 3 | (src[1] & 0xe0) >> 5; - unsigned char b = src[1] & 0x1f; + r = (src[0] & 0x7c) >> 2; + g = (src[0] & 0x03) << 3 | (src[1] & 0xe0) >> 5; + b = src[1] & 0x1f; *(d++) = ((3*r + 6*g + b)/10) << 3; src += 2; @@ -145,14 +153,15 @@ rgb15_be_gray(unsigned char *dest, unsigned char *src, int p) #if BYTE_ORDER == BIG_ENDIAN static void -rgb15_le_gray(unsigned char *dest, unsigned char *src, int p) +rgb15_le_gray(unsigned char* restrict dest, unsigned char* restrict src, int p) { - register unsigned char *d = dest; + int r,g,b; + register unsigned char* restrict d = dest; while (p--) { - unsigned char r = (src[1] & 0x7c) >> 2; - unsigned char g = (src[1] & 0x03) << 3 | (src[0] & 0xe0) >> 5; - unsigned char b = src[0] & 0x1f; + r = (src[1] & 0x7c) >> 2; + g = (src[1] & 0x03) << 3 | (src[0] & 0xe0) >> 5; + b = src[0] & 0x1f; *(d++) = ((3*r + 6*g + b)/10) << 3; src += 2; diff --git a/libng/color_yuv2rgb.c b/libng/color_yuv2rgb.c index 629643a..66291a3 100644 --- a/libng/color_yuv2rgb.c +++ b/libng/color_yuv2rgb.c @@ -61,9 +61,10 @@ static unsigned int ng_clip[256 + 2 * CLIP]; /* packed pixel yuv to gray / rgb */ static void -yuv422_to_gray(unsigned char *dest, unsigned char *s, int p) +yuv422_to_gray(unsigned char* restrict dest, unsigned char* restrict s, + int p) { - unsigned char *d = dest; + unsigned char* restrict d = dest; while (p) { d[0] = GRAY(s[0]); @@ -74,9 +75,10 @@ yuv422_to_gray(unsigned char *dest, unsigned char *s, int p) } static void -yuv422_to_rgb24(unsigned char *dest, unsigned char *s, int p) +yuv422_to_rgb24(unsigned char* restrict dest, unsigned char* restrict s, + int p) { - unsigned char *d = dest; + unsigned char* restrict d = dest; int gray; while (p) { @@ -95,9 +97,10 @@ yuv422_to_rgb24(unsigned char *dest, unsigned char *s, int p) } void -ng_yuv422_to_lut2(unsigned char *dest, unsigned char *s, int p) +ng_yuv422_to_lut2(unsigned char* restrict dest, unsigned char* restrict s, + int p) { - unsigned short *d = (unsigned short*)dest; + unsigned short* restrict d = (unsigned short*)dest; int gray; while (p) { @@ -117,9 +120,10 @@ ng_yuv422_to_lut2(unsigned char *dest, unsigned char *s, int p) } void -ng_yuv422_to_lut4(unsigned char *dest, unsigned char *s, int p) +ng_yuv422_to_lut4(unsigned char* restrict dest, unsigned char* restrict s, + int p) { - unsigned int *d = (unsigned int*)dest; + unsigned int* restrict d = (unsigned int*)dest; int gray; while (p) { @@ -144,8 +148,9 @@ ng_yuv422_to_lut4(unsigned char *dest, unsigned char *s, int p) static void yuv42xp_to_gray(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y; - unsigned char *dp,*d; + unsigned char* restrict y; + unsigned char* restrict d; + unsigned char* dp; int i,j; dp = out->data; @@ -164,9 +169,9 @@ yuv42xp_to_gray(void *h, struct ng_video_buf *out, struct ng_video_buf *in) static void yuv420p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; + unsigned char *restrict y, *restrict u, *restrict v, *restrict d; unsigned char *us,*vs; - unsigned char *dp,*d; + unsigned char *dp; int i,j,gray; dp = out->data; @@ -199,8 +204,8 @@ yuv420p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) static void yuv422p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; - unsigned char *dp,*d; + unsigned char *restrict y, *restrict u, *restrict v, *restrict d; + unsigned char *dp; int i,j,gray; dp = out->data; @@ -229,10 +234,10 @@ yuv422p_to_rgb24(void *h, struct ng_video_buf *out, struct ng_video_buf *in) void ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; + unsigned char *restrict y, *restrict u, *restrict v; unsigned char *us,*vs; unsigned char *dp; - unsigned short *d; + unsigned short *restrict d; int i,j,gray; dp = out->data; @@ -267,9 +272,9 @@ ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) void ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; + unsigned char *restrict y, *restrict u, *restrict v; unsigned char *dp; - unsigned short *d; + unsigned short *restrict d; int i,j,gray; dp = out->data; @@ -300,10 +305,10 @@ ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out, struct ng_video_buf *in) void ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; + unsigned char *restrict y, *restrict u, *restrict v; unsigned char *us,*vs; unsigned char *dp; - unsigned int *d; + unsigned int *restrict d; int i,j,gray; dp = out->data; @@ -338,9 +343,9 @@ ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in) void ng_yuv422p_to_lut4(void *h, struct ng_video_buf *out, struct ng_video_buf *in) { - unsigned char *y,*u,*v; + unsigned char *restrict y, *restrict u, *restrict v; unsigned char *dp; - unsigned int *d; + unsigned int *restrict d; int i,j,gray; dp = out->data; diff --git a/libng/grab-ng.c b/libng/grab-ng.c index 6ed2a1e..607085f 100644 --- a/libng/grab-ng.c +++ b/libng/grab-ng.c @@ -83,10 +83,10 @@ const char* ng_vfmt_to_desc[] = { /* --------------------------------------------------------------------- */ const unsigned int ng_afmt_to_channels[] = { - 0, 1, 2, 1, 2, 1, 2 + 0, 1, 2, 1, 2, 1, 2, 0 }; const unsigned int ng_afmt_to_bits[] = { - 0, 8, 8, 16, 16, 16, 16 + 0, 8, 8, 16, 16, 16, 16, 0 }; const char* ng_afmt_to_desc[] = { "none", @@ -95,7 +95,8 @@ const char* ng_afmt_to_desc[] = { "16bit mono (LE)", "16bit stereo (LE)", "16bit mono (BE)", - "16bit stereo (BE)" + "16bit stereo (BE)", + "mp3 compressed audio", }; /* --------------------------------------------------------------------- */ diff --git a/libng/grab-ng.h b/libng/grab-ng.h index 1fc35cc..3940565 100644 --- a/libng/grab-ng.h +++ b/libng/grab-ng.h @@ -22,6 +22,11 @@ extern char ng_v4l_conf[256]; message,__FILE__,__LINE__);\ exit(1);} +#if __STDC_VERSION__ < 199901 +# define restrict +#endif + + /* --------------------------------------------------------------------- */ /* defines */ @@ -52,7 +57,8 @@ extern char ng_v4l_conf[256]; #define AUDIO_S16_LE_STEREO 4 #define AUDIO_S16_BE_MONO 5 #define AUDIO_S16_BE_STEREO 6 -#define AUDIO_FMT_COUNT 7 +#define AUDIO_MP3 7 +#define AUDIO_FMT_COUNT 8 #if BYTE_ORDER == BIG_ENDIAN # define AUDIO_S16_NATIVE_MONO AUDIO_S16_BE_MONO @@ -355,6 +361,19 @@ struct ng_video_buf* ng_convert_single(struct ng_convert_handle *h, struct ng_video_buf *in); /* --------------------------------------------------------------------- */ +/* audio converters */ + +struct ng_audio_conv { + int fmtid_in; + int fmtid_out; + void* (*init)(void *priv); + struct ng_audio_buf* (*frame)(void *handle, + struct ng_audio_buf *in); + void (*fini)(void *handle); + void *priv; +}; + +/* --------------------------------------------------------------------- */ /* filters */ struct ng_filter { diff --git a/libng/plugins/Subdir.mk b/libng/plugins/Subdir.mk index 3e9943c..30c9fb1 100644 --- a/libng/plugins/Subdir.mk +++ b/libng/plugins/Subdir.mk @@ -5,6 +5,7 @@ TARGETS-plugins := \ libng/plugins/flt-invert.so \ libng/plugins/flt-disor.so \ libng/plugins/conv-mjpeg.so \ + libng/plugins/conv-audio.so \ libng/plugins/read-avi.so \ libng/plugins/write-avi.so ifeq ($(FOUND_LQT),yes) @@ -77,17 +78,17 @@ libng/plugins/drv1-v4l.so: \ libng/plugins/struct-v4l.o \ libng/plugins/struct-dump.o -libng/plugins/struct-dump.o:: structs/struct-dump.c +libng/plugins/struct-dump.o: structs/struct-dump.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) -libng/plugins/struct-v4l.o:: structs/struct-v4l.c +libng/plugins/struct-v4l.o: structs/struct-v4l.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) -libng/plugins/struct-v4l2.o:: structs/struct-v4l2.c +libng/plugins/struct-v4l2.o: structs/struct-v4l2.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) diff --git a/libng/plugins/conv-audio.c b/libng/plugins/conv-audio.c new file mode 100644 index 0000000..a510423 --- /dev/null +++ b/libng/plugins/conv-audio.c @@ -0,0 +1,163 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <dlfcn.h> + +#include "grab-ng.h" + +/* ---------------------------------------------------------------------- */ +/* stuff we need from lame.h */ + +struct lame_global_struct; +typedef struct lame_global_struct lame_global_flags; + +static lame_global_flags* (*lame_init)(void); +static int (*lame_close)(lame_global_flags *); + +static int (*lame_set_in_samplerate)(lame_global_flags *, int); +static int (*lame_set_num_channels)(lame_global_flags *, int); +static int (*lame_set_quality)(lame_global_flags *, int); +static int (*lame_init_params)(lame_global_flags * const ); + +/* + * num_samples = number of samples in the L (or R) + * channel, not the total number of samples in pcm[] + * returns # of output bytes + * mp3buffer_size_max = 1.25*num_samples + 7200 + */ +static int (*lame_encode_buffer_interleaved)( + lame_global_flags* gfp, /* global context handlei */ + short int pcm[], /* PCM data for left and right + channel, interleaved */ + int num_samples, /* number of samples per channel, + _not_ number of samples in + pcm[] */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int mp3buf_size ); /* number of valid octets in this + stream */ +static int (*lame_encode_flush)( + lame_global_flags * gfp, /* global context handle */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int size); /* number of valid octets in this stream */ + +/* ---------------------------------------------------------------------- */ +/* do dynamic linking */ + +typedef void (*dlcall)(void); +#define SYM(symbol) { .func = (dlcall*)(&symbol), .name = #symbol } +static struct { + dlcall *func; + char *name; +} symtab[] = { + SYM(lame_init), + SYM(lame_close), + SYM(lame_set_in_samplerate), + SYM(lame_set_num_channels), + SYM(lame_set_quality), + SYM(lame_init_params), + SYM(lame_encode_buffer_interleaved), + SYM(lame_encode_flush), +}; + +static int link_lame(void) +{ + void *handle; + void *symbol; + int i; + + handle = dlopen("libmp3lame.so.0",RTLD_NOW); + if (NULL == handle) + return -1; + for (i = 0; i < sizeof(symtab)/sizeof(symtab[0]); i++) { + symbol = dlsym(handle,symtab[i].name); + if (NULL == symbol) { + fprintf(stderr,"dlsym(mp3lame,%s): %s\n", + symtab[i].name, dlerror()); + dlclose(handle); + return -1; + } + *(symtab[i].func) = symbol; + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +struct mp3_enc_state { + lame_global_flags *gf; + int first; +}; + +static void* mp3_enc_init(void *priv) +{ + struct mp3_enc_state *h; + + h = malloc(sizeof(*h)); + if (NULL == h) + return NULL; + memset(h,0,sizeof(*h)); + h->gf = lame_init(); + h->first = 1; + return h; +} + +static struct ng_audio_buf* +mp3_enc_data(void *handle, struct ng_audio_buf *in) +{ + static struct ng_audio_fmt fmt = { + .fmtid = AUDIO_MP3, + .rate = 0, + }; + struct mp3_enc_state *h = handle; + struct ng_audio_buf *out; + int samples, size; + + if (h->first) { + lame_set_in_samplerate(h->gf, in->fmt.rate); + lame_set_num_channels(h->gf, ng_afmt_to_channels[in->fmt.fmtid]); + lame_set_quality(h->gf, 5 /* FIXME */); + lame_init_params(h->gf); + h->first = 0; + } + samples = in->size >> 2; + size = 7200 + samples * 5 / 4; /* worst case */ + out = ng_malloc_audio_buf(&fmt, size); + + out->size = lame_encode_buffer_interleaved + (h->gf, (short int*) in->data, samples, out->data, size); + return out; +} + +static void mp3_enc_fini(void *handle) +{ + struct mp3_enc_state *h = handle; + + lame_close(h->gf); + free(h); +} + +static struct ng_audio_conv mp3_list[] = { + { + /* --- compress --- */ + init: mp3_enc_init, + frame: mp3_enc_data, + fini: mp3_enc_fini, + fmtid_in: AUDIO_S16_NATIVE_STEREO, + fmtid_out: AUDIO_MP3, + priv: NULL, + } +}; +static const int nconv = sizeof(mp3_list)/sizeof(mp3_list[0]); + +/* ---------------------------------------------------------------------- */ +/* init stuff */ + +extern void ng_plugin_init(void); +void ng_plugin_init(void) +{ + if (0 != link_lame()) + return; + // ng_aconv_register(NG_PLUGIN_MAGIC,__FILE__,mp3_list,nconv); +} diff --git a/libng/plugins/drv0-v4l2.c b/libng/plugins/drv0-v4l2.c index 6d7b73b..bde242f 100644 --- a/libng/plugins/drv0-v4l2.c +++ b/libng/plugins/drv0-v4l2.c @@ -565,6 +565,7 @@ v4l2_tuned(void *handle) struct v4l2_tuner tuner; usleep(10000); + memset(&tuner,0,sizeof(tuner)); if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0)) return 0; return tuner.signal ? 1 : 0; @@ -862,8 +863,11 @@ v4l2_setformat(void *handle, struct ng_video_fmt *fmt) h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid]; h->fmt_v4l2.fmt.pix.width = fmt->width; h->fmt_v4l2.fmt.pix.height = fmt->height; - h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline; h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ANY; + if (fmt->bytesperline != fmt->width * ng_vfmt_to_depth[fmt->fmtid]/8) + h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline; + else + h->fmt_v4l2.fmt.pix.bytesperline = 0; if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL)) return -1; diff --git a/libng/plugins/drv1-v4l.c b/libng/plugins/drv1-v4l.c index 19da489..c41f7ad 100644 --- a/libng/plugins/drv1-v4l.c +++ b/libng/plugins/drv1-v4l.c @@ -28,7 +28,7 @@ #include "struct-dump.h" #include "struct-v4l.h" -#define SYNC_TIMEOUT 3 +#define SYNC_TIMEOUT 5 /* ---------------------------------------------------------------------- */ diff --git a/libng/plugins/write-dv.c b/libng/plugins/write-dv.c index fe17e1e..a40e219 100644 --- a/libng/plugins/write-dv.c +++ b/libng/plugins/write-dv.c @@ -222,5 +222,5 @@ struct ng_writer dv_writer = { extern void ng_plugin_init(void); void ng_plugin_init(void) { - ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&dv_writer); + //ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&dv_writer); } diff --git a/man/propwatch.1 b/man/propwatch.1 index 795c5a7..c015a24 100644 --- a/man/propwatch.1 +++ b/man/propwatch.1 @@ -1,8 +1,8 @@ -.TH propwatch 1 "(c) 1998,99 Gerd Knorr" +.TH propwatch 1 "(c) 1997-2003 Gerd Knorr" .SH NAME propwatch - a tool to monitor X11 properties .SH SYNOPSIS -.B propwatch [ toolkit-options ] property-name ... +.B propwatch [ options ] property-name ... .SH DESCRIPTION .B propwatch is a tool to monitor window properties of root and application @@ -10,24 +10,37 @@ windows. Nice for debugging property-based IPC of X11 programs. .SH OPTIONS .B propwatch uses the Athena Widgets and accepts the usual toolkit options like --geometry. +-display and -geometry. +.P +Additional options are: +.TP +.B -watch display +Display to monitor the windows on. By default the display specified +in the DISPLAY environment variable or via -display is used, but it is +possible to watch another display instead. +.TP +.B -verbose +be verbose. +.TP +.B -proplog +Log property changes to stdout. +.TP +.B -kbdlog +Log keystrokes to stdout. .P All remaining command line arguments are assumed to be property names which should be monitored. If no property names are specified, a -build in default set will be used. +build in default (WM_COMMAND) will be used. .SH ENVIRONMENT .TP .B DISPLAY specifies the display to use for the propwatch window. -.TP -.B PROPWATCH -specifies the display to monitor. It unset, DISPLAY will be used. .SH SEE ALSO -xprop(1), xhost(1), xauth(1) +xprop(1), xhost(1), xauth(1), xwd(1) .SH AUTHOR -Gerd Knorr <kraxel@goldbach.in-berlin.de> +Gerd Knorr <kraxel@bytesex.org> .SH COPYRIGHT -Copyright (C) 1997-99 Gerd Knorr +Copyright (C) 1997-2003 Gerd Knorr .br This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/man/record.1 b/man/record.1 index e6ec887..643f487 100644 --- a/man/record.1 +++ b/man/record.1 @@ -54,6 +54,10 @@ until stopped by a signal (by typing ^C for example). Limit the file size (console mode only). record will continue with a new file once the limit is reached. .TP +.B -n num +Limit the file count (console mode only). record will stop recording +after num files. +.TP .B -l Enable level triggered recording (console mode only) with the default trigger level (1000). diff --git a/man/streamer.1 b/man/streamer.1 index d450cd0..6c3431e 100644 --- a/man/streamer.1 +++ b/man/streamer.1 @@ -12,7 +12,9 @@ formats. .P streamer will use the file extention of the output file name to figure which format to use. You need the -f/-F options only if the extention -allows more than one format. +allows more than one format. If you get the "neither audio nor video +format specified/found" message and don't know why, you can enable the +debug output (-d switch) to see what is going on. .P You can safely stop the recording at any time with Ctrl+C. streamer will catch the signal and stop recording correctly (i.e. write movie @@ -22,8 +24,8 @@ file headers) before exiting. .B streamer -o foobar.jpeg write a single jpeg file. .TP -.B streamer -o quicktime.mov -f yuv2 -F stereo -r 12 -t 120 -record a short quicktime movie (120 frames / 12 fps => 10 seconds). +.B streamer -o quicktime.mov -f yuv2 -F stereo -r 12 -t 0:10 +record a short quicktime movie. .SH SEE ALSO xawtv(1), v4lctl(1) .SH AUTHOR diff --git a/man/xawtvrc.5 b/man/xawtvrc.5 index 6411c19..10b1068 100644 --- a/man/xawtvrc.5 +++ b/man/xawtvrc.5 @@ -177,6 +177,13 @@ there are two-digit station numbers starting with that digit. Enable/disable the onscreen display in fullscreen mode. Default is on. .TP +.B osd-position = x , y +Position the onscreen display, in pixels. Default is 30,20. +.TP +.B use-wm-fullscreen = on | off +Enter fullscreen mode by asking the window manager to handle that via +_NET_WM_STATE_FULLSCREEN (if supported by the wm). Default is on. +.TP .B ratio = x:y Set a fixed aspect ratio for the TV image. Default is 4:3. Use 0:0 if you don't want a fixed aspect ratio. diff --git a/mk/compile.mk b/mk/Compile.mk index a281e00..75dadde 100644 --- a/mk/compile.mk +++ b/mk/Compile.mk @@ -22,25 +22,32 @@ depfiles = mk/*.dep compile_c = $(CC) $(CFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< compile_cc = $(CXX) $(CXXFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< -fixup_deps = sed -e "s|.*\.o:|$@::|" < $(tmpdep) > $(depfile) && rm -f $(tmpdep) +fixup_deps = sed -e "s|.*\.o:|$@:|" < $(tmpdep) > $(depfile) && rm -f $(tmpdep) link_app = $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) link_so = $(CC) $(LDFLAGS) -shared -Wl,-soname,$(@F) -o $@ $^ $(LDLIBS) ar_lib = rm -f $@ && ar -r $@ $^ && ranlib $@ +moc_h = $(MOC) $< -o $@ +msgfmt_po = msgfmt -o $@ $< + # non-verbose output ifeq ($(verbose),no) - echo_compile_c = echo " CC " $@ - echo_compile_cc = echo " CXX " $@ - echo_link_app = echo " LD " $@ - echo_link_so = echo " LD " $@ - echo_ar_lib = echo " AR " $@ + echo_compile_c = echo " CC " $@ + echo_compile_cc = echo " CXX " $@ + echo_link_app = echo " LD " $@ + echo_link_so = echo " LD " $@ + echo_ar_lib = echo " AR " $@ + echo_moc_h = echo " MOC " $@ + echo_msgfmt_po = echo " MSGFMT " $@ else echo_compile_c = echo $(compile_c) echo_compile_cc = echo $(compile_cc) echo_link_app = echo $(link_app) echo_link_so = echo $(link_so) echo_ar_lib = echo $(ar_lib) + echo_moc_h = echo $(moc_h) + echo_msgfmt_po = echo $(msgfmt_po) endif %.o: %.c @@ -66,3 +73,12 @@ endif %: %.o @$(echo_link_app) @$(link_app) + +%.moc : %.h + @$(echo_moc_h) + @$(moc_h) + +%.mo : %.po + @$(echo_msgfmt_po) + @$(msgfmt_po) + diff --git a/structs/struct-dump.c b/structs/struct-dump.c index 602975d..be3e312 100644 --- a/structs/struct-dump.c +++ b/structs/struct-dump.c @@ -43,6 +43,7 @@ int print_struct(FILE *fp, struct struct_desc *desc, void *data, int16_t s16; uint8_t u8; int8_t s8; + int al = sizeof(long)-1; /* struct + union alignment */ void *p; int i,j,first; @@ -50,6 +51,7 @@ int print_struct(FILE *fp, struct struct_desc *desc, void *data, sprintf(name,"%s%s",prefix,desc[i].name); if (STRUCT == desc[i].type) { strcat(name,"."); + ptr = (void*)(((intptr_t)ptr + al) & ~al); print_struct(fp,desc[i].desc, ptr, name, tab); ptr += desc[i].length; if (!tab && desc[i+1].name != NULL) @@ -58,6 +60,7 @@ int print_struct(FILE *fp, struct struct_desc *desc, void *data, } if (UNION == desc[i].type) { u32 = *((uint32_t*)(ptr-4)); + ptr = (void*)(((intptr_t)ptr + al) & ~al); for (j = 0; desc[i].u[j].name != NULL; j++) if (desc[i].u[j].value == u32) break; diff --git a/todo/tmohan/webcam.c b/todo/tmohan/webcam.c new file mode 100644 index 0000000..0d1e35e --- /dev/null +++ b/todo/tmohan/webcam.c @@ -0,0 +1,1650 @@ +/* + * (c) 1998-2002 Gerd Knorr + * + * capture a image, compress as jpeg and upload to the webserver + * using the ftp utility or ssh + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <math.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include "grab-ng.h" +#include "jpeglib.h" +#include "ftp.h" +#include "parseconfig.h" +#include "list.h" + +const char *HTMLSTART = { +"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" +"<HTML>\n\n" +"<HEAD>\n" +"<TITLE>Webcam</TITLE>\n" +"<META HTTP-EQUIV=\"Refresh\" CONTENT=\"60\">\n" +"<META HTTP-EQUIV=\"Expires\" CONTENT=\"0\">\n" +"<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n" +"<META HTTP-EQUIV=\"Cache-Control\" content=\"no-cache\">\n" +"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n" +"</HEAD>\n\n" "<BODY BGCOLOR=\"#ffffff\">\n\n" +}; +const char *HTMLEND = { + "\n</BODY>\n\n" "</HTML>\n" +}; +const char *HTMLIMAGE = { + "<IMG VSPACE=5 SRC=\"%%webcam.jpg%%\">\n" +}; + +/* ---------------------------------------------------------------------- */ +/* configuration */ + +int daemonize = 0; +char *archive = NULL; +char *tmpdir; +struct list_head connections; +struct list_head plugin_list; +struct plugin_s +{ + struct ng_filter *filter; + struct list_head list; +}; + +char *grab_text = "webcam %Y-%m-%d %H:%M:%S"; /* strftime */ +char *grab_infofile = NULL; +int grab_width = 320; +int grab_height = 240; +int grab_delay = 3; +int grab_wait = 0; +int grab_rotate = 0; +int grab_top = 0; +int grab_left = 0; +int grab_bottom = -1; +int grab_right = -1; +int grab_quality = 75; +int grab_trigger = 0; +char *grab_trigger_area = "0%,0%,100%,100%"; +int grab_trigger_average = 0; +int grab_trigger_delay = 0; +int grab_times = -1; +int grab_fg_r = 255; +int grab_fg_g = 255; +int grab_fg_b = 255; +int grab_bg_r = -1; +int grab_bg_g = -1; +int grab_bg_b = -1; +char *grab_input = NULL; +char *grab_norm = NULL; + +/* ---------------------------------------------------------------------- */ +/* jpeg stuff */ + +static int +write_file (int fd, char *data, int width, int height) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE *fp; + int i; + unsigned char *line; + + fp = fdopen (fd, "w"); + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_compress (&cinfo); + jpeg_stdio_dest (&cinfo, fp); + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults (&cinfo); + jpeg_set_quality (&cinfo, grab_quality, TRUE); + jpeg_start_compress (&cinfo, TRUE); + + for (i = 0, line = data; i < height; i++, line += width * 3) + jpeg_write_scanlines (&cinfo, &line, 1); + + jpeg_finish_compress (&(cinfo)); + jpeg_destroy_compress (&(cinfo)); + fclose (fp); + + return 0; +} + +/* ---------------------------------------------------------------------- */ +/* image transfer */ + +struct xfer_ops; + +struct xfer_state +{ + char *name; + struct list_head list; + + /* xfer options */ + char *host; + char *user; + char *pass; + char *dir; + char *file; + char *tmpfile; + int debug; + int keepjpegs; + int currentCount; + char *htmlfile; + char *custom_htmlfile; + + /* ftp options */ + int passive, autologin; + + /* function pointers + private date */ + struct xfer_ops *ops; + void *data; +}; + +struct xfer_ops +{ + int (*open) (struct xfer_state *); + void (*info) (struct xfer_state *); + int (*xfer) (struct xfer_state *, char *image, int width, int height); + void (*close) (struct xfer_state *); +}; + +static int +ftp_open (struct xfer_state *s) +{ + s->data = ftp_init (s->name, s->autologin, s->passive, s->debug); + ftp_connect (s->data, s->host, s->user, s->pass, s->dir); + return 0; +} + +static void +ftp_info (struct xfer_state *s) +{ + fprintf (stderr, "ftp config [%s]:\n %s@%s:%s\n %s => %s\n", + s->name, s->user, s->host, s->dir, s->tmpfile, s->file); +} + +static int +ftp_xfer (struct xfer_state *s, char *image, int width, int height) +{ + char filename[1024]; + int fh; + + sprintf (filename, "%s/webcamXXXXXX", tmpdir); + if (-1 == (fh = mkstemp (filename))) + { + perror ("mkstemp"); + exit (1); + } + write_file (fh, image, width, height); + + if (!ftp_stillconnected (s->data)) + ftp_connect (s->data, s->host, s->user, s->pass, s->dir); + + char ftpfilename[1024]; + strcpy (ftpfilename, s->file); + + if (s->keepjpegs > 1) + { + //tack a number to the file. ..before the extension + char *extpos, *ext = NULL; + if ((extpos = strrchr (ftpfilename, '.'))) + { + ext = strdup (extpos); + *(extpos) = '\0'; + } + + sprintf (ftpfilename, "%s%02i", ftpfilename, s->currentCount); + if (ext) + { + strcat (ftpfilename, ext); + free (ext); + } + + } + + ftp_upload (s->data, filename, ftpfilename, s->tmpfile); + + unlink (filename); + + return 0; +} + +static void +ftp_close (struct xfer_state *s) +{ + ftp_fini (s->data); +} + +static struct xfer_ops ftp_ops = { + open:ftp_open, + info:ftp_info, + xfer:ftp_xfer, + close:ftp_close, +}; + +static int +ssh_open (struct xfer_state *s) +{ + s->data = + malloc (strlen (s->user) + strlen (s->host) + strlen (s->tmpfile) * 2 + + strlen (s->dir) + strlen (s->file) + 32); + sprintf (s->data, "ssh %s@%s \"cat >%s && mv %s %s/%s\"", s->user, s->host, + s->tmpfile, s->tmpfile, s->dir, s->file); + return 0; +} + +static void +ssh_info (struct xfer_state *s) +{ + fprintf (stderr, "ssh config [%s]:\n %s@%s:%s\n %s => %s\n", + s->name, s->user, s->host, s->dir, s->tmpfile, s->file); +} + +static int +ssh_xfer (struct xfer_state *s, char *image, int width, int height) +{ + char filename[1024]; + char *cmd = s->data; + unsigned char buf[4096]; + FILE *sshp, *imgdata; + int len, fh; + + sprintf (filename, "%s/webcamXXXXXX", tmpdir); + if (-1 == (fh = mkstemp (filename))) + { + perror ("mkstemp"); + exit (1); + } + write_file (fh, image, width, height); + + if ((sshp = popen (cmd, "w")) == NULL) + { + perror ("popen"); + exit (1); + } + if ((imgdata = fopen (filename, "rb")) == NULL) + { + perror ("fopen"); + exit (1); + } + for (;;) + { + len = fread (buf, 1, sizeof (buf), imgdata); + if (len <= 0) + break; + fwrite (buf, 1, len, sshp); + } + fclose (imgdata); + pclose (sshp); + + unlink (filename); + return 0; +} + +static void +ssh_close (struct xfer_state *s) +{ + char *cmd = s->data; + free (cmd); +} + +static struct xfer_ops ssh_ops = { + open:ssh_open, + info:ssh_info, + xfer:ssh_xfer, + close:ssh_close, +}; + +static int +local_open (struct xfer_state *s) +{ + char *t; + + if (s->dir != NULL && s->dir[0] != '\0') + { + t = malloc (strlen (s->tmpfile) + strlen (s->dir) + 2); + sprintf (t, "%s/%s", s->dir, s->tmpfile); + s->tmpfile = t; + + t = malloc (strlen (s->file) + strlen (s->dir) + 2); + sprintf (t, "%s/%s", s->dir, s->file); + s->file = t; + } + return 0; +} + +static void +local_info (struct xfer_state *s) +{ + fprintf (stderr, "write config [%s]:\n local transfer %s => %s\n", + s->name, s->tmpfile, s->file); +} + +static int +local_xfer (struct xfer_state *s, char *image, int width, int height) +{ + int fh; + + if (-1 == (fh = open (s->tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0666))) + { + fprintf (stderr, "open %s: %s\n", s->tmpfile, strerror (errno)); + exit (1); + } + write_file (fh, image, width, height); + if (rename (s->tmpfile, s->file)) + { + fprintf (stderr, "can't move %s -> %s\n", s->tmpfile, s->file); + exit (1); + } + return 0; +} + +static void +local_close (struct xfer_state *s) +{ + /* nothing */ +} + +static struct xfer_ops local_ops = { + open:local_open, + info:local_info, + xfer:local_xfer, + close:local_close, +}; + +/* ---------------------------------------------------------------------- */ +/* capture stuff */ + +static struct ng_video_buf *ng_buf; +const struct ng_vid_driver *drv; +void *h_drv; +struct ng_video_fmt fmt, gfmt; +struct ng_video_conv *conv; +struct ng_filter filter; +void *hconv; + +static void +grab_init (void) +{ + struct ng_attribute *attr; + int val, i; + + drv = ng_vid_open (ng_dev.video, NULL, NULL, 0, &h_drv); + if (NULL == drv) + { + fprintf (stderr, "no grabber device available\n"); + exit (1); + } + if (!(drv->capabilities (h_drv) & CAN_CAPTURE)) + { + fprintf (stderr, "device does'nt support capture\n"); + exit (1); + } + + if (grab_input) + { + attr = ng_attr_byid (drv->list_attrs (h_drv), ATTR_ID_INPUT); + val = ng_attr_getint (attr, grab_input); + if (-1 == val) + { + fprintf (stderr, "invalid input: %s\n", grab_input); + exit (1); + } + attr->write (attr, val); + } + if (grab_norm) + { + attr = ng_attr_byid (drv->list_attrs (h_drv), ATTR_ID_NORM); + val = ng_attr_getint (attr, grab_norm); + if (-1 == val) + { + fprintf (stderr, "invalid norm: %s\n", grab_norm); + exit (1); + } + attr->write (attr, val); + } + + /* try native */ + fmt.fmtid = VIDEO_RGB24; + fmt.width = grab_width; + fmt.height = grab_height; + if (0 == drv->setformat (h_drv, &fmt)) + return; + + /* check all available conversion functions */ + fmt.bytesperline = fmt.width * ng_vfmt_to_depth[fmt.fmtid] / 8; + for (i = 0;;) + { + conv = ng_conv_find_to (fmt.fmtid, &i); + if (NULL == conv) + break; + gfmt = fmt; + gfmt.fmtid = conv->fmtid_in; + gfmt.bytesperline = 0; + if (0 == drv->setformat (h_drv, &gfmt)) + { + fmt.width = gfmt.width; + fmt.height = gfmt.height; + hconv = conv->init (&fmt, conv->priv); + return; + } + } + fprintf (stderr, "can't get rgb24 data\n"); + exit (1); +} + +static unsigned char * +grab_one (int *width, int *height, struct ng_video_buf **buf) +{ + struct ng_video_buf *ng_cap; + + if (NULL != *buf) + ng_release_video_buf (*buf); + if (NULL == (ng_cap = drv->getimage (h_drv))) + { + fprintf (stderr, "capturing image failed\n"); + exit (1); + } + + if (NULL != conv) + { + *buf = ng_malloc_video_buf (&fmt, 3 * fmt.width * fmt.height); + conv->frame (hconv, *buf, ng_cap); + (*buf)->info = ng_cap->info; + ng_release_video_buf (ng_cap); + } + else + { + *buf = ng_cap; + } + + *width = (*buf)->fmt.width; + *height = (*buf)->fmt.height; + + return (*buf)->data; +} + +/* ---------------------------------------------------------------------- */ + +#define MSG_MAXLEN 256 + +#define CHAR_HEIGHT 11 +#define CHAR_WIDTH 6 +#define CHAR_START 4 +#include "font-6x11.h" + +static char * +get_message (void) +{ + static char buffer[MSG_MAXLEN + 1]; + FILE *fp; + char *p; + + if (NULL == grab_infofile) + return grab_text; + + if (NULL == (fp = fopen (grab_infofile, "r"))) + { + fprintf (stderr, "open %s: %s\n", grab_infofile, strerror (errno)); + return grab_text; + } + + fgets (buffer, MSG_MAXLEN, fp); + fclose (fp); + if (NULL != (p = strchr (buffer, '\n'))) + *p = '\0'; + + return buffer; +} + +static void +add_text (char *image, int width, int height) +{ + time_t t; + struct tm *tm; + char line[MSG_MAXLEN + 1], *ptr; + int i, x, y, f, len; + + time (&t); + tm = localtime (&t); + len = strftime (line, MSG_MAXLEN, get_message (), tm); + fprintf (stderr, "%s\n", line); + + for (y = 0; y < CHAR_HEIGHT; y++) + { + ptr = image + 3 * width * (height - CHAR_HEIGHT - 2 + y) + 12; + for (x = 0; x < len; x++) + { + f = fontdata[line[x] * CHAR_HEIGHT + y]; + for (i = CHAR_WIDTH - 1; i >= 0; i--) + { + if (f & (CHAR_START << i)) + { + ptr[0] = grab_fg_r; + ptr[1] = grab_fg_g; + ptr[2] = grab_fg_b; + } + else if (grab_bg_r != -1) + { + ptr[0] = grab_bg_r; + ptr[1] = grab_bg_g; + ptr[2] = grab_bg_b; + } + ptr += 3; + } + } + } +} + +/* ---------------------------------------------------------------------- */ +/* Frederic Helin <Frederic.Helin@inrialpes.fr> - 15/07/2002 */ +/* Correction fonction of stereographic radial distortion */ + +int grab_dist_on = 0; +int grab_dist_k = 700; +int grab_dist_cx = -1; +int grab_dist_cy = -1; +int grab_dist_zoom = 50; +int grab_dist_sensorw = 640; +int grab_dist_sensorh = 480; + +static unsigned char * +correct_distor (unsigned char *in, int width, int height, + int grab_zoom, int grap_k, int cx, int cy, + int grab_sensorw, int grab_sensorh) +{ + static unsigned char *corrimg = NULL; + + int i, j, di, dj; + float dr, cr, ca, sensor_w, sensor_h, sx, zoom, k; + + sensor_w = grab_dist_sensorw / 100.0; + sensor_h = grab_dist_sensorh / 100.0; + zoom = grab_zoom / 100.0; + k = grap_k / 100.0; + + if (corrimg == NULL && (corrimg = malloc (width * height * 3)) == NULL) + { + fprintf (stderr, "out of memory\n"); + exit (1); + } + + sensor_w = 6.4; + sensor_h = 4.8; + + // calc ratio x/y + sx = width * sensor_h / (height * sensor_w); + + // calc new value of k in the coordonates systeme of computer + k = k * height / sensor_h; + + // Clear image + for (i = 0; i < height * width * 3; i++) + corrimg[i] = 255; + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + + // compute radial distortion / parameters of center of image + cr = sqrt ((i - cx) / sx * (i - cx) / sx + (j - cy) * (j - cy)); + ca = atan (cr / k / zoom); + dr = k * tan (ca / 2); + + if (i == cx && j == cy) + { + di = cx; + dj = cy; + } + else + { + di = (i - cx) * dr / cr + cx; + dj = (j - cy) * dr / cr + cy; + } + + if (dj < height && di < width && di >= 0 && dj >= 0 && + j < height && i < width && i >= 0 && j >= 0) + { + corrimg[3 * (j * width + i)] = in[3 * (dj * width + di)]; + corrimg[3 * (j * width + i) + 1] = in[3 * (dj * width + di) + 1]; + corrimg[3 * (j * width + i) + 2] = in[3 * (dj * width + di) + 2]; + } + } + } + return corrimg; +} + +/* ---------------------------------------------------------------------- */ + +/*static unsigned int +compare_images(unsigned char *last, unsigned char *current, + int width, int height) +{ + unsigned char *p1 = last; + unsigned char *p2 = current; + int avg, diff, max, i = width*height*3; + + for (max = 0, avg = 0; --i; p1++,p2++) + { + //diff = (*p1 < *p2) ? (*p2 - *p1) : (*p1 - *p2); + diff = abs(*p1 - *p2); + avg += diff; + if (diff > max) + max = diff; + } + + avg = avg / width / height; + fprintf(stderr,"compare: max=%d,avg=%d\n",max,avg); + + // return max + return max; +}*/ + +static unsigned int +compare_images (unsigned char *last, unsigned char *current, + int offsetx, int offsety, int iwidth, int iheight, + int imagewidth) +{ + unsigned char *p1 = last; + unsigned char *p2 = current; + unsigned int p; + int x, y, diff, max = 0; + unsigned int avg = 0; + + offsety *= 3; + offsetx *= 3; + iheight *= 3; + iwidth *= 3; + + for (y = offsety; y < offsety + iheight; y += 3) + { + p = imagewidth * y; + + for (x = offsetx; x < offsetx + iwidth; x++) + { + p1 = last + p + x; + p2 = current + p + x; + + diff = abs (*p1 - *p2); + avg += diff; + if (diff > max) + max = diff; + } + } + + avg = 3 * avg / iwidth / iheight; + fprintf (stderr, "compare: max=%d,avg=%d\n", max, avg); + + // return max and average + return (max << 8) | avg; +} + +/*int max2 = 0; +static unsigned int +compare_images(unsigned char *saved, unsigned char *last, unsigned char *current, int width, int height) +{ + unsigned char *p1 = last; + unsigned char *p2 = current; + unsigned char *p3 = saved; + int avg, diff, max, i = width*height*3; + int avg2, diff2; + + for (max = 0, avg = 0, max2=0,avg2=0; --i; p1++,p2++,p3++) + { + diff = abs(*p1 - *p2); + avg += diff; + if (diff > max) + max = diff; + + diff2 = abs(*p3 - *p2); + avg2 += diff2; + if (diff2 > max2) + max2 = diff2; + + } + + avg = avg / width / height; + avg2 = avg2 / width / height; + fprintf(stderr,"compare: max=%d,%d,avg=%d,%d\n",max,max2,avg,avg2); + + + return max; +}*/ + +static unsigned char * +rotate_image (unsigned char *in, int *wp, int *hp, int rot, + int top, int left, int bottom, int right) +{ + static unsigned char *rotimg = NULL; + + int i, j; + + int w = *wp; + int ow = (right - left); + int oh = (bottom - top); + + if (rotimg == NULL && (rotimg = malloc (ow * oh * 3)) == NULL) + { + fprintf (stderr, "out of memory\n"); + exit (1); + } + + switch (rot) + { + default: + case 0: + for (j = 0; j < oh; j++) + { + int ir = (j + top) * w + left; + int or = j * ow; + for (i = 0; i < ow; i++) + { + rotimg[3 * (or + i)] = in[3 * (ir + i)]; + rotimg[3 * (or + i) + 1] = in[3 * (ir + i) + 1]; + rotimg[3 * (or + i) + 2] = in[3 * (ir + i) + 2]; + } + } + *wp = ow; + *hp = oh; + break; + case 1: + for (i = 0; i < ow; i++) + { + int rr = (ow - 1 - i) * oh; + int ic = i + left; + for (j = 0; j < oh; j++) + { + rotimg[3 * (rr + j)] = in[3 * ((j + top) * w + ic)]; + rotimg[3 * (rr + j) + 1] = in[3 * ((j + top) * w + ic) + 1]; + rotimg[3 * (rr + j) + 2] = in[3 * ((j + top) * w + ic) + 2]; + } + } + *wp = oh; + *hp = ow; + break; + case 2: + for (j = 0; j < oh; j++) + { + int ir = (j + top) * w; + for (i = 0; i < ow; i++) + { + rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i))] = + in[3 * (ir + i + left)]; + rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i)) + 1] = + in[3 * (ir + i + left) + 1]; + rotimg[3 * ((oh - 1 - j) * ow + (ow - 1 - i)) + 2] = + in[3 * (ir + i + left) + 2]; + } + } + *wp = ow; + *hp = oh; + break; + case 3: + for (i = 0; i < ow; i++) + { + int rr = i * oh; + int ic = i + left; + rr += oh - 1; + for (j = 0; j < oh; j++) + { + rotimg[3 * (rr - j)] = in[3 * ((j + top) * w + ic)]; + rotimg[3 * (rr - j) + 1] = in[3 * ((j + top) * w + ic) + 1]; + rotimg[3 * (rr - j) + 2] = in[3 * ((j + top) * w + ic) + 2]; + } + } + *wp = oh; + *hp = ow; + break; + } + + return rotimg; +} + +//----------------------------------------------------- +// T.Mohan - 28 July 2002 +// # strnsub() is based on source by Erik Bachmann and +// # was released to public domain on 27 Oct 1995. +//----------------------------------------------------- + +static char * +strnsub (char *pszString, char *pszPattern, char *pszReplacement, + int iMaxLength, int bOnce) +{ + char *pszSubstring, *pszTmpSubstring, *pszlast, *pszTempReplacement; + int iPatternLength, iReplacementLength; + + pszSubstring = pszString; + pszTmpSubstring = NULL; + iPatternLength = strlen (pszPattern); + pszlast = NULL; + + if (!strcmp (pszPattern, pszReplacement)) + return NULL; // Pattern == replacement: loop + + while ((pszSubstring = strstr (pszSubstring, pszPattern))) + { + iReplacementLength = strlen (pszReplacement); + pszTempReplacement = pszReplacement; + + if ((strlen (pszString) + (iReplacementLength - iPatternLength)) > + iMaxLength) + break; // Not enough space for replacement + + if (pszTmpSubstring == NULL) //allocate some memory only once + { + if ((pszTmpSubstring = + (char *) calloc (iMaxLength, sizeof (char))) == NULL) + return NULL; // oops, not enough memory? + } + + strcpy (pszTmpSubstring, pszSubstring + iPatternLength); + + while (iReplacementLength--) + { // Copy replacement + *pszSubstring++ = *pszTempReplacement++; + } + + strcpy (pszSubstring, pszTmpSubstring); + + pszlast = pszSubstring - iPatternLength; + + if (bOnce) + break; //just change one + + } + + if (pszTmpSubstring) + free (pszTmpSubstring); + + return pszlast; + +} + +//----------------------------------------------------- +// T.Mohan - 28 July 2002 +//----------------------------------------------------- +static int +ftp_upload_htmlfile (struct xfer_state *s) +{ + +#define MAXLINELEN 1024 + + FILE *filecustom, *filewrite; + int filetemp; + char line[MAXLINELEN]; + char tmpfname[1024]; + char jpegnumbered[1024], jpegfilename[1024]; + char pattern[20], pattern_newest[20]; + char *pszFound; + + strcpy (pattern, "%%webcam.jpg%%"); //replace with numbered .jpg's + strcpy (pattern_newest, "%%newest.jpg%%"); //replace with newest .jpg + pszFound = NULL; + filecustom = filewrite = NULL; + + //open the custom html file if requested + if (s->custom_htmlfile) + { + if ((filecustom = fopen (s->custom_htmlfile, "r")) == NULL) + { + perror (s->htmlfile); + return 1; + } + } + + //create a temporary file + sprintf (tmpfname, "%s/webcamhtmlXXXXXX", tmpdir); + + if (-1 == (filetemp = mkstemp (tmpfname))) + { + perror ("mkstemp create"); + fclose (filecustom); + return 1; + } + + if ((filewrite = fdopen (filetemp, "w")) == NULL) + { + perror ("htmlfile open for write"); + fclose (filecustom); + unlink (tmpfname); + return 1; + } + + if (s->keepjpegs > 1) //format the filename + { + strcpy (jpegfilename, s->file); + char *extpos, *ext = NULL; + + if ((extpos = strrchr (jpegfilename, '.'))) + { + ext = strdup (extpos); + *(extpos) = '\0'; + } + + //end up with something like 'webcam%02i.jpg' + sprintf (jpegfilename, "%s%%02i", jpegfilename); + + if (ext) //tack on the extension if there is one + { + strcat (jpegfilename, ext); + free (ext); + } + } + else + { + strcpy (jpegnumbered, s->file); + } + + //find pattern and replace with approriate filename in custom html file + int count = s->currentCount; + if (filecustom) + { + int actualcount = 0; + + while (fgets (line, sizeof (line), filecustom) != NULL) + { + if (s->keepjpegs > 1) + sprintf (jpegnumbered, jpegfilename, count); + + //replace patterns in entire line with the numbered jpeg + if (strnsub (line, pattern, jpegnumbered, MAXLINELEN, FALSE)) + { + if (--count < 1) + count = s->keepjpegs; + + actualcount++; + } + + //replace tag for %%newest.jpg%% + if (s->keepjpegs > 1) + sprintf (jpegnumbered, jpegfilename, s->currentCount); + + strnsub (line, pattern_newest, jpegnumbered, MAXLINELEN, FALSE); + + //write line + fputs (line, filewrite); + } + + if ((s->keepjpegs > 1) && (actualcount != s->keepjpegs)) + fprintf (stderr, + "\n*** Warning: Found %i patterns, but keepjpegs = %i\n\n", + actualcount, s->keepjpegs); + } + else + { + fputs (HTMLSTART, filewrite); + + int i = s->keepjpegs; + while (i--) + { + strcpy (line, HTMLIMAGE); + + if (s->keepjpegs > 1) + sprintf (jpegnumbered, jpegfilename, count); + + if (strnsub (line, pattern, jpegnumbered, MAXLINELEN, TRUE)) + { + if (--count < 1) + count = s->keepjpegs; + } + + //replace tag for %%newest.jpg%% + //sprintf(jpegnumbered,jpegfilename,s->currentCount); + //strnsub(line, pattern_newest, jpegnumbered, MAXLINELEN, FALSE); + + fputs (line, filewrite); + } + + fputs (HTMLEND, filewrite); + } + + if (filecustom) + fclose (filecustom); + if (filewrite) + fclose (filewrite); + + //upload the html file + sprintf (jpegfilename, "%s%s", s->tmpfile, ".html"); + fprintf (stderr, "%s,%s,%s\n", tmpfname, s->htmlfile, jpegfilename); + ftp_upload (s->data, tmpfname, s->htmlfile, jpegfilename); + + unlink (tmpfname); + + return 0; +} + +static void +parse_trigger_area (char *pszTriggerArea, int *ixoffset, int *iyoffset, + int *width, int *height) +{ + if (!ixoffset || !iyoffset || !width || !height) + return; + if (!pszTriggerArea) + pszTriggerArea = "0%,0%,100%,100%"; + + char *str, *perc, *tmpStr; + int count = -1, ta[4], err = 0; + + tmpStr = strdup (pszTriggerArea); + str = strtok (tmpStr, ","); + + while (str && (++count < 4)) + { + if ((perc = strstr (str, "%"))) + *perc = '\0'; + + if (perc) + ta[count] = atoi (str) * ((count % 2) ? *height : *width) / 100; + else + ta[count] = atoi (str); + + str = strtok (NULL, ","); + } + + free (tmpStr); + + //some foolproofing... + if ((ta[0] < 0) || (ta[0] > *width)) + { + ta[0] = 0; + err = 1; + } + if ((ta[1] < 0) || (ta[1] > *height)) + { + ta[1] = 0; + err = 1; + } + if ((ta[2] < 0) || (ta[2] > *width)) + { + ta[2] = *width; + err = 1; + } + if ((ta[3] < 0) || (ta[3] > *height)) + { + ta[3] = *height; + err = 1; + } + if (ta[0] >= ta[2]) + { + ta[2] = *width; + err = 1; + } + if (ta[1] >= ta[3]) + { + ta[3] = *height; + err = 1; + } + if (ta[2] <= ta[0]) + { + ta[0] = 0; + err = 1; + } + if (ta[3] <= ta[1]) + { + ta[1] = 0; + err = 1; + } + + if (err) + fprintf (stderr, "\n*** Invalid trigger area was fixed.\n\n"); + + *ixoffset = ta[0]; + *iyoffset = ta[1]; + *width = ta[2] - ta[0]; + *height = ta[3] - ta[1]; +} + +static void +draw_trigger_area (unsigned char *image, int offsetx, int offsety, + int iTriggerwidth, int iTriggerheight, int iImageWidth) +{ + unsigned char *p; + int x, y; + + offsety *= 3; + offsetx *= 3; + iTriggerheight *= 3; + iTriggerwidth *= 3; + + for (y = offsety; y < offsety + iTriggerheight; y += 3) + { + p = image + iImageWidth * y; + + for (x = offsetx; x < offsetx + iTriggerwidth; x++) + { + //trigger area is drawn inverted + *(p + x) = 255 - *(p + x); + } + } + +} + +static char * +trim (char *p) +{ + while ((*p == ' ')) + p++; + while ((p[strlen (p) - 1]) == ' ') + p[strlen (p) - 1] = '\0'; + + return p; +} + +static struct ng_filter * +get_plugin (char *name) +{ + int i; + + for (i = 0; NULL != ng_filters[i]; i++) + if (!strcmp (ng_filters[i]->name, name)) + return ng_filters[i]; + + return NULL; +} + +static void +parse_plugins (void) +{ + char *name, *attributes, *str; + int count = 0; + struct ng_filter *plugin; + struct plugin_s *currfilter = NULL; + + INIT_LIST_HEAD (&plugin_list); + + if ((str = cfg_get_str ("plugins", "names")) == NULL) + return; + + while ((name = strtok (str, ","))) + { + str = NULL; + + //remove asterix for spaces + strnsub (name, "*", " ", strlen (name), FALSE); + name = trim (name); + + //plugin actually exists? + if ((plugin = get_plugin (name)) == NULL) + { + fprintf (stderr, "plugin: [%s] not found.\n", name); + continue; + } + + currfilter = malloc (sizeof (*currfilter)); + memset (currfilter, 0, sizeof (*currfilter)); + currfilter->filter = plugin; + list_add_tail (&currfilter->list, &plugin_list); + + fprintf (stderr, "plugin: [%s] found.\n", name); + + count++; + } + + //parse the attributes + struct list_head *item; + name = NULL; + list_for_each (item, &plugin_list) + { + struct plugin_s *currfilter = NULL; + + currfilter = list_entry (item, struct plugin_s, list); + + if (name) + free (name); + name = strdup (currfilter->filter->name); + //replace spaces in the name with asterix + strnsub (name, " ", "*", strlen (name), FALSE); + attributes = cfg_get_str ("plugins", name); + //remove asterix for spaces + strnsub (name, "*", " ", strlen (name), FALSE); + + //parse the attributes + if (!attributes) + { + if (currfilter->filter->attrs) + fprintf (stderr, "plugin: [%s] Using default attributes.\n", name); + continue; + } + + char *attr = attributes; + char attrname[64], attrvalue[192]; + struct ng_attribute *nga = NULL; + while ((attributes = strtok (attr, ","))) + { + attr = NULL; + if (sscanf (attributes, " %63[^=] = %191[^\n]", attrname, attrvalue) != + 2) + fprintf (stderr, "plugin: [%s] Parse error for attribute %s\n", name, + attrname); + + trim (attrname); + + if (currfilter->filter->attrs == NULL) + { + fprintf (stderr, "plugin: [%s] has no attributes to set.\n", name); + break; + } + + if (!(nga = ng_attr_byname (currfilter->filter->attrs, attrname))) + { + fprintf (stderr, "plugin: [%s] Unkown attribute: %s\n", name, + attrname); + } + else + { + nga->write (nga, atoi (attrvalue)); + fprintf (stderr, "plugin: [%s] Wrote attribute: %s, value: %s\n", + name, attrname, attrvalue); + } + + } + + } + + if (name) + free (name); + + if (count) + fprintf (stderr, "plugin: Using %d plugin%s.\n", count, + (count == 1) ? "" : "s"); + + +} + +/* ---------------------------------------------------------------------- */ + +int +main (int argc, char *argv[]) +{ + unsigned char *image, *val, *gimg, *lastimg = NULL; + int width, height, i, fh; + char filename[1024]; + char **sections; + struct list_head *item; + struct xfer_state *s = NULL; + int iTrigX, iTrigY, iTrigWidth, iTrigHeight; + struct plugin_s *currfilter; + + /* read config */ + if (argc > 1) + { + strcpy (filename, argv[1]); + } + else + { + sprintf (filename, "%s/%s", getenv ("HOME"), ".webcamrc"); + } + + fprintf (stderr, "reading config file: %s\n", filename); + cfg_parse_file (filename); + ng_init (); + + //setup the plugins + parse_plugins (); + + if (NULL != (val = cfg_get_str ("grab", "device"))) + ng_dev.video = val; + if (NULL != (val = cfg_get_str ("grab", "text"))) + grab_text = val; + if (NULL != (val = cfg_get_str ("grab", "infofile"))) + grab_infofile = val; + if (NULL != (val = cfg_get_str ("grab", "input"))) + grab_input = val; + if (NULL != (val = cfg_get_str ("grab", "norm"))) + grab_norm = val; + if (-1 != (i = cfg_get_int ("grab", "width"))) + grab_width = i; + if (-1 != (i = cfg_get_int ("grab", "height"))) + grab_height = i; + if (-1 != (i = cfg_get_int ("grab", "delay"))) + grab_delay = i; + if (-1 != (i = cfg_get_int ("grab", "wait"))) + grab_wait = i; + if (-1 != (i = cfg_get_int ("grab", "rotate"))) + grab_rotate = i; + if (-1 != (i = cfg_get_int ("grab", "top"))) + grab_top = i; + if (-1 != (i = cfg_get_int ("grab", "left"))) + grab_left = i; + grab_bottom = cfg_get_int ("grab", "bottom"); + grab_right = cfg_get_int ("grab", "right"); + if (-1 != (i = cfg_get_int ("grab", "quality"))) + grab_quality = i; + if (-1 != (i = cfg_get_int ("grab", "trigger"))) + grab_trigger = i; + if (NULL != (val = cfg_get_str ("grab", "trigger_area"))) + grab_trigger_area = val; + if (-1 != (i = cfg_get_int ("grab", "trigger_average"))) + grab_trigger_average = i; + if (-1 != (i = cfg_get_int ("grab", "trigger_delay"))) + grab_trigger_delay = i; + if (-1 != (i = cfg_get_int ("grab", "once"))) + if (i) + grab_times = 1; + if (-1 != (i = cfg_get_int ("grab", "times"))) + grab_times = i; + if (NULL != (val = cfg_get_str ("grab", "archive"))) + archive = val; + + if (-1 != (i = cfg_get_int ("grab", "fg_red"))) + if (i >= 0 && i <= 255) + grab_fg_r = i; + if (-1 != (i = cfg_get_int ("grab", "fg_green"))) + if (i >= 0 && i <= 255) + grab_fg_g = i; + if (-1 != (i = cfg_get_int ("grab", "fg_blue"))) + if (i >= 0 && i <= 255) + grab_fg_b = i; + if (-1 != (i = cfg_get_int ("grab", "bg_red"))) + if (i >= 0 && i <= 255) + grab_bg_r = i; + if (-1 != (i = cfg_get_int ("grab", "bg_green"))) + if (i >= 0 && i <= 255) + grab_bg_g = i; + if (-1 != (i = cfg_get_int ("grab", "bg_blue"))) + if (i >= 0 && i <= 255) + grab_bg_b = i; + + if (-1 != (i = cfg_get_int ("grab", "distor"))) + grab_dist_on = i; + if (-1 != (i = cfg_get_int ("grab", "distor_k"))) + grab_dist_k = i; + if (-1 != (i = cfg_get_int ("grab", "distor_cx"))) + grab_dist_cx = i; + if (-1 != (i = cfg_get_int ("grab", "distor_cy"))) + grab_dist_cy = i; + if (-1 != (i = cfg_get_int ("grab", "distor_zoom"))) + grab_dist_zoom = i; + if (-1 != (i = cfg_get_int ("grab", "distor_sensorw"))) + grab_dist_sensorw = i; + if (-1 != (i = cfg_get_int ("grab", "distor_sensorh"))) + grab_dist_sensorh = i; + + if (grab_top < 0) + grab_top = 0; + if (grab_left < 0) + grab_left = 0; + if (grab_bottom > grab_height) + grab_bottom = grab_height; + if (grab_right > grab_width) + grab_right = grab_width; + if (grab_bottom < 0) + grab_bottom = grab_height; + if (grab_right < 0) + grab_right = grab_width; + if (grab_top >= grab_bottom) + grab_top = 0; + if (grab_left >= grab_right) + grab_left = 0; + + if (grab_dist_k < 1 || grab_dist_k > 10000) + grab_dist_k = 700; + if (grab_dist_cx < 0 || grab_dist_cx > grab_width) + grab_dist_cx = grab_width / 2; + if (grab_dist_cy < 0 || grab_dist_cy > grab_height) + grab_dist_cy = grab_height / 2; + if (grab_dist_zoom < 1 || grab_dist_zoom > 1000) + grab_dist_zoom = 100; + if (grab_dist_sensorw < 1 || grab_dist_sensorw > 9999) + grab_dist_sensorw = 640; + if (grab_dist_sensorh < 1 || grab_dist_sensorh > 9999) + grab_dist_sensorh = 480; + + INIT_LIST_HEAD (&connections); + for (sections = cfg_list_sections (); *sections != NULL; sections++) + { + if ((0 == strcasecmp (*sections, "grab")) + || (0 == strcasecmp (*sections, "plugins"))) + continue; + + /* init + set defaults */ + s = malloc (sizeof (*s)); + memset (s, 0, sizeof (*s)); + s->name = *sections; + s->host = "www"; + s->user = "webcam"; + s->pass = "xxxxxx"; + s->dir = "public_html/images"; + s->file = "webcam.jpeg"; + s->tmpfile = "uploading.jpeg"; + s->passive = 1; + s->autologin = 0; + s->ops = &ftp_ops; + s->keepjpegs = 1; //number of jpeg files to rotate through. 0 & 1 are synonymous + s->htmlfile = NULL; + s->custom_htmlfile = NULL; + s->currentCount = 0; + + /* from config */ + if (NULL != (val = cfg_get_str (*sections, "host"))) + s->host = val; + if (NULL != (val = cfg_get_str (*sections, "user"))) + s->user = val; + if (NULL != (val = cfg_get_str (*sections, "pass"))) + s->pass = val; + if (NULL != (val = cfg_get_str (*sections, "dir"))) + s->dir = val; + if (NULL != (val = cfg_get_str (*sections, "file"))) + s->file = val; + if (NULL != (val = cfg_get_str (*sections, "tmp"))) + s->tmpfile = val; + if (-1 != (i = cfg_get_int (*sections, "passive"))) + s->passive = i; + if (-1 != (i = cfg_get_int (*sections, "auto"))) + s->autologin = i; + if (-1 != (i = cfg_get_int (*sections, "debug"))) + s->debug = i; + if (-1 != (i = cfg_get_int (*sections, "local"))) + if (i) + s->ops = &local_ops; + if (-1 != (i = cfg_get_int (*sections, "ssh"))) + if (i) + s->ops = &ssh_ops; + if (-1 != (i = cfg_get_int (*sections, "keepjpegs"))) + s->keepjpegs = (i < 1) ? 1 : i; + if (NULL != (val = cfg_get_str (*sections, "htmlfile"))) + s->htmlfile = val; + if (NULL != (val = cfg_get_str (*sections, "custom_htmlfile"))) + s->custom_htmlfile = val; + + /* all done */ + list_add_tail (&s->list, &connections); + } + + /* init everything */ + grab_init (); + sleep (grab_wait); + tmpdir = (NULL != getenv ("TMPDIR")) ? getenv ("TMPDIR") : "/tmp"; + list_for_each (item, &connections) + { + s = list_entry (item, struct xfer_state, list); + s->ops->open (s); + } + + /* print config */ + fprintf (stderr, "video4linux webcam v1.5 - (c) 1998-2002 Gerd Knorr\n"); + fprintf (stderr, "grabber config:\n size %dx%d [%s]\n", + fmt.width, fmt.height, ng_vfmt_to_desc[gfmt.fmtid]); + fprintf (stderr, " input %s, norm %s, jpeg quality %d\n", + grab_input, grab_norm, grab_quality); + fprintf (stderr, " rotate=%d, top=%d, left=%d, bottom=%d, right=%d\n", + grab_rotate, grab_top, grab_left, grab_bottom, grab_right); + list_for_each (item, &connections) + { + s = list_entry (item, struct xfer_state, list); + s->ops->info (s); + } + + /* run as daemon - detach from terminal */ + if (daemonize) + { + switch (fork ()) + { + case -1: + perror ("fork"); + exit (1); + case 0: + close (0); + close (1); + close (2); + setsid (); + break; + default: + exit (0); + } + } + + + /* main loop */ + for (;;) + { + /* grab a new one */ + gimg = grab_one (&width, &height, &ng_buf); + + if (grab_top != 0 || grab_left != 0 || + grab_right != width || grab_bottom != height) + { //don't call rotate_image() if nothing to do + gimg = rotate_image (gimg, &width, &height, grab_rotate, + grab_top, grab_left, grab_bottom, grab_right); + } + + if (grab_dist_on) + { + gimg = correct_distor (gimg, width, height, + grab_dist_zoom, grab_dist_k, + grab_dist_cx, grab_dist_cy, + grab_dist_sensorw, grab_dist_sensorh); + } + + image = gimg; + + if (grab_trigger) + { + /* look if it has changed */ + if (NULL != lastimg) + { + i = compare_images (lastimg, image, iTrigX, iTrigY, iTrigWidth, + iTrigHeight, width); + + if (grab_trigger_average) + i = i & 0xFF; + else + i = i >> 8; + + if (i < grab_trigger) + { + if (grab_trigger_delay) + usleep (grab_trigger_delay * 1000); + + continue; + } + + } + else + { + lastimg = malloc (width * height * 3); + + iTrigWidth = width; + iTrigHeight = height; + fprintf (stderr, "width: %d,height:%d\n", width, height); + parse_trigger_area (grab_trigger_area, &iTrigX, &iTrigY, &iTrigWidth, + &iTrigHeight); + } + + memcpy (lastimg, image, width * height * 3); + + //draw inverted trigger area if debug > 1 + if (s->debug > 1) + draw_trigger_area (image, iTrigX, iTrigY, iTrigWidth, iTrigHeight, + width); + + } + + if (!list_empty (&plugin_list)) + { + //if we're using plugins ng_buf will have to be valid + // to pass to the filters. + //assign the current image to ng_buf and make sure fmt is + // valid due to possible size change in rotate_image() + if (!conv && !ng_buf) + ng_buf = ng_malloc_video_buf (&fmt, 3 * fmt.width * fmt.height); + + ng_buf->fmt.width = width; + ng_buf->fmt.height = height; + ng_buf->fmt.bytesperline = width * (ng_vfmt_to_depth[fmt.fmtid] / 8); + ng_buf->size = ng_buf->fmt.bytesperline * height; + memcpy (ng_buf->data, image, ng_buf->size); + + //call the plugins.... + list_for_each (item, &plugin_list) + { + currfilter = list_entry (item, struct plugin_s, list); + ng_buf = ng_filter_single (currfilter->filter, ng_buf); + image = ng_buf->data; + } + + } + + /* ok, label it and upload */ + add_text (image, width, height); + + list_for_each (item, &connections) + { + s = list_entry (item, struct xfer_state, list); + + if (++s->currentCount > s->keepjpegs) + s->currentCount = 1; + + s->ops->xfer (s, image, width, height); + + if (s->htmlfile) // || s->custom_htmlfile) + ftp_upload_htmlfile (s); + } + + if (archive) + { + time_t t; + struct tm *tm; + + time (&t); + tm = localtime (&t); + strftime (filename, sizeof (filename) - 1, archive, tm); + if (-1 == (fh = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0666))) + { + fprintf (stderr, "open %s: %s\n", filename, strerror (errno)); + exit (1); + } + write_file (fh, image, width, height); + } + + if (-1 != grab_times && --grab_times == 0) + { + fprintf (stderr, "grab \"times\" reached 0\n"); + break; + } + if (grab_delay > 0) + { + fprintf (stderr, "delay for %d seconds...\n", grab_delay); + sleep (grab_delay); + } + } + + list_for_each (item, &connections) + { + s = list_entry (item, struct xfer_state, list); + s->ops->close (s); + } + + return 0; +} diff --git a/vbistuff/Subdir.mk b/vbistuff/Subdir.mk index 8dfb8c1..4731da3 100644 --- a/vbistuff/Subdir.mk +++ b/vbistuff/Subdir.mk @@ -41,4 +41,4 @@ distclean:: rm -f $(TARGETS-vbistuff) # special dependences -vbistuff/alevtd.o:: vbistuff/alevtd.c $(HTML-alevtd) +vbistuff/alevtd.o: $(HTML-alevtd) diff --git a/x11/Subdir.mk b/x11/Subdir.mk index e4f801a..b20aeb8 100644 --- a/x11/Subdir.mk +++ b/x11/Subdir.mk @@ -120,12 +120,12 @@ MOTV-app := $(patsubst %,x11/MoTV.%.ad,$(LANGUAGES)) # local targets -x11/complete-xaw.o:: x11/complete.c +x11/complete-xaw.o: x11/complete.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) -x11/complete-motif.o:: x11/complete.c +x11/complete-motif.o: x11/complete.c @$(echo_compile_c) @$(compile_c) @$(fixup_deps) @@ -154,9 +154,9 @@ distclean:: rm -f $(MOTV-app) x11/MoTV.ad x11/MoTV.h x11/Xawtv.h x11/mtt.h # special dependences / rules -x11/xawtv.o:: x11/xawtv.c x11/Xawtv.h -x11/motv.o:: x11/motv.c x11/MoTV.h -x11/mtt.o:: x11/mtt.c x11/mtt.h +x11/xawtv.o: x11/Xawtv.h +x11/motv.o: x11/MoTV.h +x11/mtt.o: x11/mtt.h x11/MoTV.ad: $(srcdir)/x11/MoTV-default $(srcdir)/x11/MoTV-fixed cat $(srcdir)/x11/MoTV-default $(srcdir)/x11/MoTV-fixed > x11/MoTV.ad @@ -961,6 +961,8 @@ create_filter_prop(void) rc1 = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, filter_shell, NULL); + if (NULL == ng_filters) + return; for (i = 0; NULL != ng_filters[i]; i++) { if (NULL == ng_filters[i]->attrs) continue; diff --git a/x11/propwatch.c b/x11/propwatch.c index 5c25c8c..678d630 100644 --- a/x11/propwatch.c +++ b/x11/propwatch.c @@ -1,25 +1,11 @@ -#if 0 -set -x -gcc -o propwatch -I/usr/X11R6/include -L/usr/X11R6/lib \ - -lXaw3d -lXmu -lSM -lICE -lXext -lXt -lX11 $0 -exit -#endif /* - * propwatch.c -- (c) 1998,99 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * propwatch.c -- (c) 1997-2003 Gerd Knorr <kraxel@bytesex.org> * * A tool to monitor window properties of root and application windows. * Nice for debugging property-based IPC of X11 programs. * - * usage: - * propwatch [ property-list ] - * - * environment: - * $DISPLAY - which display propwatch should use for its window. - * $PROPWATCH - which display propwatch should monitor. $DISPLAY - * will be used if unset. - * * see also: - * xprop(1), xhost(1) + * xhost(1), xauth(1), xprop(1), xwd(1) * */ @@ -40,7 +26,6 @@ exit #include <X11/Xaw/Label.h> #include <X11/Xaw/List.h> #include <X11/Xaw/Viewport.h> -#include <X11/Xmu/WinUtil.h> #ifndef TRUE #define TRUE 1 @@ -53,7 +38,7 @@ struct WATCHLIST { Window win; int watch; struct WATCHLIST *next; - char text[4096]; + char *text; }; /* WM */ @@ -69,26 +54,61 @@ static Atom *watch_atom; static int watch_count; static char *watch_default[] = { - "CUT_BUFFER0", - "WM_CLASS", "WM_COMMAND", - "_MOZILLA_URL", "_XAWTV_STATION" }; + "WM_COMMAND", +}; static String *str_list; static int str_count; -static int verbose = 0; - -static char *drop[] = { - "WM_", - "CUT_BUFFER", - "KWM_ACTIVE_WINDOW", - "KWM_WIN_", - NULL + +static void AddWatch(Display *dpy, Window win, int i); +static void DeleteWatch(Window win); +static void CheckWindow(Display *dpy, Window win); +static void Update(Display *dpy, Window win, Atom prop); + +/*-------------------------------------------------------------------------*/ + +struct ARGS { + char *watch; + int verbose; + int proplog; + int kbdlog; +} args; + +XtResource args_desc[] = { + /* name, class, type, size, offset, default_type, default_addr */ + { + /* ----- Strings ----- */ + "watch", + XtCString, XtRString, sizeof(char*), + XtOffset(struct ARGS*,watch), + XtRString, NULL, + },{ + /* ----- Integer ----- */ + "verbose", + XtCValue, XtRInt, sizeof(int), + XtOffset(struct ARGS*,verbose), + XtRString, "0" + },{ + "proplog", + XtCValue, XtRInt, sizeof(int), + XtOffset(struct ARGS*,proplog), + XtRString, "0" + },{ + "kbdlog", + XtCValue, XtRInt, sizeof(int), + XtOffset(struct ARGS*,kbdlog), + XtRString, "0" + } }; +const int args_count = XtNumber(args_desc); -void AddWatch(Display *dpy, Window win, int i); -void DeleteWatch(Window win); -void CheckWindow(Display *dpy, Window win); -void Update(Display *dpy, Window win, Atom prop); +XrmOptionDescRec opt_desc[] = { + { "-watch", "watch", XrmoptionSepArg, NULL }, + { "-verbose", "verbose", XrmoptionNoArg, "1" }, + { "-proplog", "proplog", XrmoptionNoArg, "1" }, + { "-kbdlog", "kbdlog", XrmoptionNoArg, "1" }, +}; +const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec)); /*-------------------------------------------------------------------------*/ @@ -97,15 +117,19 @@ Widget app_shell; Cursor left_ptr; Cursor menu_ptr; -void QuitAction(Widget, XEvent*, String*, Cardinal*); +static void QuitAction(Widget, XEvent*, String*, Cardinal*); +static void HookAction(Widget, XEvent*, String*, Cardinal*); -void ProcessPropertyChange(Display*,XEvent*); -void ProcessKeyPress(Display*,XEvent*); -void ProcessCreateWindow(Display*,XEvent*); +static void ProcessPropertyChange(Display*,XEvent*); +static void ProcessKeyPress(Display*,XEvent*); +static void ProcessClientMessage(Display*,XEvent*); +static void ProcessCreateWindow(Display*,XEvent*); +static void ProcessEvent(Display *dpy, XEvent *event); /* Actions */ static XtActionsRec actionTable[] = { - { "Quit", QuitAction } + { "Quit", QuitAction }, + { "Hook", HookAction }, }; /*-------------------------------------------------------------------------*/ @@ -113,6 +137,8 @@ static XtActionsRec actionTable[] = { static int x11_error_dev_null(Display * dpy, XErrorEvent * event) { + if (args.verbose) + printf("x11 error -- ignored (likely just a race as X11 is async)\n"); return 0; } @@ -120,19 +146,36 @@ static void spy_input(XtPointer client_data, int *src, XtInputId *id) { Display *spy_dpy = client_data; - Window root = DefaultRootWindow(spy_dpy); XEvent event; - while (True == XCheckMaskEvent(spy_dpy, 0xffffffff, &event)) { - if (event.type == PropertyNotify) - ProcessPropertyChange(spy_dpy,&event); - else if (event.type == CreateNotify && - event.xcreatewindow.parent == root) - ProcessCreateWindow(spy_dpy,&event); - else if (event.type == DestroyNotify) { - DeleteWatch(event.xdestroywindow.window); - } + while (True == XCheckMaskEvent(spy_dpy, 0xffffffff, &event)) + ProcessEvent(spy_dpy,&event); +} + +static void +add_window(Display *dpy, Window win) +{ + Window rroot,parent,*children = NULL; + int i, n; + + if (NULL == args.watch && XtWindow(app_shell) == win) + /* don't f*ck up ourself */ + return; + + XSelectInput(dpy, win, + (args.kbdlog ? KeyPressMask | KeyReleaseMask : 0) | + PropertyChangeMask | + SubstructureNotifyMask); + + if (0 != XQueryTree(dpy, win, &rroot, &parent, &children, &n)) { + for (i = 0; i < n; i++) + add_window(dpy,children[i]); + if (children) + XFree(children); } + + /* look for properties to show */ + CheckWindow(dpy, win); } int @@ -140,34 +183,39 @@ main(int argc, char *argv[]) { Screen *scr; XColor white,red,dummy; - int i,n; - Window root,rroot,parent,*children,w; + int i; + Window root; Display *dpy, *spy_dpy; - char *spy_name,title[1024]; + char title[1024]; XEvent event; /* init X11 */ - app_shell = XtAppInitialize(&app_context, - "Propwatch", - NULL, 0, + app_shell = XtAppInitialize(&app_context, "Propwatch", + opt_desc, opt_count, &argc, argv, NULL, NULL, 0); + XtGetApplicationResources(app_shell,&args, + args_desc,args_count, + NULL,0); + XtAppAddActions(app_context,actionTable, sizeof(actionTable)/sizeof(XtActionsRec)); XtOverrideTranslations (app_shell,XtParseTranslationTable("<Message>WM_PROTOCOLS: Quit()\n")); dpy = XtDisplay(app_shell); - if (NULL != (spy_name = getenv("PROPWATCH"))) { - if (NULL == (spy_dpy = XOpenDisplay(spy_name))) + if (NULL != args.watch) { + if (NULL == (spy_dpy = XOpenDisplay(args.watch))) { + fprintf(stderr,"can't open display: %s\n",args.watch); exit(1); - sprintf(title,"watch on %s - ",spy_name); + } + sprintf(title,"watch on %s - ",args.watch); } else { spy_dpy = dpy; sprintf(title,"watch - "); } root = DefaultRootWindow(spy_dpy); - + XSetErrorHandler(x11_error_dev_null); /* args */ @@ -209,32 +257,24 @@ main(int argc, char *argv[]) vp = XtVaCreateManagedWidget("vp",viewportWidgetClass,app_shell, XtNallowHoriz, False, XtNallowVert, True, - XtNwidth, 400, - XtNheight, 250, + XtNwidth, 600, + XtNheight, 400, NULL); bl = XtVaCreateManagedWidget("box",listWidgetClass,vp, XtNdefaultColumns,1, XtNforceColumns,True, NULL); - - XSelectInput(spy_dpy,root, /* KeyPressMask | */ - SubstructureNotifyMask | PropertyChangeMask); - CheckWindow(spy_dpy,root); - - XQueryTree(spy_dpy, root, &rroot, &parent, &children, &n); - for (i = 0; i < n; i++) { - w = XmuClientWindow(spy_dpy, children[i]); - XSelectInput(spy_dpy,w, /* KeyPressMask | */ - StructureNotifyMask | PropertyChangeMask); - CheckWindow(spy_dpy,w); - } - XFree((char *) children); + XtOverrideTranslations(bl,XtParseTranslationTable + ("<Key>Q: Quit()\n" + "<Key>P: Hook(xprop)\n")); /* display main window */ XtRealizeWidget(app_shell); XDefineCursor(dpy,XtWindow(app_shell),left_ptr); XSetWMProtocols(dpy,XtWindow(app_shell),&wm_del_win,1); + add_window(spy_dpy,root); + /* enter main loop */ if (spy_dpy != dpy) { XtAppAddInput(app_context,ConnectionNumber(spy_dpy), @@ -245,16 +285,7 @@ main(int argc, char *argv[]) XtAppNextEvent(app_context,&event); if (XtDispatchEvent(&event)) continue; - if (event.type == PropertyNotify) { - ProcessPropertyChange(spy_dpy,&event); - } else if (event.type == CreateNotify && - event.xcreatewindow.parent == root) { - ProcessCreateWindow(spy_dpy,&event); - } else if (event.type == KeyPress) { - ProcessKeyPress(spy_dpy,&event); - } else if (event.type == DestroyNotify) { - DeleteWatch(event.xdestroywindow.window); - } + ProcessEvent(spy_dpy,&event); } /* keep compiler happy */ @@ -350,63 +381,96 @@ CheckWindow(Display *dpy, Window win) /*-------------------------------------------------------------------------*/ -static void -PropertyToString(Display *dpy, Window win, Atom prop, char *value) +static char* str_append(char *dest, char *sep, char *quot, char *str) +{ + int size, pos; + + pos = dest ? strlen(dest) : 0; + size = str ? strlen(str) : 0; + size += sep ? strlen(sep) : 0; + size += quot ? strlen(quot)*2 : 0; + dest = realloc(dest,pos+size+1); + sprintf(dest+pos,"%s%s%s%s", + sep ? sep : "", + quot ? quot : "", + str ? str : "", + quot ? quot : ""); + return dest; +} + +static char* +PropertyToString(Display *dpy, Window win, Atom prop) { Atom type; - int format,i,j; + int format,i; unsigned long nitems,rest; - unsigned char *cdata,*name; + unsigned char *cdata; unsigned long *ldata; - char *typename; + char window[12],*name; + char *buf = NULL; + char *sep = NULL; if (Success != XGetWindowProperty (dpy,win,prop,0,64,False,AnyPropertyType, &type,&format,&nitems,&rest,&cdata)) - return; + return NULL; ldata = (unsigned long*)cdata; switch (type) { case XA_STRING: - for (i = 0, j = 0; i < nitems; i += strlen(cdata+i)+1) - j += sprintf(value+j,"\"%s\", ",cdata+i); - value[j-2]=0; + for (i = 0; i < nitems; i += strlen(cdata+i)+1) { + buf = str_append(buf,sep,"\"",cdata+i); + sep = ", "; + } break; case XA_ATOM: - for (i = 0, j = 0; i < nitems; i++) { + for (i = 0; i < nitems; i++) { name = XGetAtomName(dpy,ldata[i]); - j += sprintf(value+j,"%s, ",name); - XFree(name); - } - value[j-2]=0; - break; - case XA_WINDOW: - for (i = 0, j = 0; i < nitems; i++) { - j += sprintf(value+j,"0x%x, ",(unsigned int)ldata[i]); + buf = str_append(buf,sep,NULL,name); + sep = ", "; + if (name) + XFree(name); } - value[j-2]=0; break; default: - typename = XGetAtomName(dpy,type); - sprintf(value,"unknown type (%s)",typename); - XFree(typename); + if (32 == format) { + for (i = 0; i < nitems; i++) { + sprintf(window,"0x%x",(unsigned int)ldata[i]); + buf = str_append(buf,sep,NULL,window); + sep = ", "; + } + } else { + name = XGetAtomName(dpy,type); + buf = malloc(40 + (name ? strlen(name) : 4)); + sprintf(buf,"can't handle: format=%d type=%s", + format, name ? name : "NULL"); + if (name) + XFree(name); + } break; } - XFree(cdata); + XFree(cdata); + return buf; } void Update(Display *dpy, Window win, Atom prop) { - int n; struct WATCHLIST *this; + char *str; for (this = watchlist; this != NULL; this = this->next) if (this->win == win && watch_atom[this->watch] == prop) break; if (this) { - n = sprintf(this->text,"%8x: %s: ", (unsigned int)this->win, - watch_name[this->watch]); - PropertyToString(dpy,win,prop,this->text+n); + if (this->text) + free(this->text); + str = PropertyToString(dpy,win,prop); + this->text = malloc((str ? strlen(str) : 4) + + strlen(watch_name[this->watch]) + 20); + sprintf(this->text,"0x%08lx: %s: %s", + this->win, watch_name[this->watch], str ? str : "NULL"); + if (str) + free(str); } } @@ -415,8 +479,10 @@ ProcessPropertyChange(Display *dpy, XEvent* event) { int i; struct WATCHLIST *this; - char *name; + char *name = NULL; + char *prop = NULL; + name = XGetAtomName(dpy,event->xproperty.atom); for (i = 0; i < watch_count; i++) { if (watch_atom[i] == event->xproperty.atom) { for (this = watchlist; this != NULL; this = this->next) @@ -432,62 +498,62 @@ ProcessPropertyChange(Display *dpy, XEvent* event) } } - if (verbose) { - /* get it */ - name = XGetAtomName(dpy,event->xproperty.atom); - - for (i = 0; drop[i] != NULL; i++) - if (0 == strncmp(name,drop[i],strlen(drop[i]))) - break; - if (NULL == drop[i]) - printf("%8x: %s\n", (int)event->xproperty.window,name); - XFree(name); + if (args.proplog) { + prop = PropertyToString(dpy, event->xproperty.window, + event->xproperty.atom); + printf("0x%-8lx: PropertyChange: %s: %s\n", + event->xproperty.window, + name ? name : "NULL", + prop ? prop : "NULL"); + if (prop) + free(prop); } + if (name) + XFree(name); } void -ProcessKeyPress(Display *dpy, XEvent* event) +ProcessClientMessage(Display *dpy, XEvent* event) { - static int last_window; - - if (event->xkey.window != last_window) { - last_window = event->xkey.window; - fprintf(stderr,"\n%8x: ",last_window); - } - fprintf(stderr,"%d ",event->xkey.keycode); + fprintf(stderr,"0x%-8lx: ClientMessage\n", + event->xclient.window); } -/*-------------------------------------------------------------------------*/ +void +ProcessKeyPress(Display *dpy, XEvent* event) +{ + fprintf(stderr,"0x%-8lx: %s: code=%d sym=%s\n", + event->xkey.window, + event->type == KeyPress ? "KeyPress" : "KeyRelease", + event->xkey.keycode, + XKeysymToString(XKeycodeToKeysym(dpy,event->xkey.keycode,0))); +} void ProcessCreateWindow(Display *dpy, XEvent* event) { - Atom type; - int format; - unsigned long nitems,rest; - unsigned char *class = NULL, *class2 = NULL; - - if (Success != XGetWindowProperty - (dpy,event->xcreatewindow.window,wm_class, - 0,64,False,AnyPropertyType, - &type,&format,&nitems,&rest,&class)) - return; - if (class != NULL && strlen(class)+1 < nitems) - class2 = class + strlen(class)+1; - - if (verbose) { - printf("%8x: new: %s %s\n", - (unsigned int)event->xcreatewindow.window, - class?class:(unsigned char*)"-", - class2?class2:(unsigned char*)"-"); + add_window(dpy,event->xcreatewindow.window); +} + +void +ProcessEvent(Display *dpy, XEvent *event) +{ + if (event->type == PropertyNotify) { + ProcessPropertyChange(dpy,event); + + } else if (event->type == CreateNotify) { + ProcessCreateWindow(dpy,event); + + } else if (event->type == KeyPress || + event->type == KeyRelease) { + ProcessKeyPress(dpy,event); + + } else if (event->type == ClientMessage) { + ProcessClientMessage(dpy,event); + + } else if (event->type == DestroyNotify) { + DeleteWatch(event->xdestroywindow.window); } - - XSelectInput(dpy, event->xcreatewindow.window, /* KeyPressMask | */ - StructureNotifyMask | PropertyChangeMask); - CheckWindow(dpy, event->xcreatewindow.window); - - if (class != NULL) - XFree(class); } /*-------------------------------------------------------------------------*/ @@ -498,3 +564,35 @@ QuitAction(Widget widget, XEvent* event, String* arg, Cardinal* arg_count) exit(0); } +void +HookAction(Widget widget, XEvent* event, String* arg, Cardinal* arg_count) +{ + XawListReturnStruct *ret; + struct WATCHLIST *this; + char *dname; + char cmd[256]; + int i; + + /* find window */ + if (0 != strcmp(XtName(widget),"box")) + return; + ret = XawListShowCurrent(widget); + for (i = 0, this = watchlist; this != NULL; i++, this=this->next) + if (0 == strcmp(ret->string,this->text)) + break; + if (NULL == this) + return; + if (0 == arg_count) + return; + dname = DisplayString(XtDisplay(widget)); + + if (0 == strcmp(arg[0],"xprop")) { + /* dump window properties */ + sprintf(cmd,"xprop -display %s -id 0x%lx", + args.watch ? args.watch : dname, + this->win); + printf("### %s\n",cmd); + system(cmd); + printf("### done\n"); + } +} diff --git a/x11/wmhooks.c b/x11/wmhooks.c index 6e5dc77..5e54a75 100644 --- a/x11/wmhooks.c +++ b/x11/wmhooks.c @@ -124,7 +124,7 @@ wm_check_capability(Display *dpy, Window root, Atom list, Atom wanted) return retval; } -int +void wm_detect(Display *dpy) { Window root = DefaultRootWindow(dpy); @@ -136,7 +136,6 @@ wm_detect(Display *dpy) if (debug) fprintf(stderr,"wmhooks: netwm state above\n"); wm_stay_on_top = netwm_stay_on_top; - return 0; } if (NULL == wm_stay_on_top && 0 == wm_check_capability(dpy,root,_NET_SUPPORTED, @@ -144,7 +143,6 @@ wm_detect(Display *dpy) if (debug) fprintf(stderr,"wmhooks: netwm state stays_on_top\n"); wm_stay_on_top = netwm_old_stay_on_top; - return 0; } if (NULL == wm_fullscreen && 0 == wm_check_capability(dpy,root,_NET_SUPPORTED, @@ -152,7 +150,6 @@ wm_detect(Display *dpy) if (debug) fprintf(stderr,"wmhooks: netwm state fullscreen\n"); wm_fullscreen = netwm_fullscreen; - return 0; } /* gnome checks */ @@ -161,9 +158,5 @@ wm_detect(Display *dpy) if (debug) fprintf(stderr,"wmhooks: gnome layer\n"); wm_stay_on_top = gnome_stay_on_top; - return 0; } - - /* nothing found... */ - return -1; } diff --git a/x11/wmhooks.h b/x11/wmhooks.h index 3b97102..d0341fa 100644 --- a/x11/wmhooks.h +++ b/x11/wmhooks.h @@ -1,3 +1,3 @@ -int wm_detect(Display *dpy); +void wm_detect(Display *dpy); void (*wm_stay_on_top)(Display *dpy, Window win, int state); void (*wm_fullscreen)(Display *dpy, Window win, int state); @@ -530,7 +530,7 @@ display_onscreen(char *title) if (debug) fprintf(stderr,"osd: show (%s)\n",title); XtVaGetValues(app_shell,XtNx,&x,XtNy,&y,NULL); - XtVaSetValues(on_shell,XtNx,x+30,XtNy,y+20,NULL); + XtVaSetValues(on_shell,XtNx,x+osd_x,XtNy,y+osd_y,NULL); toolkit_set_label(on_label,title); XtPopup(on_shell, XtGrabNone); if (wm_stay_on_top && stay_on_top > 0) @@ -815,27 +815,67 @@ set_vidmode(XF86VidModeModeInfo *mode) } #endif -void -do_fullscreen(void) +static void +do_screensaver(int fs_state) { - static Dimension x,y,w,h; - static int timeout,interval,prefer_blanking,allow_exposures,rpx,rpy; - static int warp_pointer; + static int timeout,interval,prefer_blanking,allow_exposures; #ifdef HAVE_LIBXDPMS static BOOL dpms_on; CARD16 dpms_state; int dpms_dummy; #endif + if (fs_state) { + /* fullscreen on -- disable screensaver */ + XGetScreenSaver(dpy,&timeout,&interval, + &prefer_blanking,&allow_exposures); + XSetScreenSaver(dpy,0,0,DefaultBlanking,DefaultExposures); +#ifdef HAVE_LIBXDPMS + if ((DPMSQueryExtension(dpy, &dpms_dummy, &dpms_dummy)) && + (DPMSCapable(dpy))) { + DPMSInfo(dpy, &dpms_state, &dpms_on); + DPMSDisable(dpy); + } +#endif + xscreensaver_timer = XtAppAddTimeOut(app_context,60000, + xscreensaver_timefunc,NULL); + } else { + /* fullscreen off -- enable screensaver */ + XSetScreenSaver(dpy,timeout,interval,prefer_blanking,allow_exposures); +#ifdef HAVE_LIBXDPMS + if ((DPMSQueryExtension(dpy, &dpms_dummy, &dpms_dummy)) && + (DPMSCapable(dpy)) && (dpms_on)) { + DPMSEnable(dpy); + } +#endif + if (xscreensaver_timer) + XtRemoveTimeOut(xscreensaver_timer); + } +} + +void +do_fullscreen(void) +{ + static Dimension x,y,w,h; + static int rpx,rpy; + static int warp_pointer; + Window root,child; int wpx,wpy,mask; - if (wm_fullscreen) { - /* full service for us :-) */ + if (use_wm_fullscreen && wm_fullscreen) { + /* full service for us, next to nothing to do */ fs = !fs; if (debug) fprintf(stderr,"fullscreen %s via netwm\n", fs ? "on" : "off"); wm_fullscreen(dpy,XtWindow(app_shell),fs); + + if (0 == fs && on_timer) { + XtPopdown(on_shell); + XtRemoveTimeOut(on_timer); + on_timer = 0; + } + do_screensaver(fs); return; } @@ -854,7 +894,7 @@ do_fullscreen(void) XtRemoveTimeOut(on_timer); on_timer = 0; } - + XtVaSetValues(app_shell, XtNwidthInc, WIDTH_INC, XtNheightInc,HEIGHT_INC, @@ -864,17 +904,8 @@ do_fullscreen(void) XtNheight, h, NULL); - XSetScreenSaver(dpy,timeout,interval,prefer_blanking,allow_exposures); -#ifdef HAVE_LIBXDPMS - if ((DPMSQueryExtension(dpy, &dpms_dummy, &dpms_dummy)) && - (DPMSCapable(dpy)) && (dpms_on)) { - DPMSEnable(dpy); - } -#endif - if (xscreensaver_timer) - XtRemoveTimeOut(xscreensaver_timer); - - if (warp_pointer) + do_screensaver(0); + if (warp_pointer) XWarpPointer(dpy, None, RootWindowOfScreen(XtScreen(tv)), 0, 0, 0, 0, rpx, rpy); fs = 0; @@ -975,20 +1006,7 @@ do_fullscreen(void) NULL); XRaiseWindow(dpy, XtWindow(app_shell)); - - XGetScreenSaver(dpy,&timeout,&interval, - &prefer_blanking,&allow_exposures); - XSetScreenSaver(dpy,0,0,DefaultBlanking,DefaultExposures); -#ifdef HAVE_LIBXDPMS - if ((DPMSQueryExtension(dpy, &dpms_dummy, &dpms_dummy)) && - (DPMSCapable(dpy))) { - DPMSInfo(dpy, &dpms_state, &dpms_on); - DPMSDisable(dpy); - } -#endif - xscreensaver_timer = XtAppAddTimeOut(app_context,60000, - xscreensaver_timefunc,NULL); - + do_screensaver(1); if (warp_pointer) XWarpPointer(dpy, None, XtWindow(tv), 0, 0, 0, 0, 30, 15); fs = 1; @@ -1,7 +1,7 @@ Name: xawtv Group: Applications/Multimedia Autoreqprov: on -Version: 3.82 +Version: 3.83 Release: 0 License: GPL Summary: v4l applications |