changeset 11416:af8c66f215cf

added subdevice options, SECAM support (for what's it worth...), added \n to some verbose messages, tended to compiler warnings (signed/unsigned comparison)
author rik
date Sat, 08 Nov 2003 14:10:33 +0000
parents da41bbc78e3d
children 62eb4a5046b7
files libvo/vo_zr2.c
diffstat 1 files changed, 118 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/vo_zr2.c	Sat Nov 08 02:07:10 2003 +0000
+++ b/libvo/vo_zr2.c	Sat Nov 08 14:10:33 2003 +0000
@@ -38,6 +38,9 @@
 LIBVO_EXTERN(zr2)
 
 typedef struct {
+	/* options */
+	char *subdevice;
+
 	/* information for (and about) the zoran card */
 
 	unsigned char *buf; 		 /* the JPEGs will be placed here */
@@ -57,6 +60,7 @@
 #define ZR2_MJPEG_SIZE		1024*256	
 
 /* some convenient #define's, is this portable enough? */
+#define DBG2(...) mp_msg(MSGT_VO, MSGL_DBG2, "vo_zr2: " __VA_ARGS__)
 #define VERBOSE(...) mp_msg(MSGT_VO, MSGL_V, "vo_zr2: " __VA_ARGS__)
 #define ERROR(...) mp_msg(MSGT_VO, MSGL_ERR, "vo_zr2: " __VA_ARGS__)
 #define WARNING(...) mp_msg(MSGT_VO, MSGL_WARN, "vo_zr2: " __VA_ARGS__)
@@ -75,6 +79,7 @@
 
 static char *guess_device(char *suggestion) {
 	struct stat vstat;
+	int res;
 	char *devs[] = {
 		"/dev/video",
 		"/dev/video0",
@@ -85,10 +90,26 @@
 	};
 	char **dev = devs;
 
-	if (suggestion) return suggestion;
+	if (suggestion) {
+		if (!*suggestion) {
+			ERROR("error: specified device name is empty string\n");
+			return NULL;
+		}
+
+		res = stat(suggestion, &vstat);
+		if (res == 0 && S_ISCHR(vstat.st_mode)) {
+			VERBOSE("using device %s\n", suggestion);
+			return suggestion;
+		} else {
+			if (res != 0) ERROR("%s does not exist\n", suggestion);
+			else ERROR("%s is no character device\n", suggestion);
+			/* don't try to be smarter than the user, just exit */
+			return NULL;
+		}
+	}
 
 	while (*(++dev) != NULL) {
-		if ((stat(*dev, &vstat) == 0) && S_ISCHR(vstat.st_mode)) {
+		if (stat(*dev, &vstat) == 0 && S_ISCHR(vstat.st_mode)) {
 			VERBOSE("guessed video device %s\n", *dev);
 			return *dev;
 		}
@@ -111,14 +132,14 @@
 static uint32_t draw_image(mp_image_t *mpi) {
 	vo_zr2_priv_t *p = &priv;
 	int size = (int)mpi->planes[1];
-	if (size > p->zrq.size) {
+	if (size > (int)p->zrq.size) {
 		ERROR("incoming JPEG image (size=%d) doesn't fit in buffer\n",
 				size);
 		return VO_FALSE;
 	}
 
 	/* looking for free buffer */
-	if (p->queue - p->sync < p->zrq.count) p->frame = p->queue;
+	if (p->queue - p->sync < (int)p->zrq.count) p->frame = p->queue;
 	else {
 		if (ioctl(p->vdes, MJPIOC_SYNC, &p->zs) < 0) {
 			ERROR("error waiting for buffer to become free\n");
@@ -134,52 +155,126 @@
 	return VO_TRUE;
 }
 
+static char *normstring(int norm) {
+	switch (norm) {
+		case VIDEO_MODE_PAL:
+			return "PAL";
+		case VIDEO_MODE_NTSC:
+			return "NTSC";
+		case VIDEO_MODE_SECAM:
+			return "SECAM";
+		case VIDEO_MODE_AUTO:
+			return "auto";
+	}
+	return "undefined";
+}
+
 static uint32_t preinit(const char *arg) {
-	char *dev;
+	char *dev = NULL, *ptr = NULL, *tmp;
 	vo_zr2_priv_t *p = &priv;
+	int last = 0, norm = VIDEO_MODE_AUTO;
 
 	VERBOSE("preinit() called\n");
 	memset(p, 0, sizeof(*p)); /* set defaults */
+	p->vdes = -1;
 
 	if (arg) {
-		ERROR("no subdevice parameters supported yet: %s\n",arg);
+		/* save subdevice string */
+		p->subdevice = strdup(arg);
+		if (!p->subdevice) {
+			ERROR("out of memory, this is bad\n");
+			uninit();
+			return 1;
+		}
+
+		tmp = ptr = p->subdevice;
+		do {
+			while (*tmp != ':' && *tmp) tmp++;
+			if (*tmp == ':') *tmp++ = '\0';
+			else last = 1;
+			DBG2("processing subdevice option \"%s\"\n", ptr);
+			if (!strncmp("dev=", ptr, 4)) {
+				dev = ptr + 4;
+				VERBOSE("user specified device \"%s\"\n", dev);
+			} else if (!strcasecmp("PAL", ptr)) {
+				norm = VIDEO_MODE_PAL;
+				VERBOSE("user specified video norm PAL\n");
+			} else if (!strcasecmp("SECAM", ptr)) {
+				norm = VIDEO_MODE_SECAM;
+				VERBOSE("user specified video norm SECAM\n");
+			} else if (!strcasecmp("NTSC", ptr)) {
+				norm = VIDEO_MODE_NTSC;
+				VERBOSE("user specified video norm NTSC\n");
+			} else if (!strcmp("prebuf", ptr)) {
+				WARNING("prebuffering is not yet supported\n");
+			} else {
+				WARNING("ignoring unknown subdevice option " 
+						"\"%s\", or missing argument\n",
+						ptr);
+			}
+			ptr = tmp;
+		} while (!last);
+	}
+
+	dev = guess_device(dev);
+	if (!dev) {
+		uninit();
 		return 1;
-    	}
-
-	dev = guess_device(NULL);
-	if (!dev) return 1;
+	}
 
 	p->vdes = open(dev, O_RDWR);
 	if (p->vdes < 0) {
 		ERROR("error opening %s: %s\n", dev, strerror(errno));
+		uninit();
 		return 1;
 	}
 	
 	/* check if we really are dealing with a zoran card */
 	if (ioctl(p->vdes, MJPIOC_G_PARAMS, &p->zp) < 0) {
 		ERROR("%s probably is not a DC10(+)/buz/lml33\n", dev);
+		uninit();
 		return 1;
 	}
 
 	VERBOSE("kernel driver version %d.%d, current norm is %s\n", 
 			p->zp.major_version, p->zp.minor_version,
-			p->zp.norm == VIDEO_MODE_PAL ? "PAL" : "NTSC");
+			normstring(p->zp.norm));
 
+	/* changing the norm in the zoran_params and MJPIOC_S_PARAMS
+	 * does noting, so bail out if the norm is not correct */
+	if (p->zp.norm != norm) {
+		ERROR("mplayer currently can't change the video norm, "
+				"change it with (eg.) XawTV and retry.\n");
+		uninit();
+		return 1;
+	}
+		
 	/* gather useful information */
 	if (ioctl(p->vdes, VIDIOCGCAP, &p->vc) < 0) {
 		ERROR("error getting video capabilities from %s\n", dev);
+		uninit();
 		return 1;
 	}
-
+	
 	VERBOSE("card reports maxwidth=%d, maxheight=%d\n", 
 			p->vc.maxwidth, p->vc.maxheight);
 
+	/* according to the mjpegtools source, some cards return a bogus 
+	 * vc.maxwidth, correct it here. If a new zoran card appears with a 
+	 * maxwidth different 640, 720 or 768 this code may lead to problems */
+	if (p->vc.maxwidth != 640 && p->vc.maxwidth != 768) {
+		VERBOSE("card probably reported bogus width (%d), "
+				"changing to 720\n", p->vc.maxwidth);
+		p->vc.maxwidth = 720;
+	}
+
 	p->zrq.count = ZR2_MJPEG_NBUFFERS;
 	p->zrq.size = ZR2_MJPEG_SIZE;
 
 	if (ioctl(p->vdes, MJPIOC_REQBUFS, &p->zrq)) {
 		ERROR("error requesting %d buffers of size %d\n", 
 				ZR2_MJPEG_NBUFFERS, ZR2_MJPEG_NBUFFERS);
+		uninit();
 		return 1;
 	}
 	
@@ -192,6 +287,7 @@
 
 	if (p->buf == MAP_FAILED) {
 		ERROR("error mapping requested buffers: %s", strerror(errno));
+		uninit();
 		return 1;
 	}
 
@@ -241,7 +337,7 @@
 
 	/* we assume sample_aspect = 1 */
 	if (fields == 1) {
-		if (2*d_width <= p->vc.maxwidth) {
+		if (2*d_width <= (uint32_t)p->vc.maxwidth) {
 			VERBOSE("stretching x direction to preserve aspect\n");
 			d_width *= 2;
 		} else VERBOSE("unable to preserve aspect, screen width "
@@ -260,15 +356,15 @@
 	else WARNING("d_height must be {1,2,4}*height, using defaults\n");
 #endif
 
-	if (stretchx*width > p->vc.maxwidth) {
-		ERROR("movie to be played is too wide, width=%d>maxwidth=%d",
+	if (stretchx*width > (uint32_t)p->vc.maxwidth) {
+		ERROR("movie to be played is too wide, width=%d>maxwidth=%d\n",
 				width*stretchx, p->vc.maxwidth);
 		err = 1;
 	}
 
-	if (stretchy*height > p->vc.maxheight) {
-		ERROR("movie to be played is too heigh, height=%d>maxheight=%d",
-				height*stretchy, p->vc.maxheight);
+	if (stretchy*height > (uint32_t)p->vc.maxheight) {
+		ERROR("movie to be played is too heigh, height=%d>maxheight"
+				"=%d\n", height*stretchy, p->vc.maxheight);
 		err = 1;
 	}
 
@@ -357,12 +453,13 @@
 
 static void uninit(void) {
 	vo_zr2_priv_t *p = &priv;
-	VERBOSE("uninit() called\n");
+	VERBOSE("uninit() called (may be called from preinit() on error)\n");
 
 	stop_playing(p);
 
-	if (munmap(p->buf, p->zrq.size*p->zrq.count)) 
+	if (p->buf && munmap(p->buf, p->zrq.size*p->zrq.count)) 
 		ERROR("error munmapping buffer: %s\n", strerror(errno));
 
-	close(p->vdes);
+	if (p->vdes >= 0) close(p->vdes);
+	free(p->subdevice);
 }