diff options
Diffstat (limited to 'libvo')
-rw-r--r-- | libvo/vo_zr2.c | 141 |
1 files changed, 119 insertions, 22 deletions
diff --git a/libvo/vo_zr2.c b/libvo/vo_zr2.c index a26edd7aaf..e81575bc71 100644 --- a/libvo/vo_zr2.c +++ b/libvo/vo_zr2.c @@ -38,6 +38,9 @@ static vo_info_t info = { 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 @@ static vo_zr2_priv_t priv; #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 void stop_playing(vo_zr2_priv_t *p) { static char *guess_device(char *suggestion) { struct stat vstat; + int res; char *devs[] = { "/dev/video", "/dev/video0", @@ -85,10 +90,26 @@ static char *guess_device(char *suggestion) { }; 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 query_format(uint32_t format) { 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 @@ static uint32_t draw_image(mp_image_t *mpi) { 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); - return 1; - } + /* save subdevice string */ + p->subdevice = strdup(arg); + if (!p->subdevice) { + ERROR("out of memory, this is bad\n"); + uninit(); + return 1; + } - dev = guess_device(NULL); - if (!dev) 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; + } 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 @@ static uint32_t preinit(const char *arg) { if (p->buf == MAP_FAILED) { ERROR("error mapping requested buffers: %s", strerror(errno)); + uninit(); return 1; } @@ -241,7 +337,7 @@ static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, /* 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 @@ static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, 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 check_events(void) { 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); } |