changeset 1:769b155a34f9 SIMPETV_0_1

Initial revision
author darius
date Tue, 04 Jan 2005 05:17:43 +0000
parents da66cf40a013
children a3e8aae64d40
files Makefile simpletv simpletv.c xv_ext_test xv_ext_test.c
diffstat 5 files changed, 1005 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Tue Jan 04 05:17:43 2005 +0000
@@ -0,0 +1,25 @@
+all : xv_ext_test simpletv
+
+#Xv
+CFLAGS_MODE=	-DUSE_XVIMAGES -g -I/usr/local/include
+LDFLAGS_MODE=
+
+#Hermes
+#CFLAGS_MODE=	-I/usr/local/include
+#LDFLAGS_MODE=	-lHermes
+
+LDFLAGS=	-L/usr/X11R6/lib -lXv -lXext -lX11 -L/usr/local/lib -llirc_client\
+		$(LDFLAGS_MODE)
+
+CFLAGS=		-Wall -I/usr/X11R6/include $(CFLAGS_MODE)
+
+xv_ext_test : xv_ext_test.c
+	cc $(CFLAGS) -o xv_ext_test xv_ext_test.c $(LDFLAGS)
+simpletv : simpletv.c
+	cc $(CFLAGS) -o simpletv simpletv.c $(LDFLAGS)
+foo: foo.c
+	cc $(CFLAGS) -o foo foo.c $(LDFLAGS)
+
+clean:
+	-rm -f xv_ext_test simpletv
+
Binary file simpletv has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simpletv.c	Tue Jan 04 05:17:43 2005 +0000
@@ -0,0 +1,860 @@
+/* Capture and store a 24 bit RGB image as a PPM file */
+/* Copyright (c) 2000  Randall Hopper
+ *
+ * Based on a grab.c from Roger Hardiman, which was
+ * based on an original program by Mark Tinguely and Jim Lowe .
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Mark Tinguely and Jim Lowe
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <poll.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <libgen.h>
+#include <sys/soundcard.h>
+#include <machine/ioctl_bt848.h>
+#include <machine/ioctl_meteor.h>
+#include <machine/param.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xvlib.h>
+#ifndef  USE_XVIMAGES
+#include "Hermes/Hermes.h"
+#endif
+
+#include <lirc/lirc_client.h>
+
+/* Some BT848/BT878 cards have gain control hardware which takes
+   1 or 2 seconds to settle. If you get a washed out / too bright
+   image, change the GRABBER_SETTLE_TIME from 0 to either 1 or 2
+*/
+/*#define GRABBER_SETTLE_TIME 10*/
+#define GRABBER_SETTLE_TIME 0
+
+
+#define PAL 1
+#define NTSC 2
+
+/* PAL is 768 x 576. NTSC is 640 x 480 */
+#define PAL_HEIGHT 576
+#define NTSC_HEIGHT 480
+
+int bktr_fd;
+int tuner_fd;
+unsigned char *bktr_buffer;
+#if 1
+int width = 320;
+int height = 240;
+#else
+int width  = 640;
+int height = 480;
+#endif
+
+#ifndef USE_XVIMAGES
+static XImage *rgb_image;
+static Pixmap pmap;
+#endif
+static XShmSegmentInfo shminfo;
+static Display *disp;
+static Window win;
+static Visual *vis;
+static int scr;
+static GC gc;
+static int depth;
+static Colormap cmap;
+static XVisualInfo *vi;
+static int bits_per_pixel;
+static XvImage *yuv_image;
+static XvAdaptorInfo *xv_adaptors;
+static int            xv_num_adaptors;
+static int            xv_adaptor;
+static int            xv_format_id;
+
+static int channel;
+
+#define DO_IOCTL_GERR(str)     fprintf(stderr, "ioctl(%s) failed: %s\n", \
+                                       str, strerror(errno) )
+#define DO_IOCTL_SERR(str,arg) fprintf(stderr, "ioctl(%s, %ld) failed: %s\n",\
+                                       str, (long)arg, strerror(errno) )
+/*--------------------------------------------------------------------------*/
+
+void Close()
+{
+    close(tuner_fd);
+    close(bktr_fd);
+}
+
+void Open()
+{
+    struct meteor_geomet geo;
+    int		buffer_size, format, source, c;
+    char	 *device_name;
+    
+    format = PAL;		/* default value */
+    source = 1;                 /* default value */
+    device_name = "/dev/bktr0"; /* default value */
+
+    /* Open the Meteor or Bt848/Bt878 grabber */    
+    if ((bktr_fd = open(device_name, O_RDONLY)) < 0) {
+	printf("open failed: %d\n", errno);
+	exit(1);
+    }
+
+    if ((tuner_fd = open("/dev/tuner0", O_RDONLY)) < 0) {
+	printf("open failed: %d\n", errno);
+	exit(1);
+    }
+
+    /* set up the capture type and size */
+    geo.rows = height;
+    geo.columns = width;
+    geo.frames = 1;
+#ifdef USE_XVIMAGES
+    /*  Should be YUV_12, but 422 actually gives a synced picture.  Though  */
+
+    /*geo.oformat = METEOR_GEO_YUV_12;*/
+    geo.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12;
+    /* geo.oformat = METEOR_GEO_YUV_12; */
+#else
+    geo.oformat = METEOR_GEO_RGB24;
+#endif
+
+    /* switch from interlaced capture to single field capture if */
+    /* the grab height is less than half the normal TV height */
+    /* this gives better quality captures when the object in the TV */
+    /* picture is moving */
+    if ((format == PAL) && (height <= (PAL_HEIGHT/2)))
+	geo.oformat |= METEOR_GEO_ODD_ONLY;
+    if ((format == NTSC) && (height <= (NTSC_HEIGHT/2)))
+	geo.oformat |= METEOR_GEO_ODD_ONLY;
+
+    if (ioctl(bktr_fd, METEORSETGEO, &geo) < 0) {
+	printf("METEORSETGEO ioctl failed: %d\n", errno);
+	exit(1);
+    }
+
+    /* Select PAL or NTSC */
+    switch (format) {
+	case PAL:   c = METEOR_FMT_PAL; break;
+	case NTSC:  c = METEOR_FMT_NTSC; break;
+	default:    c = METEOR_FMT_NTSC; break;
+    }
+
+    c = BT848_IFORM_F_PALBDGHI;
+    if ( ioctl( bktr_fd, BT848SFMT, &c ) < 0 ) {
+	DO_IOCTL_SERR( "BT848SFMT", c );
+	return;
+    }
+    c = AUDIO_TUNER;
+    if ( ioctl( tuner_fd, BT848_SAUDIO, &c ) < 0 ) {
+	DO_IOCTL_SERR( "BT848SFMT", c );
+	return;
+    }
+    c = CHNLSET_AUSTRALIA;
+    if ( ioctl( tuner_fd, TVTUNER_SETTYPE, &c ) < 0 ) {
+	DO_IOCTL_SERR( "TVTUNER_SETTYPE", c );
+	return;
+    }
+  
+    if ( ioctl( tuner_fd, TVTUNER_SETCHNL, &channel ) < 0 ) {
+	DO_IOCTL_SERR( "TVTUNER_SETCHNL", channel );
+	return;
+    }
+  
+
+    /* Select the Video Source */
+    /* Video In, Tuner, S-Video */
+    switch (source) {
+	case 0:   c = METEOR_INPUT_DEV0; break;
+	case 1:   c = METEOR_INPUT_DEV1; break;
+	case 2:   c = METEOR_INPUT_DEV2; break;
+	case 3:   c = METEOR_INPUT_DEV3; break;
+	default:  c = METEOR_INPUT_DEV0; break;
+    }
+
+    printf("Input - %x\n", c);
+    if (ioctl(bktr_fd, METEORSINPUT, &c) < 0) {
+	printf("ioctl failed: %d\n", errno);
+	exit(1);
+    }
+
+    /* Use mmap to Map the drivers grab buffer */
+    buffer_size = width*height*4;   /* R,G,B,spare */
+    bktr_buffer = (unsigned char *)mmap((caddr_t)0,buffer_size,PROT_READ,
+					MAP_SHARED, bktr_fd, (off_t)0);
+
+    if (bktr_buffer == (unsigned char *) MAP_FAILED) 
+	exit(1);
+
+
+    /* We may need to wait for a short time to allow the grabber */
+    /* brightness to settle down */
+    sleep(GRABBER_SETTLE_TIME);
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Capture()
+{
+    int c;
+  
+    /* Perform a single frame capture */
+    c = METEOR_CAP_SINGLE ;
+    ioctl(bktr_fd, METEORCAPTUR, &c);
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SaveImage()
+{
+    unsigned char *line_buffer;
+    int o,w,h;
+    unsigned char *p;
+    unsigned char header[30];
+    char *filename = "t.ppm"  /* argv[3] */;
+
+    /* Create the output file */
+    if ((o = open(filename, O_WRONLY | O_CREAT, 0644)) < 0) {
+	printf("ppm open failed: %d\n", errno);
+	exit(1);
+    }
+
+    /* make PPM header and save to file */
+    sprintf(header, "P6\n%d\n%d\n255\n",width,height);
+    write (o, header, strlen(header));
+
+    /* save the RGB data to PPM file */
+    /* save this one line at a time */
+    line_buffer =(unsigned char *)malloc( width *3 * sizeof(unsigned char));
+    p = bktr_buffer;
+    for (h = 0; h < height; h++) {
+	for (w = 0; w < width; w++) {
+	    line_buffer[(w*3) + 2] = *p++;  /* blue */
+	    line_buffer[(w*3) + 1] = *p++;  /* green */
+	    line_buffer[(w*3) + 0] = *p++;  /* red */
+	    p++;                            /* NULL byte */
+	}
+	write(o,line_buffer, width*3);
+    }
+    close(o);
+    free(line_buffer);
+}
+
+void X_ShowCursor(void) {
+    XDefineCursor(disp, win, 0);
+}
+
+void X_HideCursor(void) {
+    Cursor no_ptr;
+    Pixmap bm_no;
+    XColor black,dummy;
+    Colormap colormap;
+    static unsigned char bm_no_data[] = {0,0,0,0, 0,0,0,0};
+    
+    colormap = DefaultColormap(disp, DefaultScreen(disp));
+    XAllocNamedColor(disp, colormap, "black", &black, &dummy);
+    bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8);
+    no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0);
+
+    XDefineCursor(disp, win, no_ptr);
+    XFreeCursor(disp, no_ptr);
+    if (bm_no != None)
+	XFreePixmap(disp, bm_no);
+    
+}
+
+/*
+ * Sends the EWMH fullscreen state event.
+ * 
+ * action: could be on of _NET_WM_STATE_REMOVE -- remove state
+ *                        _NET_WM_STATE_ADD    -- add state
+ *                        _NET_WM_STATE_TOGGLE -- toggle
+ */
+#define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
+#define _NET_WM_STATE_ADD           1    /* add/set property */
+#define _NET_WM_STATE_TOGGLE        2    /* toggle property  */
+void
+vo_x11_ewmh_fullscreen(int action) {
+    XEvent xev;
+
+    assert(action == _NET_WM_STATE_REMOVE ||
+           action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE);
+
+
+    /* init X event structure for _NET_WM_FULLSCREEN client msg */
+    xev.xclient.type = ClientMessage;
+    xev.xclient.serial = 0;
+    xev.xclient.send_event = True;
+    xev.xclient.message_type = XInternAtom(disp, "_NET_WM_STATE", False);
+    xev.xclient.window = win;
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = action;
+    xev.xclient.data.l[1] = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False);
+    xev.xclient.data.l[2] = 0;
+    xev.xclient.data.l[3] = 0;
+    xev.xclient.data.l[4] = 0;
+
+    /* finally send that damn thing */
+    if (!XSendEvent(disp, DefaultRootWindow(disp), False,
+		    SubstructureRedirectMask | SubstructureNotifyMask,
+		    &xev)) {
+	fprintf(stderr, "Failed to send fullscreen command\n");
+    }
+}
+
+
+void X_Setup(int w,int h)
+{
+    XGCValues 		gcvals;
+    Window 		root;
+    XVisualInfo 	vinfo_pref;
+    int         	num_vis;
+    XPixmapFormatValues *pf;
+    int                  num_pf, pfi, i,j;
+
+    disp = XOpenDisplay(NULL);
+    if (!disp) {
+	fprintf(stderr,"X-Error: unable to connect to display\n");
+	exit(1);
+    }
+    
+    XSynchronize( disp, True );
+
+    scr=DefaultScreen(disp);
+    vis=DefaultVisual(disp,scr);
+    root=DefaultRootWindow(disp);
+    depth=DefaultDepth(disp,scr);
+
+    vinfo_pref.screen   = scr;
+    vinfo_pref.visualid = XVisualIDFromVisual( vis );
+    vi = XGetVisualInfo( disp, VisualScreenMask | VisualIDMask, 
+			 &vinfo_pref, &num_vis );
+    assert ( num_vis == 1 );
+
+    win = XCreateSimpleWindow(disp, root, 0, 0, w, h, 0, 0, 0);
+    gc = XCreateGC(disp, win, (unsigned long)0, &gcvals);
+    XSetForeground(disp, gc, 0);
+    XSetBackground(disp, gc, 1);
+
+    XMapWindow(disp,win);
+    cmap = DefaultColormap(disp, scr);
+    XSync(disp,False);
+  
+    /*  Setup with Xv extension  */
+    xv_adaptor   = -1;
+    xv_format_id = -1;
+    XvQueryAdaptors( disp, root, &xv_num_adaptors, &xv_adaptors );
+    for ( i = 0; i < xv_num_adaptors; i++ ) {
+	XvAdaptorInfo *adaptor = &xv_adaptors[i];
+	int            takes_images;
+
+	takes_images = adaptor->type & ( XvInputMask | XvImageMask );
+	if ( takes_images ) {
+	    XvImageFormatValues *formats;
+	    int                  num_formats;
+
+	    formats = XvListImageFormats( disp, adaptor->base_id, &num_formats );
+	    for ( j = 0; j < num_formats; j++ )
+		if ( formats[j].type == XvYUV && formats[j].format == XvPlanar &&
+		     strcmp( formats[j].guid, "YV12" ) == 0 )
+		    break;
+	    if ( j < num_formats ) {
+		xv_adaptor   = i;
+		xv_format_id = formats[j].id;
+		break;
+	    }
+	}
+    }
+    assert( xv_adaptor >= 0 );
+
+    /*  Create an image to captured frames  */
+#ifdef USE_XVIMAGES
+    yuv_im	age = XvShmCreateImage( disp, xv_adaptors[xv_adaptor].base_id, 
+				  xv_format_id, 0, w, h, &shminfo );
+    if (!yuv_image)
+	fprintf(stderr,"X-Error: unable to create XvShm XImage\n");
+
+    shminfo.shmid = shmget( IPC_PRIVATE, yuv_image->data_size, IPC_CREAT|0777);
+    if (shminfo.shmid == -1)
+	fprintf(stderr,"SharedMemory Error: unable to get identifier\n");
+
+    shminfo.shmaddr = yuv_image->data = shmat(shminfo.shmid, 0, 0);
+#else
+    rgb_image = XShmCreateImage( disp, vis, depth, ZPixmap, NULL, &shminfo, w, h);
+    if (!rgb_image)
+	fprintf(stderr,"X-Error: unable to create XShm XImage\n");
+
+    shminfo.shmid = shmget( IPC_PRIVATE,
+			  rgb_image->bytes_per_line * rgb_image->height,
+			  IPC_CREAT|0777);
+    if (shminfo.shmid == -1)
+	fprintf(stderr, "SharedMemory Error: unable to get identifier\n");
+
+    shminfo.shmaddr = rgb_image->data = shmat(shminfo.shmid, 0, 0);
+#endif
+
+    if(!XShmAttach( disp,&shminfo ))
+	fprintf(stderr,"X-Error: unable to attach XShm Shared Memory Segment\n");
+
+    /*  Create a pixmap for the window background  */
+#ifdef OLD
+    pmap = XShmCreatePixmap(disp, win, shminfo.shmaddr, &shminfo, w, h, depth);
+    if (!pmap)
+	fprintf(stderr,"Unable to create pixmap\n");
+#endif
+
+    /*  Determine bits-per-pixel for pixmaps  */
+    pf = XListPixmapFormats( disp, &num_pf);
+    assert(pf);
+    for (pfi = 0; pfi < num_pf; pfi++)
+	if (pf[pfi].depth == vi->depth)
+	    break;
+    assert(pfi < num_pf);
+    bits_per_pixel = pf[pfi].bits_per_pixel;
+    XFree (pf);
+
+#ifdef OLD
+    XSetWindowBackgroundPixmap(disp,win,pmap);
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
+
+void X_Shutdown()
+{
+    XShmDetach( disp, &shminfo );
+#ifdef USE_XVIMAGES
+#  warning How do we destroy an XvImage?
+#else
+    XDestroyImage( rgb_image );
+#endif
+    shmdt( shminfo.shmaddr );
+    shmctl( shminfo.shmid, IPC_RMID, 0 );
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+void X_Display(void)
+{
+    int _w,_h,_d;
+    Window _dw;
+
+#ifdef USE_XVIMAGES
+    XGetGeometry( disp, win, &_dw, &_d, &_d, &_w, &_h, &_d, &_d);
+    XvShmPutImage( disp, xv_adaptors[ xv_adaptor ].base_id, win,
+		   gc, yuv_image, 0, 0, yuv_image->width, yuv_image->height, 
+		   0, 0, _w, _h, True );
+#else
+    XShmPutImage( disp, win, gc, rgb_image, 0,0,0,0,
+		  rgb_image->width, rgb_image->height, False );
+#endif
+    XSync(disp, False);
+}
+
+#define CMD_NONE	0
+#define CMD_CHNUP	1
+#define CMD_CHNDN	2
+#define CMD_MUTE	3
+#define CMD_QUIT	4
+#define CMD_RELOAD	5
+#define CMD_CURSOR	6
+#define CMD_VOLDN	7
+#define CMD_VOLUP	8
+#define CMD_FSTOGGLE	9
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[]) {
+#ifndef USE_XVIMAGES
+    HermesHandle conv;
+    HermesFormat fmt_source,fmt_dest;
+#endif
+    XEvent e;
+    char 		*scratch_buf, *code, *c, *mixerdev;
+    int 		frames, channelidx, oldchan, mute, cursor, fd, ret, cmd;
+    int			exitnow, mfd, uselirc, curvol;
+    struct timeval 	then, now, diff, lastmove;
+    float 		rate;
+    KeySym 		key;
+    char 		text[255];
+    int			channellist[] = { 2, 7, 9, 10, 28 };
+    struct lirc_config	*config;
+    struct pollfd	fds[1];
+    
+#define NUMCHANS (sizeof(channellist) / sizeof(channellist[0]))
+    
+    channelidx = mute = cursor = 0;
+    
+    oldchan = channel = channellist[channelidx];
+    
+#ifndef USE_XVIMAGES
+    if (!Hermes_Init()) {
+	printf("Couldn't initialise Hermes!\n");
+	exit(1);
+    }
+
+    conv=Hermes_ConverterInstance(HERMES_CONVERT_NORMAL);
+    if (!conv) {
+	printf("Could not obtain converter instance from Hermes!\n");
+	exit(1);
+    }
+#endif
+  
+    X_Setup(width, height);
+    XSelectInput(disp, win, KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
+
+    X_HideCursor();
+    
+    /* Open Capture device  */
+    Open();
+
+    /* Open audio mixer */
+    mixerdev = "/dev/mixer";
+    if ((mfd = open(mixerdev, O_RDWR)) == -1)
+	fprintf(stderr, "Unable to open %s - %s\n", mixerdev, strerror(errno));
+
+    /* Talk to LIRC */
+    if ((fd = lirc_init(basename(argv[0]), 1)) == -1) {
+	fprintf(stderr, "Unable to init lirc client library\n");
+	uselirc = 0;
+    } else {
+	if (lirc_readconfig(NULL, &config, NULL) != 0) {
+	    fprintf(stderr, "Unable to parse config file\n");
+	    uselirc = 0;
+	} else
+	    uselirc = 1;
+	fds[0].fd = fd;
+	fds[0].events = POLLRDNORM;    
+    }
+
+#ifndef USE_XVIMAGES
+    /*  Conversion from and to formats  */
+    fmt_source.indexed=0;
+    fmt_source.bits=32;
+    fmt_source.r=0xff0000;
+    fmt_source.g=0x00ff00;
+    fmt_source.b=0x0000ff;
+    fmt_source.a=0;
+
+    fmt_dest.indexed=0;
+    fmt_dest.bits=bits_per_pixel;
+    fmt_dest.r=vi->red_mask;
+    fmt_dest.g=vi->green_mask;
+    fmt_dest.b=vi->blue_mask;
+    fmt_dest.a=0;
+#else
+    scratch_buf = malloc(width * height);
+#endif
+
+    frames = 0;
+    gettimeofday(&then, NULL);
+    gettimeofday(&lastmove, NULL);
+
+    exitnow = 0;
+    
+    /*  Capture loop  */
+    while (1) {
+	if (frames == 50) {
+	    gettimeofday(&now, NULL);
+	    timersub(&now, &then, &diff);
+
+	    rate = (float)frames / (float)(diff.tv_usec / 1000000.0 + diff.tv_sec);
+				
+	    printf("%d frames in %.2f seconds, rate %.2f\n", frames, (float)(diff.tv_usec / 1000000.0) + diff.tv_sec, rate);
+	    gettimeofday(&then, NULL);
+	    frames = 0;
+	    XResetScreenSaver(disp);
+	}
+	frames++;
+
+	timersub(&now, &lastmove, &diff);
+	if (((float)diff.tv_usec / 1000000.0 + (float)diff.tv_sec) > 2.0) {
+	    if (cursor) {
+		X_HideCursor();
+		cursor = 0;
+	    }
+	} else {
+	    if (!cursor) {
+		X_ShowCursor();
+		cursor = 1;
+	    }
+	}
+
+	if (XCheckMaskEvent(disp, PointerMotionMask, &e) && e.type == MotionNotify) {
+	    gettimeofday(&lastmove, NULL);
+	}
+	
+	cmd = CMD_NONE;
+
+	if (XCheckMaskEvent(disp, ButtonReleaseMask, &e)) {
+	    printf("e.type = %d\n", e.type);
+	    cmd = CMD_MUTE;
+	}
+	
+	if (XCheckMaskEvent(disp, KeyReleaseMask, &e) && e.type == KeyRelease) {
+	    gettimeofday(&lastmove, NULL);
+
+	    XLookupString(&e.xkey, text, 255, &key, 0);
+	    printf("Press - %c\n", text[0]);
+
+	    switch (text[0]) {
+	    case 'q':
+		cmd = CMD_QUIT;
+		break;
+	    
+	    case '=':
+	    case '+':
+		cmd = CMD_CHNUP;
+		break;
+		
+	    case '-':
+		cmd = CMD_CHNDN;
+		break;
+		
+	    case 'h':
+		cmd = CMD_CURSOR;
+		break;
+		
+	    case 'm':
+		cmd = CMD_MUTE;
+		break;
+		
+	    case 'r':
+		cmd = CMD_RELOAD;
+		break;
+
+	    case ',':
+		cmd = CMD_VOLDN;
+		break;
+		
+	    case '.':
+		cmd = CMD_VOLUP;
+		break;
+
+	    case 'f':
+		cmd = CMD_FSTOGGLE;
+		break;
+	    }
+	}
+
+	/* Poll for IR events */
+	if (uselirc) {
+	    fds[0].revents = 0;
+	
+	    while (1) {
+		if (poll(fds, 1, 0) == -1) {
+		    fprintf(stderr, "Poll failed - %s\n", strerror(errno));
+		    exit(EXIT_FAILURE);
+		}
+		if ((fds[0].revents & POLLRDNORM) != 0) {
+		    fprintf(stderr, "Processing IR..\n");
+
+		    if (lirc_nextcode(&code) == 0) {
+			if(code == NULL)
+			    continue;
+
+			while ((ret = lirc_code2char(config, code, &c)) == 0 &&
+			       c != NULL) {
+			    fprintf(stderr, "Got command \"%s\"\n", c);
+
+			    if (!strcmp(c, "Mute"))
+				cmd = CMD_MUTE;
+			    else if (!strcmp(c, "CH_UP"))
+				cmd = CMD_CHNUP;
+			    else if (!strcmp(c, "CH_DOWN"))
+				cmd = CMD_CHNDN;
+			    else if (!strcmp(c, "Power"))
+				cmd = CMD_QUIT;
+			    else if (!strcmp(c, "VOL_UP"))
+				cmd = CMD_VOLUP;
+			    else if (!strcmp(c, "VOL_DOWN"))
+				cmd = CMD_VOLDN;
+			    else if (!strcmp(c, "AV/TV"))
+				cmd = CMD_FSTOGGLE;
+
+			    free(code);
+			}
+		    }
+		} else
+		    break;
+	    }
+	}
+	
+	switch (cmd) {
+	case CMD_QUIT:
+	    exitnow = 1;
+	    break;
+	    
+	case CMD_CHNUP:
+	case CMD_CHNDN:
+	    if (cmd == CMD_CHNUP)
+		channelidx++;
+	    else
+		channelidx--;
+
+	    if (channelidx < 0) 
+		channelidx = NUMCHANS - 1;
+	    if (channelidx > NUMCHANS - 1)
+		channelidx = 0;
+	    
+	    channel = channellist[channelidx];
+	    
+	    printf("Channel - %d\n", channel);
+	    if (oldchan != channel) {
+		oldchan = channel;
+		
+		if ( ioctl( tuner_fd, TVTUNER_SETCHNL, &channel ) < 0 ) {
+		    DO_IOCTL_SERR( "TVTUNER_SETCHNL", channel );
+		    exit(1);
+		}
+	    }
+	    break;
+	    
+	case CMD_MUTE:
+	    if (mute)
+		mute = 0;
+	    else
+		mute = 1;
+
+	    printf("Mute - %d\n", mute);
+	    if (ioctl(tuner_fd, BT848_SAUDIO, &mute) < 0) {
+		DO_IOCTL_SERR("BT848_SAUDIO", mute);
+		exit(1);
+	    }
+	    break;
+
+	case CMD_CURSOR:
+	    if (cursor) {
+		printf("Cursor hidden\n");
+		X_HideCursor();
+		cursor = 0;
+	    } else {
+		printf("Cursor revealed\n");
+		X_ShowCursor();
+		cursor = 1;
+	    }
+	    break;
+	    
+	case CMD_RELOAD:
+	    printf("Reloading\n");
+	    Close();
+	    Open();
+	    break;
+
+	case CMD_VOLUP:
+	case CMD_VOLDN:
+	    if (ioctl(mfd, MIXER_READ(SOUND_MIXER_VOLUME), &curvol) == -1) {
+		fprintf(stderr, "Unable to read current volume - %s\n", strerror(errno));
+		break;
+	    }
+	    
+	    curvol = curvol & 0x7f;
+	    
+	    if (cmd == CMD_VOLUP)
+		curvol += 5;
+	    else
+		curvol -= 5;
+	    
+	    if (curvol < 0)
+		curvol = 0;
+	    if (curvol > 100)
+		curvol = 100;
+	    
+	    printf("Setting volume to %d\n", curvol);
+	    curvol |= curvol << 8;
+	    
+	    if (ioctl(mfd, MIXER_WRITE(SOUND_MIXER_VOLUME), &curvol) == -1) {
+		fprintf(stderr, "Unable to write volume - %s\n", strerror(errno));
+		break;
+	    }
+	    break;
+
+	case CMD_FSTOGGLE:
+	    vo_x11_ewmh_fullscreen(_NET_WM_STATE_TOGGLE);
+	    break;
+	    
+	}
+
+	Capture();
+
+#ifdef USE_XVIMAGES
+	/*  bktr's YUV_12 is planar W*H bytes Y, W/2*H/2 bytes U,  */
+	/*   W/2*H/2 bytes V.  Xv's YV12 is the same with U and V  */
+	/*   planes reversed.                                      */
+	{
+	    int y_off, u_off, v_off;
+	    y_off = 0;
+	    u_off = width * height;
+	    v_off = u_off + width*height/4;
+
+	    assert(yuv_image->data_size == width * height * 3 / 2 );
+	    memcpy(yuv_image->data        , bktr_buffer        , u_off-y_off );
+	    memcpy(yuv_image->data + u_off, bktr_buffer + v_off, v_off-u_off );
+	    memcpy(yuv_image->data + v_off, bktr_buffer + u_off, v_off-u_off );
+	}
+#else
+	/*SaveImage();*/
+
+	Hermes_ConverterRequest(conv,&fmt_source,&fmt_dest);
+	Hermes_ConverterCopy(conv,bktr_buffer,0,0,width,height,width*4,
+			     rgb_image->data,0,0,width,height,
+			     rgb_image->bytes_per_line);
+#endif
+
+	X_Display();
+	if (exitnow) {
+	    printf("quitting\n");
+	    break;
+	}
+    }
+
+#ifndef USE_XVIMAGES
+    Hermes_ConverterReturn(conv);
+    Hermes_Done();
+#endif
+
+    X_Shutdown();
+    lirc_freeconfig(config);
+    lirc_deinit();
+
+    return 0;
+}
Binary file xv_ext_test has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xv_ext_test.c	Tue Jan 04 05:17:43 2005 +0000
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/extensions/Xvlib.h>
+
+char *XvAdaptorTypeMaskToString( int mask )
+{
+  static char buf[160];
+
+  buf[0] = '\0';
+  if ( mask & XvInputMask  )  sprintf( buf+strlen(buf), "XvInputMask, " );
+  if ( mask & XvOutputMask )  sprintf( buf+strlen(buf), "XvOutputMask, " );
+  if ( mask & XvVideoMask  )  sprintf( buf+strlen(buf), "XvVideoMask, " );
+  if ( mask & XvStillMask  )  sprintf( buf+strlen(buf), "XvStillMask, " );
+  if ( mask & XvImageMask  )  sprintf( buf+strlen(buf), "XvImageMask, " );
+
+  if ( buf[0] )
+    buf[ strlen(buf)-2 ] = '\0';
+  return buf;
+}
+
+int main()
+{
+  Display *display;
+  XvImageFormatValues *formats;
+  XvAdaptorInfo *adaptors;
+  int            num_adaptors, num_formats;
+  int            i,j;
+  unsigned int   xv_version, xv_release, xv_request_base,
+                 xv_event_base, xv_error_base;
+
+  display = XOpenDisplay(NULL);
+
+  /*  XvQueryVersion  */
+  if ( XvQueryExtension( display, 
+                         &xv_version, &xv_release, &xv_request_base,
+                         &xv_event_base, &xv_error_base ) != Success ) {
+    fprintf( stderr, "XvQueryExtension failed\n" );
+    exit(1);
+  }
+  printf( "\nXvQueryExtension():\n" );
+  printf( "  version = %d, release = %d, request_base = %d,\n",
+          xv_version, xv_release, xv_request_base );
+  printf( "  event_base = %d, error_base = %d\n",
+          xv_event_base, xv_error_base );
+
+  /*  XvQueryAdaptors  */
+  XvQueryAdaptors( display, DefaultRootWindow(display), &num_adaptors, 
+                   &adaptors);
+
+  printf( "\nXvQueryAdaptors():\n" );
+  for ( i = 0; i < num_adaptors; i++ ) {
+    printf( "  Adaptor %2d:\n", i );
+    printf( "    base_id      = %ld\n", adaptors[i].base_id );
+    printf( "    num_ports    = %ld\n", adaptors[i].num_ports );
+    printf( "    type         = %d (%s)\n", 
+            adaptors[i].type, 
+            XvAdaptorTypeMaskToString( adaptors[i].type ) );
+    printf( "    name         = %s\n", adaptors[i].name );
+    printf( "    num_adaptors = %ld\n", adaptors[i].num_adaptors);
+    printf( "    num_formats  = %ld\n", adaptors[i].num_formats);
+    printf( "    formats      =\n" );
+
+    for ( j = 0; j < adaptors[i].num_formats; j++ )
+      printf( "      Format %2d:  depth = %.2d, visual_id = 0x%.2lx\n", 
+              j, 
+              adaptors[i].formats[j].depth, 
+              adaptors[i].formats[j].visual_id );
+  }
+
+  /*  XvListImageFormats  */
+  printf( "\nXvListImageFormats():\n" );
+  for ( i = 0; i < num_adaptors; i++ ) {
+    printf( "  Adaptor %2d:\n", i );
+    formats = XvListImageFormats( display, adaptors[i].base_id, 
+                                  &num_formats );
+    printf( "    num_formats = %d\n", num_formats );
+    for ( j = 0; j < num_formats; j++ ) {
+      printf( "    Format %2d:\n", j );
+      printf( "      id                = %d\n", formats[j].id               );
+      printf( "      type              = %d (%s)\n", formats[j].type,
+              formats[j].type == XvRGB ? "XvRGB" : "XvYUV" );
+      printf( "      byte_order        = %d (%s)\n", 
+              formats[j].byte_order,
+              formats[j].byte_order == LSBFirst ? "LSBFirst" : "MSBFirst" );
+      printf( "      guid              = %.4s\n", formats[j].guid           );
+      printf( "      bits_per_pixel    = %d\n", formats[j].bits_per_pixel   );
+      printf( "      format            = %d (%s)\n", formats[j].format,
+              formats[j].format == XvPacked ? "XvPacked" : "XvPlanar" );
+      printf( "      num_planes        = %d\n", formats[j].num_planes       );
+
+      if ( formats[j].type == XvRGB ) {
+        printf( "      depth             = %d\n", formats[j].depth          );
+        printf( "      red_mask          = %x\n", formats[j].red_mask       );
+        printf( "      green_mask        = %x\n", formats[j].green_mask     );
+        printf( "      blue_mask         = %x\n", formats[j].blue_mask      );
+      }
+      if ( formats[j].type == XvYUV ) {
+        printf( "      sample_bits (yuv) = ( %d, %d, %d )\n",
+                formats[j].y_sample_bits, 
+                formats[j].u_sample_bits, 
+                formats[j].v_sample_bits );
+        printf( "      horz_period (yuv) = ( %d, %d, %d )\n", 
+                formats[j].horz_y_period,
+                formats[j].horz_u_period,
+                formats[j].horz_v_period );
+        printf( "      vert_period       = ( %d, %d, %d )\n", 
+                formats[j].vert_y_period,
+                formats[j].vert_u_period,
+                formats[j].vert_v_period );
+        printf( "      component_order = %.32s\n", 
+                formats[j].component_order );
+        printf( "      scanline_order  = %d\n", formats[j].scanline_order   );
+      }
+    }
+  }
+
+  XvFreeAdaptorInfo( adaptors );
+  return(0);
+}
+