aboutsummaryrefslogtreecommitdiffhomepage
path: root/libvo
diff options
context:
space:
mode:
Diffstat (limited to 'libvo')
-rw-r--r--libvo/vo_zr2.c141
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);
}