aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:38 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:38 +0200
commit6fdf6d3b6364f8e2da4e2db6468153c426a59533 (patch)
tree3f67f267f03be2e4f082af39bd9b490469f47ca2
parent54705a2f70386897bf3d186cdc4b7c47b3082444 (diff)
v3.69
-rw-r--r--Changes23
-rw-r--r--README.recording2
-rw-r--r--TODO3
-rw-r--r--build-test2
-rw-r--r--debian/changelog8
-rw-r--r--libng/OVERVIEW73
-rw-r--r--libng/color_lut.c4
-rw-r--r--libng/color_packed.c2
-rw-r--r--libng/color_yuv2rgb.c2
-rw-r--r--libng/grab-ng.c120
-rw-r--r--libng/grab-ng.h33
-rw-r--r--libng/plugins/Makefile.in11
-rw-r--r--libng/plugins/conv-mjpeg.c2
-rw-r--r--libng/plugins/drv0-bsd.c37
-rw-r--r--libng/plugins/drv0-v4l2.c70
-rw-r--r--libng/plugins/drv1-v4l.c6
-rw-r--r--libng/plugins/flt-debug.c124
-rw-r--r--libng/plugins/flt-gamma.c180
-rw-r--r--libng/plugins/flt-invert.c2
-rw-r--r--libng/plugins/flt-nop.c69
-rw-r--r--libng/plugins/snd-oss.c9
-rw-r--r--libng/plugins/write-avi.c2
-rw-r--r--libng/plugins/write-qt.c5
-rw-r--r--libng/writefile.c4
-rw-r--r--man/xawtv-remote.125
-rw-r--r--radio/radio.c54
-rw-r--r--radio/radio.man19
-rw-r--r--radio/x21
-rw-r--r--src/Makefile.in8
-rw-r--r--src/MoTV-de6
-rw-r--r--src/MoTV-default6
-rw-r--r--src/MoTV-fixed14
-rw-r--r--src/MoTV-it6
-rw-r--r--src/MoTV.de.ad20
-rw-r--r--src/MoTV.it.ad20
-rw-r--r--src/capture.c3
-rw-r--r--src/channel.c98
-rw-r--r--src/channel.h1
-rw-r--r--src/commands.c97
-rw-r--r--src/gl.ad20
-rw-r--r--src/gl.c506
-rw-r--r--src/gl.h17
-rw-r--r--src/main.c54
-rw-r--r--src/motif.c171
-rw-r--r--src/streamer.c6
-rw-r--r--src/v4l-conf.c29
-rw-r--r--src/x11.c1
-rw-r--r--src/xv.c22
-rw-r--r--tools/record.c227
-rw-r--r--tools/record.man38
-rw-r--r--webcam/webcam.c2
-rw-r--r--xawtv.spec2
52 files changed, 1814 insertions, 472 deletions
diff --git a/Changes b/Changes
index cafb1c2..c7c8c16 100644
--- a/Changes
+++ b/Changes
@@ -1,4 +1,27 @@
+3.68 => 3.69
+============
+
+ * added API versioning to the plugins.
+ * added attributes to struct ng_filter, so you can control filter
+ settings via GUI.
+ * added gamma filter plugin.
+ * updated documentation (libng/OVERVIEW), added some hints for
+ filter plugin programming. Note: motv has a menu to deal with
+ filters, xawtv has no GUI elements yet.
+ * more record tool improvements (level trigger for recording).
+ * removed fixed 0-65535 range for integer attributes, using min and
+ max values instead. This also affects the attributes specified
+ within the config file.
+ * Some improvements for the radio utility.
+ * make v4l-conf run most code as real user, not root. That should
+ improve security and also make v4l-conf not fail on ~/.Xauthority
+ located at root-squash mounted NFS dirs.
+ * hacked up a test app to play with OpenGL textures for video
+ playback. Not built by default. Needs Motif. Check src/gl.c if
+ you wanna have a look.
+
+
3.67 => 3.68
============
diff --git a/README.recording b/README.recording
index 71c7cc3..06622ed 100644
--- a/README.recording
+++ b/README.recording
@@ -89,7 +89,7 @@ real: 3.638s audio: [+-]0.023s video: [+-]0.042s
since you've started recording.
- "audio" says how much audio data was recorded: simply the total
number of bytes divided by the data rate (bytes/second). It is
- displayer relative to real time.
+ displayed relative to real time.
- "video" is the same for video: total frames divided by the
frames/second (also displayed relative to real time).
diff --git a/TODO b/TODO
index d951296..c4e21ed 100644
--- a/TODO
+++ b/TODO
@@ -21,4 +21,5 @@ avi
* grayscale avi recording (anybody knows how to do this? 256 color
with a gray palette?)
* OpenDML index support
- * showriff has problems with files > 2 GB. Not sure if it's me or glibc...
+ * record even/odd fields separately instead of writing interlaced
+ frames.
diff --git a/build-test b/build-test
index df41902..6ff800d 100644
--- a/build-test
+++ b/build-test
@@ -54,7 +54,7 @@ make distclean
make distclean
# library link order
-./configure && make CC="gcc -static" || exit 1
+CFLAGS="-static" ./configure && make || exit 1
make distclean
# 2.2.x kernel headers
diff --git a/debian/changelog b/debian/changelog
index f5dc953..80460aa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+xawtv (3.69) unstable; urgency=low
+
+ * new release (closes: #112892)
+ * various bugs are fixed in other releases but I forgot to mention them
+ in the changelog (closes: #122672, #116477, #119935, #116476).
+
+ -- Gerd Knorr <kraxel@debian.org> Thu, 31 Jan 2002 12:05:43 +0100
+
xawtv (3.68) unstable; urgency=low
* new release.
diff --git a/libng/OVERVIEW b/libng/OVERVIEW
index 1da6931..c192407 100644
--- a/libng/OVERVIEW
+++ b/libng/OVERVIEW
@@ -54,18 +54,19 @@ buffers provided by the hardware drivers, where ng_video_buf->data is
a pointer directly to the mmap()ed buffer(s).
-video capture / overlay drivers (struct ng_driver)
---------------------------------------------------
+video capture / overlay drivers (struct ng_vid_driver)
+------------------------------------------------------
This is a interface to a capture driver. Right now three different
ones exist:
- (1) video4linux (current linux API, see grab-v4l.c).
+ (1) video4linux (current linux API, see plugins/drv1-v4l.c).
(2) video4linux two (work in progress - new API for linux, see
- grab-v4l2.c).
- (3) bktr (bt848/878 driver for FreeBSD + OpenBSD, see grab-bsd.c).
+ plugins/drv0-v4l2.c).
+ (3) bktr (bt848/878 driver for FreeBSD + OpenBSD, see
+ plugins/drv0-bsd.c).
-xawtv uses struct ng_driver for Xvideo support too (see src/xv.c).
+xawtv uses struct ng_vid_driver for Xvideo support too (see src/xv.c).
open()/close() should be clear. The capabilities() function returns a
bitfield which specifies the capabilities of the driver. The *attr*
@@ -112,19 +113,61 @@ might change in the future. There are a number of standard attributes
defined (tv norm, volume and the like), but it is also possible to
specify non-standard attributes.
-struct ng_driver has functions to list/read/modify the available
-attributes. A number of helper functions to search a attribute list
-by id / name and for multiple choice attribute handling are available
+struct ng_attribute also has functions to list/read/modify the given
+attribute. A number of helper functions to search a attribute list by
+id / name and for multiple choice attribute handling are available
too.
-audio
------
+audio recording + mixer control
+-------------------------------
-Right now there are only some structs for audio formats and audio data
-chunks. The movie writers use these. No recording code yet. xawtv's
-audio recording code is in src/oss.c, maybe I move that to libng some
-day. Need to create some sensible interface for it first.
+There are only some structs for audio formats and audio data chunks.
+The movie writers use these. There are also interfaces for sound
+recording and mixer control (struct ng_dsp_driver + struct
+ng_mix_driver) and a implementation for the OSS API (in
+plugins/snd-oss.c).
+
+I'm not that happy with the current design of the mixer stuff, it
+might change in the future.
+
+
+color space conversion and compression
+--------------------------------------
+
+struct ng_video_conv describes a converter. There are plenty built-in
+into libng, but it is also possible to add more using plugins. These
+converters handle (a) color space conversion (yuv -> rgb), (b) convert
+rgb with different color depths, (c) handle compression.
+
+
+image filtering
+---------------
+
+I've recently added a interfaces for image filtering (i.e. on-the-fly
+image processing). struct ng_filter is it, in plugins/flt-*.c is some
+sample code. There is no complex stuff yet.
+
+For now filters are limited: They work on a frame-by-frame base,
+i.e. for one frame which gets passed in one is expected to come out.
+Read: you can't (yet?) merge multiple frames into one. The input and
+output format is expected to be the same.
+
+Filters should be able to handle as much formats as possible, neither
+xawtv nor libng attempt to do any conversions (i.e. do yuv->rgb ->
+filter -> rgb->yuv for you because the filter works in RGB space
+only). ng_filter->fmts lists the supported formats of a given filter,
+and if the required format isn't supported by some filter it is simply
+skipped and no filtering takes place.
+
+Most frequently formats are:
+ * RGB (various depts), to display images on the X11 screen, for ppm
+ capture, ...
+ * packed pixel yuv (If xawtv/motv blits images using the Xvideo
+ extention instead of normal X11 ximages).
+ * planar yuv (for recording compressed video, libjpeg can be feeded
+ directly with planar yuv to save some CPU cycles for rgb->yuv color
+ space conversion).
misc
diff --git a/libng/color_lut.c b/libng/color_lut.c
index 58952ab..e04dd73 100644
--- a/libng/color_lut.c
+++ b/libng/color_lut.c
@@ -300,7 +300,7 @@ ng_lut_init(unsigned long red_mask, unsigned long green_mask,
}
for (i = 0; i < nconv2; i++)
lut2_list[i].fmtid_out = fmtid;
- ng_conv_register(lut2_list,nconv2);
+ ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut2_list,nconv2);
break;
case 32:
if (swap) {
@@ -312,7 +312,7 @@ ng_lut_init(unsigned long red_mask, unsigned long green_mask,
}
for (i = 0; i < nconv4; i++)
lut4_list[i].fmtid_out = fmtid;
- ng_conv_register(lut4_list,nconv4);
+ ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut4_list,nconv4);
break;
}
}
diff --git a/libng/color_packed.c b/libng/color_packed.c
index 90178ad..1b07b00 100644
--- a/libng/color_packed.c
+++ b/libng/color_packed.c
@@ -250,5 +250,5 @@ static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv);
void
ng_color_packed_init(void)
{
- ng_conv_register(conv_list,nconv);
+ ng_conv_register(NG_PLUGIN_MAGIC,"built-in",conv_list,nconv);
}
diff --git a/libng/color_yuv2rgb.c b/libng/color_yuv2rgb.c
index abab3cb..6926c9c 100644
--- a/libng/color_yuv2rgb.c
+++ b/libng/color_yuv2rgb.c
@@ -431,5 +431,5 @@ void ng_color_yuv2rgb_init(void)
ng_clip[i] = 255;
/* register stuff */
- ng_conv_register(conv_list,nconv);
+ ng_conv_register(NG_PLUGIN_MAGIC,"built-in",conv_list,nconv);
}
diff --git a/libng/grab-ng.c b/libng/grab-ng.c
index e404566..0797d93 100644
--- a/libng/grab-ng.c
+++ b/libng/grab-ng.c
@@ -254,6 +254,51 @@ ng_attr_listchoices(struct ng_attribute *attr)
fprintf(stderr,"\n");
}
+int
+ng_attr_int2percent(struct ng_attribute *attr, int value)
+{
+ int range,percent;
+
+ range = attr->max - attr->min;
+ percent = (value - attr->min) * 100 / range;
+ if (percent < 0)
+ percent = 0;
+ if (percent > 100)
+ percent = 100;
+ return percent;
+}
+
+int
+ng_attr_percent2int(struct ng_attribute *attr, int percent)
+{
+ int range,value;
+
+ range = attr->max - attr->min;
+ value = percent * range / 100 + attr->min;
+ if (value < attr->min)
+ value = attr->min;
+ if (value > attr->max)
+ value = attr->max;
+ return value;
+}
+
+int
+ng_attr_parse_int(struct ng_attribute *attr, char *str)
+{
+ int value,n;
+
+ if (0 == sscanf(str,"%d%n",&value,&n))
+ /* parse error */
+ return attr->defval;
+ if (str[n] == '%')
+ value = ng_attr_percent2int(attr,value);
+ if (value < attr->min)
+ value = attr->min;
+ if (value > attr->max)
+ value = attr->max;
+ return value;
+}
+
/* --------------------------------------------------------------------- */
void
@@ -318,43 +363,76 @@ static void ng_register_listadd(void ***list, void *add)
(*list)[n++] = NULL;
}
-void
-ng_conv_register(struct ng_video_conv *list, int count)
+static int ng_check_magic(int magic, char *plugname, char *type)
+{
+ if (magic != NG_PLUGIN_MAGIC) {
+ fprintf(stderr, "ERROR: plugin magic mismatch [xawtv=%d,%s=%d]\n",
+ NG_PLUGIN_MAGIC,plugname,magic);
+ return -1;
+ }
+#if 0
+ if (ng_debug)
+ fprintf(stderr,"plugins: %s registered by %s\n",type,plugname);
+#endif
+ return 0;
+}
+
+int
+ng_conv_register(int magic, char *plugname,
+ struct ng_video_conv *list, int count)
{
int n;
-
+
+ if (0 != ng_check_magic(magic,plugname,"converters"))
+ return -1;
for (n = 0; n < count; n++)
ng_register_listadd((void***)(&ng_conv),&list[n]);
+ return 0;
}
-void
-ng_filter_register(struct ng_filter *filter)
+int
+ng_filter_register(int magic, char *plugname, struct ng_filter *filter)
{
+ if (0 != ng_check_magic(magic,plugname,"filter"))
+ return -1;
ng_register_listadd((void***)(&ng_filters),filter);
+ return 0;
}
-void
-ng_writer_register(struct ng_writer *writer)
+int
+ng_writer_register(int magic, char *plugname, struct ng_writer *writer)
{
+ if (0 != ng_check_magic(magic,plugname,"writer"))
+ return -1;
ng_register_listadd((void***)(&ng_writers),writer);
+ return 0;
}
-void
-ng_vid_driver_register(struct ng_vid_driver *driver)
+int
+ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver)
{
+ if (0 != ng_check_magic(magic,plugname,"video drv"))
+ return -1;
ng_register_listadd((void***)(&ng_vid_drivers),driver);
+ return 0;
}
-void
-ng_dsp_driver_register(struct ng_dsp_driver *driver)
+int
+ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver)
{
+ if (0 != ng_check_magic(magic,plugname,"dsp drv"))
+ return -1;
ng_register_listadd((void***)(&ng_dsp_drivers),driver);
+ return 0;
}
-void
-ng_mix_driver_register(struct ng_mix_driver *driver)
+int
+ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver)
{
+ if (0 != ng_check_magic(magic,plugname,"mixer drv"))
+ return -1;
ng_register_listadd((void***)(&ng_mix_drivers),driver);
+ return 0;
}
struct ng_video_conv*
@@ -363,7 +441,7 @@ ng_conv_find(int out, int *i)
struct ng_video_conv *ret = NULL;
for (; ng_conv[*i] != NULL; (*i)++) {
-#if 1
+#if 0
fprintf(stderr,"\tconv: %-28s => %s\n",
ng_vfmt_to_desc[ng_conv[*i]->fmtid_in],
ng_vfmt_to_desc[ng_conv[*i]->fmtid_out]);
@@ -489,6 +567,20 @@ ng_get_timestamp()
return ts;
}
+struct ng_video_buf*
+ng_filter_single(struct ng_filter *filter, struct ng_video_buf *in)
+{
+ struct ng_video_buf *out = in;
+ void *handle;
+
+ if (NULL != filter && filter->fmts & (1 << in->fmt.fmtid)) {
+ handle = filter->init(&in->fmt);
+ out = filter->frame(handle,in);
+ filter->fini(handle);
+ }
+ return out;
+}
+
/* --------------------------------------------------------------------- */
static void clip_dump(char *state, struct OVERLAY_CLIP *oc, int count)
diff --git a/libng/grab-ng.h b/libng/grab-ng.h
index 91dc188..1f4554b 100644
--- a/libng/grab-ng.h
+++ b/libng/grab-ng.h
@@ -114,7 +114,7 @@ struct ng_video_fmt {
struct ng_video_buf {
struct ng_video_fmt fmt;
int size;
- char *data;
+ unsigned char *data;
/* meta info for frame */
struct {
@@ -199,7 +199,9 @@ struct ng_attribute {
const char *name;
int type;
int defval;
- struct STRTAB *choices;
+ struct STRTAB *choices; /* ATTR_TYPE_CHOICE */
+ int min,max; /* ATTR_TYPE_INTEGER */
+ int points; /* ATTR_TYPE_INTEGER -- fixed point */
const void *priv;
void *handle;
int (*read)(struct ng_attribute*);
@@ -211,6 +213,9 @@ struct ng_attribute* ng_attr_byname(struct ng_attribute *attrs, char *name);
const char* ng_attr_getstr(struct ng_attribute *attr, int value);
int ng_attr_getint(struct ng_attribute *attr, char *value);
void ng_attr_listchoices(struct ng_attribute *attr);
+int ng_attr_int2percent(struct ng_attribute *attr, int value);
+int ng_attr_percent2int(struct ng_attribute *attr, int percent);
+int ng_attr_parse_int(struct ng_attribute *attr, char *str);
/* --------------------------------------------------------------------- */
@@ -291,6 +296,7 @@ struct ng_video_conv {
struct ng_filter {
char *name;
int fmts;
+ struct ng_attribute* attrs;
void* (*init)(struct ng_video_fmt *fmt);
struct ng_video_buf* (*frame)(void *handle,
struct ng_video_buf *in);
@@ -299,6 +305,9 @@ struct ng_filter {
/* --------------------------------------------------------------------- */
+/* must be changed if we break compatibility */
+#define NG_PLUGIN_MAGIC 20020118
+
extern struct ng_video_conv **ng_conv;
extern struct ng_filter **ng_filters;
extern struct ng_writer **ng_writers;
@@ -306,12 +315,18 @@ extern struct ng_vid_driver **ng_vid_drivers;
extern struct ng_dsp_driver **ng_dsp_drivers;
extern struct ng_mix_driver **ng_mix_drivers;
-void ng_conv_register(struct ng_video_conv *list, int count);
-void ng_filter_register(struct ng_filter *filter);
-void ng_writer_register(struct ng_writer *writer);
-void ng_vid_driver_register(struct ng_vid_driver *driver);
-void ng_dsp_driver_register(struct ng_dsp_driver *driver);
-void ng_mix_driver_register(struct ng_mix_driver *driver);
+int ng_conv_register(int magic, char *plugname,
+ struct ng_video_conv *list, int count);
+int ng_filter_register(int magic, char *plugname,
+ struct ng_filter *filter);
+int ng_writer_register(int magic, char *plugname,
+ struct ng_writer *writer);
+int ng_vid_driver_register(int magic, char *plugname,
+ struct ng_vid_driver *driver);
+int ng_dsp_driver_register(int magic, char *plugname,
+ struct ng_dsp_driver *driver);
+int ng_mix_driver_register(int magic, char *plugname,
+ struct ng_mix_driver *driver);
struct ng_video_conv* ng_conv_find(int out, int *i);
@@ -326,6 +341,8 @@ ng_mix_init(char *device, char *channel);
long long ng_get_timestamp(void);
void ng_check_clipping(int width, int height, int xadjust, int yadjust,
struct OVERLAY_CLIP *oc, int *count);
+struct ng_video_buf*
+ng_filter_single(struct ng_filter *filter, struct ng_video_buf *in);
/* --------------------------------------------------------------------- */
diff --git a/libng/plugins/Makefile.in b/libng/plugins/Makefile.in
index c75fce9..ca1bfe2 100644
--- a/libng/plugins/Makefile.in
+++ b/libng/plugins/Makefile.in
@@ -4,20 +4,25 @@ VPATH=$(srcdir)
include ../../Make.config
CFLAGS=-g -fPIC @CFLAGS@ $(WARN_FLAGS) $(LFS_FLAGS) -I../.. -I..
-PLUGINS=flt-nop.so flt-invert.so conv-mjpeg.so write-avi.so \
+PLUGINS=flt-invert.so flt-gamma.so conv-mjpeg.so write-avi.so \
@PLUGINS@
all build: $(PLUGINS)
-.SUFFIXES: .so .o
+.SUFFIXES: .so .o .c
.o.so:
gcc $(CFLAGS) -shared -Wl,-soname,$@ -o $@ $<
+.c.o:
+ gcc $(CFLAGS) -DPLUGNAME='"$<"' -c -o $@ $<
+
+flt-gamma.so: flt-gamma.o
+ gcc $(CFLAGS) -shared -Wl,-soname,$@ -o $@ $< -lm
write-qt.so: write-qt.o
gcc $(CFLAGS) -shared -Wl,-soname,$@ -o $@ $< $(QT_LIBS)
clean:
- rm -f $(PLUGINS) *.o
+ rm -f $(PLUGINS) flt-debug.so *.o
distclean realclean: clean
rm -f Makefile *~ *.bak
diff --git a/libng/plugins/conv-mjpeg.c b/libng/plugins/conv-mjpeg.c
index e3fe237..d2d3af4 100644
--- a/libng/plugins/conv-mjpeg.c
+++ b/libng/plugins/conv-mjpeg.c
@@ -399,5 +399,5 @@ static const int nconv = sizeof(mjpg_list)/sizeof(struct ng_video_conv);
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_conv_register(mjpg_list,nconv);
+ ng_conv_register(NG_PLUGIN_MAGIC,PLUGNAME,mjpg_list,nconv);
}
diff --git a/libng/plugins/drv0-bsd.c b/libng/plugins/drv0-bsd.c
index 7ece078..da76cd5 100644
--- a/libng/plugins/drv0-bsd.c
+++ b/libng/plugins/drv0-bsd.c
@@ -182,18 +182,24 @@ static struct ng_attribute bsd_attr[] = {
id: ATTR_ID_HUE,
name: "hue",
type: ATTR_TYPE_INTEGER,
+ min: BT848_HUEREGMIN,
+ max: BT848_HUEREGMAX,
read: bsd_read_attr,
write: bsd_write_attr,
},{
id: ATTR_ID_BRIGHT,
name: "bright",
type: ATTR_TYPE_INTEGER,
+ min: BT848_BRIGHTREGMIN,
+ max: BT848_BRIGHTREGMAX,
read: bsd_read_attr,
write: bsd_write_attr,
},{
id: ATTR_ID_CONTRAST,
name: "contrast",
type: ATTR_TYPE_INTEGER,
+ min: BT848_CONTRASTREGMIN,
+ max: BT848_CONTRASTREGMAX,
read: bsd_read_attr,
write: bsd_write_attr,
},{
@@ -275,7 +281,7 @@ xioctl(int fd, int cmd, void *arg)
/* ---------------------------------------------------------------------- */
-void
+static void
bsd_print_format(struct meteor_pixfmt *pf, int format)
{
switch (pf->type) {
@@ -444,24 +450,18 @@ static struct ng_attribute* bsd_attrs(void *handle)
/* ---------------------------------------------------------------------- */
static int
-bsd_get_range(int id, int *min, int *max, int *get, int *set)
+bsd_get_range(int id, int *get, int *set)
{
switch (id) {
case ATTR_ID_HUE:
- *min = BT848_HUEREGMIN;
- *max = BT848_HUEREGMAX;
*get = BT848_GHUE;
*set = BT848_SHUE;
break;
case ATTR_ID_BRIGHT:
- *min = BT848_BRIGHTREGMIN;
- *max = BT848_BRIGHTREGMAX;
*get = BT848_GBRIG;
*set = BT848_SBRIG;
break;
case ATTR_ID_CONTRAST:
- *min = BT848_CONTRASTREGMIN;
- *max = BT848_CONTRASTREGMAX;
*get = BT848_GCONT;
*set = BT848_SCONT;
break;
@@ -474,7 +474,7 @@ bsd_get_range(int id, int *min, int *max, int *get, int *set)
static int bsd_read_attr(struct ng_attribute *attr)
{
struct bsd_handle *h = attr->handle;
- int arg, min, max, get, set, i;
+ int arg, get, set, i;
int value = -1;
switch (attr->id) {
@@ -497,12 +497,9 @@ static int bsd_read_attr(struct ng_attribute *attr)
case ATTR_ID_HUE:
case ATTR_ID_BRIGHT:
case ATTR_ID_CONTRAST:
- bsd_get_range(attr->id,&min,&max,&get,&set);
- if (-1 != xioctl(h->tfd,get,&arg)) {
- value = (arg + min) * 65536 / (max - min);
- if (value < 0) value = 0;
- if (value > 65535) value = 65535;
- }
+ bsd_get_range(attr->id,&get,&set);
+ if (-1 != xioctl(h->tfd,get,&arg))
+ value = arg;
break;
default:
break;
@@ -513,7 +510,7 @@ static int bsd_read_attr(struct ng_attribute *attr)
static void bsd_write_attr(struct ng_attribute *attr, int value)
{
struct bsd_handle *h = attr->handle;
- int arg, min, max, get, set;
+ int arg, get, set;
switch (attr->id) {
case ATTR_ID_NORM:
@@ -530,10 +527,8 @@ static void bsd_write_attr(struct ng_attribute *attr, int value)
case ATTR_ID_HUE:
case ATTR_ID_BRIGHT:
case ATTR_ID_CONTRAST:
- bsd_get_range(attr->id,&min,&max,&get,&set);
- arg = value * (max - min) / 65536 + min;
- if (arg < min) value = min;
- if (arg > max) value = max;
+ bsd_get_range(attr->id,&get,&set);
+ arg = value;
xioctl(h->tfd,set,&arg);
break;
default:
@@ -806,5 +801,5 @@ static struct ng_video_buf* bsd_getimage(void *handle)
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_vid_driver_register(&bsd_driver);
+ ng_vid_driver_register(NG_PLUGIN_MAGIC,PLUGNAME,&bsd_driver);
}
diff --git a/libng/plugins/drv0-v4l2.c b/libng/plugins/drv0-v4l2.c
index 0a2bbf4..a921833 100644
--- a/libng/plugins/drv0-v4l2.c
+++ b/libng/plugins/drv0-v4l2.c
@@ -552,40 +552,6 @@ static struct V4L2_ATTR {
};
#define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR))
-static int
-v4l2_to_me(const struct v4l2_queryctrl *ctl, int value)
-{
- int me = 65536;
- int v4l2;
-
- v4l2 = ctl->maximum - ctl->minimum;
- if (v4l2 > 16384) {
- v4l2 >>= 2;
- me >>= 2;
- }
- value = (value - ctl->minimum) * me / v4l2;
- if (value < 0) value = 0;
- if (value > 65535) value = 65535;
- return value;
-}
-
-static int
-me_to_v4l2(const struct v4l2_queryctrl *ctl, int value)
-{
- int me = 65536;
- int v4l2;
-
- v4l2 = ctl->maximum - ctl->minimum;
- if (v4l2 > 16384) {
- v4l2 >>= 2;
- me >>= 2;
- }
- value = value * v4l2 / me + ctl->minimum;
- if (value < ctl->minimum) value = ctl->minimum;
- if (value > ctl->maximum) value = ctl->maximum;
- return value;
-}
-
static struct STRTAB*
v4l2_menu(int fd, const struct v4l2_queryctrl *ctl)
{
@@ -633,7 +599,9 @@ v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl,
switch (ctl->type) {
case V4L2_CTRL_TYPE_INTEGER:
h->attr[h->nattr].type = ATTR_TYPE_INTEGER;
- h->attr[h->nattr].defval = v4l2_to_me(ctl,ctl->default_value);
+ h->attr[h->nattr].defval = ctl->default_value;
+ h->attr[h->nattr].min = ctl->minimum;
+ h->attr[h->nattr].max = ctl->maximum;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
h->attr[h->nattr].type = ATTR_TYPE_BOOL;
@@ -672,14 +640,7 @@ static int v4l2_read_attr(struct ng_attribute *attr)
if (NULL != ctl) {
c.id = ctl->id;
xioctl(h->fd,VIDIOC_G_CTRL,&c,0);
- if (ctl->type == V4L2_CTRL_TYPE_INTEGER) {
- value = v4l2_to_me(ctl,c.value);
- if (ng_debug)
- fprintf(stderr,"v4l2: attr read int %d => %d\n",
- c.value,value);
- } else {
- value = c.value;
- }
+ value = c.value;
} else if (attr->id == ATTR_ID_NORM) {
value = -1; /* FIXME */
@@ -691,6 +652,7 @@ static int v4l2_read_attr(struct ng_attribute *attr)
memset(&tuner,0,sizeof(tuner));
xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
value = tuner.audmode;
+#if 1
if (ng_debug) {
fprintf(stderr,"v4l2: tuner cap:%s%s%s\n",
(tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
@@ -707,6 +669,7 @@ static int v4l2_read_attr(struct ng_attribute *attr)
(tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "",
(tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : "");
}
+#endif
}
return value;
}
@@ -720,14 +683,7 @@ static void v4l2_write_attr(struct ng_attribute *attr, int value)
if (NULL != ctl) {
c.id = ctl->id;
- if (ctl->type == V4L2_CTRL_TYPE_INTEGER) {
- c.value = me_to_v4l2(ctl,value);
- if (ng_debug)
- fprintf(stderr,"v4l2: attr write int %d => %d\n",
- value,c.value);
- } else {
- c.value = value;
- }
+ c.value = value;
xioctl(h->fd,VIDIOC_S_CTRL,&c,0);
} else if (attr->id == ATTR_ID_NORM) {
@@ -947,9 +903,11 @@ v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
if (NULL == fmt) {
if (ng_debug)
fprintf(stderr,"v4l2: overlay off\n");
- h->ov_enabled = 0;
- h->ov_on = 0;
- xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
+ if (h->ov_enabled) {
+ h->ov_enabled = 0;
+ h->ov_on = 0;
+ xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
+ }
return 0;
}
@@ -1092,7 +1050,7 @@ v4l2_start_streaming(struct v4l2_handle *h, int buffers)
h->buf_me[i].fmt = h->fmt_me;
h->buf_me[i].size = h->buf_me[i].fmt.bytesperline *
h->buf_me[i].fmt.height;
- h->buf_me[i].data = mmap(NULL, h->buf_me[i].size,
+ h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
h->fd, h->buf_v4l2[i].offset);
if ((void*)-1 == h->buf_me[i].data) {
@@ -1308,5 +1266,5 @@ v4l2_getimage(void *handle)
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_vid_driver_register(&v4l2_driver);
+ ng_vid_driver_register(NG_PLUGIN_MAGIC,PLUGNAME,&v4l2_driver);
}
diff --git a/libng/plugins/drv1-v4l.c b/libng/plugins/drv1-v4l.c
index 7a8d6ba..144c139 100644
--- a/libng/plugins/drv1-v4l.c
+++ b/libng/plugins/drv1-v4l.c
@@ -354,6 +354,10 @@ v4l_add_attr(struct v4l_handle *h, int id, int type,
h->attr[h->nattr].type = type;
h->attr[h->nattr].defval = defval;
h->attr[h->nattr].choices = choices;
+ if (ATTR_TYPE_INTEGER == type) {
+ h->attr[h->nattr].min = 0;
+ h->attr[h->nattr].max = 65535;
+ }
if (id < ATTR_ID_COUNT)
h->attr[h->nattr].name = ng_attr_to_desc[id];
@@ -1275,5 +1279,5 @@ v4l_getimage(void *handle)
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_vid_driver_register(&v4l_driver);
+ ng_vid_driver_register(NG_PLUGIN_MAGIC,PLUGNAME,&v4l_driver);
}
diff --git a/libng/plugins/flt-debug.c b/libng/plugins/flt-debug.c
new file mode 100644
index 0000000..e7d2c08
--- /dev/null
+++ b/libng/plugins/flt-debug.c
@@ -0,0 +1,124 @@
+/*
+ * This plugin provides some filter controls (for GUI code debugging).
+ * It does nothing else, video frames just passed through as-is.
+ *
+ * You can have a look at the invert filter for sample code which
+ * actually does some image processing.
+ *
+ * (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "grab-ng.h"
+
+/* ------------------------------------------------------------------- */
+
+static void *init(struct ng_video_fmt *out)
+{
+ /* don't have to carry around status info */
+ static int dummy;
+ return &dummy;
+}
+
+static struct ng_video_buf*
+frame(void *handle, struct ng_video_buf *in)
+{
+ /* do nothing -- just return the frame as-is */
+ return in;
+}
+
+static void fini(void *handle)
+{
+ /* nothing to clean up */
+}
+
+/* ------------------------------------------------------------------- */
+
+static int vals[3] = { 32, 1, 2 };
+
+static int read_attr(struct ng_attribute *attr)
+{
+ return vals[attr->id];
+}
+
+static void write_attr(struct ng_attribute *attr, int value)
+{
+ fprintf(stderr,PLUGNAME ": %s: %d\n", attr->name, value);
+ vals[attr->id] = value;
+}
+
+/* ------------------------------------------------------------------- */
+
+static struct STRTAB items[] = {
+ { 1, "entry 1" },
+ { 2, "entry 2" },
+ { 3, "entry 3" },
+ { -1, NULL },
+};
+
+static struct ng_attribute attrs[] = {
+ {
+ id: 0,
+ name: "scale (integer)",
+ type: ATTR_TYPE_INTEGER,
+ min: 0,
+ max: 100,
+ read: read_attr,
+ write: write_attr,
+ },{
+ id: 1,
+ name: "yes/no (boolean)",
+ type: ATTR_TYPE_BOOL,
+ read: read_attr,
+ write: write_attr,
+ },{
+ id: 2,
+ name: "menu (choice)",
+ type: ATTR_TYPE_CHOICE,
+ choices: items,
+ read: read_attr,
+ write: write_attr,
+ },{
+ /* end of list */
+ }
+};
+
+static struct ng_filter filter = {
+ name: "gui debug",
+ attrs: attrs,
+ fmts:
+ (1 << VIDEO_RGB08) |
+ (1 << VIDEO_GRAY) |
+ (1 << VIDEO_RGB15_LE) |
+ (1 << VIDEO_RGB16_LE) |
+ (1 << VIDEO_RGB15_BE) |
+ (1 << VIDEO_RGB16_BE) |
+ (1 << VIDEO_BGR24) |
+ (1 << VIDEO_BGR32) |
+ (1 << VIDEO_RGB24) |
+ (1 << VIDEO_RGB32) |
+ (1 << VIDEO_YUV422) |
+ (1 << VIDEO_YUV422P) |
+ (1 << VIDEO_YUV420P),
+ init: init,
+ frame: frame,
+ fini: fini,
+};
+
+extern void ng_plugin_init(void);
+void ng_plugin_init(void)
+{
+ ng_filter_register(NG_PLUGIN_MAGIC,PLUGNAME,&filter);
+}
+
+/*
+ * Local variables:
+ * compile-command: "make flt-debug.so"
+ * End:
+ */
diff --git a/libng/plugins/flt-gamma.c b/libng/plugins/flt-gamma.c
new file mode 100644
index 0000000..00b47ed
--- /dev/null
+++ b/libng/plugins/flt-gamma.c
@@ -0,0 +1,180 @@
+/*
+ * libng filter -- gamma correction
+ *
+ * (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <pthread.h>
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+
+#include "grab-ng.h"
+
+/* ------------------------------------------------------------------- */
+
+static unsigned char lut[256];
+static int g = 100;
+
+static void inline
+gamma_bytes(unsigned char *dst, unsigned char *src, int bytes)
+{
+ while (bytes--)
+ *(dst++) = lut[ *(src++) ];
+}
+
+static void inline
+gamma_native_rgb15(void *d, void *s, int pixels)
+{
+ unsigned short *dst = d;
+ unsigned short *src = s;
+ unsigned short r,g,b;
+
+ while (pixels--) {
+ r = lut[ ((*src >> 7) & 0xf8) ] & 0xf8;
+ g = lut[ ((*src >> 2) & 0xf8) ] & 0xf8;
+ b = lut[ ((*src << 3) & 0xf8) ] & 0xf8;
+ *dst = (r << 7) | (g << 2) | (b >> 3);
+ src++; dst++;
+ }
+}
+
+static void inline
+gamma_native_rgb16(void *d, void *s, int pixels)
+{
+ unsigned short *dst = d;
+ unsigned short *src = s;
+ unsigned short r,g,b;
+
+ while (pixels--) {
+ r = lut[ ((*src >> 8) & 0xf8) ] & 0xf8;
+ g = lut[ ((*src >> 3) & 0xfc) ] & 0xfc;
+ b = lut[ ((*src << 3) & 0xf8) ] & 0xf8;
+ *dst = (r << 8) | (g << 3) | (b >> 3);
+ src++; dst++;
+ }
+}
+
+/* ------------------------------------------------------------------- */
+
+static void *init(struct ng_video_fmt *out)
+{
+ /* don't have to carry around status info */
+ static int dummy;
+ return &dummy;
+}
+
+static struct ng_video_buf*
+frame(void *handle, struct ng_video_buf *in)
+{
+ struct ng_video_buf *out;
+ unsigned char *dst;
+ unsigned char *src;
+ int y,cnt;
+
+ out = ng_malloc_video_buf(&in->fmt, in->fmt.height * in->fmt.bytesperline);
+ out->info = in->info;
+
+ dst = out->data;
+ src = in->data;
+ cnt = in->fmt.width * ng_vfmt_to_depth[in->fmt.fmtid] / 8;
+ for (y = 0; y < in->fmt.height; y++) {
+ switch (in->fmt.fmtid) {
+ case VIDEO_GRAY:
+ case VIDEO_BGR24:
+ case VIDEO_RGB24:
+ case VIDEO_BGR32:
+ case VIDEO_RGB32:
+ gamma_bytes(dst,src,cnt);
+ break;
+ case VIDEO_RGB15_NATIVE:
+ gamma_native_rgb15(dst,src,in->fmt.width);
+ break;
+ case VIDEO_RGB16_NATIVE:
+ gamma_native_rgb16(dst,src,in->fmt.width);
+ break;
+ }
+ dst += out->fmt.bytesperline;
+ src += in->fmt.bytesperline;
+ }
+
+ ng_release_video_buf(in);
+ return out;
+}
+
+static void fini(void *handle)
+{
+ /* nothing to clean up */
+}
+
+/* ------------------------------------------------------------------- */
+
+static void calc_lut(void)
+{
+ int i,val;
+
+ for (i = 0; i < 256; i++) {
+ val = 255 * pow((float)i/255, 10000.0/g);
+ if (val < 0) val = 0;
+ if (val > 255) val = 255;
+ lut[i] = val;
+ }
+}
+
+static int read_attr(struct ng_attribute *attr)
+{
+ return g;
+}
+
+static void write_attr(struct ng_attribute *attr, int value)
+{
+ g = value;
+ calc_lut();
+}
+
+/* ------------------------------------------------------------------- */
+
+static struct ng_attribute attrs[] = {
+ {
+ id: 0,
+ name: "gamma value",
+ type: ATTR_TYPE_INTEGER,
+ defval: 100,
+ min: 1,
+ max: 999,
+ points: 2,
+ read: read_attr,
+ write: write_attr,
+ },{
+ /* end of list */
+ }
+};
+
+static struct ng_filter filter = {
+ name: "gamma",
+ attrs: attrs,
+ fmts:
+ (1 << VIDEO_GRAY) |
+ (1 << VIDEO_RGB15_NATIVE) |
+ (1 << VIDEO_RGB16_NATIVE) |
+ (1 << VIDEO_BGR24) |
+ (1 << VIDEO_RGB24) |
+ (1 << VIDEO_BGR32) |
+ (1 << VIDEO_RGB32),
+ init: init,
+ frame: frame,
+ fini: fini,
+};
+
+extern void ng_plugin_init(void);
+void ng_plugin_init(void)
+{
+ calc_lut();
+ ng_filter_register(NG_PLUGIN_MAGIC,PLUGNAME,&filter);
+}
diff --git a/libng/plugins/flt-invert.c b/libng/plugins/flt-invert.c
index f2809dd..8621a86 100644
--- a/libng/plugins/flt-invert.c
+++ b/libng/plugins/flt-invert.c
@@ -131,5 +131,5 @@ static struct ng_filter filter = {
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_filter_register(&filter);
+ ng_filter_register(NG_PLUGIN_MAGIC,PLUGNAME,&filter);
}
diff --git a/libng/plugins/flt-nop.c b/libng/plugins/flt-nop.c
deleted file mode 100644
index 62701f2..0000000
--- a/libng/plugins/flt-nop.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * very simple libng filter -- does nothing.
- * main purpose is to have one bugfree[tm] plugin for debugging.
- *
- * If you looking for a template for your own plugin better have a
- * look at invert.c. This one is very simple too, but it serves
- * better as template because it actually does something.
- *
- * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-
-#include "grab-ng.h"
-
-/* ------------------------------------------------------------------- */
-
-static void *init(struct ng_video_fmt *out)
-{
- /* don't have to carry around status info */
- static int dummy;
- return &dummy;
-}
-
-static struct ng_video_buf*
-frame(void *handle, struct ng_video_buf *in)
-{
- /* do nothing -- just return the frame as-is */
- return in;
-}
-
-static void fini(void *handle)
-{
- /* nothing to clean up */
-}
-
-/* ------------------------------------------------------------------- */
-
-static struct ng_filter filter = {
- name: "nop",
- fmts:
- (1 << VIDEO_RGB08) |
- (1 << VIDEO_GRAY) |
- (1 << VIDEO_RGB15_LE) |
- (1 << VIDEO_RGB16_LE) |
- (1 << VIDEO_RGB15_BE) |
- (1 << VIDEO_RGB16_BE) |
- (1 << VIDEO_BGR24) |
- (1 << VIDEO_BGR32) |
- (1 << VIDEO_RGB24) |
- (1 << VIDEO_RGB32) |
- (1 << VIDEO_YUV422) |
- (1 << VIDEO_YUV422P) |
- (1 << VIDEO_YUV420P),
- init: init,
- frame: frame,
- fini: fini,
-};
-
-extern void ng_plugin_init(void);
-void ng_plugin_init(void)
-{
- ng_filter_register(&filter);
-}
diff --git a/libng/plugins/snd-oss.c b/libng/plugins/snd-oss.c
index 69058ed..2546976 100644
--- a/libng/plugins/snd-oss.c
+++ b/libng/plugins/snd-oss.c
@@ -43,6 +43,8 @@ static struct ng_attribute mixer_attrs[] = {
id: ATTR_ID_VOLUME,
name: "volume",
type: ATTR_TYPE_INTEGER,
+ min: 0,
+ max: 100,
read: mixer_read_attr,
write: mixer_write_attr,
},{
@@ -120,7 +122,7 @@ mixer_read_attr(struct ng_attribute *attr)
case ATTR_ID_VOLUME:
if (-1 == ioctl(h->mix,MIXER_READ(h->dev),&h->volume))
perror("oss mixer read volume");
- vol = (h->volume & 0x7f) * 65535 / 100;
+ vol = h->volume & 0x7f;
return vol;
case ATTR_ID_MUTE:
return h->muted;
@@ -136,7 +138,6 @@ mixer_write_attr(struct ng_attribute *attr, int val)
switch (attr->id) {
case ATTR_ID_VOLUME:
- val = val * 100 / 65535;
val &= 0x7f;
h->volume = val | (val << 8);
if (-1 == ioctl(h->mix,MIXER_WRITE(h->dev),&h->volume))
@@ -464,6 +465,6 @@ static struct ng_dsp_driver oss_dsp = {
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_dsp_driver_register(&oss_dsp);
- ng_mix_driver_register(&oss_mixer);
+ ng_dsp_driver_register(NG_PLUGIN_MAGIC,PLUGNAME,&oss_dsp);
+ ng_mix_driver_register(NG_PLUGIN_MAGIC,PLUGNAME,&oss_mixer);
}
diff --git a/libng/plugins/write-avi.c b/libng/plugins/write-avi.c
index 8bf289b..70fa72a 100644
--- a/libng/plugins/write-avi.c
+++ b/libng/plugins/write-avi.c
@@ -665,5 +665,5 @@ struct ng_writer avi_writer = {
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_writer_register(&avi_writer);
+ ng_writer_register(NG_PLUGIN_MAGIC,PLUGNAME,&avi_writer);
}
diff --git a/libng/plugins/write-qt.c b/libng/plugins/write-qt.c
index 94c0179..4e364d1 100644
--- a/libng/plugins/write-qt.c
+++ b/libng/plugins/write-qt.c
@@ -1,5 +1,4 @@
#include "config.h"
-#ifdef HAVE_LIBQUICKTIME
#include <stdlib.h>
#include <stdio.h>
@@ -286,7 +285,5 @@ struct ng_writer qt_writer = {
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
- ng_writer_register(&qt_writer);
+ ng_writer_register(NG_PLUGIN_MAGIC,PLUGNAME,&qt_writer);
}
-
-#endif /* HAVE_LIBQUICKTIME */
diff --git a/libng/writefile.c b/libng/writefile.c
index 88dd100..8393a69 100644
--- a/libng/writefile.c
+++ b/libng/writefile.c
@@ -608,6 +608,6 @@ struct ng_writer raw_writer = {
void
ng_writefile_init(void)
{
- ng_writer_register(&files_writer);
- ng_writer_register(&raw_writer);
+ ng_writer_register(NG_PLUGIN_MAGIC,"built-in",&files_writer);
+ ng_writer_register(NG_PLUGIN_MAGIC,"built-in",&raw_writer);
}
diff --git a/man/xawtv-remote.1 b/man/xawtv-remote.1
index f3e1201..f3b038c 100644
--- a/man/xawtv-remote.1
+++ b/man/xawtv-remote.1
@@ -66,20 +66,21 @@ Set the video input (Television/Composite1/...)
.B capture [ on | off | overlay | grabdisplay ]
Set capture mode.
.TP
-.B volume <n>
+.B volume <arg>
.TP
-.B color <n>
+.B color <arg>
.TP
-.B hue <n>
+.B hue <arg>
.TP
-.B bright <n>
+.B bright <arg>
.TP
-.B contrast <n>
-Set the parameter to the specified value. Range for all values is 0
-<= n <= 65535. <n> can be either absolute (like "32768") or relative
-(marked by a sign, like "+1000" or "-512"). "inc" and "dec" are
-accepted too and increase/decrease the parameter by one percent.
-"volume" additionally accepts "mute".
+.B contrast <arg>
+Set the parameter to the specified value. <arg> can be one of the
+following: A percent value ("70%" for example). Some absolute value
+("32768"), the valid range is hardware specific. Relative values can
+be specified too by prefixing with "+=" or "-=" ("+=10%" or "-=2000").
+The keywords "inc" and "dec" are accepted to and will increase and
+decrease the given value in small steps.
.TP
.B setattr <name> <value>
Set set the value of some attribute (color, contrast, ... can be set
@@ -88,6 +89,10 @@ this way too).
.B show [ <name> ]
Show the value current of some attribute.
.TP
+.B list
+List all available attributes with all properties (default value,
+range, ...)
+.TP
.B snap [ jpeg | ppm ] [ full | win | widthxheight ] <filename>
Capture one image.
.TP
diff --git a/radio/radio.c b/radio/radio.c
index e69120d..1a66605 100644
--- a/radio/radio.c
+++ b/radio/radio.c
@@ -210,20 +210,23 @@ make_label(int ifreq)
float g[411],baseline;
int astation[100],max_astation=0,current_astation=-1;
+int write_config;
static void
foundone(int m)
{
int i;
- for(i=0;i<100 && astation[i];i++) {
+ for (i=0; i<100 && astation[i]; i++) {
if(abs(astation[i]-m) <5 ) // 20 kHz width
break;
}
- if(g[m] > g[astation[i]]) { // select bigger signal
+ if (g[m] > g[astation[i]]) { // select bigger signal
astation[i]=m;
max_astation=i;
fprintf(stderr,"Station %2d: %6.2f MHz - %.2f\n",i,87.5+m*0.05,g[m]);
+ if (write_config)
+ printf("%d0000=scan-%d\n",(int)((87.5+m*0.05)*100),i);
}
}
@@ -306,6 +309,8 @@ findstations(void)
if(g[i]>maxg) maxg=g[i];
}
+ if (write_config)
+ printf("[Stations]\n");
baseline=get_baseline(ming,maxg);
findmax();
}
@@ -358,6 +363,8 @@ usage(FILE *out)
" -c dev use given device [default: %s]\n"
" -s scan\n"
" -S scan + write radio.fmmap\n"
+ " -i scan, write initial ~/.radio config file to\n"
+ " stdout and quit\n"
" -q quit. Useful with other options to control the\n"
" radio device without entering interactive mode,\n"
" i.e. \"radio -qf 91.4\"\n"
@@ -381,7 +388,7 @@ main(int argc, char *argv[])
/* parse args */
for (;;) {
- c = getopt(argc, argv, "mhqdsSf:c:");
+ c = getopt(argc, argv, "mhiqdsSf:c:");
if (c == -1)
break;
switch (c) {
@@ -400,6 +407,11 @@ main(int argc, char *argv[])
case 's':
scan = 1;
break;
+ case 'i':
+ write_config = 1;
+ scan = 1;
+ quit = 1;
+ break;
case 'f':
if (1 == sscanf(optarg,"%f",&ffreq)) {
ifreq = (int)(ffreq * 1000000);
@@ -493,11 +505,11 @@ main(int argc, char *argv[])
wrefresh(wcommand);
/* JMMV: Added key information and windows division */
- mvwprintw(woptions, 1, 1, "UP Key - increment frequency");
- mvwprintw(woptions, 2, 1, "DOWN Key - decrease frequency");
- mvwprintw(woptions, 3, 1, "g - go to frequency...");
- mvwprintw(woptions, 4, 1, "x - exit");
- mvwprintw(woptions, 5, 1, "ESC, q, e - mute and exit");
+ mvwprintw(woptions, 1, 1, "Up/Down - inc/dec frequency");
+ mvwprintw(woptions, 2, 1, "PgUp/PgDown - next/prev station");
+ mvwprintw(woptions, 3, 1, "g - go to frequency...");
+ mvwprintw(woptions, 4, 1, "x - exit");
+ mvwprintw(woptions, 5, 1, "ESC, q, e - mute and exit");
wrefresh(woptions);
for (i = 0, c = 1; i < 8; i++) {
if (fkeys[i]) {
@@ -573,6 +585,7 @@ main(int argc, char *argv[])
break;
case KEY_PPAGE:
case KEY_NPAGE:
+ case ' ':
if (max_astation) {
current_astation += (key == KEY_NPAGE) ? -1 : 1;
if(current_astation<0)
@@ -580,6 +593,17 @@ main(int argc, char *argv[])
if(current_astation>max_astation)
current_astation=0;
ifreq=87500000+astation[current_astation]*50000;
+ } else {
+ for (i = 0; i < stations; i++) {
+ if (ifreq == freqs[i])
+ break;
+ }
+ if (i != stations) {
+ i += (key == KEY_NPAGE) ? -1 : 1;
+ if (i < 0 || i >= stations)
+ i = 0;
+ ifreq = freqs[i];
+ }
}
break;
case '1':
@@ -603,7 +627,19 @@ main(int argc, char *argv[])
ifreq = fkeys[i];
mvwprintw(wcommand, 1, 2, "Go to preset station %d", i+1);
}
- break;
+ break;
+ case 'L' & 0x1f: /* Ctrl-L */
+ redrawwin(stdscr);
+ redrawwin(wfreq);
+ redrawwin(woptions);
+ redrawwin(wstations);
+ redrawwin(wcommand);
+ wrefresh(stdscr);
+ wrefresh(wfreq);
+ wrefresh(woptions);
+ wrefresh(wstations);
+ wrefresh(wcommand);
+ break;
}
}
if (mute)
diff --git a/radio/radio.man b/radio/radio.man
index e60a4a3..8fc4904 100644
--- a/radio/radio.man
+++ b/radio/radio.man
@@ -35,6 +35,12 @@ Do a scan for radio stations.
Same as above + write a radio.fmmap with the signal for every
frequency. You can get a graph for it with gnuplot (plot
"radio.fmmap" w lin).
+.TP
+.B -i
+Scan, write a initial ~/.radio file to stdout and quit. So you can
+create a config file where you only have to fill in the correct
+station names later this way: "radio -i > ~/.radio". See below for
+the config file syntax.
.SH CONFIGURATION
.B radio
picks up station names and present stations from a config file.
@@ -64,6 +70,19 @@ The [Buttons] section can have up to eight entries. That are
the present stations, they get mapped to F1-F8. The [Stations]
section maps frequencies to station names. The frequencies in
both sections are specified in Hz.
+.SH KEYS
+.nf
+X exit
+ESC,Q,E mute and exit.
+up/down inc/dec frequency
+pgup/pgdown next/previous station. This one uses the
+ stations from the config file by default.
+ When started with the -s option these keys
+ will cycle througth the stations found during
+ the scan.
+F1-F8, 1-8 preset buttons.
+Ctrl+L redraw screen.
+.fi
.SH AUTHOR
Gerd Knorr <kraxel@bytesex.org>
.SH COPYRIGHT
diff --git a/radio/x b/radio/x
new file mode 100644
index 0000000..25a5fd3
--- /dev/null
+++ b/radio/x
@@ -0,0 +1,21 @@
+[Stations]
+87900000=scan-0
+89550000=scan-1
+90150000=scan-2
+91350000=scan-3
+93600000=scan-4
+94300000=scan-5
+95800000=scan-6
+97650000=scan-7
+98800000=scan-8
+99650000=scan-9
+100600000=scan-10
+101250000=scan-11
+101850000=scan-12
+102600000=scan-13
+103400000=scan-14
+104600000=scan-15
+105500000=scan-16
+105950000=scan-17
+106800000=scan-18
+107450000=scan-19
diff --git a/src/Makefile.in b/src/Makefile.in
index 7c478a0..4483a4d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -106,6 +106,10 @@ xawtv-remote: xawtv-remote.o
mididump: midictrl.c
$(CC) $(CFLAGS) -DSTANDALONE -o $@ $(srcdir)/midictrl.c $(ALSA_LIBS)
+gl: gl.o RegEdit.o
+ $(CC) $(CFLAGS) -o $@ gl.o RegEdit.o $(MOTIF_LIBS) \
+ -lGLU -lGL -lng -ljpeg $(DLFLAGS)
+
channel-no-x11.o: $(srcdir)/channel.c
$(CC) $(CFLAGS) -DNO_X11=1 -c -o $@ $(srcdir)/channel.c
@@ -164,9 +168,9 @@ clean:
-rm -f *.o *.moc *core TAGS Xawtv.h MoTV.h MoTV.ad $(I18N)
realclean distclean: clean
- -rm -f $(PROGS) Makefile *~ *.bak
+ -rm -f $(PROGS) Makefile *~ *.bak gl
-depend dep: Xawtv.h MoTV.h
+depend dep: Xawtv.h MoTV.h gl.h
$(DEPEND) -- $(CFLAGS) -- *.c
diff --git a/src/MoTV-de b/src/MoTV-de
index 8626825..1d973d7 100644
--- a/src/MoTV-de
+++ b/src/MoTV-de
@@ -35,7 +35,7 @@ MoTV.about_box_popup.title: Über motv
MoTV*about_box_popup*messageString: \
motv - Motif TV application \n\
\n\
- (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2002 Gerd Knorr <kraxel@bytesex.org>
MoTV.errbox_popup.title: Fehler
@@ -171,8 +171,8 @@ control*menubar*norm.labelString: Fernsehnorm
control*menubar*norm.mnemonic: n
! filter menu
-control*menubar*none.labelString: Kein filter
-control*menubar*none.mnemonic: K
+control*menubar*fnone.labelString: Kein filter
+control*menubar*fnone.mnemonic: K
! help menu
control*menubar*man.labelString: Manual anzeigen
diff --git a/src/MoTV-default b/src/MoTV-default
index 5c68b6b..526adc1 100644
--- a/src/MoTV-default
+++ b/src/MoTV-default
@@ -35,7 +35,7 @@ MoTV.about_box_popup.title: About motv
MoTV*about_box_popup*messageString: \
motv - Motif TV application \n\
\n\
- (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2002 Gerd Knorr <kraxel@bytesex.org>
MoTV.errbox_popup.title: Errors
@@ -175,8 +175,8 @@ control*menubar*norm.labelString: TV Norm
control*menubar*norm.mnemonic: N
! filter menu
-control*menubar*none.labelString: No filter
-control*menubar*none.mnemonic: N
+control*menubar*fnone.labelString: No filter
+control*menubar*fnone.mnemonic: N
! help menu
control*menubar*man.labelString: Show manpage
diff --git a/src/MoTV-fixed b/src/MoTV-fixed
index 9a96802..6a7c422 100644
--- a/src/MoTV-fixed
+++ b/src/MoTV-fixed
@@ -179,11 +179,9 @@ control.form.status.f.?.labelString:
scale.form.shadowThickness: 0
scale*XmScale.orientation: HORIZONTAL
-scale*XmScale.showValue: false
+scale*XmScale.showValue: true
scale*XmScale.highlightOnEnter: true
scale*XmScale.highlightThickness: 1
-scale*XmScale.minimum: 0
-scale*XmScale.maximum: 65535
scale*XmScale.topAttachment: ATTACH_WIDGET
scale*XmScale.leftAttachment: ATTACH_FORM
scale*XmScale.rightAttachment: ATTACH_FORM
@@ -195,6 +193,16 @@ scale*XmScale.width: 160
! ----------------------------------------------------------------------------
+! filter property controls
+
+filter*label.frameChildType: FRAME_TITLE_CHILD
+filter*XmScale.showValue: true
+filter*XmScale.highlightOnEnter: true
+filter*XmScale.highlightThickness: 1
+filter*XmScale.orientation: HORIZONTAL
+
+
+! ----------------------------------------------------------------------------
! levels window (sound level monitor)
levels*highlightThickness: 1
diff --git a/src/MoTV-it b/src/MoTV-it
index 61ef5e4..41b81fd 100644
--- a/src/MoTV-it
+++ b/src/MoTV-it
@@ -36,7 +36,7 @@ MoTV.about_box_popup.title: Info su motv
MoTV*about_box_popup*messageString: \
motv - Motif TV application \n\
\n\
- (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2002 Gerd Knorr <kraxel@bytesex.org>
MoTV.errbox_popup.title: Errori
@@ -176,8 +176,8 @@ control*menubar*norm.labelString: Protocollo TV
control*menubar*norm.mnemonic: N
! filter menu
-!control*menubar*none.labelString: No filter
-!control*menubar*none.mnemonic: N
+!control*menubar*fnone.labelString: No filter
+!control*menubar*fnone.mnemonic: N
! help menu
control*menubar*man.labelString: Mostra la manpage
diff --git a/src/MoTV.de.ad b/src/MoTV.de.ad
index 9955c9a..6aa818a 100644
--- a/src/MoTV.de.ad
+++ b/src/MoTV.de.ad
@@ -35,7 +35,7 @@ MoTV.about_box_popup.title: Über motv
MoTV*about_box_popup*messageString: \
motv - Motif TV application \n\
\n\
- (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2002 Gerd Knorr <kraxel@bytesex.org>
MoTV.errbox_popup.title: Fehler
@@ -171,8 +171,8 @@ control*menubar*norm.labelString: Fernsehnorm
control*menubar*norm.mnemonic: n
! filter menu
-control*menubar*none.labelString: Kein filter
-control*menubar*none.mnemonic: K
+control*menubar*fnone.labelString: Kein filter
+control*menubar*fnone.mnemonic: K
! help menu
control*menubar*man.labelString: Manual anzeigen
@@ -440,11 +440,9 @@ control.form.status.f.?.labelString:
scale.form.shadowThickness: 0
scale*XmScale.orientation: HORIZONTAL
-scale*XmScale.showValue: false
+scale*XmScale.showValue: true
scale*XmScale.highlightOnEnter: true
scale*XmScale.highlightThickness: 1
-scale*XmScale.minimum: 0
-scale*XmScale.maximum: 65535
scale*XmScale.topAttachment: ATTACH_WIDGET
scale*XmScale.leftAttachment: ATTACH_FORM
scale*XmScale.rightAttachment: ATTACH_FORM
@@ -456,6 +454,16 @@ scale*XmScale.width: 160
! ----------------------------------------------------------------------------
+! filter property controls
+
+filter*label.frameChildType: FRAME_TITLE_CHILD
+filter*XmScale.showValue: true
+filter*XmScale.highlightOnEnter: true
+filter*XmScale.highlightThickness: 1
+filter*XmScale.orientation: HORIZONTAL
+
+
+! ----------------------------------------------------------------------------
! levels window (sound level monitor)
levels*highlightThickness: 1
diff --git a/src/MoTV.it.ad b/src/MoTV.it.ad
index 8cd2fd0..fd60263 100644
--- a/src/MoTV.it.ad
+++ b/src/MoTV.it.ad
@@ -36,7 +36,7 @@ MoTV.about_box_popup.title: Info su motv
MoTV*about_box_popup*messageString: \
motv - Motif TV application \n\
\n\
- (c) 2001 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2002 Gerd Knorr <kraxel@bytesex.org>
MoTV.errbox_popup.title: Errori
@@ -176,8 +176,8 @@ control*menubar*norm.labelString: Protocollo TV
control*menubar*norm.mnemonic: N
! filter menu
-!control*menubar*none.labelString: No filter
-!control*menubar*none.mnemonic: N
+!control*menubar*fnone.labelString: No filter
+!control*menubar*fnone.mnemonic: N
! help menu
control*menubar*man.labelString: Mostra la manpage
@@ -446,11 +446,9 @@ control.form.status.f.?.labelString:
scale.form.shadowThickness: 0
scale*XmScale.orientation: HORIZONTAL
-scale*XmScale.showValue: false
+scale*XmScale.showValue: true
scale*XmScale.highlightOnEnter: true
scale*XmScale.highlightThickness: 1
-scale*XmScale.minimum: 0
-scale*XmScale.maximum: 65535
scale*XmScale.topAttachment: ATTACH_WIDGET
scale*XmScale.leftAttachment: ATTACH_FORM
scale*XmScale.rightAttachment: ATTACH_FORM
@@ -462,6 +460,16 @@ scale*XmScale.width: 160
! ----------------------------------------------------------------------------
+! filter property controls
+
+filter*label.frameChildType: FRAME_TITLE_CHILD
+filter*XmScale.showValue: true
+filter*XmScale.highlightOnEnter: true
+filter*XmScale.highlightThickness: 1
+filter*XmScale.orientation: HORIZONTAL
+
+
+! ----------------------------------------------------------------------------
! levels window (sound level monitor)
levels*highlightThickness: 1
diff --git a/src/capture.c b/src/capture.c
index 8a65b7b..a309bf2 100644
--- a/src/capture.c
+++ b/src/capture.c
@@ -746,6 +746,9 @@ movie_grab_put_video(struct movie_handle *h, struct ng_video_buf **ret)
buf = ng_grabber_grab_image(0);
if (NULL == buf)
return -1;
+#if 0 /* FIXME */
+ buf = ng_filter_single(cur_filter,buf);
+#endif
/* rate control */
expected = buf->info.ts * h->fps / 1000000000000;
diff --git a/src/channel.c b/src/channel.c
index a267a4c..221a62a 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -53,7 +53,7 @@
struct CHANNEL defaults = {
name: "defaults",
cname: "none",
- capture: CAPTURE_OVERLAY,
+ capture: CAPTURE_ON,
audio: -1,
color: -1,
bright: -1,
@@ -69,7 +69,7 @@ int last_sender = -1, cur_sender = -1, cur_channel = -1, cur_fine = 0;
int cur_freq;
struct ng_filter *cur_filter;
-int cur_capture;
+int cur_capture = CAPTURE_OFF;
int have_config;
int keypad_ntsc = 0;
int keypad_partial = 1;
@@ -342,18 +342,22 @@ init_channel(char *name, struct CHANNEL *c)
c->fine = n;
if (NULL != (val = cfg_get_str(name,"key")))
- c->key = strdup(val);
- if (-1 != (n = attr_to_int(cfg_get_str(name,"midi"))))
- c->midi = n;
-
- if (-1 != (n = attr_to_int(cfg_get_str(name,"color"))))
- c->color = n;
- if (-1 != (n = attr_to_int(cfg_get_str(name,"bright"))))
- c->bright = n;
- if (-1 != (n = attr_to_int(cfg_get_str(name,"hue"))))
- c->hue = n;
- if (-1 != (n = attr_to_int(cfg_get_str(name,"contrast"))))
- c->contrast = n;
+ c->key = strdup(val);
+ if (NULL != (val = cfg_get_str(name,"midi")))
+ c->midi = atoi(val);
+
+ attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
+ if (attr && NULL != (val = cfg_get_str(name,"color")))
+ c->color = ng_attr_parse_int(attr,val);
+ attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
+ if (attr && NULL != (val = cfg_get_str(name,"bright")))
+ c->bright = ng_attr_parse_int(attr,val);
+ attr = ng_attr_byid(attrs,ATTR_ID_HUE);
+ if (attr && NULL != (val = cfg_get_str(name,"hue")))
+ c->hue = ng_attr_parse_int(attr,val);
+ attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
+ if (attr && NULL != (val = cfg_get_str(name,"contrast")))
+ c->contrast = ng_attr_parse_int(attr,val);
}
void
@@ -503,6 +507,7 @@ parse_config(void)
void
save_config()
{
+ struct ng_attribute *attr;
char filename1[100], filename2[100];
FILE *fp;
int i;
@@ -589,14 +594,23 @@ save_config()
ng_attr_getstr(ng_attr_byid(attrs,ATTR_ID_INPUT),
cur_attrs[ATTR_ID_INPUT]));
fprintf(fp,"capture = %s\n",int_to_str(cur_capture,captab));
- if (cur_attrs[ATTR_ID_COLOR] != 32768)
- fprintf(fp,"color = %d\n",cur_attrs[ATTR_ID_COLOR]);
- if (cur_attrs[ATTR_ID_BRIGHT] != 32768)
- fprintf(fp,"bright = %d\n",cur_attrs[ATTR_ID_BRIGHT]);
- if (cur_attrs[ATTR_ID_HUE] != 32768)
- fprintf(fp,"hue = %d\n",cur_attrs[ATTR_ID_HUE]);
- if (cur_attrs[ATTR_ID_CONTRAST] != 32768)
- fprintf(fp,"contrast = %d\n",cur_attrs[ATTR_ID_CONTRAST]);
+
+ attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
+ if (attr && attr->defval != cur_attrs[ATTR_ID_COLOR])
+ fprintf(fp,"color = %d%%\n",
+ ng_attr_int2percent(attr,cur_attrs[ATTR_ID_COLOR]));
+ attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
+ if (attr && attr->defval != cur_attrs[ATTR_ID_BRIGHT])
+ fprintf(fp,"bright = %d%%\n",
+ ng_attr_int2percent(attr,cur_attrs[ATTR_ID_BRIGHT]));
+ attr = ng_attr_byid(attrs,ATTR_ID_HUE);
+ if (attr && attr->defval != cur_attrs[ATTR_ID_HUE])
+ fprintf(fp,"hue = %d%%\n",
+ ng_attr_int2percent(attr,cur_attrs[ATTR_ID_HUE]));
+ attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
+ if (attr && attr->defval != cur_attrs[ATTR_ID_CONTRAST])
+ fprintf(fp,"contrast = %d%%\n",
+ ng_attr_int2percent(attr,cur_attrs[ATTR_ID_CONTRAST]));
fprintf(fp,"\n");
/* write channels */
@@ -625,15 +639,23 @@ save_config()
if (channels[i]->capture != cur_capture)
fprintf(fp,"capture = %s\n",
int_to_str(channels[i]->capture,captab));
-
- if (cur_attrs[ATTR_ID_COLOR] != channels[i]->color)
- fprintf(fp,"color = %d\n",channels[i]->color);
- if (cur_attrs[ATTR_ID_BRIGHT] != channels[i]->bright)
- fprintf(fp,"bright = %d\n",channels[i]->bright);
- if (cur_attrs[ATTR_ID_HUE] != channels[i]->hue)
- fprintf(fp,"hue = %d\n",channels[i]->hue);
- if (cur_attrs[ATTR_ID_CONTRAST] != channels[i]->contrast)
- fprintf(fp,"contrast = %d\n",channels[i]->contrast);
+
+ attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
+ if (attr && cur_attrs[ATTR_ID_COLOR] != channels[i]->color)
+ fprintf(fp,"color = %d%%\n",
+ ng_attr_int2percent(attr,channels[i]->color));
+ attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
+ if (attr && cur_attrs[ATTR_ID_BRIGHT] != channels[i]->bright)
+ fprintf(fp,"bright = %d%%\n",
+ ng_attr_int2percent(attr,channels[i]->bright));
+ attr = ng_attr_byid(attrs,ATTR_ID_HUE);
+ if (attr && cur_attrs[ATTR_ID_HUE] != channels[i]->hue)
+ fprintf(fp,"hue = %d%%\n",
+ ng_attr_int2percent(attr,channels[i]->hue));
+ attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
+ if (attr && cur_attrs[ATTR_ID_CONTRAST] != channels[i]->contrast)
+ fprintf(fp,"contrast = %d%%\n",
+ ng_attr_int2percent(attr,channels[i]->contrast));
fprintf(fp,"\n");
}
@@ -675,17 +697,3 @@ int_to_str(int n, struct STRTAB *tab)
return tab[i].str;
return NULL;
}
-
-int
-attr_to_int(char *attr)
-{
- int val,n;
-
- if (NULL == attr)
- return -1;
- if (0 == sscanf(attr,"%d%n",&val,&n))
- return 0;
- if (attr[n] == '%')
- return val*65536/100;
- return val;
-}
diff --git a/src/channel.h b/src/channel.h
index 4cb24c0..562d53c 100644
--- a/src/channel.h
+++ b/src/channel.h
@@ -94,4 +94,3 @@ extern struct STRTAB captab[];
int str_to_int(char *str, struct STRTAB *tab);
const char* int_to_str(int n, struct STRTAB *tab);
-int attr_to_int(char *attr);
diff --git a/src/commands.c b/src/commands.c
index 195c9d0..f4040b8 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -77,6 +77,7 @@ static int capture_handler(char *name, int argc, char **argv);
static int volume_handler(char *name, int argc, char **argv);
static int attr_handler(char *name, int argc, char **argv);
static int show_handler(char *name, int argc, char **argv);
+static int list_handler(char *name, int argc, char **argv);
static int dattr_handler(char *name, int argc, char **argv);
static int snap_handler(char *name, int argc, char **argv);
@@ -109,6 +110,7 @@ static struct COMMANDS {
{ "bright", 0, attr_handler },
{ "contrast", 0, attr_handler },
{ "show", 0, show_handler },
+ { "list", 0, list_handler },
{ "mute", 0, volume_handler },
{ "volume", 0, volume_handler },
@@ -355,12 +357,13 @@ set_title(void)
}
static void
-set_msg_int(const char *name, int val)
+set_msg_int(struct ng_attribute *attr, int val)
{
static char title[256];
if (display_message) {
- sprintf(title,"%s: %d%%",name,val*100/65535);
+ sprintf(title,"%s: %d%%",attr->name,
+ ng_attr_int2percent(attr,val));
display_message(title);
}
}
@@ -389,29 +392,33 @@ set_msg_str(char *name, char *val)
/* ----------------------------------------------------------------------- */
-#define STEP (65536/100)
-
-static int update_int(int old, char *new)
+static int update_int(struct ng_attribute *attr, int old, char *new)
{
- int ret = old;
+ int value = old;
+ int step;
+
+ step = (attr->max - attr->min) * 3 / 100;
+ if (step == 0)
+ step = 1;
if (0 == strcasecmp(new,"inc"))
- ret += STEP;
+ value += step;
else if (0 == strcasecmp(new,"dec"))
- ret -= STEP;
- else if (new[0] == '+')
- ret += attr_to_int(new+1);
- else if (new[0] == '-')
- ret -= attr_to_int(new+1);
- else if (isdigit(new[0]))
- ret = attr_to_int(new);
+ value -= step;
+ else if (0 == strncasecmp(new,"+=",2))
+ value += ng_attr_parse_int(attr,new+2);
+ else if (0 == strncasecmp(new,"-=",2))
+ value -= ng_attr_parse_int(attr,new+2);
+ else if (isdigit(new[0]) || '+' == new[0] || '-' == new[0])
+ value = ng_attr_parse_int(attr,new);
else
fprintf(stderr,"update_int: can't parse %s\n",new);
- if (ret < 0) ret = 0;
- if (ret > 65535) ret = 65535;
-
- return ret;
+ if (value < attr->min)
+ value = attr->min;
+ if (value > attr->max)
+ value = attr->max;
+ return value;
}
/* ----------------------------------------------------------------------- */
@@ -735,6 +742,8 @@ static int capture_handler(char *name, int argc, char **argv)
static int volume_handler(char *name, int argc, char **argv)
{
+ struct ng_attribute *vol = ng_attr_byid(attrs,ATTR_ID_VOLUME);
+
if (0 == argc)
goto display;
@@ -752,15 +761,19 @@ static int volume_handler(char *name, int argc, char **argv)
} else {
/* volume */
cur_attrs[ATTR_ID_VOLUME] =
- update_int(cur_attrs[ATTR_ID_VOLUME],argv[0]);
+ update_int(vol,cur_attrs[ATTR_ID_VOLUME],argv[0]);
}
set_volume();
display:
if (cur_attrs[ATTR_ID_MUTE])
set_msg_str("volume","muted");
- else
- set_msg_int("volume",cur_attrs[ATTR_ID_VOLUME]);
+ else {
+ if (vol)
+ set_msg_int(vol,cur_attrs[ATTR_ID_VOLUME]);
+ else
+ set_msg_str("volume","unmuted");
+ }
return 0;
}
@@ -816,10 +829,10 @@ static int attr_handler(char *name, int argc, char **argv)
break;
case ATTR_TYPE_INTEGER:
if (argc > arg) {
- val = update_int(cur_attrs[attr->id],argv[arg]);
+ val = update_int(attr,cur_attrs[attr->id],argv[arg]);
set_attr(attr,val);
}
- set_msg_int(attr->name,cur_attrs[attr->id]);
+ set_msg_int(attr,cur_attrs[attr->id]);
break;
case ATTR_TYPE_BOOL:
if (argc > arg) {
@@ -872,6 +885,43 @@ static int show_handler(char *name, int argc, char **argv)
return 0;
}
+static int list_handler(char *name, int argc, char **argv)
+{
+ struct ng_attribute *attr;
+ int val,i;
+
+ printf("%-10.10s | type | %-7.7s | %-7.7s | %s\n",
+ "attribute","current","default","comment");
+ printf("-----------+--------+---------+--------"
+ "-+-------------------------------------\n");
+ for (attr = attrs; attr->name != NULL; attr++) {
+ val = cur_attrs[attr->id];
+ switch (attr->type) {
+ case ATTR_TYPE_CHOICE:
+ printf("%-10.10s | choice | %-7.7s | %-7.7s |",
+ attr->name,
+ ng_attr_getstr(attr,val),
+ ng_attr_getstr(attr,attr->defval));
+ for (i = 0; attr->choices[i].str != NULL; i++)
+ printf(" %s",attr->choices[i].str);
+ printf("\n");
+ break;
+ case ATTR_TYPE_INTEGER:
+ printf("%-10.10s | int | %7d | %7d | range is %d => %d\n",
+ attr->name, val, attr->defval,
+ attr->min, attr->max);
+ break;
+ case ATTR_TYPE_BOOL:
+ printf("%-10.10s | bool | %-7.7s | %-7.7s |\n",
+ attr->name,
+ val ? "on" : "off",
+ attr->defval ? "on" : "off");
+ break;
+ }
+ }
+ return 0;
+}
+
static int dattr_handler(char *name, int argc, char **argv)
{
struct ng_attribute *attr = NULL;
@@ -958,6 +1008,7 @@ static int snap_handler(char *hname, int argc, char **argv)
ret = -1;
goto done;
}
+ buf = ng_filter_single(cur_filter,buf);
if (NULL == filename) {
if (-1 != cur_sender) {
diff --git a/src/gl.ad b/src/gl.ad
new file mode 100644
index 0000000..738641e
--- /dev/null
+++ b/src/gl.ad
@@ -0,0 +1,20 @@
+! general
+gl.title: OpenGL TV test utility
+
+! arrange widgets
+gl.form.*.leftAttachment: ATTACH_FORM
+gl.form.*.rightAttachment: ATTACH_FORM
+gl.form.view.topAttachment: ATTACH_WIDGET
+gl.form.view.topWidget: bar
+gl.form.view.bottomAttachment: ATTACH_FORM
+gl.form.view.background: black
+gl.form.view.foreground: white
+
+! menu
+gl*bar.file.labelString: File
+gl*bar.file.mnemonic: F
+gl*bar*quit.labelString: Quit
+gl*bar*quit.mnemonic: Q
+gl*bar*quit.acceleratorText: Q
+gl*bar*quit.accelerator: <Key>Q
+
diff --git a/src/gl.c b/src/gl.c
new file mode 100644
index 0000000..8ca704f
--- /dev/null
+++ b/src/gl.c
@@ -0,0 +1,506 @@
+/*
+ * gl.c -- try using OpenGL to blit video frames to the screen
+ *
+ * (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+#include <Xm/Form.h>
+#include <Xm/RowColumn.h>
+#include <Xm/CascadeB.h>
+#include <Xm/PushB.h>
+#include <Xm/DrawingA.h>
+#include <Xm/Protocols.h>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glx.h>
+
+#include "RegEdit.h"
+#include "grab-ng.h"
+
+/* --------------------------------------------------------------------- */
+
+XtAppContext app_context;
+Widget app_shell,view;
+Display *dpy;
+
+static String fallback_ressources[] = {
+#include "gl.h"
+ NULL
+};
+
+struct ARGS {
+ char *device;
+ int width;
+ int height;
+ int help;
+ int tex;
+} args;
+
+XtResource args_desc[] = {
+ /* name, class, type, size, offset, default_type, default_addr */
+ {
+ /* Strings */
+ "device",
+ XtCString, XtRString, sizeof(char*),
+ XtOffset(struct ARGS*,device),
+ XtRString, NULL,
+ },{
+ /* Integer */
+ "gw",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,width),
+ XtRString, "0"
+ },{
+ "gh",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,height),
+ XtRString, "0"
+ },{
+ "tex",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,tex),
+ XtRString, "1"
+ },{
+ "help",
+ XtCValue, XtRInt, sizeof(int),
+ XtOffset(struct ARGS*,help),
+ XtRString, "0"
+ }
+};
+const int args_count = XtNumber(args_desc);
+
+XrmOptionDescRec opt_desc[] = {
+ { "-c", "device", XrmoptionSepArg, NULL },
+ { "-device", "device", XrmoptionSepArg, NULL },
+ { "-x", "gw", XrmoptionSepArg, NULL },
+ { "-width", "gw", XrmoptionSepArg, NULL },
+ { "-y", "gh", XrmoptionSepArg, NULL },
+ { "-height", "gh", XrmoptionSepArg, NULL },
+
+ { "-img", "tex", XrmoptionNoArg, "0" },
+ { "-tex", "tex", XrmoptionNoArg, "1" },
+
+ { "-h", "help", XrmoptionNoArg, "1" },
+ { "-help", "help", XrmoptionNoArg, "1" },
+ { "--help", "help", XrmoptionNoArg, "1" },
+};
+const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec));
+
+/* --------------------------------------------------------------------- */
+
+static inline int fix_width(int width) { return width & ~0x03; }
+static inline int fix_height(int height) { return height; }
+
+/* --------------------------------------------------------------------- */
+
+const struct ng_vid_driver *drv;
+void *h_drv;
+struct ng_video_fmt fmt,gfmt;
+struct ng_video_conv *conv;
+void *hconv;
+int cap_on;
+
+static void
+grab_init(char *dev)
+{
+ ng_debug=1;
+ drv = ng_vid_open(dev ? dev : ng_dev.video,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"grab: no grabber device available\n");
+ exit(1);
+ }
+ if (!(drv->capabilities(h_drv) & CAN_CAPTURE)) {
+ fprintf(stderr,"grab: device does'nt support capture\n");
+ exit(1);
+ }
+}
+
+static void
+grab_size(int format, int width, int height)
+{
+ int i;
+
+ /* cleanup */
+ if (conv) {
+ conv->fini(hconv);
+ conv = NULL;
+ hconv = NULL;
+ }
+ if (cap_on) {
+ drv->stopvideo(h_drv);
+ cap_on = 0;
+ }
+
+ /* try native format */
+ memset(&fmt,0,sizeof(fmt));
+ fmt.fmtid = format;
+ fmt.width = fix_width(width);
+ fmt.height = fix_height(height);
+ if (0 == drv->setformat(h_drv,&fmt)) {
+ drv->startvideo(h_drv,-1,4);
+ cap_on = 1;
+ fprintf(stderr,"grab: native [%s]\n",ng_vfmt_to_desc[fmt.fmtid]);
+ return;
+ }
+
+ /* check all available conversion functions */
+ fmt.bytesperline = fmt.width*ng_vfmt_to_depth[fmt.fmtid]/8;
+ for (i = 0;;) {
+ conv = ng_conv_find(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);
+ drv->startvideo(h_drv,-1,4);
+ cap_on = 1;
+ fprintf(stderr,"grab: convert [%s => %s]\n",
+ ng_vfmt_to_desc[gfmt.fmtid],
+ ng_vfmt_to_desc[fmt.fmtid]);
+ return;
+ }
+ }
+ fprintf(stderr,"grab: can't get rgb24 data\n");
+ exit(1);
+}
+
+static struct ng_video_buf*
+grab_one(void)
+{
+ struct ng_video_buf *cap,*buf;
+ int size;
+
+ if (NULL == (cap = drv->nextframe(h_drv))) {
+ fprintf(stderr,"capturing image failed\n");
+ exit(1);
+ }
+
+ if (NULL != conv) {
+ size = (fmt.width * fmt.height * ng_vfmt_to_depth[fmt.fmtid]) >> 3;
+ buf = ng_malloc_video_buf(&fmt,size);
+ conv->frame(hconv,buf,cap);
+ buf->info = cap->info;
+ ng_release_video_buf(cap);
+ } else {
+ buf = cap;
+ }
+ return buf;
+}
+
+static void grab_mute(int state)
+{
+ struct ng_attribute *attr,*attrs;
+
+ if (NULL == (attrs = drv->list_attrs(h_drv)))
+ return;
+ if (NULL == (attr = ng_attr_byid(attrs,ATTR_ID_MUTE)))
+ return;
+ attr->write(attr,state);
+}
+
+/* --------------------------------------------------------------------- */
+
+static int gl_attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+static Dimension wwidth,wheight;
+
+static void gl_resize(Widget widget)
+{
+ int w,h,i;
+
+ XtVaGetValues(widget,XmNwidth,&wwidth,XmNheight,&wheight,NULL);
+ fprintf(stderr,"gl: resize %dx%d\n",wwidth,wheight);
+
+ wwidth = fix_width(wwidth);
+ wheight = fix_height(wheight);
+
+ glViewport(0, 0, wwidth, wheight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0.0, wwidth, 0.0, wheight);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ w = wwidth;
+ h = wheight;
+ if (args.width)
+ w = args.width;
+ if (args.height)
+ h = args.height;
+
+ if (args.tex) {
+ fprintf(stderr,"gl: texture size in: %dx%d\n",w,h);
+ /* check against max size */
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE,&i);
+ fprintf(stderr,"gl: texture size max: %d\n",i);
+ if (w > i)
+ w = i;
+ if (h > i)
+ h = i;
+ /* textures have power-of-two x,y dimensions */
+ for (i = 0; w >= (1 << i); i++)
+ ;
+ w = (1 << (i-1));
+ for (i = 0; h >= (1 << i); i++)
+ ;
+ h = (1 << (i-1));
+ fprintf(stderr,"gl: texture size out: %dx%d\n",w,h);
+ }
+ grab_size(VIDEO_RGB24,w,h);
+}
+
+static void gl_redraw(Widget widget)
+{
+ fprintf(stderr,"gl: redraw\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ glXSwapBuffers(XtDisplay(widget), XtWindow(widget));
+}
+
+static void gl_blit_img(Widget widget, struct ng_video_buf *buf)
+{
+ float xs = (float)wwidth / buf->fmt.width;
+ float ys = (float)wheight / buf->fmt.height;
+
+ glRasterPos2i(0, wheight);
+ glPixelZoom(xs,-ys);
+ glDrawPixels(buf->fmt.width, buf->fmt.height,
+ GL_RGB,GL_UNSIGNED_BYTE,
+ buf->data);
+ glXSwapBuffers(XtDisplay(widget), XtWindow(widget));
+}
+
+static void gl_blit_tex(Widget widget, struct ng_video_buf *buf)
+{
+ static GLint tex;
+ static int width,height;
+
+ if (0 == tex) {
+ glGenTextures(1,&tex);
+ glBindTexture(GL_TEXTURE_2D,tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ if (width != buf->fmt.width || height != buf->fmt.height) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ buf->fmt.width,buf->fmt.height,0,
+ GL_RGB,GL_UNSIGNED_BYTE,buf->data);
+ width = buf->fmt.width;
+ height = buf->fmt.height;
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0,0,buf->fmt.width,buf->fmt.height,
+ GL_RGB,GL_UNSIGNED_BYTE,buf->data);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0,1); glVertex3f(0,0,0);
+ glTexCoord2f(0,0); glVertex3f(0,wheight,0);
+ glTexCoord2f(1,0); glVertex3f(wwidth,wheight,0);
+ glTexCoord2f(1,1); glVertex3f(wwidth,0,0);
+ glEnd();
+ glXSwapBuffers(XtDisplay(widget), XtWindow(widget));
+ glDisable(GL_TEXTURE_2D);
+}
+
+static void gl_blit(Widget widget, struct ng_video_buf *buf)
+{
+ if (args.tex)
+ gl_blit_tex(view,buf);
+ else
+ gl_blit_img(view,buf);
+}
+
+static void gl_init(Widget widget)
+{
+ XVisualInfo *visinfo;
+ GLXContext ctx;
+
+ fprintf(stderr,"gl: init\n");
+ visinfo = glXChooseVisual(XtDisplay(widget),
+ DefaultScreen(XtDisplay(widget)),
+ gl_attrib);
+ if (!visinfo) {
+ fprintf(stderr,"gl: can't get visual (rgb,db)\n");
+ exit(1);
+ }
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ glXMakeCurrent(XtDisplay(widget),XtWindow(widget),ctx);
+ fprintf(stderr, "gl: DRI: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
+
+ glClearColor (0.0, 0.0, 0.0, 0.0);
+ glShadeModel(GL_FLAT);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void event(Widget widget, XtPointer client_data,
+ XEvent *event, Boolean *d)
+{
+ switch (event->type) {
+ case Expose:
+ if (0 != event->xexpose.count)
+ return;
+ fprintf(stderr,"ev: expose\n");
+ gl_redraw(widget);
+ break;
+ case ConfigureNotify:
+ fprintf(stderr,"ev: configure\n");
+ XClearArea(XtDisplay(widget),XtWindow(widget),0,0,0,0,True);
+ gl_resize(widget);
+ break;
+ case MapNotify:
+ fprintf(stderr,"ev: map\n");
+ gl_resize(widget);
+ break;
+ case UnmapNotify:
+ fprintf(stderr,"ev: unmap\n");
+ break;
+ default:
+ fprintf(stderr,"ev: unknown\n");
+ break;
+ }
+}
+
+static void
+quit_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ grab_mute(1);
+ exit(0);
+}
+
+static Boolean
+idle(XtPointer client_data)
+{
+ static const char progress[] = "|/-\\";
+ static int count,lastcount;
+ static struct timeval t,lastt;
+ struct ng_video_buf *buf;
+
+ gettimeofday(&t,NULL);
+ if (t.tv_sec != lastt.tv_sec) {
+ fprintf(stderr,"%5d fps\r",count-lastcount);
+ lastt = t;
+ lastcount = count;
+ }
+
+ buf = grab_one();
+ gl_blit(view,buf);
+ ng_release_video_buf(buf);
+ fprintf(stderr,"%c\r",progress[(count++)%4]);
+ return False;
+}
+
+static void create_widgets(Widget parent)
+{
+ Widget form,menubar,menu,push;
+
+ /* form container */
+ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, parent,
+ NULL);
+
+ /* menu bar */
+ menubar = XmCreateMenuBar(form,"bar",NULL,0);
+ XtManageChild(menubar);
+
+ /* file menu */
+ menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0);
+ XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar,
+ XmNsubMenuId,menu,NULL);
+ push = XtVaCreateManagedWidget("quit",xmPushButtonWidgetClass,menu,NULL);
+ XtAddCallback(push,XmNactivateCallback,quit_cb,NULL);
+
+ /* main view */
+ view = XtVaCreateManagedWidget("view", xmDrawingAreaWidgetClass,form,
+ XmNwidth,320,
+ XmNheight,240,
+ NULL);
+ XtAddEventHandler(view, StructureNotifyMask | ExposureMask,
+ True, event, NULL);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "\n"
+ "gl - OpenGL TV test application\n"
+ "\n"
+ "use some other TV application to initialize the hardware first,\n"
+ "this is *really* a test utility only -- without controls\n"
+ "\n"
+ "known options:\n"
+ " -h,-help this text\n"
+ " -c,-device dev capture device [default: %s]\n"
+ " -x,-width n capture width [default: window size]\n"
+ " -y,-height n capture height [default: window size]\n"
+ " -tex blit frames using texture mapping [default]\n"
+ " -img blit frames using glDrawPixels\n"
+ "\n",
+ ng_dev.video);
+}
+
+int
+main(int argc, char *argv[])
+{
+ Atom del;
+
+ ng_init();
+ XtSetLanguageProc(NULL,NULL,NULL);
+ app_shell = XtVaAppInitialize(&app_context, "gl",
+ opt_desc, opt_count,
+ &argc, argv,
+ fallback_ressources,
+ NULL);
+ XtGetApplicationResources(app_shell,&args,
+ args_desc,args_count,
+ NULL,0);
+ if (args.help) {
+ usage();
+ exit(1);
+ }
+
+ dpy = XtDisplay(app_shell);
+ XmdRegisterEditres(app_shell);
+ del = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
+ XmAddWMProtocolCallback(app_shell,del,quit_cb,NULL);
+ create_widgets(app_shell);
+
+ XtRealizeWidget(app_shell);
+ grab_init(args.device);
+ grab_mute(0);
+ gl_init(view);
+
+ XtAppAddWorkProc(app_context,idle,NULL);
+ XtAppMainLoop(app_context);
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * Local variables:
+ * compile-command: "make gl"
+ * End:
+ */
diff --git a/src/gl.h b/src/gl.h
new file mode 100644
index 0000000..fb5ba97
--- /dev/null
+++ b/src/gl.h
@@ -0,0 +1,17 @@
+"gl.title: OpenGL TV test utility",
+"",
+"gl.form.*.leftAttachment: ATTACH_FORM",
+"gl.form.*.rightAttachment: ATTACH_FORM",
+"gl.form.view.topAttachment: ATTACH_WIDGET",
+"gl.form.view.topWidget: bar",
+"gl.form.view.bottomAttachment: ATTACH_FORM",
+"gl.form.view.background: black",
+"gl.form.view.foreground: white",
+"",
+"gl*bar.file.labelString: File",
+"gl*bar.file.mnemonic: F",
+"gl*bar*quit.labelString: Quit",
+"gl*bar*quit.mnemonic: Q",
+"gl*bar*quit.acceleratorText: Q",
+"gl*bar*quit.accelerator: <Key>Q",
+"",
diff --git a/src/main.c b/src/main.c
index c7906bb..fc1cd6c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -534,7 +534,8 @@ new_attr(struct ng_attribute *attr, int val)
XtVaSetValues(a->cmd,XtNlabel,label,NULL);
break;
case ATTR_TYPE_INTEGER:
- set_float(a->scroll,XtNtopOfThumb,(float)val/65536);
+ set_float(a->scroll,XtNtopOfThumb,
+ (float)(val-attr->min) / (attr->max - attr->min));
break;
}
return;
@@ -662,19 +663,21 @@ pixit(void)
fmt = x11_fmt;
fmt.width = pix_width;
fmt.height = pix_height;
- if (NULL != (buf = ng_grabber_get_image(&fmt)) &&
- 0 != (pix = x11_create_pixmap(dpy,&vinfo,colormap,buf->data,
- fmt.width,fmt.height,
- channels[cur_sender]->name))) {
- XtVaSetValues(channels[cur_sender]->button,
- XtNbackgroundPixmap,pix,
- XtNlabel,"",
- XtNwidth,pix_width,
- XtNheight,pix_height,
- NULL);
- if (channels[cur_sender]->pixmap)
- XFreePixmap(dpy,channels[cur_sender]->pixmap);
- channels[cur_sender]->pixmap = pix;
+ if (NULL != (buf = ng_grabber_get_image(&fmt))) {
+ buf = ng_filter_single(cur_filter,buf);
+ if (0 != (pix = x11_create_pixmap(dpy,&vinfo,colormap,buf->data,
+ fmt.width,fmt.height,
+ channels[cur_sender]->name))) {
+ XtVaSetValues(channels[cur_sender]->button,
+ XtNbackgroundPixmap,pix,
+ XtNlabel,"",
+ XtNwidth,pix_width,
+ XtNheight,pix_height,
+ NULL);
+ if (channels[cur_sender]->pixmap)
+ XFreePixmap(dpy,channels[cur_sender]->pixmap);
+ channels[cur_sender]->pixmap = pix;
+ }
ng_release_video_buf(buf);
}
video_gd_restart();
@@ -963,20 +966,25 @@ static void
jump_scb(Widget widget, XtPointer clientdata, XtPointer call_data)
{
struct xaw_attribute *a = clientdata;
+ struct ng_attribute *attr = a->attr;
const char *name;
char val[16];
- int value;
-
- value = (int)(*(float*)call_data * 65535);
- if (value > 65535) value = 65535;
- if (value < 0) value = 0;
+ int value,range;
+
+ range = attr->max - attr->min;
+ value = (int)(*(float*)call_data * range) + attr->min;
+ fprintf(stderr,"value is %d\n",value);
+ if (value < attr->min)
+ value = attr->min;
+ if (value > attr->max)
+ value = attr->max;
sprintf(val,"%d",value);
if (a) {
name = a->attr->name;
do_va_cmd(3,"setattr",name,val);
} else {
- name = XtName(XtParent(widget));
+ name = XtName(XtParent(widget));
do_va_cmd(2,name,val);
}
}
@@ -986,7 +994,7 @@ scroll_scb(Widget widget, XtPointer clientdata, XtPointer call_data)
{
long move = (long)call_data;
Dimension length;
- float shown,top1,top2;
+ float shown,top1,top2;
XtVaGetValues(widget,
XtNlength, &length,
@@ -997,8 +1005,8 @@ scroll_scb(Widget widget, XtPointer clientdata, XtPointer call_data)
top2 = top1 + (float)move/length/5;
if (top2 < 0) top2 = 0;
if (top2 > 1) top2 = 1;
-#if 0
- fprintf(stderr,"scroll by %d\tlength %d\tshown %f\ttop %f => %f\n",
+#if 1
+ fprintf(stderr,"scroll by %ld\tlength %d\tshown %f\ttop %f => %f\n",
move,length,shown,top1,top2);
#endif
jump_scb(widget,clientdata,&top2);
diff --git a/src/motif.c b/src/motif.c
index a37cb91..91f7a9a 100644
--- a/src/motif.c
+++ b/src/motif.c
@@ -1,7 +1,7 @@
/*
* OpenMotif user interface
*
- * (c) 2000-01 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
*
*/
@@ -125,7 +125,7 @@ static Widget launch_menu,opt_menu,cap_menu,freq_menu;
static Widget vtx_shell,vtx_label;
static Widget chan_viewport,chan_box;
static Widget st_freq,st_chan,st_name,st_key;
-static Widget scale_shell;
+static Widget scale_shell,filter_shell;
static Widget w_full;
/* properties */
@@ -164,6 +164,7 @@ static struct MY_TOPLEVELS {
{ "control", &control_shell },
{ "streamer", &str_shell },
{ "scale", &scale_shell },
+ { "filter", &filter_shell },
{ "levels", &levels_shell },
};
#define TOPLEVELS (sizeof(my_toplevels)/sizeof(struct MY_TOPLEVELS))
@@ -175,6 +176,15 @@ struct motif_attribute {
};
static struct motif_attribute *motif_attrs;
+struct filter_attribute {
+ struct filter_attribute *next;
+ struct ng_filter *filter;
+ struct ng_attribute *attr;
+ int value;
+ Widget widget;
+};
+static struct filter_attribute *filter_attrs;
+
/*----------------------------------------------------------------------*/
/* debug/test code */
@@ -770,6 +780,127 @@ create_prop(void)
/*----------------------------------------------------------------------*/
static void
+filter_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
+{
+ struct filter_attribute *f = clientdata;
+ Widget w;
+
+ switch (f->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ XmScaleGetValue(f->widget,&f->value);
+ break;
+ case ATTR_TYPE_BOOL:
+ f->value = XmToggleButtonGetState(f->widget);
+ break;
+ case ATTR_TYPE_CHOICE:
+ w = NULL;
+ XtVaGetValues(f->widget,XmNmenuHistory,&w,NULL);
+ f->value = ng_attr_getint(f->attr,XtName(w));
+ break;
+ }
+ f->attr->write(f->attr,f->value);
+}
+
+static void
+filter_add_ctrls(Widget rc, struct ng_filter *filter,
+ struct ng_attribute *attr)
+{
+ struct filter_attribute *f;
+ Widget opt,push;
+ XmString str;
+ Arg args[2];
+ int i;
+
+ f = malloc(sizeof(*f));
+ memset(f,0,sizeof(*f));
+ f->filter = filter;
+ f->attr = attr;
+ f->next = filter_attrs;
+ f->value = attr->read(attr);
+ filter_attrs = f;
+
+ str = XmStringGenerate((char*)attr->name, NULL, XmMULTIBYTE_TEXT, NULL);
+ switch (attr->type) {
+ case ATTR_TYPE_INTEGER:
+ f->widget = XtVaCreateManagedWidget("scale",
+ xmScaleWidgetClass,rc,
+ XmNtitleString,str,
+ XmNminimum,attr->min,
+ XmNmaximum,attr->max,
+ XmNdecimalPoints,attr->points,
+ NULL);
+ XmScaleSetValue(f->widget,f->value);
+ XtAddCallback(f->widget,XmNvalueChangedCallback,filter_cb,f);
+ break;
+ case ATTR_TYPE_BOOL:
+ f->widget = XtVaCreateManagedWidget("bool",
+ xmToggleButtonWidgetClass,rc,
+ XmNlabelString,str,
+ NULL);
+ XmToggleButtonSetState(f->widget,f->value,False);
+ XtAddCallback(f->widget,XmNvalueChangedCallback,filter_cb,f);
+ break;
+ case ATTR_TYPE_CHOICE:
+ f->widget = XmCreatePulldownMenu(rc,"choiceM",NULL,0);
+ XtSetArg(args[0],XmNsubMenuId,f->widget);
+ XtSetArg(args[1],XmNlabelString,str);
+ opt = XmCreateOptionMenu(rc,"choiceO",args,2);
+ XtManageChild(opt);
+ for (i = 0; attr->choices[i].str != NULL; i++) {
+ push = XtVaCreateManagedWidget(attr->choices[i].str,
+ xmPushButtonWidgetClass,f->widget,
+ NULL);
+ XtAddCallback(push,XmNactivateCallback,filter_cb,f);
+ if (f->value == attr->choices[i].nr)
+ XtVaSetValues(f->widget,XmNmenuHistory,push,NULL);
+ }
+ break;
+ }
+ XmStringFree(str);
+}
+
+static void
+create_filter_prop(void)
+{
+ Widget rc1,frame,rc2;
+ XmString str;
+ int i,j;
+
+ filter_shell = XtVaAppCreateShell("filter","MoTV",
+ topLevelShellWidgetClass,
+ dpy,
+ XtNclientLeader,app_shell,
+ XtNvisual,vinfo.visual,
+ XtNcolormap,colormap,
+ XtNdepth,vinfo.depth,
+ XmNdeleteResponse,XmDO_NOTHING,
+ NULL);
+ XmdRegisterEditres(filter_shell);
+ XmAddWMProtocolCallback(filter_shell,wm_delete_window,
+ popupdown_cb,filter_shell);
+
+ rc1 = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, filter_shell,
+ NULL);
+
+ for (i = 0; NULL != ng_filters[i]; i++) {
+ if (NULL == ng_filters[i]->attrs)
+ continue;
+ str = XmStringGenerate(ng_filters[i]->name, NULL,
+ XmMULTIBYTE_TEXT, NULL);
+ frame = XtVaCreateManagedWidget("frame",xmFrameWidgetClass,rc1,NULL);
+ XtVaCreateManagedWidget("label",xmLabelWidgetClass,frame,
+ XmNlabelString,str,
+ NULL);
+ rc2 = XtVaCreateManagedWidget("rc",xmRowColumnWidgetClass,frame,NULL);
+ XmStringFree(str);
+ for (j = 0; NULL != ng_filters[i]->attrs[j].name; j++)
+ filter_add_ctrls(rc2,ng_filters[i],&ng_filters[i]->attrs[j]);
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+static void
scroll_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
{
struct motif_attribute *a = clientdata;
@@ -1203,7 +1334,7 @@ create_control(void)
menu = XmCreatePulldownMenu(menubar,"filterM",NULL,0);
XtVaCreateManagedWidget("filter",xmCascadeButtonWidgetClass,menubar,
XmNsubMenuId,menu,NULL);
- push = XtVaCreateManagedWidget("none",
+ push = XtVaCreateManagedWidget("fnone",
xmPushButtonWidgetClass,menu,
NULL);
XtAddCallback(push,XmNactivateCallback,action_cb,"Filter()");
@@ -1214,6 +1345,10 @@ create_control(void)
sprintf(action,"Filter(%s)",ng_filters[i]->name);
XtAddCallback(push,XmNactivateCallback,action_cb,strdup(action));
}
+ XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL);
+ push = XtVaCreateManagedWidget("fopts",xmPushButtonWidgetClass,menu,
+ NULL);
+ XtAddCallback(push,XmNactivateCallback,action_cb,"Popup(filter)");
}
/* menu - help */
@@ -1377,6 +1512,9 @@ create_scale(void)
a->widget = XtVaCreateManagedWidget(attr->name,
xmScaleWidgetClass, form,
XmNtopWidget,attach,
+ XmNminimum,attr->min,
+ XmNmaximum,attr->max,
+ XmNdecimalPoints,attr->points,
NULL);
} else {
str = XmStringGenerate((char*)attr->name, NULL,
@@ -1385,6 +1523,9 @@ create_scale(void)
xmScaleWidgetClass, form,
XmNtopWidget,attach,
XmNtitleString,str,
+ XmNminimum,attr->min,
+ XmNmaximum,attr->max,
+ XmNdecimalPoints,attr->points,
NULL);
XmStringFree(str);
}
@@ -1434,17 +1575,19 @@ pixit(void)
fmt = x11_fmt;
fmt.width = pix_width;
fmt.height = pix_height;
- if (NULL != (buf = ng_grabber_get_image(&fmt)) &&
- 0 != (pix = x11_create_pixmap(dpy,&vinfo,colormap,buf->data,
- fmt.width,fmt.height,
- channels[cur_sender]->name))) {
- XtVaSetValues(channels[cur_sender]->button,
- XmNlabelPixmap,pix,
- XmNlabelType,XmPIXMAP,
- NULL);
- if (channels[cur_sender]->pixmap)
+ if (NULL != (buf = ng_grabber_get_image(&fmt))) {
+ buf = ng_filter_single(cur_filter,buf);
+ if (0 != (pix = x11_create_pixmap(dpy,&vinfo,colormap,buf->data,
+ fmt.width,fmt.height,
+ channels[cur_sender]->name))) {
+ XtVaSetValues(channels[cur_sender]->button,
+ XmNlabelPixmap,pix,
+ XmNlabelType,XmPIXMAP,
+ NULL);
+ if (channels[cur_sender]->pixmap)
XFreePixmap(dpy,channels[cur_sender]->pixmap);
- channels[cur_sender]->pixmap = pix;
+ channels[cur_sender]->pixmap = pix;
+ }
ng_release_video_buf(buf);
}
video_gd_restart();
@@ -2452,6 +2595,7 @@ ipc_init(struct ipc_data *ipc)
fmt = x11_fmt;
fmt.fmtid = VIDEO_RGB24;
buf = ng_grabber_get_image(&fmt);
+ buf = ng_filter_single(cur_filter,buf);
ipc->buf = ng_malloc_video_buf(&buf->fmt,buf->size);
ipc->buf->info = buf->info;
memcpy(ipc->buf->data,buf->data,buf->size);
@@ -3011,6 +3155,7 @@ main(int argc, char *argv[])
create_prop();
create_pref();
create_levels();
+ create_filter_prop();
stderr_init();
/* read config file + related settings */
diff --git a/src/streamer.c b/src/streamer.c
index fa014db..601833f 100644
--- a/src/streamer.c
+++ b/src/streamer.c
@@ -294,14 +294,16 @@ parse_time(char *time)
static void
do_rec_status(char *message)
{
- fprintf(stderr,"%s \r",message);
+ if (!quiet)
+ fprintf(stderr,"%s \r",message);
}
static void
ctrlc(int signal)
{
static char text[] = "^C - one moment please\n";
- write(2,text,strlen(text));
+ if (!quiet)
+ write(2,text,strlen(text));
signaled=1;
}
diff --git a/src/v4l-conf.c b/src/v4l-conf.c
index 60b2cf5..170fd0d 100644
--- a/src/v4l-conf.c
+++ b/src/v4l-conf.c
@@ -153,6 +153,22 @@ dev_open(const char *device, int major)
return fd;
}
+static void real_user(void)
+{
+ if (-1 == seteuid(getuid())) {
+ perror("seteuid(user)");
+ exit(1);
+ }
+}
+
+static void root_user(void)
+{
+ if (-1 == seteuid(0)) {
+ perror("seteuid(root)");
+ exit(1);
+ }
+}
+
/* ---------------------------------------------------------------- */
/* get mode info */
@@ -431,6 +447,9 @@ main(int argc, char *argv[])
Display *dpy;
#endif
+ /* we don't need root proviliges for now ... */
+ real_user();
+
/* Make sure fd's 0 1 2 are open, otherwise
* we might end up sending perror() messages to
* the `device' file */
@@ -574,10 +593,18 @@ main(int argc, char *argv[])
fprintf(stderr,"base=unknown\n");
}
- /* Set the parameters */
+ /* Set the parameters (needs root) */
+ root_user();
fd = dev_open(videodev, 81 /* VIDEO_MAJOR */);
if (-1 == displayinfo_v4l2(fd,&d))
displayinfo_v4l(fd,&d);
close(fd);
return 0;
}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Local variables:
+ * compile-command: "(cd ..; make)"
+ * End:
+ */
diff --git a/src/x11.c b/src/x11.c
index 69a6c40..2ac4d85 100644
--- a/src/x11.c
+++ b/src/x11.c
@@ -427,6 +427,7 @@ freeze_image(Display *dpy, Colormap colormap)
fmt = x11_fmt;
if (NULL != (buf = ng_grabber_get_image(&fmt))) {
+ buf = ng_filter_single(cur_filter,buf);
pix = x11_create_pixmap(dpy,&vinfo,colormap,buf->data,
buf->fmt.width, buf->fmt.height,
NULL);
diff --git a/src/xv.c b/src/xv.c
index 57682f9..757c6e1 100644
--- a/src/xv.c
+++ b/src/xv.c
@@ -117,17 +117,11 @@ static int xv_read_attr(struct ng_attribute *attr)
struct xv_handle *h = attr->handle;
const XvAttribute *at = attr->priv;
Atom atom;
- int range, value = 0;
+ int value = 0;
if (NULL != at) {
atom = XInternAtom(dpy, at->name, False);
XvGetPortAttribute(dpy, h->vi_port,atom,&value);
- if (ATTR_TYPE_INTEGER == attr->type) {
- range = at->max_value - at->min_value;
- value = (value - at->min_value) * 65536 / range;
- if (value < 0) value = 0;
- if (value > 65535) value = 65535;
- }
if (debug)
fprintf(stderr,"xv: get %s: %d\n",at->name,value);
@@ -146,16 +140,10 @@ static void xv_write_attr(struct ng_attribute *attr, int value)
struct xv_handle *h = attr->handle;
const XvAttribute *at = attr->priv;
Atom atom;
- int range,i;
+ int i;
if (NULL != at) {
atom = XInternAtom(dpy, at->name, False);
- if (ATTR_TYPE_INTEGER == attr->type) {
- range = at->max_value - at->min_value;
- value = value * range / 65536 + at->min_value;
- if (value < at->min_value) value = at->min_value;
- if (value > at->max_value) value = at->max_value;
- }
XvSetPortAttribute(dpy, h->vi_port,atom,value);
if (debug)
fprintf(stderr,"xv: set %s: %d\n",at->name,value);
@@ -193,12 +181,16 @@ xv_add_attr(struct xv_handle *h, int id, int type,
if (0 == strcmp(xvattr[i].atom,at->name))
break;
if (-1 == xvattr[i].type)
- /* ignore this one*/
+ /* ignore this one */
return;
if (NULL != xvattr[i].atom) {
h->attr[h->nattr].id = xvattr[i].id;
h->attr[h->nattr].type = xvattr[i].type;
h->attr[h->nattr].priv = at;
+ if (ATTR_TYPE_INTEGER == h->attr[h->nattr].type) {
+ h->attr[h->nattr].min = at->min_value;
+ h->attr[h->nattr].max = at->max_value;
+ }
} else {
/* unknown */
return;
diff --git a/tools/record.c b/tools/record.c
index 47136d9..ee084ad 100644
--- a/tools/record.c
+++ b/tools/record.c
@@ -44,7 +44,8 @@ static int sound_blksize;
static short *sound_buffer;
static int maxl,maxr;
static int secl,secr;
-static struct timeval tl,tr;
+static int *histl,*histr,histn,histi;
+static int peak_seconds = 2;
static char *audio_dev = "/dev/dsp";
static int
@@ -106,6 +107,13 @@ sound_open(int rate)
sound_blksize = 4096;
sound_buffer = malloc(sound_blksize);
+ /* peak level history */
+ histn = peak_seconds * rate * 4 / sound_blksize;
+ histl = malloc(histn * sizeof(int));
+ histr = malloc(histn * sizeof(int));
+ memset(histl,0,histn * sizeof(int));
+ memset(histr,0,histn * sizeof(int));
+
/* trigger record */
trigger = ~PCM_ENABLE_INPUT;
ioctl(sound_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
@@ -118,7 +126,6 @@ sound_open(int rate)
static int
sound_read(void)
{
- struct timeval now;
int i,rc,have;
short *v;
@@ -154,22 +161,17 @@ sound_read(void)
}
/* max for the last second */
- gettimeofday(&now,NULL);
- if ((tl.tv_sec == now.tv_sec-1 && tl.tv_usec < now.tv_usec) ||
- (tl.tv_sec < now.tv_sec-1)) {
- secl = 0;
- }
- if ((tr.tv_sec == now.tv_sec-1 && tr.tv_usec < now.tv_usec) ||
- (tr.tv_sec < now.tv_sec-1)) {
- secr = 0;
- }
- if (secl < maxl) {
- secl = maxl;
- tl = now;
- }
- if (secr < maxr) {
- secr = maxr;
- tr = now;
+ histl[histi] = maxl;
+ histr[histi] = maxr;
+ histi++;
+ if (histn == histi)
+ histi = 0;
+
+ for (secl = 0, secr = 0, i = 0; i < histn; i++) {
+ if (secl < histl[i])
+ secl = histl[i];
+ if (secr < histr[i])
+ secr = histr[i];
}
return 0;
}
@@ -408,64 +410,27 @@ enum MODE {
NCURSES = 1,
CONSOLE = 2,
};
-
-char *progname;
-int stop,verbose;
-char *input = "line";
-char *filename = "new";
enum MODE mode = NCURSES;
+int stop,verbose;
+char *filename = "record";
int rate = 44100;
static void
ctrlc(int signal)
{
if (verbose)
- fprintf(stderr,"%s - exiting \n",
+ fprintf(stderr,"\n%s - exiting\n",
sys_siglist[signal]);
stop = 1;
}
-static void
-usage(FILE *fp)
-{
- fprintf(fp,
- "%s records sound in CD-Quality (44100/16bit/stereo).\n"
- "It has a nice ascii-art input-level meter. It is a\n"
- "interactive curses application. You'll need a fast\n"
- "terminal, don't try this on a 9600 bps vt100...\n"
- "\n"
- "%s has seven options:\n"
- " -h this text\n"
- " -o file output file name [%s], a number and the .wav\n"
- " extention are added by %s.\n"
- " -i ctrl mixer control [%s]. This should be the one\n"
- " where you can adjust the record level for\n"
- " your audio source, line and igain are good\n"
- " candidates.\n"
- " -d dev set audio device [%s]\n"
- " -m dev set mixer device [%s]\n"
- " -r rate set sample rate [%d]\n"
- "\n"
- "for non-interactive usage only:\n"
- " -c enable console (non-interactive) mode\n"
- " -v be verbose (show progress)\n"
- " -t mm:ss limit the time to record. By default it records\n"
- " until stopped by a signal (^C)\n"
- " -s size set max file size [2GB]. You have to give number\n"
- " and unit without space inbetween, i.e. \"100mb\".\n"
- "\n",
- progname,progname,filename,progname,input,
- audio_dev,mixer_dev,
- rate);
-}
-
static int
record_start(char *outfile, int *nr)
{
int wav;
do {
- sprintf(outfile,"%s%02d.wav",filename,(*nr)++);
+ sprintf(outfile,"%s%03d.wav",filename,(*nr)++);
wav = open(outfile, O_WRONLY | O_EXCL | O_CREAT, 0666);
} while ((-1 == wav) && (EEXIST == errno));
if (-1 == wav) {
@@ -476,6 +441,22 @@ record_start(char *outfile, int *nr)
return wav;
}
+static void
+record_stop(int fd)
+{
+ wav_stop_write(fd);
+ close(fd);
+ switch (mode) {
+ case CONSOLE:
+ if (verbose)
+ printf("\n");
+ break;
+ case NCURSES:
+ mvprintw(3,0,"%*.*s",COLS-1,COLS-1,blank);
+ break;
+ }
+}
+
static off_t
parse_size(const char *arg)
{
@@ -502,12 +483,12 @@ str_mb(off_t value)
{
static char buf[32];
- if (value > 1000000000) {
+ if (value > (1 << 30)) {
value = (value * 10) >> 30;
sprintf(buf,"%d.%d GB",(int)(value/10),(int)(value%10));
return buf;
}
- if (value > 1000000) {
+ if (value > (1 << 20)) {
value = (value * 10) >> 20;
sprintf(buf,"%d.%d MB",(int)(value/10),(int)(value%10));
return buf;
@@ -517,6 +498,52 @@ str_mb(off_t value)
return buf;
}
+/* -------------------------------------------------------------------- */
+
+char *progname;
+char *input = "line";
+char *str_maxsize = "2GB";
+int level_trigger;
+
+static void
+usage(FILE *fp)
+{
+ fprintf(fp,
+ "\n"
+ "%s records sound in CD-Quality (44100/16bit/stereo).\n"
+ "It has a nice ascii-art input-level meter. It is a\n"
+ "interactive curses application. You'll need a fast\n"
+ "terminal, don't try this on a 9600 bps vt100...\n"
+ "\n"
+ "%s has several options:\n"
+ " -h this text\n"
+ " -o file output file basename [%s], a number and the .wav\n"
+ " extention are added by %s.\n"
+ " -i ctrl mixer control [%s]. This should be the one\n"
+ " where you can adjust the record level for\n"
+ " your audio source, \"line\", \"mic\" and \"igain\"\n"
+ " are good candidates.\n"
+ " -m dev set mixer device [%s]\n"
+ " -d dev set dsp device [%s]\n"
+ " -r rate set sample rate [%d]\n"
+ " -p sec peak seconds [%d]\n"
+ "\n"
+ "for non-interactive usage only:\n"
+ " -c enable console (non-interactive) mode\n"
+ " -v be verbose (show progress)\n"
+ " -t mm:ss limit the time to record. By default it records\n"
+ " 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"
+ " -l signal level triggered recording.\n"
+ " -L level same as above + specify trigger level [%d]\n"
+ "\n",
+ progname,progname,filename,progname,
+ input,mixer_dev,audio_dev,
+ rate,peak_seconds,str_maxsize,
+ level_trigger ? level_trigger : 1000);
+}
+
int
main(int argc, char *argv[])
{
@@ -527,19 +554,29 @@ main(int argc, char *argv[])
int sec,maxhour,maxmin,maxsec;
off_t maxsize;
+ /* init some vars */
progname = strrchr(argv[0],'/');
progname = progname ? progname+1 : argv[0];
+ maxsec = 0;
+ delay = 0;
+ auto_adjust = 1;
+ record = 0;
+ nr = 0;
/* parse options */
- maxsec = 0;
- maxsize = parse_size("2G");
for (;;) {
- if (-1 == (c = getopt(argc, argv, "vhci:o:d:m:r:t:s:")))
+ if (-1 == (c = getopt(argc, argv, "vhlci:o:d:m:r:t:s:L:p:")))
break;
switch (c) {
case 'v':
verbose = 1;
break;
+ case 'l':
+ level_trigger = 1000;
+ break;
+ case 'L':
+ level_trigger = atoi(optarg);
+ break;
case 'i':
input = optarg;
break;
@@ -558,6 +595,9 @@ main(int argc, char *argv[])
case 'r':
rate = atoi(optarg);
break;
+ case 'p':
+ peak_seconds = atoi(optarg);
+ break;
case 't':
if (3 != sscanf(optarg,"%d:%d:%d",&maxhour,&maxmin,&maxsec)) {
maxhour = 0;
@@ -570,11 +610,7 @@ main(int argc, char *argv[])
maxsec += maxhour * 60 * 60;
break;
case 's':
- maxsize = parse_size(optarg);
- if (-1 == maxsize) {
- fprintf(stderr,"size parse error\n");
- exit(1);
- }
+ str_maxsize = optarg;
break;
case 'h':
usage(stdout);
@@ -584,13 +620,14 @@ main(int argc, char *argv[])
exit(1);
}
}
+ maxsize = parse_size(str_maxsize);
+ if (-1 == maxsize) {
+ fprintf(stderr,"maxsize parse error [%s]\n",str_maxsize);
+ exit(1);
+ }
mixer_open(mixer_dev,input);
sound_open(rate);
- delay = 0;
- auto_adjust = 1;
- record = 0;
- nr = 0;
outfile = malloc(strlen(filename)+16);
if (mode == NCURSES) {
@@ -671,8 +708,7 @@ main(int argc, char *argv[])
case 'N':
case 'n':
if (record) {
- wav_stop_write(wav);
- close(wav);
+ record_stop(wav);
wav = record_start(outfile,&nr);
}
break;
@@ -686,10 +722,8 @@ main(int argc, char *argv[])
auto_adjust=0;
} else {
/* stop */
- wav_stop_write(wav);
- close(wav);
+ record_stop(wav);
record=0;
- mvprintw(3,0,"%*.*s",COLS-1,COLS-1,blank);
}
break;
case KEY_RIGHT:
@@ -712,18 +746,39 @@ main(int argc, char *argv[])
}
if (mode == CONSOLE) {
- wav = record_start(outfile,&nr);
- record=1;
+ if (!level_trigger) {
+ wav = record_start(outfile,&nr);
+ record=1;
+ }
for (;!stop;) {
if (-1 == sound_read())
break;
+ if (level_trigger) {
+ if (!record &&
+ (maxl > level_trigger ||
+ maxr > level_trigger)) {
+ wav = record_start(outfile,&nr);
+ record=1;
+ }
+ if (record &&
+ secl < level_trigger &&
+ secr < level_trigger) {
+ record_stop(wav);
+ record=0;
+ }
+ }
+ if (!record) {
+ printf("waiting for signal [%d/%d]... \r",maxl,maxr);
+ fflush(stdout);
+ continue;
+ }
+
sec = (done_size + wav_size) / (rate*4);
if (maxsec && sec >= maxsec)
break;
if (wav_size + sound_blksize + sizeof(WAVEHDR) > maxsize) {
- wav_stop_write(wav);
- close(wav);
+ record_stop(wav);
wav = record_start(outfile,&nr);
}
wav_write_audio(wav,sound_buffer,sound_blksize);
@@ -742,14 +797,10 @@ main(int argc, char *argv[])
fflush(stdout);
}
}
- if (verbose)
- printf("\n");
}
- if (record) {
- wav_stop_write(wav);
- close(wav);
- }
+ if (record)
+ record_stop(wav);
mixer_close();
exit(0);
}
diff --git a/tools/record.man b/tools/record.man
index 96a7291..668332c 100644
--- a/tools/record.man
+++ b/tools/record.man
@@ -14,24 +14,32 @@ TV card etc.)
.B -h
display help text
.TP
-.B -i dev
-mixer input. This should be the one where you can
-adjust the record level for your audio source.
-Default is "line".
-.TP
.B -o file
basename for the output file(s), a number and the .wav
-extention are added by record. Default is "new".
+extention are added by record. Default is "record".
.TP
-.B -d dev
-set audio device. Default is "/dev/dsp".
+.B -i dev
+mixer control. This should be the one where you can adjust the record
+level for your audio source. Default is "line". "mic" and "igain"
+are good candidates too. Best way to figure is to start your favorite
+mixer tool and check out which one works ...
.TP
.B -m dev
set mixer device. Default is "/dev/mixer".
.TP
+.B -d dev
+set audio device. Default is "/dev/dsp".
+.TP
.B -r rate
set sample rate. Default is 44100.
.TP
+.B -p sec
+peak seconds (number of seconds which should be scanned for the volume
+maximum). This affects both peak level display and level triggered
+recording (see below). Default is two seconds.
+.P
+record can also be used non-interactive:
+.TP
.B -c
enable console (non-interactive) mode.
.TP
@@ -45,5 +53,19 @@ until stopped by a signal (by typing ^C for example).
.B -s size
Limit the file size (console mode only). record will continue with
a new file once the limit is reached.
+.TP
+.B -l
+Enable level triggered recording (console mode only) with the default
+trigger level (1000).
+.TP
+.B -L level
+Enable level triggered recording with the specified trigger level.
+.P
+If level triggered recording is active, record will start and stop
+recording depending on the signal strength. Recording will be started
+if the signal strength is above the trigger level (1000/32768 =>
+around 3%). Recording will be stopped if the signal is below the
+trigger level for some time (two seconds by default, the -p switch
+changes this).
.SH AUTHOR
Gerd Knorr <kraxel@bytesex.org>
diff --git a/webcam/webcam.c b/webcam/webcam.c
index b26de87..51da219 100644
--- a/webcam/webcam.c
+++ b/webcam/webcam.c
@@ -148,12 +148,14 @@ grab_init(void)
return;
/* check all available conversion functions */
+ fmt.bytesperline = fmt.width*ng_vfmt_to_depth[fmt.fmtid]/8;
for (i = 0;;) {
conv = ng_conv_find(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;
diff --git a/xawtv.spec b/xawtv.spec
index 3fcb585..690f42f 100644
--- a/xawtv.spec
+++ b/xawtv.spec
@@ -2,7 +2,7 @@ Name: xawtv
Group: Applications/Multimedia
Requires: v4l-conf, tv-common
Autoreqprov: on
-Version: 3.68
+Version: 3.69
Release: 0
License: GPL
Summary: Video4Linux TV application (Athena)

Privacy Policy