changeset 4214:664984198aef

zr driver (tv-out for DC10/DC10+, iomega buz, LML33...) added - patch by Rik Snel <rsnel@cube.dyndns.org>
author arpi
date Thu, 17 Jan 2002 01:32:29 +0000
parents f1e1b02314ef
children 14b8bc735bf5
files libvo/video_out.c libvo/vo_zr.c libvo/zoran.h
diffstat 3 files changed, 1018 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/video_out.c	Thu Jan 17 01:28:20 2002 +0000
+++ b/libvo/video_out.c	Thu Jan 17 01:32:29 2002 +0000
@@ -64,6 +64,7 @@
 extern vo_functions_t video_out_tdfxfb;
 extern vo_functions_t video_out_null;
 //extern vo_functions_t video_out_odivx;
+extern vo_functions_t video_out_zr;
 extern vo_functions_t video_out_pgm;
 extern vo_functions_t video_out_md5;
 extern vo_functions_t video_out_syncfb;
@@ -131,6 +132,9 @@
 #ifdef HAVE_DXR3
 	&video_out_dxr3,
 #endif
+#ifdef HAVE_ZR
+	&video_out_zr,
+#endif
 
 #ifdef HAVE_PNG
 	&video_out_png,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvo/vo_zr.c	Thu Jan 17 01:32:29 2002 +0000
@@ -0,0 +1,642 @@
+/* 
+ * vo_zr.c - playback on zoran cards 
+ * Copyright (C) Rik Snel 2001,2002, License GNU GPL v2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include "zoran.h"
+
+#include "config.h"
+#define ZR_USES_LIBJPEG
+
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "../mp_msg.h"
+#include "../cfgparser.h"
+
+LIBVO_EXTERN (zr)
+
+static vo_info_t vo_info = 
+{
+	"Zoran ZR360[56]7/ZR36060 Driver (DC10(+)/buz/lml33/MatroxRR)",
+	"zr",
+	"Rik Snel <snel@phys.uu.nl>",
+	""
+};
+
+/* General variables */
+
+static int image_width;
+static int image_height;
+static int off_y, off_c, stride; /* for use by 'draw slice' */
+static int framenum;
+static int fields = 1; /* currently no interlacing */
+static int forceinter = 0;
+static int vdec = 1;
+static int size;
+static int quality = 70;
+
+typedef struct {
+	int width;
+	int height;
+	int xoff;
+	int yoff;
+	int set;
+} geo;
+geo g = {0, 0, 0, 0, 0};
+
+static uint8_t *image=NULL;
+static uint8_t *buf=NULL;
+
+
+/* Variables needed for Zoran */
+
+int vdes;  /* the file descriptor of the video device */
+int frame = 0, synco = 0, queue = 0; /* buffer management */
+struct zoran_params zp;
+struct zoran_requestbuffers zrq;
+struct zoran_sync zs;
+struct video_capability vc;
+#define MJPEG_NBUFFERS	2
+#define MJPEG_SIZE	1024*256
+
+//should be command line options
+int norm = VIDEO_MODE_AUTO; 
+char *device = "/dev/video";
+
+
+#ifdef ZR_USES_LIBJPEG
+#include<jpeglib.h>
+int ccount;
+unsigned char *ccbuf;
+struct jpeg_compress_struct cinfo;
+struct jpeg_destination_mgr jdest;
+struct jpeg_error_mgr jerr;
+
+/* minimal destination handler to output to buffer */
+METHODDEF(void) init_destination(struct jpeg_compress_struct *cinfo) {
+//	printf("init_destination called %p %d\n", ccbuf, ccount);
+	cinfo->dest->next_output_byte = (JOCTET*)(ccbuf+ccount);
+	cinfo->dest->free_in_buffer = MJPEG_SIZE - ccount;
+}
+
+METHODDEF(boolean) empty_output_buffer(struct jpeg_compress_struct *cinfo) {
+//	printf("empty_output_buffer called\n");
+	mp_msg(MSGT_VO, MSGL_ERR, "empty_output_buffer called, may not happen because buffer must me large enough\n");
+	return(FALSE);
+}
+
+METHODDEF(void) term_destination(struct jpeg_compress_struct *cinfo) {
+//	printf("term_destination called %p %d\n", ccbuf, ccount);
+	ccount = MJPEG_SIZE - cinfo->dest->free_in_buffer;
+}
+/* end of minimal destination handler */
+
+JSAMPARRAY ***jsi;
+
+#else
+#include "../libavcodec/avcodec.h"
+AVCodec *codec;
+AVCodecContext codec_context;
+AVPicture picture;
+#endif 
+
+static int jpegdct = JDCT_IFAST; 
+
+int init_codec() {
+#ifdef ZR_USES_LIBJPEG
+	int i, j, k;
+	cinfo.err = jpeg_std_error(&jerr);
+	jpeg_create_compress(&cinfo);
+
+	cinfo.dest = &jdest;
+	cinfo.dest->init_destination = init_destination;
+	cinfo.dest->empty_output_buffer = empty_output_buffer;
+	cinfo.dest->term_destination = term_destination;
+
+	cinfo.input_components = 3;
+
+	jpeg_set_defaults(&cinfo);
+
+	cinfo.image_width = image_width;
+	cinfo.image_height = image_height/fields;
+	cinfo.input_gamma = 1.0;
+	cinfo.in_color_space = JCS_YCbCr;
+	cinfo.raw_data_in = TRUE;
+	cinfo.comp_info[0].h_samp_factor = 2;
+	cinfo.comp_info[0].v_samp_factor = 1;
+	cinfo.comp_info[1].h_samp_factor = 1;
+	cinfo.comp_info[1].v_samp_factor = 1;
+	cinfo.comp_info[2].h_samp_factor = 1;
+	cinfo.comp_info[2].v_samp_factor = 1;
+	cinfo.dct_method = jpegdct;
+	jpeg_set_quality(&cinfo, quality, FALSE);
+	jsi = malloc(sizeof(JSAMPARRAY**)*fields);
+
+	/* Just some clutter to give libjpeg the pointers,
+	 * and I don't want to recalculate everything everytime
+	 * it is needed */
+	for (k = 0; k < fields; k++) {
+	jsi[k] = malloc(sizeof(JSAMPARRAY*)*image_height/(8*fields));
+
+	for (i = 0; i < image_height/(8*fields); i++) {
+		jsi[k][i] = malloc(3*sizeof(JSAMPARRAY));
+		jsi[k][i][0] = malloc(8*sizeof(JSAMPROW));
+		jsi[k][i][1] = malloc(8*sizeof(JSAMPROW));
+		jsi[k][i][2] = malloc(8*sizeof(JSAMPROW));
+		for (j = 0; j < 8; j++) {
+			jsi[k][i][0][j] = (JSAMPROW)(image + 
+					(fields*(8*i + j) + k)*image_width);
+			jsi[k][i][1][j] = (JSAMPROW)(image + size + 
+					(fields*(8*i + j)/2)*image_width/2);
+			jsi[k][i][2][j] = (JSAMPROW)(image + 3*size/2 + 
+					(fields*(8*i + j)/2)*image_width/2);
+		}
+	}
+
+	}
+#else
+	AVCodecContext *c = &codec_context;
+	codec = avcodec_find_encoder(CODEC_ID_MJPEG);
+	if (!codec) {
+		/* maybe libavcodec was not initialized */
+		avcodec_init();
+		avcodec_register_all();
+		codec = avcodec_find_encoder(CODEC_ID_MJPEG);
+		if (!codec) {
+			mp_msg(MSGT_VO, MSGL_ERR, "MJPG codec not found in libavcodec\n");
+			return 1;
+		}
+	}
+	/* put default values */
+	memset(c, 0, sizeof(*c));
+
+	c->width = image_width;
+	c->height = image_height;
+	c->bit_rate = 4000000;
+	c->frame_rate = 25*FRAME_RATE_BASE;
+	//c->gop_size = 1;
+	c->pix_fmt = PIX_FMT_YUV422P;
+
+	if (avcodec_open(c, codec) < 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "MJPG codec could not be opened\n");
+		return 1;
+	}
+
+	picture.data[0] = image;
+	picture.data[1] = image + size;
+	picture.data[2] = image + 3*size/2;
+	picture.linesize[0] = image_width;
+	picture.linesize[1] = image_width/2;
+	picture.linesize[2] = image_width/2;
+#endif 
+	return 0;
+}
+
+
+int zoran_getcap() {
+	vdes = open(device, O_RDWR);
+	/* before we can ask for the maximum resolution, we must set 
+	 * the correct tv norm */
+
+	if (ioctl(vdes, BUZIOC_G_PARAMS, &zp) < 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "device at %s is probably not a DC10(+)/buz/lml33\n", device);
+		return 1;
+	}
+	
+	if (zp.norm != norm && norm != VIDEO_MODE_AUTO) {
+		/* attempt to set requested norm */
+		zp.norm = norm;
+		if (ioctl(vdes, BUZIOC_S_PARAMS, &zp) < 0) {
+			mp_msg(MSGT_VO, MSGL_ERR,
+				"unable to change video norm, use another program to change it (XawTV)\n");
+			return 1;
+		}
+		ioctl(vdes, BUZIOC_G_PARAMS, &zp);
+		if (norm != zp.norm) {
+			mp_msg(MSGT_VO, MSGL_ERR,
+				"unable to change video norm, use another program to change it (XawTV)\n");
+			return 1;
+		}
+	}
+	
+	if (vdes < 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "error opening %s\n", 
+				device);
+		return 1;
+	}
+
+
+	if (ioctl(vdes, VIDIOCGCAP, &vc) < 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "error getting video capabilities from %s\n");
+		return 1;
+	}
+	mp_msg(MSGT_VO, MSGL_V, "zr36067 reports: maxwidth=%d, maxheight=%d\n", vc.maxwidth, vc.maxheight);
+	
+	return 0;
+}
+	
+int init_zoran() {
+	/* center the image, and stretch it as far as possible (try to keep
+	 * aspect) and check if it fits */
+	if (image_width > vc.maxwidth) {
+		mp_msg(MSGT_VO, MSGL_ERR, "movie to be played is too wide, max width currenty %d\n", vc.maxwidth);
+		return 1;
+	}
+
+	if (image_height > vc.maxheight) {
+		mp_msg(MSGT_VO, MSGL_ERR, "movie to be played is too high, max height currenty %d\n", vc.maxheight);
+		return 1;
+	}
+
+	zp.decimation = 0;
+	zp.HorDcm = (vc.maxwidth >= 2*(int)image_width) ? 2 : 1;
+	zp.VerDcm = 1;
+	if (zp.HorDcm == 2 && 4*image_width <= vc.maxwidth && 
+			4*image_height/fields <= vc.maxheight) {
+		zp.HorDcm = 4;
+		zp.VerDcm = 2;
+	}
+	if (((forceinter == 0 && vdec >= 2) || (forceinter == 1 && vdec == 4)) && 4*image_height/fields <= vc.maxheight) {
+		zp.VerDcm = 2;
+	}
+	zp.TmpDcm = 1;
+	zp.field_per_buff = fields;
+	zp.img_x = (vc.maxwidth - zp.HorDcm*(int)image_width)/2;
+	zp.img_y = (vc.maxheight - zp.VerDcm*(3-fields)*(int)image_height)/4;
+	zp.img_width = zp.HorDcm*image_width;
+	zp.img_height = zp.VerDcm*image_height/fields;
+	mp_msg(MSGT_VO, MSGL_V, "zr: geometry (after 'scaling'): %dx%d+%d+%d fields=%d, w=%d, h=%d\n", zp.img_width, zp.img_height, zp.img_x, zp.img_y, fields, image_width, image_height);
+
+	if (ioctl(vdes, BUZIOC_S_PARAMS, &zp) < 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "error setting display parameters\n");
+		return 1;
+	}
+
+	zrq.count = MJPEG_NBUFFERS;
+	zrq.size = MJPEG_SIZE;
+
+	if (ioctl(vdes, BUZIOC_REQBUFS, &zrq)) {
+		mp_msg(MSGT_VO, MSGL_ERR, "error requesting %d buffers of size %d\n", zrq.count, zrq.size);
+		return 1;
+	}
+
+	buf = (char*)mmap(0, zrq.count*zrq.size, PROT_READ|PROT_WRITE,
+			MAP_SHARED, vdes, 0);
+
+	if (buf == MAP_FAILED) {
+		mp_msg(MSGT_VO, MSGL_ERR, "error requesting %d buffers of size %d\n", zrq.count, zrq.size);
+		return 1;
+	}
+	return 0;
+}
+
+void uninit_zoran(void) {
+	if (image) {
+		free(image);
+		image=NULL;
+	}
+	while (queue > synco + 1) {
+		if (ioctl(vdes, BUZIOC_SYNC, &zs) < 0) 
+			mp_msg(MSGT_VO, MSGL_ERR, "error waiting for buffers to become free"); 
+		synco++;
+	}
+	/* stop streaming */
+	frame = -1;
+	if (ioctl(vdes, BUZIOC_QBUF_PLAY, &frame) < 0) 
+		mp_msg(MSGT_VO, MSGL_ERR, "error stopping playback of last frame");
+	close(vdes);
+}
+
+static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width, 
+	uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format)
+{
+	int j;
+	/* this allows to crop parts from incoming picture,
+	 * for easy 512x240 -> 352x240 */
+	/* These values must be multples of 2 */
+
+	if (g.set) {
+		if (g.width%2 != 0 || g.height%2 != 0 ||
+				g.xoff%2 != 0 || g.yoff%2 != 0) {
+			mp_msg(MSGT_VO, MSGL_ERR, "arguments in -zrcrop must be multiples of 2\n");
+			return 1;
+		}
+		if (g.width <= 0 || g.height <= 0 ||
+				g.xoff < 0 || g.yoff < 0) {
+			mp_msg(MSGT_VO, MSGL_ERR, "width and height must be positive and offset nonnegative\n");
+			return 1;
+		}
+		if (g.width + g.xoff > width) {
+			mp_msg(MSGT_VO, MSGL_ERR, "width+xoffset (%d+%d>%d) is too big\n", g.width, g.xoff, width);
+			return 1;
+		}
+		if (g.height + g.yoff > height) {
+			mp_msg(MSGT_VO, MSGL_ERR, "height+yoffset (%d+%d>%d) is too big\n", g.height, g.yoff, height);
+			return 1;
+		}
+	} else {
+		g.width = width;
+		g.height = height;
+		g.xoff = 0;
+		g.yoff = 0;
+	}
+	/* we must know the maximum resolution of the device
+	 * it differs for DC10+ and buz for example */
+	zoran_getcap(); /*must be called before init_zoran */
+	if (g.height/vdec > vc.maxheight/2 || (forceinter == 1 && vdec == 1))
+		fields = 2;
+	printf("fields=%d\n", fields);
+	/* the height must be a multiple of fields*8 and the width
+	 * must be a multiple of 16 */
+	/* add some black borders to make it so, and center the image*/
+	image_height = fields*8*((g.height/vdec - 1)/(fields*8) + 1);
+	image_width = 16*((g.width - 1)/16 + 1);
+	off_y = (image_height - g.height/vdec)/2;
+	if (off_y%2 != 0) off_y++;
+	off_y *= image_width;
+	off_c = off_y/4;
+	off_y += (image_width - g.width)/2;
+	if (off_y%2 != 0) off_y--;
+	off_c += (image_width - g.width)/4;
+	framenum = 0;
+	size = image_width*image_height;
+	mp_msg(MSGT_VO, MSGL_V, "input: %dx%d, cropped: %dx%d, output: %dx%d, off_y=%d, off_c=%d\n", width, height, g.width, g.height, image_width, image_height, off_y, off_c);
+	
+	image = malloc(2*size); /* this buffer allows for YUV422 data,
+				 * so it is a bit too big for YUV420 */
+	if (!image) {
+		mp_msg(MSGT_VO, MSGL_ERR, "Memory exhausted\n");
+		return 1;
+	}
+	/* and make sure that the borders are _really_ black */
+	memset(image, 0, image_width*image_height);
+	memset(image + size, 0x80, image_width*image_height/4);
+	memset(image + 3*size/2, 0x80, image_width*image_height/4);
+
+	if (init_codec()) {
+		return 1;
+	}
+	
+	if (init_zoran()) {
+#ifdef ZR_USES_LIBJPEG
+		jpeg_destroy_compress(&cinfo);
+#else
+		avcodec_close(&codec_context);
+#endif
+		return 1;
+	}
+
+	return 0;
+}
+
+static const vo_info_t* get_info(void) {
+	return &vo_info;
+}
+
+static void draw_osd(void) {
+}
+
+static void flip_page (void) {
+#ifdef ZR_USES_LIBJPEG
+	int i, j, k;
+#else
+	AVCodecContext *c = &codec_context;
+#endif
+
+	/* do we have a free buffer? */
+	if (queue-synco < zrq.count) {
+		frame = queue;
+	} else {
+		if (ioctl(vdes, BUZIOC_SYNC, &zs) < 0) 
+			mp_msg(MSGT_VO, MSGL_ERR, "error waiting for buffers to become free"); 
+		frame = zs.frame;
+		synco++;
+	}
+
+#ifdef ZR_USES_LIBJPEG
+	ccbuf = buf + frame*zrq.size;
+	ccount = 0;
+	k = fields;
+	for (j=0; j < k; j++) {
+
+	jpeg_start_compress(&cinfo, TRUE);
+	i=0;
+	while (cinfo.next_scanline < cinfo.image_height) {
+		jpeg_write_raw_data(&cinfo, jsi[j][i], 8);
+		i++;
+	}
+	jpeg_finish_compress(&cinfo);
+
+	}
+#else
+	avcodec_encode_video(c, buf + frame*zrq.size, MJPEG_SIZE, &picture);
+#endif
+
+	if (ioctl(vdes, BUZIOC_QBUF_PLAY, &frame) < 0) 
+		mp_msg(MSGT_VO, MSGL_ERR,
+				"error queueing buffer for playback");
+	queue++;
+
+	framenum++;
+	return;
+}
+
+static uint32_t draw_frame(uint8_t * src[]) {
+	return 0;
+}
+
+static uint32_t query_format(uint32_t format) {
+	if(format==IMGFMT_YV12) return 1;
+	return 0;
+}
+
+static void uninit(void) {
+	uninit_zoran();
+
+#ifdef ZR_USES_LIBJPEG
+	jpeg_destroy_compress(&cinfo);
+#else
+	avcodec_close(&codec_context);
+#endif
+}
+
+static void check_events(void) {
+}
+
+
+static uint32_t draw_slice(uint8_t *srcimg[], int stride[],
+		int w, int h, int x, int y) {
+	int i;
+	/* Apply 'geometry', crop unwanted parts */
+	uint8_t *dst;
+	uint8_t *src;
+	//printf("before: w=%d, h=%d, x=%d, y=%d, src0=%p, src1=%p, src2=%p\n", w, h, x, y, srcimg[0], srcimg[1], srcimg[2]);
+	if (x < g.xoff) {
+		srcimg[0] += g.xoff - x;
+		srcimg[1] += (g.xoff - x)/2;
+		srcimg[2] += (g.xoff - x)/2;
+		w -= g.xoff - x;
+		if (w < 0) return 0;
+		x = 0 /*g.xoff*/;
+	} else {
+		x -= g.xoff;
+	}
+	if (x + w > g.width) {
+		w = g.width - x;
+		if (w < 0) return 0;
+	}
+	if (y < g.yoff) {
+		srcimg[0] += (g.yoff - y)*stride[0];
+		srcimg[1] += ((g.yoff - y)/2)*stride[1];
+		srcimg[2] += ((g.yoff - y)/2)*stride[2];
+		h -= g.yoff - y;
+		if (h < 0) return 0;
+		y = 0;
+	} else {
+		y -= g.yoff;
+	}
+	if (y + h > g.height) {
+		h = g.height - y;
+		if (h < 0) return 0;
+	}
+	//printf("after: w=%d, h=%d, x=%d, y=%d, src0=%p, src1=%p, src2=%p\n", w, h, x, y, srcimg[0], srcimg[1], srcimg[2]);
+	dst=image + off_y + image_width*(y/vdec)+x;
+	src=srcimg[0];
+	// copy Y:
+	for (i = 0; i < h; i++) {
+		if ((i + x)%vdec == 0) {
+			memcpy(dst,src,w);
+			dst+=image_width;
+		}
+		src+=stride[0];
+
+	}
+	{
+    		// copy U+V:
+		uint8_t *src1=srcimg[1];
+		uint8_t *src2=srcimg[2];
+		uint8_t *dst1=image + size + off_c+ (y/(vdec*2))*image_width/2+(x/2);
+		uint8_t *dst2=image + 3*size/2 + off_c + 
+			(y/(vdec*2))*image_width/2+(x/2);
+		for (i = 0; i< h/2; i++) {
+			if ((i+x/2)%vdec == 0) {
+				memcpy(dst1,src1,w/2);
+				memcpy(dst2,src2,w/2);
+				dst1+=image_width/2;
+				dst2+=image_width/2;
+			}
+			src1+=stride[1];
+			src2+=stride[2];
+		}
+    	}
+ 	return 0;
+}
+
+
+/* copied and adapted from vo_aa_parseoption */
+int
+vo_zr_parseoption(struct config * conf, char *opt, char *param){
+    /* got an option starting with zr */
+    char *x, *help;
+    int i;
+    /* do WE need it ?, always */
+    if (!strcasecmp(opt, "zrdev")) {
+	if (param == NULL) return ERR_MISSING_PARAM;
+	//if ((i=getcolor(param))==-1) return ERR_OUT_OF_RANGE;
+	//aaopt_osdcolor=i;
+	device = malloc(strlen(param)+1);
+	strcpy(device, param);
+	mp_msg(MSGT_VO, MSGL_V, "zr: using device %s\n", device);
+	return 1;
+    } else if (!strcasecmp(opt, "zrfi")) {
+	    if (param != NULL) {
+		    return ERR_OUT_OF_RANGE;
+	    }
+	    forceinter = 1;
+	    return 1;
+    } else if (!strcasecmp(opt, "zrcrop")){
+	if (param == NULL) return ERR_MISSING_PARAM;
+	if (sscanf(param, "%dx%d+%d+%d", &g.width, &g.height, 
+				&g.xoff, &g.yoff) != 4) {
+		g.xoff = 0; g.yoff = 0;
+		if (sscanf(param, "%dx%d", &g.width, &g.height) != 2) {
+			mp_msg(MSGT_VO, MSGL_ERR, "argument to -zrcrop must be of the form 352x288+16+0\n");
+			return ERR_OUT_OF_RANGE;
+		}
+	}
+	g.set = 1;
+	mp_msg(MSGT_VO, MSGL_V, "zr: cropping %s\n", param);
+	return 1;
+    }else if (!strcasecmp(opt, "zrvdec")) {
+        i = atoi(param);
+	if (i != 1 && i != 2 && i != 4) return ERR_OUT_OF_RANGE;
+	vdec = i;
+	return 1;
+    }else if (!strcasecmp(opt, "zrquality")) {
+        i = atoi(param);
+	if (i < 30 || i > 100) return ERR_OUT_OF_RANGE;
+	quality = i;
+	return 1;
+    }else if (!strcasecmp(opt, "zrdct")) {
+	if (param == NULL) return ERR_MISSING_PARAM;
+	if (!strcasecmp(param, "IFAST")) {
+            jpegdct = JDCT_IFAST;
+	    return 1;
+	} else if (!strcasecmp(param, "ISLOW")) {
+            jpegdct = JDCT_ISLOW;
+	    return 1;
+	} else if (!strcasecmp(param, "FLOAT")) {
+            jpegdct = JDCT_FLOAT;
+	    return 1;
+	} else {
+           return ERR_OUT_OF_RANGE;
+        }
+    }else if (!strcasecmp(opt, "zrnorm")) {
+	if (param == NULL) return ERR_MISSING_PARAM;
+	if (!strcasecmp(param, "NTSC")) {
+            mp_msg(MSGT_VO, MSGL_V, "zr: Norm set to NTSC\n");
+            norm = VIDEO_MODE_NTSC;
+	    return 1;
+	} else if (!strcasecmp(param, "PAL")) {
+	    mp_msg(MSGT_VO, MSGL_V, "zr: Norm set to PAL\n");
+            norm = VIDEO_MODE_PAL;
+	    return 1;
+	} else {
+           return ERR_OUT_OF_RANGE;
+        }
+    }else if (!strcasecmp(opt, "zrhelp")){
+	printf("Help for -vo zr: Zoran ZR360[56]7/ZR36060 based MJPEG capture/playback cards\n");
+	printf("\n");
+	printf("Here are the zr options:\n");
+	printf(
+		    "\n"
+		    "  -zrcrop     specify part of the input image that\n"
+		    "              you want to see as an x-style geometry string\n"
+		    "              example: -zrcrop 352x288+16+0\n"
+		    "  -zrvdec     vertical decimation 1, 2 or 4\n"
+		    "  -zrfi       force interlacing ('wide screen')\n"
+		    "              (by default we only interlace if the movie\n"
+		    "              is higher than half of the screen height)\n"
+		    "  -zrquality  jpeg compression quality 30-100\n"
+                    "  -zrdct      specify DCT method: IFAST, ISLOW or FLOAT\n"
+		    "  -zrdev      playback device (example -zrdev /dev/video1\n"
+		    "  -zrnorm     specify norm PAL/NTSC [dev: leave at current setting]\n"
+		    "\n"
+	      );
+	exit(0);
+		
+    }
+    return ERR_NOT_AN_OPTION;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvo/zoran.h	Thu Jan 17 01:32:29 2002 +0000
@@ -0,0 +1,372 @@
+/* 
+    zoran - Iomega Buz driver
+
+    Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+
+   based on
+
+    zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+   and
+
+    bttv - Bt848 frame grabber driver
+    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BUZ_H_
+#define _BUZ_H_
+
+#include <linux/config.h>
+
+#if LINUX_VERSION_CODE < 0x20212
+typedef struct wait_queue *wait_queue_head_t;
+#endif
+
+/* The Buz only supports a maximum width of 720, but some V4L
+   applications (e.g. xawtv are more happy with 768).
+   If XAWTV_HACK is defined, we try to fake a device with bigger width */
+
+//#define XAWTV_HACK
+
+//#ifdef XAWTV_HACK
+//#define   BUZ_MAX_WIDTH   768   /* never display more than 768 pixels */
+#define   BUZ_MAX_WIDTH   (zr->timing->Wa)
+//#else
+//#define   BUZ_MAX_WIDTH   720   /* never display more than 720 pixels */
+//#endif
+//#define   BUZ_MAX_HEIGHT  576   /* never display more than 576 rows */
+#define   BUZ_MAX_HEIGHT  (zr->timing->Ha)
+#define   BUZ_MIN_WIDTH    32	/* never display less than 32 pixels */
+#define   BUZ_MIN_HEIGHT   24	/* never display less than 24 rows */
+
+struct zoran_requestbuffers {
+	unsigned long count;	/* Number of buffers for MJPEG grabbing */
+	unsigned long size;	/* Size PER BUFFER in bytes */
+};
+
+struct zoran_sync {
+	unsigned long frame;	/* number of buffer that has been free'd */
+	unsigned long length;	/* number of code bytes in buffer (capture only) */
+	unsigned long seq;	/* frame sequence number */
+	struct timeval timestamp;	/* timestamp */
+};
+
+struct zoran_status {
+	int input;		/* Input channel, has to be set prior to BUZIOC_G_STATUS */
+	int signal;		/* Returned: 1 if valid video signal detected */
+	int norm;		/* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int color;		/* Returned: 1 if color signal detected */
+};
+
+struct zoran_params {
+
+	/* The following parameters can only be queried */
+
+	int major_version;	/* Major version number of driver */
+	int minor_version;	/* Minor version number of driver */
+
+	/* Main control parameters */
+
+	int input;		/* Input channel: 0 = Composite, 1 = S-VHS */
+	int norm;		/* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+	int decimation;		/* decimation of captured video,
+				   enlargement of video played back.
+				   Valid values are 1, 2, 4 or 0.
+				   0 is a special value where the user
+				   has full control over video scaling */
+
+	/* The following parameters only have to be set if decimation==0,
+	   for other values of decimation they provide the data how the image is captured */
+
+	int HorDcm;		/* Horizontal decimation: 1, 2 or 4 */
+	int VerDcm;		/* Vertical decimation: 1 or 2 */
+	int TmpDcm;		/* Temporal decimation: 1 or 2,
+				   if TmpDcm==2 in capture every second frame is dropped,
+				   in playback every frame is played twice */
+	int field_per_buff;	/* Number of fields per buffer: 1 or 2 */
+	int img_x;		/* start of image in x direction */
+	int img_y;		/* start of image in y direction */
+	int img_width;		/* image width BEFORE decimation,
+				   must be a multiple of HorDcm*16 */
+	int img_height;		/* image height BEFORE decimation,
+				   must be a multiple of VerDcm*8 */
+
+	/* --- End of parameters for decimation==0 only --- */
+
+	/* JPEG control parameters */
+
+	int quality;		/* Measure for quality of compressed images.
+				   Scales linearly with the size of the compressed images.
+				   Must be beetween 0 and 100, 100 is a compression
+				   ratio of 1:4 */
+
+	int odd_even;		/* Which field should come first ??? */
+
+	int APPn;		/* Number of APP segment to be written, must be 0..15 */
+	int APP_len;		/* Length of data in JPEG APPn segment */
+	char APP_data[60];	/* Data in the JPEG APPn segment. */
+
+	int COM_len;		/* Length of data in JPEG COM segment */
+	char COM_data[60];	/* Data in JPEG COM segment */
+
+	unsigned long jpeg_markers;	/* Which markers should go into the JPEG output.
+					   Unless you exactly know what you do, leave them untouched.
+					   Inluding less markers will make the resulting code
+					   smaller, but there will be fewer aplications
+					   which can read it.
+					   The presence of the APP and COM marker is
+					   influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3)	/* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4)	/* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5)	/* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6)	/* Comment segment */
+#define JPEG_MARKER_APP (1<<7)	/* App segment, driver will allways use APP0 */
+
+	int VFIFO_FB;		/* Flag for enabling Video Fifo Feedback.
+				   If this flag is turned on and JPEG decompressing
+				   is going to the screen, the decompress process
+				   is stopped every time the Video Fifo is full.
+				   This enables a smooth decompress to the screen
+				   but the video output signal will get scrambled */
+
+	/* Misc */
+
+	char reserved[312];	/* Makes 512 bytes for this structure */
+};
+
+/*
+Private IOCTL to set up for displaying MJPEG
+*/
+#define BUZIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct zoran_params)
+#define BUZIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct zoran_params)
+#define BUZIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct zoran_requestbuffers)
+#define BUZIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define BUZIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define BUZIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct zoran_sync)
+#define BUZIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct zoran_status)
+
+
+#ifdef __KERNEL__
+
+#define BUZ_NUM_STAT_COM    4
+#define BUZ_MASK_STAT_COM   3
+
+#define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
+#define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
+
+#if VIDEO_MAX_FRAME <= 32
+#   define   V4L_MAX_FRAME   32
+#elif VIDEO_MAX_FRAME <= 64
+#   define   V4L_MAX_FRAME   64
+#else
+#   error   "Too many video frame buffers to handle"
+#endif
+#define   V4L_MASK_FRAME   (V4L_MAX_FRAME - 1)
+
+
+#include "zr36057.h"
+
+enum card_type {
+        UNKNOWN = 0,
+        DC10,
+        DC10plus,
+        LML33,
+        BUZ
+};
+
+enum zoran_codec_mode {
+	BUZ_MODE_IDLE,		/* nothing going on */
+	BUZ_MODE_MOTION_COMPRESS,	/* grabbing frames */
+	BUZ_MODE_MOTION_DECOMPRESS,	/* playing frames */
+	BUZ_MODE_STILL_COMPRESS,	/* still frame conversion */
+	BUZ_MODE_STILL_DECOMPRESS	/* still frame conversion */
+};
+
+enum zoran_buffer_state {
+	BUZ_STATE_USER,		/* buffer is owned by application */
+	BUZ_STATE_PEND,		/* buffer is queued in pend[] ready to feed to I/O */
+	BUZ_STATE_DMA,		/* buffer is queued in dma[] for I/O */
+	BUZ_STATE_DONE		/* buffer is ready to return to application */
+};
+
+struct zoran_gbuffer {
+	u32 *frag_tab;		/* addresses of frag table */
+	u32 frag_tab_bus;	/* same value cached to save time in ISR */
+	enum zoran_buffer_state state;	/* non-zero if corresponding buffer is in use in grab queue */
+	struct zoran_sync bs;	/* DONE: info to return to application */
+};
+
+struct v4l_gbuffer {
+	char *fbuffer;			/* virtual  address of frame buffer */
+	unsigned long fbuffer_phys;	/* physical address of frame buffer */
+	unsigned long fbuffer_bus;	/* bus      address of frame buffer */
+	enum zoran_buffer_state state;	/* state: unused/pending/done */
+};
+
+struct tvnorm {
+	u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart;
+};
+
+struct zoran {
+	struct video_device video_dev;
+	struct i2c_bus i2c;
+
+	int initialized;		/* flag if zoran has been correctly initalized */
+	int user;			/* number of current users (0 or 1) */
+        enum card_type card;
+        struct tvnorm *timing;
+
+	unsigned short id;		/* number of this device */
+	char name[32];			/* name of this device */
+	struct pci_dev *pci_dev;	/* PCI device */
+	unsigned char revision;		/* revision of zr36057 */
+	unsigned int zr36057_adr;	/* bus address of IO mem returned by PCI BIOS */
+	unsigned char *zr36057_mem;	/* pointer to mapped IO memory */
+
+	int map_mjpeg_buffers;		/* Flag which bufferset will map by next mmap() */
+
+	spinlock_t lock;		/* Spinlock irq and hardware */
+	struct semaphore sem;		/* Guard parallel ioctls and mmap */
+
+	/* Video for Linux parameters */
+
+	struct video_picture picture;	/* Current picture params */
+	struct video_buffer buffer;	/* Current buffer params */
+	struct video_window window;	/* Current window params */
+	int buffer_set, window_set;	/* Flags if the above structures are set */
+	int video_interlace;		/* Image on screen is interlaced */
+
+	u32 *overlay_mask;
+        wait_queue_head_t v4l_capq;
+
+	int v4l_overlay_active;		/* Overlay grab is activated */
+	int v4l_memgrab_active;		/* Memory grab is activated */
+
+	int v4l_grab_frame;		/* Frame number being currently grabbed */
+#define NO_GRAB_ACTIVE (-1)
+	int v4l_grab_seq;		/* Number of frames grabbed */
+	int gwidth;			/* Width of current memory capture */
+	int gheight;			/* Height of current memory capture */
+	int gformat;			/* Format of ... */
+	int gbpl;			/* byte per line of ... */
+
+	/* V4L grab queue of frames pending */
+
+	unsigned v4l_pend_head;
+	unsigned v4l_pend_tail;
+	int v4l_pend[V4L_MAX_FRAME];
+
+	struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME];	/* V4L   buffers' info */
+
+	/* Buz MJPEG parameters */
+
+	unsigned long jpg_nbufs;	/* Number of buffers */
+	unsigned long jpg_bufsize;	/* Size of mjpeg buffers in bytes */
+	int jpg_buffers_allocated;	/* Flag if buffers are allocated  */
+	int need_contiguous;	/* Flag if contiguous buffers are needed */
+
+	enum zoran_codec_mode codec_mode;	/* status of codec */
+	struct zoran_params params;	/* structure with a lot of things to play with */
+
+	wait_queue_head_t jpg_capq;	/* wait here for grab to finish */
+
+	/* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */
+	/* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */
+	/* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */
+	unsigned long jpg_que_head;	/* Index where to put next buffer which is queued */
+	unsigned long jpg_dma_head;	/* Index of next buffer which goes into stat_com  */
+	unsigned long jpg_dma_tail;	/* Index of last buffer in stat_com               */
+	unsigned long jpg_que_tail;	/* Index of last buffer in queue                  */
+	unsigned long jpg_seq_num;	/* count of frames since grab/play started        */
+	unsigned long jpg_err_seq;	/* last seq_num before error                      */
+	unsigned long jpg_err_shift;
+	unsigned long jpg_queued_num;	/* count of frames queued since grab/play started */
+
+	/* zr36057's code buffer table */
+	u32 *stat_com;			/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+
+	/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
+	int jpg_pend[BUZ_MAX_FRAME];
+
+	/* array indexed by frame number */
+	struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME];	/* MJPEG buffers' info */
+
+	/* Additional stuff for testing */
+	struct proc_dir_entry *zoran_proc;
+
+	int testing;
+	int jpeg_error;
+	int intr_counter_GIRQ1;
+	int intr_counter_GIRQ0;
+	int intr_counter_CodRepIRQ;
+	int intr_counter_JPEGRepIRQ;
+	int field_counter;
+	int IRQ1_in;
+	int IRQ1_out;
+	int JPEG_in;
+	int JPEG_out;
+	int JPEG_0;
+	int JPEG_1;
+	int END_event_missed;
+	int JPEG_missed;
+	int JPEG_error;
+	int num_errors;
+	int JPEG_max_missed;
+	int JPEG_min_missed;
+
+	u32 last_isr;
+	unsigned long frame_num;
+
+	wait_queue_head_t test_q;
+};
+
+#endif
+
+/*The following should be done in more portable way. It depends on define
+  of _ALPHA_BUZ in the Makefile.*/
+
+#ifdef _ALPHA_BUZ
+#define btwrite(dat,adr)    writel((dat),(char *) (zr->zr36057_adr+(adr)))
+#define btread(adr)         readl(zr->zr36057_adr+(adr))
+#else
+#define btwrite(dat,adr)    writel((dat), (char *) (zr->zr36057_mem+(adr)))
+#define btread(adr)         readl(zr->zr36057_mem+(adr))
+#endif
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#define I2C_TSA5522        0xc2
+#define I2C_TDA9850        0xb6
+#define I2C_HAUPEE         0xa0
+#define I2C_STBEE          0xae
+#define   I2C_SAA7111        0x48
+#define   I2C_SAA7110        0x9c
+#define   I2C_SAA7185        0x88
+//#define   I2C_ADV7175        0xd4
+#define   I2C_ADV7175        0x54
+
+#define TDA9850_CON1       0x04
+#define TDA9850_CON2       0x05
+#define TDA9850_CON3       0x06
+#define TDA9850_CON4       0x07
+#define TDA9850_ALI1       0x08
+#define TDA9850_ALI2       0x09
+#define TDA9850_ALI3       0x0a
+
+#endif