aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:37 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-04-01 11:24:37 +0200
commitf6d2dd2b56d8ae71234f8a1f5196d45f8eaf0e6a (patch)
tree1365b455c9aecea5af3585b1569032115caa8b63
parenta14893d52b6b3ee54d173e4289ae9416e8a8aa14 (diff)
v3.41
-rw-r--r--Changes23
-rw-r--r--KNOWN_PROBLEMS7
-rw-r--r--README23
-rw-r--r--README.recording74
-rw-r--r--debian/changelog6
-rw-r--r--libng/grab-bsd.c15
-rw-r--r--libng/grab-ng.c35
-rw-r--r--libng/grab-ng.h18
-rw-r--r--libng/grab-v4l.c34
-rw-r--r--libng/grab-v4l2.c57
-rw-r--r--libng/writeavi.c91
-rw-r--r--libng/writefile.c29
-rw-r--r--libng/writeqt.c36
-rw-r--r--man/xawtv.man18
-rw-r--r--radio/radio.c18
-rw-r--r--src/capture.c165
-rw-r--r--src/commands.c1
-rw-r--r--src/commands.h1
-rw-r--r--src/grab.c20
-rw-r--r--src/grab.h3
-rw-r--r--src/main.c70
-rw-r--r--src/sound.c340
-rw-r--r--src/sound.h9
-rw-r--r--src/streamer.c153
-rw-r--r--src/x11.c2
-rw-r--r--src/xt.c1
-rw-r--r--src/xt.h1
-rw-r--r--src/xv.c86
-rw-r--r--src/xv.h11
-rw-r--r--xawtv.spec2
30 files changed, 853 insertions, 496 deletions
diff --git a/Changes b/Changes
index cbffd46..2d999eb 100644
--- a/Changes
+++ b/Changes
@@ -1,4 +1,27 @@
+3.40 => 3.41
+============
+
+ * changed xawtv's internal time representation.
+ * rewrote rate control again. xawtv can puts frames twice into
+ the queue now, recording @ 25fps without frame drops is no
+ problem any more.
+ * made video stream recording optional. streamer can record
+ video only, video/audio and audio only (xawtv GUI not updated
+ yet). This implies that for avi and quicktime streams specifing
+ a video format isn't optional any more. If no video format is
+ given, streamer will not pick one for you, but will record audio
+ only.
+ * reorganized sound recording code a bit, added byteswapping support.
+ * MIT SHM failures with XvImages are catched now (=> hw scaling on
+ a remote display should work -- untested)
+ * gracefully fallback to "normal" rgb ximages if hw scaling with
+ Xvideo failes because the v4l driver can't capture packed yuv.
+ * 0.05 MHz steps for the radio app (Nils Kassube <kassube@gmx.net>).
+ * fixed one more segfault.
+ * updated README.recording
+
+
3.39 => 3.40 [the segfault bugfix release]
==========================================
diff --git a/KNOWN_PROBLEMS b/KNOWN_PROBLEMS
index 5c8d807..dec5386 100644
--- a/KNOWN_PROBLEMS
+++ b/KNOWN_PROBLEMS
@@ -1,4 +1,11 @@
+bttv + ATI Rage128 + DRI seem not to play nicely together (hard freeze).
+Don't know why. Happens with the ATI only, other gfx cards work fine.
+Suspect it's either a hardware problem or a bug somewhere in DRI (either
+kernel or xfree86). The only workaround I know of is to turn off DRI.
+
+--
+
For some people xawtv failes with
Error: Couldn't find per display information
diff --git a/README b/README
index f15857b..9b573e9 100644
--- a/README
+++ b/README
@@ -1,4 +1,8 @@
+IMPORTANT: Don't send me mails with images attached unless I ask you
+to do so. Mails with images attached will go to /dev/null unseen.
+
+
small is beautiful
==================
@@ -14,17 +18,16 @@ file. There are a few incompatible changes you have to take care
of.
READ THE F*** MANUAL FIRST (this README file, Trouble-Shooting file,
-xawtv man page, bttv driver documentation, the Sound-FAQ)
+KNOWN_PROBLEMS file, xawtv man page, documentation for the driver
+you are using).
If you have problems after upgrading, please check the ChangeLog for
hints first. Looking into the ChangeLog is a good idea in general,
becauce it is updated for every release, the other files are updated
-less freqently...
+less freqently and might be a bit outdated.
For problem/bug reports:
- * emails with images attached will to to /dev/null.
- * emails with the word "nagra" or "premiere" will go to /dev/null.
* emails with questions answered in the documentation will go to
/dev/null.
* emails which don't have any useful informations (like "xawtv
@@ -33,10 +36,11 @@ For problem/bug reports:
"useful informations" includes at least:
- xawtv version
- kernel version
- - driver version
- - which grabber board
+ - which driver (+ version if you know)
+ - which hardware (althrouth I'll probably can help with bttv
+ driver problems only).
- which TV norms are used in your country.
- - if xawtv prints errors, include these too.
+ - if xawtv prints errors, include these too (cut+paste)
- don't forget a description of your problem :-)
If you are using bttv as driver:
@@ -51,6 +55,9 @@ For patches/changes:
* Please add a comment what is changed and and why you changed it.
* Please send unified diffs ("diff -u") against the latest version.
* Please don't reformat my source code.
+ * Complete patches have better chances to go in. Quick+dirty hacks
+ which need cleanups and lack documentation updates are less likely
+ to go in simply because I need more time to deal with them.
compile & install
@@ -222,4 +229,4 @@ Have fun!
Gerd
--
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
diff --git a/README.recording b/README.recording
index d0f8103..9acedbe 100644
--- a/README.recording
+++ b/README.recording
@@ -8,9 +8,11 @@ linux sound drivers, you probably have to change this to line-in with
one of the available mixer tools. Also keep in mind that ALSA has
all mixer controls at 0 (i.e. muted) by default.
-/me uses kmix (because it is small). The inputs where the sound cards
-record from have a red background color. With the right mouse botton
-you'll get a menu where you can change the settings.
+/me uses kmix (because it doesn't need much space on the screen).
+The inputs where the sound cards record from have a red background
+color. With the right mouse botton you'll get a menu where you can
+change the settings. FreeBSD has a aumix version with X11 GUI in
+the ports collection which is very nice too.
Note on stereo: xanim seems not be able to playback stereo sound
correctly.
@@ -54,19 +56,10 @@ Known problems (and workarounds)
streamer/xawtv can't handle floating point frame rates (like 29.97).
Bad luck for now [to be fixed].
-streamer/xawtv can't deal very good with lost frames, it can't do
-(yet) tricks like stuffing the next frame twice it has lost one.
-That's a problem if you want to record at full framerate. A
-workaround is to use a slightly lower rate, say 24 instead of 25 fps
-(for PAL). If you lose a single frame now and then, streamer can deal
-with that much better because there is one "unused" frame per second.
-streamer can use that spare frame make video catch up if it lags
-behind a bit and avoid that audio/video run out of sync in the long
-run.
-
The timestamping for the video frames isn't very exact as it does
_not_ come from the v4l(1) driver but is just a gettimeofday() call
after receiving the video frame. API design bug, needs fixing.
+With v4l2 xawtv uses the frame timestamps provided by the driver.
Troubleshooting syncronisation problems
@@ -98,7 +91,60 @@ fine. Possible fixes: Try using more buffers. Try recording
compressed video. Try tuning the hard disk using hdparm. Buy a
faster hard disk. Buy a faster computer.
+If xawtv/streamer says "queueing frame twice" it has put a the same
+video frame twice into the output queue to avoid video running out of
+sync. If this happens alot it indicates that either your computer
+can't keep up with compressing the frames or that your v4l device
+can't capture frames with the frame rate you are asking for. A single
+message now and then is harmless.
+
+
+Read/Playback stuff
+===================
+
+avi format
+----------
+
+ * xanim plays everything without problems.
+ * QuickTime[tm] (MacOS) plays the uncompressed formats just
+ fine and complains about mjpeg/jpeg.
+ * Windows Media Player plays the uncompressed formats fine.
+ mjpeg/jpeg work too if a codec is installed (/me has a very
+ old one from MainConcept).
+ * avifile can't deal with the uncompressed video correctly.
+ mjpeg/jpeg doesn't work either for me as it seems not to
+ recognise the MainConcept codec, althought I've copied
+ stuff to /usr/lib/win32. Maybe it works with another
+ one.
+ * MainActor (linux) can read the mjpeg but not the jpeg
+ compressed files.
+
+
+quicktime format
+----------------
+
+ * xmovie + broadcast2000 can read the files without problems
+ (not exactly surprising as they use the quicktime4linux
+ library too ...).
+ * QuickTime[tm] (MacOS/Windows) plays them without problems.
+ * xanim says it can't find any data in the mov file. It used
+ to work with older versions of the quicktime4linux library
+ (before 64bit support was added), so I suspect xanim simply
+ can't deal with 64bit mov files.
+
+
+raw data
+--------
+
+ * ImageMagick can deal with this, you have to specify the image
+ format + size on the command line like this:
+ display -size 320x240 rgb:file.raw
+ It can handle multiple frames in one big file too.
+
+
+Have fun,
+
Gerd
--
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
diff --git a/debian/changelog b/debian/changelog
index b7b20f5..1d836f2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+xawtv (3.41) unstable; urgency=low
+
+ * new release.
+
+ -- Gerd Knorr <kraxel@debian.org> Fri, 23 Mar 2001 22:49:04 +0100
+
xawtv (3.40) unstable; urgency=high
* new release (closes: #90003).
diff --git a/libng/grab-bsd.c b/libng/grab-bsd.c
index 3dc6507..308b93e 100644
--- a/libng/grab-bsd.c
+++ b/libng/grab-bsd.c
@@ -57,8 +57,8 @@ struct bsd_handle {
int ov_enabled,ov_on;
/* capture */
- int fps,frames;
- struct timeval start;
+ int fps;
+ long long start;
struct ng_video_fmt fmt;
struct meteor_video nofb;
struct meteor_geomet capgeo;
@@ -719,8 +719,7 @@ static int bsd_startvideo(void *handle, int fps, int buffers)
set_overlay(h,0);
h->fps = fps;
- h->frames = 0;
- gettimeofday(&h->start,NULL);
+ h->start = ng_get_timestamp();
set_capture(h,1);
xioctl(h->fd, METEORSSIGNAL, &signal_on);
xioctl(h->fd, METEORCAPTUR, &start);
@@ -742,25 +741,21 @@ static struct ng_video_buf* bsd_nextframe(void *handle)
{
struct bsd_handle *h = handle;
struct ng_video_buf *buf;
- int size,rc;
+ int size;
sigset_t sa_mask;
size = h->fmt.bytesperline * h->fmt.height;
buf = ng_malloc_video_buf(&h->fmt,size);
- next_frame:
alarm(1);
sigfillset(&sa_mask);
sigdelset(&sa_mask,SIGUSR1);
sigdelset(&sa_mask,SIGALRM);
sigsuspend(&sa_mask);
alarm(0);
- rc = ng_grabber_swrate(&h->start,h->fps,h->frames);
- if (rc <= 0)
- goto next_frame;
memcpy(buf->data,h->map,size);
- h->frames++;
+ buf->ts = ng_get_timestamp() - h->start;
return buf;
}
diff --git a/libng/grab-ng.c b/libng/grab-ng.c
index 622fadb..9e4bac5 100644
--- a/libng/grab-ng.c
+++ b/libng/grab-ng.c
@@ -59,7 +59,7 @@ const char* ng_vfmt_to_desc[] = {
"32 bit TrueColor (BE: -rgb)",
"16 bit TrueColor (lut)",
"32 bit TrueColor (lut)",
- "16 bit YUV 4:2:2",
+ "16 bit YUV 4:2:2 (packed)",
"16 bit YUV 4:2:2 (planar)",
"12 bit YUV 4:2:0 (planar)",
"MJPEG (AVI)",
@@ -350,29 +350,18 @@ ng_grabber_open(char *device, struct ng_video_fmt *screen, void *base,
return ng_drivers[i];
}
-int
-ng_grabber_swrate(struct timeval *start, int fps, int count)
+long long
+ng_get_timestamp()
{
- struct timeval now;
- int msecs,frames;
- static int lasterr;
-
- if (-1 == fps)
- return 1;
-
- gettimeofday(&now,NULL);
- msecs = now.tv_usec/1000 - start->tv_usec/1000;
- msecs += now.tv_sec*1000 - start->tv_sec*1000;
- frames = msecs * fps / 1000;
- if (ng_debug > 1)
- fprintf(stderr,"rate: msecs=%d fps=%d -> frames=%d |"
- " count=%d ret=%d\n",
- msecs,fps,frames,count,frames-count+1);
- if (frames-count > 3 && frames-count != lasterr) {
- lasterr = frames-count;
- fprintf(stderr,"rate control: video lags %d frames behind\n",lasterr);
- }
- return frames-count+1;
+ struct timeval tv;
+ long long ts;
+
+ gettimeofday(&tv,NULL);
+ ts = tv.tv_sec;
+ ts *= 1000000;
+ ts += tv.tv_usec;
+ ts *= 1000;
+ return ts;
}
/* --------------------------------------------------------------------- */
diff --git a/libng/grab-ng.h b/libng/grab-ng.h
index 649beb9..18f0cfc 100644
--- a/libng/grab-ng.h
+++ b/libng/grab-ng.h
@@ -40,6 +40,14 @@ extern char ng_v4l_conf[256];
#define AUDIO_S16_BE_MONO 5
#define AUDIO_S16_BE_STEREO 6
#define AUDIO_FMT_COUNT 7
+#if BYTE_ORDER == BIG_ENDIAN
+# define AUDIO_S16_NATIVE_MONO AUDIO_S16_BE_MONO
+# define AUDIO_S16_NATIVE_STEREO AUDIO_S16_BE_STEREO
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define AUDIO_S16_NATIVE_MONO AUDIO_S16_LE_MONO
+# define AUDIO_S16_NATIVE_STEREO AUDIO_S16_LE_STEREO
+#endif
#define ATTR_TYPE_INTEGER 1 /* range 0 - 65535 */
#define ATTR_TYPE_CHOICE 2 /* multiple choice */
@@ -97,7 +105,8 @@ struct ng_video_buf {
int size;
char *data;
- /* FIXME: time (struct timeval?) */
+ /* frame timestamp */
+ long long ts;
/*
* the lock is for the reference counter.
@@ -133,7 +142,7 @@ struct ng_audio_buf {
int size;
char *data;
- /* FIXME: time */
+ long long ts;
};
@@ -225,7 +234,6 @@ struct ng_driver {
/* --------------------------------------------------------------------- */
-/* TODO: color space conversion / compression */
/* maybe add filters for on-the-fly image processing later */
struct ng_video_conv {
@@ -240,6 +248,7 @@ struct ng_video_conv {
void *priv;
};
+
/* --------------------------------------------------------------------- */
extern const struct ng_driver *ng_drivers[];
@@ -251,7 +260,7 @@ struct ng_video_conv* ng_conv_find(int out, int *i);
const struct ng_driver*
ng_grabber_open(char *device, struct ng_video_fmt *screen,
void *base, void **handle);
-int ng_grabber_swrate(struct timeval *start, int fps, int count);
+long long ng_get_timestamp(void);
/* --------------------------------------------------------------------- */
@@ -274,4 +283,3 @@ void ng_conv_nop_fini(void *handle);
init: ng_packed_init, \
frame: ng_packed_frame, \
fini: ng_conv_nop_fini
-
diff --git a/libng/grab-v4l.c b/libng/grab-v4l.c
index dd04209..4dc01fb 100644
--- a/libng/grab-v4l.c
+++ b/libng/grab-v4l.c
@@ -159,9 +159,8 @@ struct v4l_handle {
/* capture */
int use_read;
struct ng_video_fmt fmt;
- struct timeval start;
+ long long start;
int fps;
- int frames;
/* capture via read() */
struct ng_video_fmt rd_fmt;
@@ -428,7 +427,6 @@ v4l_open(char *device)
inputs[i].nr = -1;
inputs[i].str = NULL;
v4l_add_attr(h,ATTR_ID_INPUT,ATTR_TYPE_CHOICE,0,inputs);
- h->input = -1;
/* audios */
if (ng_debug)
@@ -616,14 +614,10 @@ static int v4l_read_attr(void *handle, struct ng_attribute *attr)
switch (attr->id) {
case ATTR_ID_INPUT:
- return h->input;
+ return -1;
case ATTR_ID_NORM:
- if (-1 != h->input) {
- xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]);
- return h->channels[h->input].norm;
- } else {
- return -1;
- }
+ xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]);
+ return h->channels[h->input].norm;
case ATTR_ID_MUTE:
xioctl(h->fd, VIDIOCGAUDIO, &h->audio);
return h->audio.flags & VIDEO_AUDIO_MUTE;
@@ -1141,9 +1135,8 @@ v4l_startvideo(void *handle, int fps, int buffers)
h->nbuf = buffers;
mm_queue_all(h);
}
- gettimeofday(&h->start,NULL);
+ h->start = ng_get_timestamp();
h->fps = fps;
- h->frames = 0;
return 0;
}
@@ -1166,7 +1159,7 @@ v4l_nextframe(void *handle)
{
struct v4l_handle *h = handle;
struct ng_video_buf* buf = NULL;
- int rc, frame = 0;
+ int frame = 0;
if (ng_debug > 1)
fprintf(stderr,"v4l: getimage\n");
@@ -1176,7 +1169,6 @@ v4l_nextframe(void *handle)
return NULL;
}
- next_frame:
if (h->use_read) {
if (buf)
ng_release_video_buf(buf);
@@ -1185,23 +1177,15 @@ v4l_nextframe(void *handle)
v4l_overlay_set(h,h->ov_enabled);
if (NULL == buf)
return NULL;
+ buf->ts = ng_get_timestamp() - h->start;
+ return buf;
} else {
mm_queue_all(h);
frame = mm_waiton(h);
if (-1 == frame)
return NULL;
- }
-
- /* rate control */
- rc = ng_grabber_swrate(&h->start,h->fps,h->frames);
- if (rc <= 0)
- goto next_frame;
-
- h->frames++;
- if (h->use_read) {
- return buf;
- } else {
h->buf_me[frame].refcount++;
+ h->buf_me[frame].ts = ng_get_timestamp() - h->start;
return h->buf_me+frame;
}
}
diff --git a/libng/grab-v4l2.c b/libng/grab-v4l2.c
index 1f6951f..08cf8cb 100644
--- a/libng/grab-v4l2.c
+++ b/libng/grab-v4l2.c
@@ -24,8 +24,6 @@
#endif
#include <pthread.h>
-#include <X11/Intrinsic.h>
-
#include "grab-ng.h"
#ifndef __linux__
@@ -90,8 +88,8 @@ struct v4l2_handle {
struct ng_attribute *attr;
/* capture */
- int fps,frames;
- struct timeval start;
+ int fps,first;
+ long long start;
struct v4l2_format fmt_v4l2;
struct ng_video_fmt fmt_me;
struct v4l2_requestbuffers reqbufs;
@@ -1132,8 +1130,8 @@ v4l2_startvideo(void *handle, int fps, int buffers)
if (0 != h->fps)
fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n");
h->fps = fps;
- h->frames = 0;
- gettimeofday(&h->start,NULL);
+ h->first = 1;
+ h->start = 0;
if (h->cap.flags & V4L2_FLAG_STREAMING)
v4l2_start_streaming(h,buffers);
@@ -1161,34 +1159,31 @@ v4l2_nextframe(void *handle)
struct ng_video_buf *buf = NULL;
int size,frame = 0;
- for (;;) {
- if (h->cap.flags & V4L2_FLAG_STREAMING) {
- v4l2_queue_all(h);
- frame = v4l2_waiton(h);
- if (-1 == frame)
- return NULL;
- h->buf_me[frame].refcount++;
- buf = &h->buf_me[frame];
- } else {
- size = h->fmt_me.bytesperline * h->fmt_me.height;
- buf = ng_malloc_video_buf(&h->fmt_me,size);
- if (size != read(h->fd,buf->data,size)) {
- ng_release_video_buf(buf);
- return NULL;
- }
- }
-
- /* rate control -- FIXME: use timecode instead */
- if (ng_grabber_swrate(&h->start,h->fps,h->frames) > 0)
- break;
-
- if (h->cap.flags & V4L2_FLAG_STREAMING) {
- h->buf_me[frame].refcount--;
- } else {
+ if (h->cap.flags & V4L2_FLAG_STREAMING) {
+ v4l2_queue_all(h);
+ frame = v4l2_waiton(h);
+ if (-1 == frame)
+ return NULL;
+ h->buf_me[frame].refcount++;
+ buf = &h->buf_me[frame];
+ buf->ts = h->buf_v4l2[frame].timestamp;
+ } else {
+ size = h->fmt_me.bytesperline * h->fmt_me.height;
+ buf = ng_malloc_video_buf(&h->fmt_me,size);
+ if (size != read(h->fd,buf->data,size)) {
ng_release_video_buf(buf);
+ return NULL;
}
+ buf->ts = ng_get_timestamp();
+ }
+
+ if (h->first) {
+ h->first = 0;
+ h->start = buf->ts;
+ if (ng_debug)
+ fprintf(stderr,"v4l2: start ts=%lld\n",h->start);
}
- h->frames++;
+ buf->ts -= h->start;
return buf;
}
diff --git a/libng/writeavi.c b/libng/writeavi.c
index 46a86a4..100ccdc 100644
--- a/libng/writeavi.c
+++ b/libng/writeavi.c
@@ -358,7 +358,7 @@ avi_open(char *filename, char *dummy,
{
const struct avi_video_priv *pvideo = priv_video;
struct avi_handle *h;
- int i,frame_bytes,depth;
+ int i,frame_bytes,depth,streams,rate;
if (NULL == (h = malloc(sizeof(*h))))
return NULL;
@@ -379,11 +379,6 @@ avi_open(char *filename, char *dummy,
h->vec = malloc(sizeof(struct iovec) * video->height);
strcpy(h->file,filename);
- for (i = 0; i < 4; i++) {
- h->avi_hdr_video.strh.handler[i] = pvideo->handler[i];
- h->avi_hdr_video.strf.compression[i] = pvideo->compress[i];
- }
-
if (-1 == (h->fd = open(h->file,O_CREAT | O_RDWR | O_TRUNC, 0666))) {
fprintf(stderr,"open %s: %s\n",h->file,strerror(errno));
free(h);
@@ -391,30 +386,44 @@ avi_open(char *filename, char *dummy,
}
/* general */
+ streams = 0;
+ rate = 0;
+ if (h->video.fmtid != VIDEO_NONE) {
+ streams++;
+ rate += pvideo->bytesperpixel * fps;
+ h->avi_hdr.avih.width = AVI_SWAP4(h->video.width);
+ h->avi_hdr.avih.height = AVI_SWAP4(h->video.height);
+ }
+ if (h->audio.fmtid != AUDIO_NONE) {
+ streams++;
+ rate += ng_afmt_to_channels[h->audio.fmtid] *
+ ng_afmt_to_bits[h->audio.fmtid] *
+ h->audio.rate / 8;
+ }
h->avi_hdr.avih.us_frame = AVI_SWAP4(1000000/fps);
- h->avi_hdr.avih.bps =
- AVI_SWAP4(pvideo->bytesperpixel * fps +
- ng_afmt_to_channels[h->audio.fmtid] *
- ng_afmt_to_bits[h->audio.fmtid] *
- h->audio.rate / 8);
- h->avi_hdr.avih.streams = AVI_SWAP4(h->audio.fmtid != AUDIO_NONE ? 2 : 1);
- h->avi_hdr.avih.width = AVI_SWAP4(h->video.width);
- h->avi_hdr.avih.height = AVI_SWAP4(h->video.height);
+ h->avi_hdr.avih.bps = AVI_SWAP4(rate);
+ h->avi_hdr.avih.streams = AVI_SWAP4(streams);
h->hdr_size += write(h->fd,&h->avi_hdr,sizeof(struct AVI_HDR));
/* video */
- frame_bytes = pvideo->bytesperpixel * h->video.width * h->video.height;
- depth = ng_vfmt_to_depth[h->video.fmtid];
- h->frame_hdr.size = AVI_SWAP4(frame_bytes);
- h->avi_hdr_video.strh.scale = AVI_SWAP4(1000000/fps);
- h->avi_hdr_video.strh.rate = AVI_SWAP4(1000000);
- h->avi_hdr_video.strf.size = AVI_SWAP4(sizeof(avi_hdr_video.strf));
- h->avi_hdr_video.strf.width = AVI_SWAP4(h->video.width);
- h->avi_hdr_video.strf.height = AVI_SWAP4(h->video.height);
- h->avi_hdr_video.strf.planes = AVI_SWAP2(1);
- h->avi_hdr_video.strf.bit_cnt = AVI_SWAP2(depth ? depth : 24);
- h->avi_hdr_video.strf.image_size = AVI_SWAP4(frame_bytes);
- h->hdr_size += write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
+ if (h->video.fmtid != VIDEO_NONE) {
+ for (i = 0; i < 4; i++) {
+ h->avi_hdr_video.strh.handler[i] = pvideo->handler[i];
+ h->avi_hdr_video.strf.compression[i] = pvideo->compress[i];
+ }
+ frame_bytes = pvideo->bytesperpixel * h->video.width * h->video.height;
+ depth = ng_vfmt_to_depth[h->video.fmtid];
+ h->frame_hdr.size = AVI_SWAP4(frame_bytes);
+ h->avi_hdr_video.strh.scale = AVI_SWAP4(1000000/fps);
+ h->avi_hdr_video.strh.rate = AVI_SWAP4(1000000);
+ h->avi_hdr_video.strf.size = AVI_SWAP4(sizeof(avi_hdr_video.strf));
+ h->avi_hdr_video.strf.width = AVI_SWAP4(h->video.width);
+ h->avi_hdr_video.strf.height = AVI_SWAP4(h->video.height);
+ h->avi_hdr_video.strf.planes = AVI_SWAP2(1);
+ h->avi_hdr_video.strf.bit_cnt = AVI_SWAP2(depth ? depth : 24);
+ h->avi_hdr_video.strf.image_size = AVI_SWAP4(frame_bytes);
+ h->hdr_size += write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
+ }
/* audio */
if (h->audio.fmtid != AUDIO_NONE) {
@@ -446,7 +455,8 @@ avi_open(char *filename, char *dummy,
h->hdr_size += write(h->fd,&h->avi_hdr_audio,
sizeof(struct AVI_HDR_AUDIO));
}
- h->hdr_size += write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
+ if (h->video.fmtid != VIDEO_NONE)
+ h->hdr_size += write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
/* data */
if (-1 == write(h->fd,&h->avi_data,sizeof(struct AVI_DATA))) {
@@ -542,18 +552,21 @@ avi_close(void *handle)
struct avi_handle *h = handle;
/* write frame index */
- if (!h->bigfile) {
- avi_writeindex(h);
- } else {
- avi_bigfile(h,1);
- h->idx_size = 0;
+ if (h->video.fmtid != VIDEO_NONE) {
+ if (!h->bigfile) {
+ avi_writeindex(h);
+ } else {
+ avi_bigfile(h,1);
+ h->idx_size = 0;
+ }
}
/* fill in some statistic values ... */
h->avi_hdr.riff_size = AVI_SWAP4(h->hdr_size+h->data_size+h->idx_size);
h->avi_hdr.hdrl_size = AVI_SWAP4(h->hdr_size - 4*5);
h->avi_hdr.avih.frames = AVI_SWAP4(h->frames);
- h->avi_hdr_video.strh.length = AVI_SWAP4(h->frames);
+ if (h->video.fmtid != VIDEO_NONE)
+ h->avi_hdr_video.strh.length = AVI_SWAP4(h->frames);
if (h->audio.fmtid != AUDIO_NONE)
h->avi_hdr_audio.strh.length =
AVI_SWAP4(h->audio_size/h->avi_hdr_audio.strh.scale);
@@ -562,11 +575,14 @@ avi_close(void *handle)
/* ... and write header again */
lseek(h->fd,0,SEEK_SET);
write(h->fd,&h->avi_hdr,sizeof(struct AVI_HDR));
- write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
+ if (h->video.fmtid != VIDEO_NONE)
+ write(h->fd,&h->avi_hdr_video,sizeof(struct AVI_HDR_VIDEO));
if (h->audio.fmtid != AUDIO_NONE)
write(h->fd,&h->avi_hdr_audio,sizeof(struct AVI_HDR_AUDIO));
- h->avi_hdr_odml.total_frames = h->frames_total;
- write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
+ if (h->video.fmtid != VIDEO_NONE) {
+ h->avi_hdr_odml.total_frames = h->frames_total;
+ write(h->fd,&h->avi_hdr_odml,sizeof(struct AVI_HDR_ODML));
+ }
write(h->fd,&h->avi_data,sizeof(struct AVI_DATA));
close(h->fd);
@@ -618,12 +634,15 @@ static const struct ng_format_list avi_vformats[] = {
static const struct ng_format_list avi_aformats[] = {
{
name: "mono8",
+ ext: "avi",
fmtid: AUDIO_U8_MONO,
},{
name: "mono16",
+ ext: "avi",
fmtid: AUDIO_S16_LE_MONO,
},{
name: "stereo",
+ ext: "avi",
fmtid: AUDIO_S16_LE_STEREO,
},{
/* EOF */
diff --git a/libng/writefile.c b/libng/writefile.c
index 156d6d5..5775f1c 100644
--- a/libng/writefile.c
+++ b/libng/writefile.c
@@ -280,7 +280,7 @@ files_open(char *filesname, char *audioname,
{
struct files_handle *h;
- if (NULL == filesname)
+ if (video->fmtid != VIDEO_NONE && NULL == filesname)
return NULL;
if (NULL == (h = malloc(sizeof(*h))))
return NULL;
@@ -289,7 +289,8 @@ files_open(char *filesname, char *audioname,
memset(h,0,sizeof(*h));
h->video = *video;
h->audio = *audio;
- strcpy(h->file,filesname);
+ if (filesname)
+ strcpy(h->file,filesname);
if (h->audio.fmtid != AUDIO_NONE) {
h->wav_fd = open(audioname, O_CREAT | O_RDWR | O_TRUNC, 0666);
@@ -404,17 +405,19 @@ raw_open(char *videoname, char *audioname,
}
/* video */
- if (NULL != videoname) {
- h->fd = open(videoname, O_CREAT | O_RDWR | O_TRUNC, 0666);
- if (-1 == h->fd) {
- fprintf(stderr,"open %s: %s\n",videoname,strerror(errno));
- if (h->wav_fd)
- close(h->wav_fd);
- free(h);
- return NULL;
+ if (h->video.fmtid != VIDEO_NONE) {
+ if (NULL != videoname) {
+ h->fd = open(videoname, O_CREAT | O_RDWR | O_TRUNC, 0666);
+ if (-1 == h->fd) {
+ fprintf(stderr,"open %s: %s\n",videoname,strerror(errno));
+ if (h->wav_fd)
+ close(h->wav_fd);
+ free(h);
+ return NULL;
+ }
+ } else {
+ h->fd = 1; /* use stdout */
}
- } else {
- h->fd = 1; /* use stdout */
}
return h;
@@ -449,7 +452,7 @@ raw_close(void *handle)
wav_stop_write(h->wav_fd,&h->wav_header,h->wav_size);
close(h->wav_fd);
}
- if (1 != h->fd)
+ if (h->video.fmtid != VIDEO_NONE && 1 != h->fd)
close(h->fd);
free(h);
return 0;
diff --git a/libng/writeqt.c b/libng/writeqt.c
index 53941cc..cfaf85d 100644
--- a/libng/writeqt.c
+++ b/libng/writeqt.c
@@ -52,7 +52,8 @@ qt_open(char *filename, char *dummy,
memset(h,0,sizeof(*h));
h->video = *video;
h->audio = *audio;
- h->lib_video = pvideo->libencode;
+ if (h->video.fmtid != VIDEO_NONE)
+ h->lib_video = pvideo->libencode;
if (h->audio.fmtid != AUDIO_NONE)
h->lib_audio = paudio->libencode;
@@ -72,18 +73,18 @@ qt_open(char *filename, char *dummy,
(char*)paudio->codec);
h->audio_sample = ng_afmt_to_channels[h->audio.fmtid] *
ng_afmt_to_bits[h->audio.fmtid] / 8;
+ if (h->lib_audio && !quicktime_supported_audio(h->fh, 0)) {
+ fprintf(stderr,"libquicktime: audio codec not supported\n");
+ goto fail;
+ }
}
-
- quicktime_set_video(h->fh,1,h->video.width,h->video.height,fps,
- (char*)pvideo->codec);
- if (h->lib_video && !quicktime_supported_video(h->fh, 0)) {
- fprintf(stderr,"libquicktime: video codec not supported\n");
- goto fail;
- }
- if (h->lib_video && h->audio.fmtid != AUDIO_NONE &&
- !quicktime_supported_audio(h->fh, 0)) {
- fprintf(stderr,"libquicktime: audio codec not supported\n");
- goto fail;
+ if (h->video.fmtid != VIDEO_NONE) {
+ quicktime_set_video(h->fh,1,h->video.width,h->video.height,fps,
+ (char*)pvideo->codec);
+ if (h->lib_video && !quicktime_supported_video(h->fh, 0)) {
+ fprintf(stderr,"libquicktime: video codec not supported\n");
+ goto fail;
+ }
}
quicktime_set_info(h->fh, "Dumme Bemerkungen gibt's hier umsonst.");
return h;
@@ -133,10 +134,10 @@ int
qt_close(void *handle)
{
struct qt_handle *h = handle;
-#if 0
- free (qt_row_pointers);
-#endif
- return quicktime_close(h->fh);
+
+ quicktime_close(h->fh);
+ if (h->rows)
+ free(h->rows);
return 0;
}
@@ -212,14 +213,17 @@ static const struct qt_audio_priv qt_stereo = {
static const struct ng_format_list qt_aformats[] = {
{
name: "mono8",
+ ext: "mov",
fmtid: AUDIO_U8_MONO,
priv: &qt_mono8,
},{
name: "mono16",
+ ext: "mov",
fmtid: AUDIO_S16_BE_MONO,
priv: &qt_mono16,
},{
name: "stereo",
+ ext: "mov",
fmtid: AUDIO_S16_BE_STEREO,
priv: &qt_stereo,
},{
diff --git a/man/xawtv.man b/man/xawtv.man
index d36c3d4..1df5021 100644
--- a/man/xawtv.man
+++ b/man/xawtv.man
@@ -297,15 +297,25 @@ source = Composite1
key = K
.fi
.SH BUGS
-If xawtv dumps core, you can fix this with "ulimit -c 0".
+The mono/stereo display is \fBnot\fP reliable due to v4l API
+restrictions. The API can not report back the current audio
+mode, but a list of the currently available modes. xawtv just
+does a guess based on that, assuming the driver uses the best
+available mode. Depending on your hardware this might not
+be true.
+.P
+If in doubt whenever stereo \fBreally\fP works, please tune
+in MTV and listen, don't trust what xawtv says.
+.P
+.B Bug reports with images attached go to /dev/null unseen.
.SH SEE ALSO
fbtv(1), v4l-conf(1)
.br
-http://www.in-berlin.de/User/kraxel/xawtv.html (homepage)
+http://www.strusel007.de/kraxel/xawtv/ (homepage)
.SH AUTHOR
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
.SH COPYRIGHT
-Copyright (C) 1997-99 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Copyright (C) 1997-99 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/radio/radio.c b/radio/radio.c
index 1faf9ab..e608b18 100644
--- a/radio/radio.c
+++ b/radio/radio.c
@@ -100,8 +100,8 @@ void print_freq(float freq)
{
int x,y,i;
char text[10];
- sprintf(text,"%5.1f",freq);
- for (i = 0, x = 12; i < 5; i++, x+=4) {
+ sprintf(text,"%6.2f",freq);
+ for (i = 0, x = 8; i < 6; i++, x+=4) {
if (text[i] >= '0' && text[i] <= '9') {
for (y = 0; y < 3; y++)
mvwprintw(wfreq,y+1,x,"%s",digit[y][text[i]-'0']);
@@ -167,7 +167,7 @@ make_label(int ifreq)
if (NULL != (l = find_label(ifreq)))
return l;
- sprintf(text,"%5.1f MHz",(float)ifreq/1000000);
+ sprintf(text,"%6.2f MHz",(float)ifreq/1000000);
return text;
}
@@ -183,8 +183,8 @@ main(int argc, char *argv[])
if (argc > 1 && 1 == sscanf(argv[1],"%f",&ffreq)) {
ifreq = (int)(ffreq * 1000000);
- ifreq += 50000;
- ifreq -= ifreq % 100000;
+ ifreq += 25000;
+ ifreq -= ifreq % 50000;
}
if (-1 == (fd = open(DEVICE, O_RDONLY))) {
@@ -300,11 +300,15 @@ main(int argc, char *argv[])
ifreq = newfreq * 1000000;
break;
case KEY_UP:
- ifreq += 100000;
+ ifreq += 50000;
+ if (ifreq > 108000000)
+ ifreq = 87500000;
mvwprintw(wcommand, 1, 2, "Increment frequency");
break;
case KEY_DOWN:
- ifreq -= 100000;
+ ifreq -= 50000;
+ if (ifreq < 87500000)
+ ifreq = 108000000;
mvwprintw(wcommand, 1, 2, "Decrease frequency");
break;
case KEY_F(1):
diff --git a/src/capture.c b/src/capture.c
index e75f6d7..9e9c2fd 100644
--- a/src/capture.c
+++ b/src/capture.c
@@ -100,29 +100,33 @@ flushit(void *arg)
/*-------------------------------------------------------------------------*/
struct movie_handle {
+ /* general */
pthread_mutex_t lock;
const struct ng_writer *writer;
void *handle;
pthread_t tflush;
- struct timeval start;
- long long rusec;
+ long long start;
+ long long rts;
long long stopby;
int slots;
+ /* video */
struct ng_video_fmt vfmt;
int fps;
int frames;
struct FIFO vfifo;
pthread_t tvideo;
- long long vusec;
+ long long vts;
+ /* audio */
+ void *sndhandle;
struct ng_audio_fmt afmt;
unsigned long bytes_per_sec;
unsigned long bytes;
struct FIFO afifo;
pthread_t taudio;
pthread_t raudio;
- long long ausec;
+ long long ats;
};
static void*
@@ -140,9 +144,6 @@ writer_audio_thread(void *arg)
pthread_mutex_lock(&h->lock);
h->writer->wr_audio(h->handle,buf);
pthread_mutex_unlock(&h->lock);
-#if 0
- free(buf->data);
-#endif
free(buf);
}
if (debug)
@@ -177,28 +178,17 @@ record_audio_thread(void *arg)
{
struct movie_handle *h = arg;
struct ng_audio_buf *buf;
- int size,left,last;
if (debug)
fprintf(stderr,"record_audio_thread start [pid=%d]\n",getpid());
- size = sound_bufsize();
- for (last = 0; !last;) {
- buf = malloc(sizeof(*buf)+size);
- buf->fmt = h->afmt;
- buf->size = size;
- buf->data = ((char*)buf) + sizeof(*buf);
- memset(buf->data,0,size);
- sound_read(buf->data);
- if (h->stopby) {
- left = (h->stopby - h->ausec) * h->bytes_per_sec / 1000000;
- if (left <= size) {
- size = left;
- last = 1;
- }
- }
+ for (;;) {
+ buf = oss_read(h->sndhandle,h->stopby);
+ if (NULL == buf)
+ break;
+ if (0 == buf->size)
+ continue;
+ h->ats = buf->ts;
fifo_put(&h->afifo,buf);
- h->bytes += size;
- h->ausec = (long long)h->bytes * 1000000 / h->bytes_per_sec;
}
fifo_put(&h->afifo,NULL);
if (debug)
@@ -227,27 +217,32 @@ movie_writer_init(char *moviename, char *audioname,
h->slots = slots;
/* audio */
- if (audio->fmtid != AUDIO_NONE)
- sound_open(audio);
if (audio->fmtid != AUDIO_NONE) {
+ h->sndhandle = oss_open(NULL,audio);
+ if (NULL == h->sndhandle) {
+ free(h);
+ return NULL;
+ }
fifo_init(&h->afifo,"audio",slots);
pthread_create(&h->taudio,NULL,writer_audio_thread,h);
h->bytes_per_sec = ng_afmt_to_bits[audio->fmtid] *
ng_afmt_to_channels[audio->fmtid] * audio->rate / 8;
+ h->afmt = *audio;
}
- h->afmt = *audio;
/* video */
- if (-1 == ng_grabber_setparams(video,0)) {
- if (h->afmt.fmtid != AUDIO_NONE)
- sound_close();
- free(h);
- return NULL;
- }
- fifo_init(&h->vfifo,"video",slots);
- pthread_create(&h->tvideo,NULL,writer_video_thread,h);
- h->vfmt = *video;
- h->fps = fps;
+ if (video->fmtid != VIDEO_NONE) {
+ if (-1 == ng_grabber_setparams(video,0)) {
+ if (h->afmt.fmtid != AUDIO_NONE)
+ oss_close(h->sndhandle);
+ free(h);
+ return NULL;
+ }
+ fifo_init(&h->vfifo,"video",slots);
+ pthread_create(&h->tvideo,NULL,writer_video_thread,h);
+ h->vfmt = *video;
+ h->fps = fps;
+ }
/* open file */
h->handle = writer->wr_open(moviename,audioname,
@@ -262,12 +257,13 @@ movie_writer_init(char *moviename, char *audioname,
if (h->afmt.fmtid != AUDIO_NONE) {
pthread_cancel(h->taudio);
pthread_join(h->taudio,&dummy);
- sound_close();
+ oss_close(h->sndhandle);
+ }
+ if (h->vfmt.fmtid != VIDEO_NONE) {
+ pthread_cancel(h->tvideo);
+ pthread_join(h->tvideo,&dummy);
}
- pthread_cancel(h->tvideo);
- pthread_join(h->tvideo,&dummy);
free(h);
-
return NULL;
}
@@ -276,10 +272,11 @@ movie_writer_start(struct movie_handle *h)
{
if (debug)
fprintf(stderr,"movie_writer_start\n");
- gettimeofday(&h->start,NULL);
+ h->start = ng_get_timestamp();
if (h->afmt.fmtid != AUDIO_NONE)
- sound_startrec();
- drv->startvideo(h_drv,h->fps,h->slots);
+ oss_startrec(h->sndhandle);
+ if (h->vfmt.fmtid != VIDEO_NONE)
+ drv->startvideo(h_drv,h->fps,h->slots);
if (h->afmt.fmtid != AUDIO_NONE)
pthread_create(&h->raudio,NULL,record_audio_thread,h);
pthread_create(&h->tflush,NULL,flushit,NULL);
@@ -296,18 +293,20 @@ movie_writer_stop(struct movie_handle *h)
if (debug)
fprintf(stderr,"movie_writer_stop\n");
- if (h->afmt.fmtid != AUDIO_NONE) {
+ if (h->vfmt.fmtid != VIDEO_NONE && h->afmt.fmtid != AUDIO_NONE) {
for (frames = 0; frames < 16; frames++) {
- stopby = (long long)(h->frames + frames) * 1000000 / h->fps;
- if (stopby > h->ausec)
+ stopby = (long long)(h->frames + frames) * 1000000000 / h->fps;
+ if (stopby > h->ats)
break;
}
frames++;
- h->stopby = (long long)(h->frames + frames) * 1000000 / h->fps;
+ h->stopby = (long long)(h->frames + frames) * 1000000000 / h->fps;
while (frames) {
movie_grab_put_video(h);
frames--;
}
+ } else if (h->afmt.fmtid != AUDIO_NONE) {
+ h->stopby = h->ats;
}
/* send EOF + join threads */
@@ -316,51 +315,73 @@ movie_writer_stop(struct movie_handle *h)
pthread_join(h->raudio,&dummy);
pthread_join(h->taudio,&dummy);
}
- pthread_join(h->tvideo,&dummy);
+ if (h->vfmt.fmtid != VIDEO_NONE)
+ pthread_join(h->tvideo,&dummy);
pthread_cancel(h->tflush);
pthread_join(h->tflush,&dummy);
/* close file */
h->writer->wr_close(h->handle);
- drv->stopvideo(h_drv);
if (h->afmt.fmtid != AUDIO_NONE)
- sound_close();
+ oss_close(h->sndhandle);
+ if (h->vfmt.fmtid != VIDEO_NONE)
+ drv->stopvideo(h_drv);
+ free(h);
return 0;
}
/*-------------------------------------------------------------------------*/
static void
-movie_check_times(struct movie_handle *h)
+movie_print_timestamps(struct movie_handle *h)
{
- struct timeval now;
-
- gettimeofday(&now,NULL);
- h->rusec = 1000000 * (now.tv_sec - h->start.tv_sec);
- h->rusec += (now.tv_usec - h->start.tv_usec);
-
- fprintf(stderr,"real: %d.%03ds audio: %d.%03ds video: %d.%03ds\r",
- (int)((h->rusec / 1000000)),
- (int)((h->rusec % 1000000) / 1000),
- (int)((h->ausec / 1000000)),
- (int)((h->ausec % 1000000) / 1000),
- (int)((h->vusec / 1000000)),
- (int)((h->vusec % 1000000) / 1000));
+ h->rts = ng_get_timestamp() - h->start;
+ fprintf(stderr,"real: %d.%03ds audio: %d.%03ds video: %d.%03ds \r",
+ (int)((h->rts / 1000000000)),
+ (int)((h->rts % 1000000000) / 1000000),
+ (int)((h->ats / 1000000000)),
+ (int)((h->ats % 1000000000) / 1000000),
+ (int)((h->vts / 1000000000)),
+ (int)((h->vts % 1000000000) / 1000000));
}
int
movie_grab_put_video(struct movie_handle *h)
{
- struct ng_video_buf *buf;
+ struct ng_video_buf *cap,*buf;
+ int expected;
if (debug > 1)
fprintf(stderr,"grab_put_video\n");
- /* get next frame */
- buf = ng_grabber_capture(NULL,0);
+ /* fetch next frame */
+ cap = ng_grabber_getimage(0);
+ if (NULL == cap)
+ return -1;
+
+ /* rate control + put into fifo */
+ expected = cap->ts * h->fps / 1000000000;
+ if (expected < h->frames) {
+ if (debug > 1)
+ fprintf(stderr,"rate: ignoring frame\n");
+ ng_release_video_buf(cap);
+ return 0;
+ }
+ buf = ng_grabber_convert(NULL,cap);
+ if (NULL == buf)
+ return -1;
+ if (expected > h->frames) {
+ fprintf(stderr,"rate: queueing frame twice (%d)\n",
+ expected-h->frames);
+ buf->refcount++;
+ fifo_put(&h->vfifo,buf);
+ h->frames++;
+ }
+ h->vts = buf->ts;
fifo_put(&h->vfifo,buf);
h->frames++;
- h->vusec = (long long)h->frames * 1000000 / h->fps;
- movie_check_times(h);
- return 0;
+
+ /* feedback */
+ movie_print_timestamps(h);
+ return h->frames;
}
diff --git a/src/commands.c b/src/commands.c
index 2add6c4..38f979d 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -52,6 +52,7 @@ void (*movie_hook)(int argc, char **argv);
int debug;
int do_overlay;
char *snapbase = "snap";
+int have_shmem;
struct ng_video_fmt x11_fmt;
int cur_attrs[256];
diff --git a/src/commands.h b/src/commands.h
index 4245cc3..df30186 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -26,6 +26,7 @@ extern void (*movie_hook)(int argc, char **argv);
extern int debug;
extern int do_overlay;
extern char *snapbase;
+extern int have_shmem;
extern struct ng_video_fmt x11_fmt;
extern int cur_attrs[256];
diff --git a/src/grab.c b/src/grab.c
index 519ca0a..7512732 100644
--- a/src/grab.c
+++ b/src/grab.c
@@ -133,14 +133,16 @@ ng_grabber_copy(struct ng_video_buf *dest,
}
struct ng_video_buf*
-ng_grabber_capture(struct ng_video_buf *dest, int single)
+ng_grabber_getimage(int single)
{
- struct ng_video_buf *buf;
-
if (-1 == gfmt.fmtid)
return NULL;
+ return single ? drv->getimage(h_drv) : drv->nextframe(h_drv);
+}
- buf = single ? drv->getimage(h_drv) : drv->nextframe(h_drv);
+struct ng_video_buf*
+ng_grabber_convert(struct ng_video_buf *dest, struct ng_video_buf *buf)
+{
if (NULL == buf)
return NULL;
@@ -155,6 +157,7 @@ ng_grabber_capture(struct ng_video_buf *dest, int single)
} else {
ng_grabber_copy(dest,buf);
}
+ dest->ts = buf->ts;
ng_release_video_buf(buf);
buf = dest;
}
@@ -165,3 +168,12 @@ ng_grabber_capture(struct ng_video_buf *dest, int single)
}
return buf;
}
+
+struct ng_video_buf*
+ng_grabber_capture(struct ng_video_buf *dest, int single)
+{
+ struct ng_video_buf *buf;
+
+ buf = ng_grabber_getimage(single);
+ return ng_grabber_convert(dest,buf);
+}
diff --git a/src/grab.h b/src/grab.h
index fc9f134..6bec7a2 100644
--- a/src/grab.h
+++ b/src/grab.h
@@ -11,5 +11,8 @@ extern int fd_grab;
void grabber_run_v4l_conf(void);
int ng_grabber_setparams(struct ng_video_fmt *fmt, int fix_ratio);
+struct ng_video_buf* ng_grabber_getimage(int single);
+struct ng_video_buf* ng_grabber_convert(struct ng_video_buf *dest,
+ struct ng_video_buf *buf);
struct ng_video_buf* ng_grabber_capture(struct ng_video_buf *dest,
int single);
diff --git a/src/main.c b/src/main.c
index 383440c..ecf1832 100644
--- a/src/main.c
+++ b/src/main.c
@@ -588,6 +588,7 @@ static void *grab_ximage_shm;
static GC grab_gc;
static int win_width, win_height;
static int grabdisplay_suspended;
+static int use_hw_scale;
#ifdef HAVE_LIBXV
static XvImage *xv_image = NULL;
@@ -635,7 +636,7 @@ grabdisplay_idle(XtPointer data)
goto oops;
#ifdef HAVE_LIBXV
- if (have_xv_scale) {
+ if (use_hw_scale) {
if (NULL == xv_image)
goto oops;
buf.fmt = xv_fmt;
@@ -645,14 +646,13 @@ grabdisplay_idle(XtPointer data)
goto oops;
} else {
errors = 0;
- XvShmPutImage(dpy, im_port, XtWindow(tv), grab_gc, xv_image,
- 0, 0, xv_fmt.width, xv_fmt.height,
- 0, 0, win_width, win_height,
- False);
+ XVPUTIMAGE(dpy, im_port, XtWindow(tv), grab_gc, xv_image,
+ 0, 0, xv_fmt.width, xv_fmt.height,
+ 0, 0, win_width, win_height);
}
-
- } else {
+ }
#endif
+ if (!use_hw_scale) {
if (!grab_ximage)
goto oops;
buf.fmt = x11_fmt;
@@ -667,9 +667,7 @@ grabdisplay_idle(XtPointer data)
(win_height - x11_fmt.height) >> 1,
x11_fmt.width, x11_fmt.height);
}
-#ifdef HAVE_LIBXV
}
-#endif
if (debug) {
gettimeofday(&t,&tz);
@@ -703,10 +701,10 @@ static void
grabdisplay_restart(void)
{
#ifdef HAVE_LIBXV
- if (have_xv_scale)
+ if (use_hw_scale)
ng_grabber_setparams(&xv_fmt,0);
- else
#endif
+ if (!use_hw_scale)
ng_grabber_setparams(&x11_fmt,0);
if (cur_capture != CAPTURE_OFF)
@@ -750,26 +748,25 @@ grabdisplay_setsize(int width, int height)
tv_pix = 0;
}
+ use_hw_scale = 0;
#ifdef HAVE_LIBXV
if (xv_image) {
xv_destroy_ximage(dpy,xv_image,xv_shm);
xv_image = NULL;
}
if (have_xv_scale) {
-#if 0
- /* FIXME: no hard coded max size, better ask the X-Server */
- xv_fmt.width = (width > 320) ? 320 : width;
- xv_fmt.height = (height > 240) ? 240 : height;
-#else
xv_fmt.width = width;
xv_fmt.height = height;
-#endif
xv_fmt.fmtid = VIDEO_YUV422;
xv_fmt.bytesperline = 0;
- ng_grabber_setparams(&xv_fmt,0);
- xv_image = xv_create_ximage(dpy, xv_fmt.width, xv_fmt.height, &xv_shm);
- } else {
+ if (0 == ng_grabber_setparams(&xv_fmt,0)) {
+ xv_image = xv_create_ximage(dpy, xv_fmt.width, xv_fmt.height,
+ &xv_shm);
+ use_hw_scale = 1;
+ }
+ }
#endif
+ if (0 == use_hw_scale) {
ng_grabber_setparams(&x11_fmt,1);
grab_ximage = x11_create_ximage(dpy,&vinfo,
x11_fmt.width,x11_fmt.height,
@@ -778,9 +775,7 @@ grabdisplay_setsize(int width, int height)
fprintf(stderr,"oops: out of memory\n");
exit(1);
}
-#ifdef HAVE_LIBXV
}
-#endif
if (cur_capture == CAPTURE_GRABDISPLAY)
drv->startvideo(h_drv,-1,2);
}
@@ -2461,20 +2456,23 @@ usage(void)
"\n"
"usage: xawtv [ options ] [ station ]\n"
"options:\n"
- " -v, -debug n debug level n, n = [0..2]\n"
- " -remote assume remote display\n"
- " -n -noconf don't read the config file\n"
- " -m -nomouse startup with mouse pointer disabled\n"
- " -f -fullscreen startup in fullscreen mode\n"
- " -dga/-nodga enable/disable DGA extention\n"
- " -vm/-novm enable/disable VidMode extention\n"
- " -xv/-noxv enable/disable Xvideo extention\n"
- " -b -bpp n color depth of the display is n (n=24,32)\n"
- " -o -outfile file filename base for snapshots\n"
- " -c -device file use <file> as video4linux device\n"
- " -shift x shift display by x bytes\n"
- " -fb let fb (not X) set up v4l device\n"
- " -h -help print this text\n"
+ " -v, -debug n debug level n, n = [0..2]\n"
+ " -remote assume remote display\n"
+ " -n -noconf don't read the config file\n"
+ " -m -nomouse startup with mouse pointer disabled\n"
+ " -f -fullscreen startup in fullscreen mode\n"
+ " -dga/-nodga enable/disable DGA extention\n"
+ " -vm/-novm enable/disable VidMode extention\n"
+ " -xv/-noxv enable/disable Xvideo extention (for video overlay)\n"
+ " -scale/-noscale enable/disable Xvideo extention (for image scaling)\n"
+ " you might need that if your hardware does support\n"
+ " neither hardware overlay nor yuv capture\n"
+ " -b -bpp n color depth of the display is n (n=24,32)\n"
+ " -o -outfile file filename base for snapshots\n"
+ " -c -device file use <file> as video4linux device\n"
+ " -shift x shift display by x bytes\n"
+ " -fb let fb (not X) set up v4l device\n"
+ " -h -help print this text\n"
"station:\n"
" this is one of the stations listed in $HOME/.xawtv\n"
"\n"
diff --git a/src/sound.c b/src/sound.c
index b8917b4..35d954e 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -22,8 +22,6 @@
static char *names[] = SOUND_DEVICE_NAMES;
-static int fd, blocksize;
-
static int mix;
static int dev = -1;
static int volume;
@@ -32,113 +30,6 @@ extern int debug;
/* -------------------------------------------------------------------- */
-static const int afmt_to_oss[] = {
- 0,
- AFMT_U8,
- AFMT_U8,
- AFMT_S16_LE,
- AFMT_S16_LE,
- AFMT_S16_BE,
- AFMT_S16_BE
-};
-
-int
-sound_open(struct ng_audio_fmt *fmt)
-{
- int afmt,channels,frag;
-
- if (-1 == (fd = open("/dev/dsp", O_RDONLY))) {
- perror("open /dev/dsp");
- goto err;
- }
- fcntl(fd,F_SETFD,FD_CLOEXEC);
-
- afmt = afmt_to_oss[fmt->fmtid];
- channels = ng_afmt_to_channels[fmt->fmtid];
- frag = 0x7fff000c; /* 4k */
-
- /* format */
- ioctl(fd, SNDCTL_DSP_SETFMT, &afmt);
- if (afmt != afmt_to_oss[fmt->fmtid]) {
- fprintf(stderr,"SNDCTL_DSP_SETFMT(%d): %s\n",
- afmt_to_oss[fmt->fmtid],strerror(errno));
- goto err;
- }
-
- /* channels */
- ioctl(fd, SNDCTL_DSP_CHANNELS, &channels);
- if (channels != ng_afmt_to_channels[fmt->fmtid]) {
- fprintf(stderr,"SNDCTL_DSP_CHANNELS(%d): %s\n",
- ng_afmt_to_channels[fmt->fmtid],strerror(errno));
- goto err;
- }
-
- /* sample rate */
- ioctl(fd, SNDCTL_DSP_SPEED, &fmt->rate);
- ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
-
- if (-1 == ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) {
- perror("SNDCTL_DSP_GETBLKSIZE");
- goto err;
- }
-
- if (debug)
- fprintf(stderr,"sound rec: bs=%d rate=%d channels=%d bits=%d (%s)\n",
- blocksize,fmt->rate,
- ng_afmt_to_channels[fmt->fmtid],
- ng_afmt_to_bits[fmt->fmtid],
- ng_afmt_to_desc[fmt->fmtid]);
- return fd;
-
- err:
- fprintf(stderr,"oss: requested sound format not supported by driver\n");
- fmt->rate = 0;
- fmt->fmtid = AUDIO_NONE;
- return -1;
-}
-
-int
-sound_bufsize()
-{
- return blocksize;
-}
-
-void
-sound_startrec()
-{
- int trigger;
-
- /* trigger record */
- trigger = PCM_ENABLE_INPUT;
- ioctl(fd,SNDCTL_DSP_SETTRIGGER,&trigger);
-}
-
-void
-sound_read(char *buffer)
-{
- int rc,count=0;
-
- /* FreeBSD returns chunks smaller than blocksize */
- for (;;) {
- rc = read(fd,buffer+count,blocksize-count);
- if (rc < 0) {
- perror("read /dev/dsp");
- exit(1);
- }
- count += rc;
- if (count == blocksize)
- return;
- }
-}
-
-void
-sound_close()
-{
- close(fd);
-}
-
-/* -------------------------------------------------------------------- */
-
int
mixer_open(char *filename, char *device)
{
@@ -237,3 +128,234 @@ mixer_get_muted()
{
return (-1 == dev) ? -1 : muted;
}
+
+/* -------------------------------------------------------------------- */
+
+struct oss_handle {
+ int fd;
+
+ /* oss */
+ struct ng_audio_fmt ifmt;
+ int afmt,channels,rate;
+ int blocksize;
+
+ /* me */
+ struct ng_audio_fmt ofmt;
+ int byteswap;
+ int bytes;
+ int bytes_per_sec;
+};
+
+static const int afmt_to_oss[AUDIO_FMT_COUNT] = {
+ 0,
+ AFMT_U8,
+ AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_S16_LE,
+ AFMT_S16_BE,
+ AFMT_S16_BE
+};
+
+static int
+oss_setformat(struct oss_handle *h, struct ng_audio_fmt *fmt)
+{
+ int frag;
+
+ if (0 == afmt_to_oss[fmt->fmtid])
+ return -1;
+
+ h->afmt = afmt_to_oss[fmt->fmtid];
+ h->channels = ng_afmt_to_channels[fmt->fmtid];
+ frag = 0x7fff000c; /* 4k */
+
+ /* format */
+ ioctl(h->fd, SNDCTL_DSP_SETFMT, &h->afmt);
+ if (h->afmt != afmt_to_oss[fmt->fmtid]) {
+ fprintf(stderr,"oss: SNDCTL_DSP_SETFMT(%d): %s\n",
+ afmt_to_oss[fmt->fmtid],strerror(errno));
+ goto err;
+ }
+
+ /* channels */
+ ioctl(h->fd, SNDCTL_DSP_CHANNELS, &h->channels);
+ if (h->channels != ng_afmt_to_channels[fmt->fmtid]) {
+ fprintf(stderr,"oss: SNDCTL_DSP_CHANNELS(%d): %s\n",
+ ng_afmt_to_channels[fmt->fmtid],strerror(errno));
+ goto err;
+ }
+
+ /* sample rate */
+ h->rate = fmt->rate;
+ ioctl(h->fd, SNDCTL_DSP_SPEED, &h->rate);
+ ioctl(h->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+
+ if (-1 == ioctl(h->fd, SNDCTL_DSP_GETBLKSIZE, &h->blocksize)) {
+ perror("SNDCTL_DSP_GETBLKSIZE");
+ goto err;
+ }
+
+ if (debug)
+ fprintf(stderr,"oss: bs=%d rate=%d channels=%d bits=%d (%s)\n",
+ h->blocksize,h->rate,
+ ng_afmt_to_channels[fmt->fmtid],
+ ng_afmt_to_bits[fmt->fmtid],
+ ng_afmt_to_desc[fmt->fmtid]);
+ return 0;
+
+ err:
+ if (debug)
+ fprintf(stderr,"oss: sound format not supported [%s]\n",
+ ng_afmt_to_desc[fmt->fmtid]);
+ return -1;
+}
+
+void*
+oss_open(char *device, struct ng_audio_fmt *fmt)
+{
+ struct oss_handle *h;
+ struct ng_audio_fmt ifmt;
+
+ h = malloc(sizeof(*h));
+ if (NULL == h)
+ return NULL;
+ memset(h,0,sizeof(*h));
+
+ if (-1 == (h->fd = open(device ? device : "/dev/dsp", O_RDONLY))) {
+ fprintf(stderr,"oss: open %s: %s\n",
+ device ? device : "/dev/dsp",
+ strerror(errno));
+ goto err;
+ }
+ fcntl(h->fd,F_SETFD,FD_CLOEXEC);
+
+ if (0 == oss_setformat(h,fmt)) {
+ /* fine, native format works */
+ fmt->rate = h->rate;
+ h->ifmt = *fmt;
+ h->ofmt = *fmt;
+ h->bytes_per_sec = ng_afmt_to_bits[h->ifmt.fmtid] *
+ ng_afmt_to_channels[h->ifmt.fmtid] * h->ifmt.rate / 8;
+ return h;
+ }
+
+ /* try byteswapping */
+ ifmt = *fmt;
+ switch (fmt->fmtid) {
+ case AUDIO_S16_LE_MONO: ifmt.fmtid = AUDIO_S16_BE_MONO; break;
+ case AUDIO_S16_LE_STEREO: ifmt.fmtid = AUDIO_S16_BE_STEREO; break;
+ case AUDIO_S16_BE_MONO: ifmt.fmtid = AUDIO_S16_LE_MONO; break;
+ case AUDIO_S16_BE_STEREO: ifmt.fmtid = AUDIO_S16_LE_STEREO; break;
+ }
+ if (0 == oss_setformat(h,&ifmt)) {
+ if (debug)
+ fprintf(stderr,"oss: byteswapping pcm data\n");
+ h->byteswap = 1;
+ ifmt.rate = h->rate;
+ fmt->rate = h->rate;
+ h->ifmt = ifmt;
+ h->ofmt = *fmt;
+ h->bytes_per_sec = ng_afmt_to_bits[h->ifmt.fmtid] *
+ ng_afmt_to_channels[h->ifmt.fmtid] * h->ifmt.rate / 8;
+ return h;
+ }
+
+ fprintf(stderr,"oss: can't record %s\n",
+ ng_afmt_to_desc[fmt->fmtid]);
+
+ err:
+ fmt->rate = 0;
+ fmt->fmtid = AUDIO_NONE;
+ if (h->fd)
+ close(h->fd);
+ free(h);
+ return NULL;
+}
+
+void
+oss_startrec(void *handle)
+{
+ struct oss_handle *h = handle;
+ int trigger;
+
+ trigger = PCM_ENABLE_INPUT;
+ ioctl(h->fd,SNDCTL_DSP_SETTRIGGER,&trigger);
+}
+
+static struct ng_audio_buf*
+oss_bufalloc(struct ng_audio_fmt *fmt, int size)
+{
+ struct ng_audio_buf *buf;
+
+ buf = malloc(sizeof(*buf)+size);
+ memset(buf,0,sizeof(*buf));
+ buf->fmt = *fmt;
+ buf->size = size;
+ buf->data = (char*)buf + sizeof(*buf);
+ return buf;
+}
+
+static void
+oss_bufread(int fd,char *buffer,int blocksize)
+{
+ int rc,count=0;
+
+ /* why FreeBSD returns chunks smaller than blocksize? */
+ for (;;) {
+ rc = read(fd,buffer+count,blocksize-count);
+ if (rc < 0) {
+ perror("read /dev/dsp");
+ exit(1);
+ }
+ count += rc;
+ if (count == blocksize)
+ return;
+ }
+}
+
+static void
+oss_bufswap(void *ptr, int size)
+{
+ unsigned short *buf = ptr;
+ int i;
+
+ size = size >> 1;
+ for (i = 0; i < size; i++)
+ buf[i] = ((buf[i] >> 8) & 0xff) | ((buf[i] << 8) & 0xff00);
+}
+
+struct ng_audio_buf*
+oss_read(void *handle, long long stopby)
+{
+ struct oss_handle *h = handle;
+ struct ng_audio_buf* buf;
+ int bytes;
+
+ if (stopby) {
+ bytes = stopby * h->bytes_per_sec / 1000000000 - h->bytes;
+ if (debug)
+ fprintf(stderr,"oss: left: %d bytes (%.3fs)\n",
+ bytes,(float)bytes/h->bytes_per_sec);
+ if (bytes > h->blocksize)
+ bytes = h->blocksize;
+ if (0 == bytes)
+ return NULL;
+ } else {
+ bytes = h->blocksize;
+ }
+ buf = oss_bufalloc(&h->ofmt,bytes);
+ oss_bufread(h->fd,buf->data,bytes);
+ if (h->byteswap)
+ oss_bufswap(buf->data,bytes);
+ h->bytes += bytes;
+ buf->ts = (long long)h->bytes * 1000000000 / h->bytes_per_sec;
+ return buf;
+}
+
+void
+oss_close(void *handle)
+{
+ struct oss_handle *h = handle;
+
+ close(h->fd);
+ free(h);
+}
diff --git a/src/sound.h b/src/sound.h
index 9feac31..b45c69c 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -1,11 +1,10 @@
#ifndef _SOUND_H_
#define _SOUND_H_
-int sound_open(struct ng_audio_fmt *fmt);
-int sound_bufsize(void);
-void sound_startrec(void);
-void sound_read(char *buffer);
-void sound_close(void);
+void* oss_open(char *device, struct ng_audio_fmt *fmt);
+void oss_startrec(void *handle);
+struct ng_audio_buf* oss_read(void *handle, long long stopby);
+void oss_close(void *handle);
int mixer_open(char *filename, char *device);
void mixer_close(void);
diff --git a/src/streamer.c b/src/streamer.c
index c61a1d1..cbf3385 100644
--- a/src/streamer.c
+++ b/src/streamer.c
@@ -57,7 +57,7 @@ static struct ng_audio_fmt audio = {
static void *movie_state;
static int absframes = 1;
-static int fd = -1, quiet = 0, fps = 10;
+static int quiet = 0, fps = 10;
static int signaled = 0, wait_seconds = 0;
@@ -163,45 +163,65 @@ void
find_formats(void)
{
const struct ng_writer *wr = NULL;
- char *ext = NULL;
+ char *mext = NULL;
+ char *aext = NULL;
int w,v=-1,a=-1;
if (moviename) {
- ext = strrchr(moviename,'.');
- if (ext)
- ext++;
+ mext = strrchr(moviename,'.');
+ if (mext)
+ mext++;
+ }
+ if (audioname) {
+ aext = strrchr(audioname,'.');
+ if (aext)
+ aext++;
}
for (w = 0; NULL != ng_writers[w]; w++) {
wr = ng_writers[w];
- for (v = 0; NULL != wr->video[v].name; v++) {
- if (ext && 0 != strcasecmp(wr->video[v].ext,ext))
+ if ((!wr->combined && mext) || NULL != vfmt_name) {
+ if (NULL == wr->video)
+ continue;
+ for (v = 0; NULL != wr->video[v].name; v++) {
+ if (mext && 0 != strcasecmp(wr->video[v].ext,mext))
+ continue;
+ if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name))
+ continue;
+ break;
+ }
+ if (NULL == wr->video[v].name)
continue;
- if (vfmt_name && 0 != strcasecmp(wr->video[v].name,vfmt_name))
+ }
+ if ((!wr->combined && aext) || NULL != afmt_name) {
+ if (NULL == wr->audio)
continue;
- if (!afmt_name)
+ for (a = 0; NULL != wr->audio[a].name; a++) {
+ if (!wr->combined &&
+ aext && 0 != strcasecmp(wr->audio[a].ext,aext))
+ continue;
+ if (wr->combined &&
+ mext && 0 != strcasecmp(wr->audio[a].ext,mext))
+ continue;
+ if (afmt_name && 0 != strcasecmp(wr->audio[a].name,afmt_name))
+ continue;
break;
- if (wr->audio && NULL != afmt_name) {
- for (a = 0; NULL != wr->audio[a].name; a++) {
- if (0 != strcasecmp(wr->audio[a].name,afmt_name))
- continue;
- break;
- }
- if (NULL != wr->audio[a].name)
- break;
}
+ if (NULL == wr->audio[a].name)
+ continue;
}
- if (NULL != wr->video[v].name)
- break;
+ break;
}
- if (NULL != wr->video[v].name) {
- writer = wr;
- video.fmtid = wr->video[v].fmtid;
- video_priv = wr->video[v].priv;
+ if (NULL != ng_writers[w]) {
+ writer = wr;
+ if (-1 != v) {
+ video.fmtid = wr->video[v].fmtid;
+ video_priv = wr->video[v].priv;
+ }
if (-1 != a) {
audio.fmtid = wr->audio[a].fmtid;
audio_priv = wr->audio[a].priv;
}
- }
+ }
}
/* ---------------------------------------------------------------------- */
@@ -219,7 +239,7 @@ ctrlc(int signal)
int
main(int argc, char **argv)
{
- int c,count=0,queued=0;
+ int c,queued=0;
/* parse options */
for (;;) {
@@ -300,8 +320,12 @@ main(int argc, char **argv)
find_formats();
/* sanity checks */
- if (video.fmtid == VIDEO_NONE) {
- fprintf(stderr,"no video (and/or audio) format found\n");
+ if (video.fmtid == VIDEO_NONE && audio.fmtid == AUDIO_NONE) {
+ fprintf(stderr,"neither audio nor video format specified/found\n");
+ exit(1);
+ }
+ if (NULL == writer) {
+ fprintf(stderr,"no output driver found\n");
exit(1);
}
if (audio.fmtid != AUDIO_NONE && !writer->combined && NULL == audioname) {
@@ -310,30 +334,32 @@ main(int argc, char **argv)
}
/* open */
- if (!quiet)
+ if (writer && !quiet)
fprintf(stderr,"%s / video: %s / audio: %s\n",writer->name,
ng_vfmt_to_desc[video.fmtid],ng_afmt_to_desc[audio.fmtid]);
- drv = ng_grabber_open(v4l_device,NULL,0,&h_drv);
- if (NULL == drv) {
- fprintf(stderr,"no grabber device available\n");
- exit(1);
- }
- f_drv = drv->capabilities(h_drv);
- a_drv = drv->list_attrs(h_drv);
- if (!(f_drv & CAN_CAPTURE)) {
- fprintf(stderr,"%s: capture not supported\n",drv->name);
- exit(1);
+ if (video.fmtid != VIDEO_NONE) {
+ drv = ng_grabber_open(v4l_device,NULL,0,&h_drv);
+ if (NULL == drv) {
+ fprintf(stderr,"no grabber device available\n");
+ exit(1);
+ }
+ f_drv = drv->capabilities(h_drv);
+ a_drv = drv->list_attrs(h_drv);
+ if (!(f_drv & CAN_CAPTURE)) {
+ fprintf(stderr,"%s: capture not supported\n",drv->name);
+ exit(1);
+ }
+ audio_on();
+ audio_init();
+
+ /* modify settings */
+ if (input != NULL)
+ do_va_cmd(2,"setinput",input);
+ if (tvnorm != NULL)
+ do_va_cmd(2,"setnorm",tvnorm);
}
- audio_on();
- audio_init();
-
- /* modify settings */
- if (input != NULL)
- do_va_cmd(2,"setinput",input);
- if (tvnorm != NULL)
- do_va_cmd(2,"setnorm",tvnorm);
-
+
/* init movie writer */
movie_state = movie_writer_init
(moviename, audioname, writer,
@@ -341,29 +367,38 @@ main(int argc, char **argv)
&audio, audio_priv, bufcount);
if (NULL == movie_state) {
fprintf(stderr,"movie writer initialisation failed\n");
- audio_off();
- drv->close(h_drv);
+ if (video.fmtid != VIDEO_NONE) {
+ audio_off();
+ drv->close(h_drv);
+ }
exit(1);
}
- /* wait for some cameras to wake up and adjust light and all that */
- sleep(wait_seconds);
-
/* catch ^C */
signal(SIGINT,ctrlc);
+ /* wait for some cameras to wake up and adjust light and all that */
+ if (wait_seconds)
+ sleep(wait_seconds);
+
/* main loop */
movie_writer_start(movie_state);
- for (;queued < absframes && !signaled; count++) {
- /* video */
- movie_grab_put_video(movie_state);
- queued++;
+ for (;queued < absframes && !signaled;) {
+ if (video.fmtid != VIDEO_NONE) {
+ /* video */
+ queued = movie_grab_put_video(movie_state);
+ } else {
+ /* quick+dirty: use #frames as #seconds */
+ sleep(1);
+ queued++;
+ }
}
movie_writer_stop(movie_state);
/* done */
- audio_off();
- drv->close(h_drv);
- close(fd);
+ if (video.fmtid != VIDEO_NONE) {
+ audio_off();
+ drv->close(h_drv);
+ }
return 0;
}
diff --git a/src/x11.c b/src/x11.c
index 2a8ed53..96ed0f8 100644
--- a/src/x11.c
+++ b/src/x11.c
@@ -214,7 +214,7 @@ x11_init(Display *dpy, XVisualInfo *vinfo)
return format;
}
-int
+static int
x11_error_dev_null(Display * dpy, XErrorEvent * event)
{
x11_error++;
diff --git a/src/xt.c b/src/xt.c
index 06d1eb8..de1ae70 100644
--- a/src/xt.c
+++ b/src/xt.c
@@ -56,7 +56,6 @@ Colormap colormap;
int have_dga = 0;
int have_vm = 0;
-int have_shmem = 0;
#ifdef HAVE_LIBXXF86VM
int vm_count;
diff --git a/src/xt.h b/src/xt.h
index f99b58b..d0d991a 100644
--- a/src/xt.h
+++ b/src/xt.h
@@ -42,7 +42,6 @@ extern Colormap colormap;
extern int have_dga;
extern int have_vm;
-extern int have_shmem;
#ifdef HAVE_LIBXXF86VM
extern int vm_count;
diff --git a/src/xv.c b/src/xv.c
index cd0fe13..386d7d9 100644
--- a/src/xv.c
+++ b/src/xv.c
@@ -305,29 +305,82 @@ static struct ng_attribute* xv_attrs(void *handle)
/* ********************************************************************* */
+extern int have_shmem;
+static int x11_error = 0;
+static int
+x11_error_dev_null(Display * dpy, XErrorEvent * event)
+{
+ x11_error++;
+ if (debug > 1)
+ fprintf(stderr," x11-error\n");
+ return 0;
+}
+
XvImage*
xv_create_ximage(Display *dpy, int width, int height, void **shm)
{
XvImage *xvimage = NULL;
- XShmSegmentInfo *shminfo = malloc(sizeof(XShmSegmentInfo));
+ unsigned char *ximage_data;
+#ifdef HAVE_MITSHM
+ XShmSegmentInfo *shminfo;
+ void *old_handler;
+#endif
if (debug)
fprintf(stderr,"xv: xv_create_ximage\n");
- memset(shminfo, 0, sizeof(XShmSegmentInfo));
- xvimage = XvShmCreateImage(dpy, im_port, im_format, 0,
- width, height, shminfo);
- shminfo->shmid = shmget(IPC_PRIVATE, xvimage->data_size,
- IPC_CREAT | 0777);
- shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
- shminfo->readOnly = False;
- xvimage->data = shminfo->shmaddr;
-
- XShmAttach(dpy, shminfo);
- XSync(dpy, False);
- shmctl(shminfo->shmid, IPC_RMID, 0);
+ if (have_shmem) {
+ x11_error = 0;
+ old_handler = XSetErrorHandler(x11_error_dev_null);
+ shminfo = malloc(sizeof(XShmSegmentInfo));
+ memset(shminfo, 0, sizeof(XShmSegmentInfo));
+ xvimage = XvShmCreateImage(dpy, im_port, im_format, 0,
+ width, height, shminfo);
+ if (xvimage) {
+ shminfo->shmid = shmget(IPC_PRIVATE, xvimage->data_size,
+ IPC_CREAT | 0777);
+ if (-1 == shminfo->shmid) {
+ have_shmem = 0;
+ XFree(xvimage);
+ xvimage = NULL;
+ free(shminfo);
+ shminfo = *shm = NULL;
+ goto no_sysvipc;
+ }
+ shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
+ shminfo->readOnly = False;
+ xvimage->data = shminfo->shmaddr;
+ XShmAttach(dpy, shminfo);
+ XSync(dpy, False);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ if (x11_error) {
+ have_shmem = 0;
+ XFree(xvimage);
+ xvimage = NULL;
+ shmdt(shminfo->shmaddr);
+ free(shminfo);
+ shminfo = *shm = NULL;
+ goto no_sysvipc;
+ }
+ } else {
+ have_shmem = 0;
+ free(shminfo);
+ shminfo = *shm = NULL;
+ goto no_sysvipc;
+ }
+ XSetErrorHandler(old_handler);
+ *shm = shminfo;
+ return xvimage;
+ }
- *shm = shminfo;
+ no_sysvipc:
+ *shm = NULL;
+ if (NULL == (ximage_data = malloc(width * height * 2))) {
+ fprintf(stderr,"out of memory\n");
+ return NULL;
+ }
+ xvimage = XvCreateImage(dpy, im_port, im_format, ximage_data,
+ width, height);
return xvimage;
}
@@ -354,7 +407,10 @@ void xv_init(int xvideo, int hwscale, int port)
struct STRTAB *inputs = NULL;
char *h;
int i, vi_port = -1, vi_adaptor = -1;
-
+
+ if (!xvideo && !hwscale)
+ return;
+
if (Success != XvQueryExtension(dpy,&ver,&rel,&req,&ev,&err)) {
if (debug)
fprintf(stderr,"Xv: Server has no Xvideo extention support\n");
diff --git a/src/xv.h b/src/xv.h
index e7b521f..412a6fa 100644
--- a/src/xv.h
+++ b/src/xv.h
@@ -7,4 +7,15 @@ void xv_video(Window win, int width, int height, int on);
#ifdef HAVE_LIBXV
XvImage* xv_create_ximage(Display *dpy, int width, int height, void **shm);
void xv_destroy_ximage(Display *dpy, XvImage * xvimage, void *shm);
+
+# ifdef HAVE_MITSHM
+# define XVPUTIMAGE(dpy,port,dr,gc,xi,a,b,c,d,x,y,w,h) \
+ if (have_shmem) \
+ XvShmPutImage(dpy,port,dr,gc,xi,a,b,c,d,x,y,w,h,True); \
+ else \
+ XvPutImage(dpy,port,dr,gc,xi,a,b,c,d,x,y,w,h)
+# else
+# define XVPUTIMAGE(dpy,port,dr,gc,xi,a,b,c,d,x,y,w,h) \
+ XvPutImage(dpy,port,dr,gc,xi,a,b,c,d,x,y,w,h)
+# endif
#endif
diff --git a/xawtv.spec b/xawtv.spec
index d33cc38..b0b4983 100644
--- a/xawtv.spec
+++ b/xawtv.spec
@@ -8,7 +8,7 @@
Summary: Video4Linux Stream Capture Viewer
Name: xawtv
-Version: 3.40
+Version: 3.41
Release: 1
Source0: xawtv_%{version}.tar.gz
Group: X11/Applications

Privacy Policy