summaryrefslogtreecommitdiffstats
path: root/libvo
diff options
context:
space:
mode:
authorrik <rik@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-08-05 20:03:22 +0000
committerrik <rik@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-08-05 20:03:22 +0000
commited9ba575cbb65f7d143d62d632d9b55d454c67c8 (patch)
treebf8376c54645b6fdf051b517feeb1f736bae019f /libvo
parent2213dfe8ccbbcfaac94412727a1271b59d518bd4 (diff)
downloadmpv-ed9ba575cbb65f7d143d62d632d9b55d454c67c8.tar.bz2
mpv-ed9ba575cbb65f7d143d62d632d9b55d454c67c8.tar.xz
cinerama support in -vo zr for people with more than one zoran card, documentation contained in -zrhelp
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@6933 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libvo')
-rw-r--r--libvo/vo_zr.c833
1 files changed, 468 insertions, 365 deletions
diff --git a/libvo/vo_zr.c b/libvo/vo_zr.c
index d08a00ac13..f733e5ba79 100644
--- a/libvo/vo_zr.c
+++ b/libvo/vo_zr.c
@@ -40,61 +40,77 @@ static vo_info_t vo_info =
""
};
+#define ZR_MAX_DEVICES 4
/* General variables */
-static int image_width;
-static int image_height;
-static int off_y, off_c, stride; /* for use by 'draw slice/frame' */
-static int framenum;
-static int fields = 1; /* currently no interlacing */
-static int zrfd = 0;
-static int bw = 0; /* if bw == 1, then display in black&white */
-static int vdec = 1;
-static int hdec = 1;
-static int size;
-static int quality = 2;
-static unsigned char *y_data, *u_data, *v_data;
-static int y_stride, u_stride, v_stride;
-
typedef struct {
int width;
int height;
int xoff;
int yoff;
int set;
-} geo;
-geo g = {0, 0, 0, 0, 0};
+} geo_t;
+
+static int zr_count = 1;
+static int zr_parsing = 0;
+static int framenum;
+
+typedef struct {
+ /* commandline args given for this device (and defaults) */
+ int vdec, hdec; /* requested decimation 1,2,4 */
+ int fd; /* force decimation */
+ int xdoff, ydoff; /* offset from upperleft of screen
+ * default is 'centered' */
+ int quality; /* jpeg quality 1=best, 20=bad */
+ geo_t g; /* view window (zrcrop) */
+ char *device; /* /dev/video1 */
+ int bw; /* if bw == 1, display in black&white */
+ int norm; /* PAL/NTSC */
+
+ /* buffers + pointers + info */
+
+ unsigned char *image;
+ int image_width, image_height, size;
+ int off_y, off_c, stride; /* for use by 'draw slice/frame' */
+
+ unsigned char *buf; /* the jpeg images will be placed here */
+ jpeg_enc_t *j;
+ unsigned char *y_data, *u_data, *v_data; /* used by the jpeg encoder */
+ int y_stride, u_stride, v_stride; /* these point somewhere in image */
+
+ /* information for (and about) the zoran card */
+
+ int vdes; /* file descriptor of card */
+ int frame, synco, queue; /* buffer management */
+ struct mjpeg_sync zs; /* state information */
+ struct mjpeg_params p;
+ struct video_capability vc; /* max resolution and so on */
+ int fields, stretchy; /* must the *image be interlaced
+ or stretched to fit on the screen? */
+} zr_info_t;
+
+static zr_info_t zr_info[ZR_MAX_DEVICES] = {
+ {1, 1, 1, -1, -1, 2, {0, 0, 0, 0, 0}, NULL, 0, VIDEO_MODE_AUTO, NULL, 0, 0, 0, 0, 0,
+ 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 1, 1, -1, -1, 2, {0, 0, 0, 0, 0}, NULL, 0, VIDEO_MODE_AUTO, NULL, 0, 0, 0, 0, 0,
+ 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 1, 1, -1, -1, 2, {0, 0, 0, 0, 0}, NULL, 0, VIDEO_MODE_AUTO, NULL, 0, 0, 0, 0, 0,
+ 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 1, 1, -1, -1, 2, {0, 0, 0, 0, 0}, NULL, 0, VIDEO_MODE_AUTO, NULL, 0, 0, 0, 0, 0,
+ 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
-static uint8_t *image=NULL;
-static uint8_t *buf=NULL;
-static jpeg_enc_t *j;
-/* Variables needed for Zoran */
-int vdes; /* the file descriptor of the video device */
-int frame = 0, synco = 0, queue = 0; /* buffer management */
-struct mjpeg_params zp;
-struct mjpeg_requestbuffers zrq;
-struct mjpeg_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;
-#if 0
-#ifndef VO_ZR_DEFAULT_DEVICE
-#define VO_ZR_DEFAULT_DEVICE "/dev/video"
-#endif
-#endif
-char *device = NULL;
-int zoran_getcap() {
+int zoran_getcap(zr_info_t *zr) {
char* dev;
- if (device)
- dev = device;
+ if (zr->device)
+ dev = zr->device;
else { /* code borrowed from mjpegtools lavplay.c // 20020416 too */
struct stat vstat;
@@ -126,9 +142,9 @@ int zoran_getcap() {
mp_msg(MSGT_VO, MSGL_V, "zr: found video device %s\n", dev);
}
- vdes = open(dev, O_RDWR);
+ zr->vdes = open(dev, O_RDWR);
- if (vdes < 0) {
+ if (zr->vdes < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: error opening %s: %s\n",
dev, strerror(errno));
return 1;
@@ -137,61 +153,72 @@ int zoran_getcap() {
/* before we can ask for the maximum resolution, we must set
* the correct tv norm */
- if (ioctl(vdes, MJPIOC_G_PARAMS, &zp) < 0) {
+ if (ioctl(zr->vdes, MJPIOC_G_PARAMS, &zr->p) < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: device at %s is probably not a DC10(+)/buz/lml33\n", dev);
return 1;
}
- if (zp.norm != norm && norm != VIDEO_MODE_AUTO) {
+ if (zr->p.norm != zr->norm && zr->norm != VIDEO_MODE_AUTO) {
/* attempt to set requested norm */
- zp.norm = norm;
- if (ioctl(vdes, MJPIOC_S_PARAMS, &zp) < 0) {
+ zr->p.norm = zr->norm;
+ if (ioctl(zr->vdes, MJPIOC_S_PARAMS, &zr->p) < 0) {
mp_msg(MSGT_VO, MSGL_ERR,
"zr: unable to change video norm, use another program to change it (XawTV)\n");
return 1;
}
- ioctl(vdes, MJPIOC_G_PARAMS, &zp);
- if (norm != zp.norm) {
+ ioctl(zr->vdes, MJPIOC_G_PARAMS, &zr->p);
+ if (zr->norm != zr->p.norm) {
mp_msg(MSGT_VO, MSGL_ERR,
"zr: unable to change video norm, use another program to change it (XawTV)\n");
return 1;
}
}
- if (ioctl(vdes, VIDIOCGCAP, &vc) < 0) {
+ if (ioctl(zr->vdes, VIDIOCGCAP, &zr->vc) < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: error getting video capabilities from %s\n");
return 1;
}
- mp_msg(MSGT_VO, MSGL_V, "zr: MJPEG card reports maxwidth=%d, maxheight=%d\n", vc.maxwidth, vc.maxheight);
+ mp_msg(MSGT_VO, MSGL_V, "zr: MJPEG card reports maxwidth=%d, maxheight=%d\n", zr->vc.maxwidth, zr->vc.maxheight);
return 0;
}
-int init_zoran(int zrhdec, int zrvdec) {
+int init_zoran(zr_info_t *zr, int stretchx, int stretchy) {
+ struct mjpeg_requestbuffers zrq;
/* 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, "zr: movie to be played is too wide, max width currenty %d\n", vc.maxwidth);
+ if (zr->image_width > zr->vc.maxwidth) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: movie to be played is too wide, max width currenty %d\n", zr->vc.maxwidth);
return 1;
}
- if (image_height > vc.maxheight) {
- mp_msg(MSGT_VO, MSGL_ERR, "zr: movie to be played is too high, max height currenty %d\n", vc.maxheight);
+ if (zr->image_height > zr->vc.maxheight) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: movie to be played is too high, max height currenty %d\n", zr->vc.maxheight);
return 1;
}
- zp.decimation = 0;
- zp.HorDcm = zrhdec;
- zp.VerDcm = zrvdec;
- zp.TmpDcm = 1;
- zp.field_per_buff = fields;
- zp.img_x = (vc.maxwidth - zp.HorDcm*(int)image_width/hdec)/2;
- zp.img_y = (vc.maxheight - zp.VerDcm*(3-fields)*(int)image_height)/4;
- zp.img_width = zp.HorDcm*image_width/hdec;
- 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, (3-fields)*zp.img_height, zp.img_x, zp.img_y, fields, image_width/hdec, image_height);
-
- if (ioctl(vdes, MJPIOC_S_PARAMS, &zp) < 0) {
+ zr->p.decimation = 0;
+ zr->p.HorDcm = stretchx;
+ zr->p.VerDcm = stretchy;
+ zr->p.TmpDcm = 1;
+ zr->p.field_per_buff = zr->fields;
+ if (zr->xdoff == -1) {
+ zr->p.img_x = (zr->vc.maxwidth -
+ zr->p.HorDcm*(int)zr->image_width/zr->hdec)/2;
+ } else {
+ zr->p.img_x = zr->xdoff;
+ }
+ if (zr->ydoff == -1) {
+ zr->p.img_y = (zr->vc.maxheight - zr->p.VerDcm*
+ (3-zr->fields)*(int)zr->image_height)/4;
+ } else {
+ zr->p.img_y = zr->ydoff;
+ }
+ zr->p.img_width = zr->p.HorDcm*zr->image_width/zr->hdec;
+ zr->p.img_height = zr->p.VerDcm*zr->image_height/zr->fields;
+ mp_msg(MSGT_VO, MSGL_V, "zr: geometry (after 'scaling'): %dx%d+%d+%d fields=%d, w=%d, h=%d\n", zr->p.img_width, (3-zr->fields)*zr->p.img_height, zr->p.img_x, zr->p.img_y, zr->fields, zr->image_width/zr->hdec, zr->image_height);
+
+ if (ioctl(zr->vdes, MJPIOC_S_PARAMS, &zr->p) < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: error setting display parameters\n");
return 1;
}
@@ -199,234 +226,250 @@ int init_zoran(int zrhdec, int zrvdec) {
zrq.count = MJPEG_NBUFFERS;
zrq.size = MJPEG_SIZE;
- if (ioctl(vdes, MJPIOC_REQBUFS, &zrq)) {
+ if (ioctl(zr->vdes, MJPIOC_REQBUFS, &zrq)) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: 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);
+ zr->buf = (unsigned char*)mmap(0, zrq.count*zrq.size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, zr->vdes, 0);
- if (buf == MAP_FAILED) {
+ if (zr->buf == MAP_FAILED) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: 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;
+void uninit_zoran(zr_info_t *zr) {
+ if (zr->image) {
+ free(zr->image);
+ zr->image=NULL;
}
- while (queue > synco + 1) {
- if (ioctl(vdes, MJPIOC_SYNC, &zs) < 0)
+ while (zr->queue > zr->synco + 1) {
+ if (ioctl(zr->vdes, MJPIOC_SYNC, &zr->zs) < 0)
mp_msg(MSGT_VO, MSGL_ERR, "zr: error waiting for buffers to become free\n");
- synco++;
+ zr->synco++;
}
/* stop streaming */
- frame = -1;
- if (ioctl(vdes, MJPIOC_QBUF_PLAY, &frame) < 0)
+ zr->frame = -1;
+ if (ioctl(zr->vdes, MJPIOC_QBUF_PLAY, &zr->frame) < 0)
mp_msg(MSGT_VO, MSGL_ERR, "zr: error stopping playback of last frame\n");
- close(vdes);
+ close(zr->vdes);
}
-static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width,
- uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format,const vo_tune_info_t *info)
-{
- int i, stretchx, stretchy;
- /* this allows to crop parts from incoming picture,
- * for easy 512x240 -> 352x240 */
- /* These values must be multples of 2 */
- if (format != IMGFMT_YV12 && format != IMGFMT_YUY2) {
- printf("vo_zr called with wrong format");
- exit(1);
- }
- stride = 2*width;
- if (g.set) {
- if (g.width%2 != 0 || g.height%2 != 0 ||
- g.xoff%2 != 0 || g.yoff%2 != 0) {
+int zr_geometry_sane(geo_t *g, unsigned int width, unsigned int height) {
+ 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, "zr: arguments in -zrcrop must be multiples of 2\n");
return 1;
}
- if (g.width <= 0 || g.height <= 0 ||
- g.xoff < 0 || g.yoff < 0) {
+ if (g->width <= 0 || g->height <= 0 ||
+ g->xoff < 0 || g->yoff < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "zr: width and height must be positive and offset nonnegative\n");
return 1;
}
- if (g.width + g.xoff > width) {
- mp_msg(MSGT_VO, MSGL_ERR, "zr: width+xoffset (%d+%d>%d) is too big\n", g.width, g.xoff, width);
+ if (g->width + g->xoff > width) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: 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, "zr: height+yoffset (%d+%d>%d) is too big\n", g.height, g.yoff, height);
+ if (g->height + g->yoff > height) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: 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;
- g.set = 1;
+ g->width = width;
+ g->height = height;
+ g->xoff = 0;
+ g->yoff = 0;
+ g->set = 1;
}
- /* 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 */
- /* make the scaling decision
- * we are capable of stretching the image in the horizontal
- * direction by factors 1, 2 and 4
- * we can stretch the image in the vertical direction by a factor
- * of 1 and 2 AND we must decide about interlacing */
- if (g.width > vc.maxwidth/2 || g.height > vc.maxheight/2) {
- stretchx = 1;
- stretchy = 1;
- fields = 2;
- if (vdec == 2) {
- fields = 1;
- } else if (vdec == 4) {
- fields = 1;
- stretchy = 2;
- }
- stretchx = hdec;
- } else if (g.width > vc.maxwidth/4 || g.height > vc.maxheight/4) {
- stretchx = 2;
- stretchy = 1;
- fields = 1;
- if (vdec == 2) {
- stretchy = 2;
- } else if (vdec == 4) {
- if (!zrfd) {
- mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 2 (use -zrfd to keep vdec=4)\n");
- vdec = 2;
+ return 0;
+}
+
+
+static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width,
+ uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format,const vo_tune_info_t *info)
+{
+ int i, tmp, stretchx, stretchy;
+ framenum = 0;
+ if (format != IMGFMT_YV12 && format != IMGFMT_YUY2) {
+ printf("vo_zr called with wrong format");
+ exit(1);
+ }
+ for (i = 0; i < zr_count; i++) {
+ zr_info_t *zr = &zr_info[i];
+ geo_t *g = &zr->g;
+
+ zr->stride = 2*width;
+ if (zr_geometry_sane(g, width, height)) return 1;
+
+ /* we must know the maximum resolution of the device
+ * it differs for DC10+ and buz for example */
+ zoran_getcap(zr); /*must be called before init_zoran */
+ /* make the scaling decision
+ * we are capable of stretching the image in the horizontal
+ * direction by factors 1, 2 and 4
+ * we can stretch the image in the vertical direction by a
+ * factor of 1 and 2 AND we must decide about interlacing */
+ if (g->width > zr->vc.maxwidth/2 ||
+ g->height > zr->vc.maxheight/2) {
+ stretchx = 1;
+ stretchy = 1;
+ zr->fields = 2;
+ if (zr->vdec == 2) {
+ zr->fields = 1;
+ } else if (zr->vdec == 4) {
+ zr->fields = 1;
+ stretchy = 2;
}
- stretchy = 2;
- }
- if (hdec == 2) {
- stretchx = 4;
- } else if (hdec == 4){
- if (!zrfd) {
- mp_msg(MSGT_VO, MSGL_WARN, "zr: horizontal decimation too high, changing to 2 (use -zrfd to keep hdec=4)\n");
- hdec = 2;
+ stretchx = zr->hdec;
+ } else if (g->width > zr->vc.maxwidth/4 ||
+ g->height > zr->vc.maxheight/4) {
+ stretchx = 2;
+ stretchy = 1;
+ zr->fields = 1;
+ if (zr->vdec == 2) {
+ stretchy = 2;
+ } else if (zr->vdec == 4) {
+ if (!zr->fd) {
+ mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 2 (use -zrfd to keep vdec=4)\n");
+ zr->vdec = 2;
+ }
+ stretchy = 2;
+ }
+ if (zr->hdec == 2) {
+ stretchx = 4;
+ } else if (zr->hdec == 4){
+ if (!zr->fd) {
+ mp_msg(MSGT_VO, MSGL_WARN, "zr: horizontal decimation too high, changing to 2 (use -zrfd to keep hdec=4)\n");
+ zr->hdec = 2;
+ }
+ stretchx = 4;
}
+ } else {
+ /* output image is maximally stretched */
stretchx = 4;
+ stretchy = 2;
+ zr->fields = 1;
+ if (zr->vdec != 1 && !zr->fd) {
+ mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep vdec=%d)\n", zr->vdec);
+ zr->vdec = 1;
+ }
+ if (zr->hdec != 1 && !zr->fd) {
+ mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep hdec=%d)\n", zr->hdec);
+ zr->hdec = 1;
+ }
}
- } else {
- /* output image is maximally stretched */
- stretchx = 4;
- stretchy = 2;
- fields = 1;
- if (vdec != 1 && !zrfd) {
- mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep vdec=%d)\n", vdec);
- vdec = 1;
+ /* It can be that the original frame was too big for display,
+ * or that the width of the decimated image (for example) after
+ * padding up to a multiple of 16 has become too big. (orig
+ * width 720 (exactly right for the Buz) after decimation 360,
+ * after padding up to a multiple of 16 368, display 736 -> too
+ * large). In these situations we auto(re)crop. */
+ tmp = 16*((g->width - 1)/(zr->hdec*16) + 1);
+ if (stretchx*tmp > zr->vc.maxwidth) {
+ g->xoff += 2*((g->width - zr->hdec*(tmp-16))/4);
+ /* g->off must be a multiple of 2 */
+ g->width = zr->hdec*(tmp - 16);
+ g->set = 0; /* we abuse this field to
+ report that g has changed*/
}
-
- if (hdec != 1 && !zrfd) {
- mp_msg(MSGT_VO, MSGL_WARN, "zr: vertical decimation too high, changing to 1 (use -zrfd to keep hdec=%d)\n", hdec);
- hdec = 1;
+ tmp = 8*zr->fields*((g->height - 1)/(zr->vdec*zr->fields*8)+1);
+ if (stretchy*tmp > zr->vc.maxheight) {
+ g->yoff += 2*((g->height - zr->vdec*
+ (tmp - 8*zr->fields))/4);
+ g->height = zr->vdec*(tmp - 8*zr->fields);
+ g->set = 0;
+ }
+ if (!g->set)
+ mp_msg(MSGT_VO, MSGL_V, "zr: auto(re)cropping %dx%d+%d+%d to make the image fit on the screen\n", g->width, g->height, g->xoff, g->yoff);
+
+ /* 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*/
+ zr->image_height = zr->fields*8*((g->height/zr->vdec - 1)/
+ (zr->fields*8) + 1);
+ zr->image_width = (zr->hdec*16)*((g->width - 1)/(zr->hdec*16) + 1);
+ zr->off_y = (zr->image_height - g->height/zr->vdec)/2;
+ if (zr->off_y%2 != 0) zr->off_y++;
+ zr->off_y *= zr->image_width;
+ zr->off_c = zr->off_y/4;
+ zr->off_y += (zr->image_width - g->width)/2;
+ if (zr->off_y%2 != 0) zr->off_y--;
+ zr->off_c += (zr->image_width - g->width)/4;
+ zr->size = zr->image_width*zr->image_height;
+ mp_msg(MSGT_VO, MSGL_V, "zr: input: %dx%d, cropped: %dx%d, output: %dx%d, off_y=%d, off_c=%d\n", width, height, g->width, g->height, zr->image_width, zr->image_height, zr->off_y, zr->off_c);
+
+ zr->image = malloc(2*zr->size); /* this buffer allows for YUV422 data,
+ * so it is a bit too big for YUV420 */
+ if (!zr->image) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: Memory exhausted\n");
+ return 1;
+ }
+ /* and make sure that the borders are _really_ black */
+ switch (format) {
+ case IMGFMT_YV12:
+ memset(zr->image, 0, zr->size);
+ memset(zr->image + zr->size, 0x80, zr->size/4);
+ memset(zr->image + 3*zr->size/2, 0x80, zr->size/4);
+ zr->y_data = zr->image;
+ zr->u_data = zr->image + zr->size;
+ zr->v_data = zr->image + 3*zr->size/2;
+
+ zr->y_stride = zr->image_width;
+ zr->u_stride = zr->image_width/2;
+ zr->v_stride = zr->image_width/2;
+
+ zr->j = jpeg_enc_init(zr->image_width/zr->hdec,
+ zr->image_height/zr->fields,
+ zr->hdec, zr->y_stride*zr->fields,
+ zr->hdec, zr->u_stride*zr->fields,
+ zr->hdec, zr->v_stride*zr->fields,
+ 1, zr->quality, zr->bw);
+ break;
+ case IMGFMT_YUY2:
+ for (tmp = 0; tmp < 2*zr->size; tmp+=4) {
+ zr->image[tmp] = 0;
+ zr->image[tmp+1] = 0x80;
+ zr->image[tmp+2] = 0;
+ zr->image[tmp+3] = 0x80;
+ }
+
+ zr->y_data = zr->image;
+ zr->u_data = zr->image + 1;
+ zr->v_data = zr->image + 3;
+
+ zr->y_stride = 2*zr->image_width;
+ zr->u_stride = 2*zr->image_width;
+ zr->v_stride = 2*zr->image_width;
+
+ zr->j = jpeg_enc_init(zr->image_width/zr->hdec,
+ zr->image_height/zr->fields,
+ zr->hdec*2,
+ zr->y_stride*zr->fields,
+ zr->hdec*4,
+ zr->u_stride*zr->fields,
+ zr->hdec*4,
+ zr->v_stride*zr->fields,
+ 0, zr->quality, zr->bw);
+ break;
+ default:
+ mp_msg(MSGT_VO, MSGL_FATAL, "zr: internal inconsistency in vo_zr\n");
+ }
+
+
+ if (zr->j == NULL) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: error initializing the jpeg encoder\n");
+ return 1;
+ }
+
+ if (init_zoran(zr, stretchx, stretchy)) {
+ return 1;
}
- }
- /* It can be that the original frame was too big for display,
- * or that the width of the decimated image (for example) after
- * padding up to a multiple of 16 has become too big. (orig
- * width 720 (exactly right for the Buz) after decimation 360,
- * after padding up to a multiple of 16 368, display 736 -> too
- * large). In these situations we auto(re)crop. */
- i = 16*((g.width - 1)/(hdec*16) + 1);
- if (stretchx*i > vc.maxwidth) {
- g.xoff += 2*((g.width - hdec*(i-16))/4);
- /* g.off must be a multiple of 2 */
- g.width = hdec*(i - 16);
- g.set = 0; /* we abuse this field to report that g has changed*/
- }
- i = 8*fields*((g.height - 1)/(vdec*fields*8) + 1);
- if (stretchy*i > vc.maxheight) {
- g.yoff += 2*((g.height - vdec*(i - 8*fields))/4);
- g.height = vdec*(i - 8*fields);
- g.set = 0;
- }
- if (!g.set)
- mp_msg(MSGT_VO, MSGL_V, "zr: auto(re)cropping %dx%d+%d+%d to make the image fit on the screen\n", g.width, g.height, g.xoff, g.yoff);
-
- /* 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 = (hdec*16)*((g.width - 1)/(hdec*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, "zr: 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, "zr: Memory exhausted\n");
- return 1;
- }
- /* and make sure that the borders are _really_ black */
- switch (format) {
- case IMGFMT_YV12:
- 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);
- y_data = image;
- u_data = image + image_width*image_height;
- v_data = image + 3*image_width*image_height/2;
-
- y_stride = image_width;
- u_stride = image_width/2;
- v_stride = image_width/2;
-
- j = jpeg_enc_init(image_width/hdec,
- image_height/fields,
- hdec, y_stride*fields,
- hdec, u_stride*fields,
- hdec, v_stride*fields,
- 1, quality, bw);
- break;
- case IMGFMT_YUY2:
- for (i = 0; i < 2*size; i+=4) {
- image[i] = 0;
- image[i+1] = 0x80;
- image[i+2] = 0;
- image[i+3] = 0x80;
- }
-
- y_data = image;
- u_data = image + 1;
- v_data = image + 3;
-
- y_stride = 2*image_width;
- u_stride = 2*image_width;
- v_stride = 2*image_width;
-
- j = jpeg_enc_init(image_width/hdec,
- image_height/fields,
- hdec*2, y_stride*fields,
- hdec*4, u_stride*fields,
- hdec*4, v_stride*fields,
- 0, quality, bw);
- break;
- default:
- mp_msg(MSGT_VO, MSGL_FATAL, "zr: internal inconsistency in vo_zr\n");
- }
-
-
- if (j == NULL) {
- mp_msg(MSGT_VO, MSGL_ERR, "zr: error initializing the jpeg encoder\n");
- return 1;
- }
-
- if (init_zoran(stretchx, stretchy)) {
- return 1;
}
-
return 0;
}
@@ -438,23 +481,27 @@ static void draw_osd(void) {
}
static void flip_page (void) {
- int i, k;
+ int i, j, k;
//FILE *fp;
//char filename[100];
/* do we have a free buffer? */
- if (queue-synco < zrq.count) {
- frame = queue;
- } else {
- if (ioctl(vdes, MJPIOC_SYNC, &zs) < 0)
- mp_msg(MSGT_VO, MSGL_ERR, "zr: error waiting for buffers to become free\n");
- frame = zs.frame;
- synco++;
+ for (j = 0; j < zr_count; j++) {
+ zr_info_t *zr = &zr_info[j];
+ if (zr->queue-zr->synco < MJPEG_NBUFFERS) {
+ zr->frame = zr->queue;
+ } else {
+ if (ioctl(zr->vdes, MJPIOC_SYNC, &zr->zs) < 0)
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: error waiting for buffers to become free\n");
+ zr->frame = zr->zs.frame;
+ zr->synco++;
+ }
+ k=0;
+ for (i = 0; i < zr->fields; i++)
+ k+=jpeg_enc_frame(zr->j, zr->y_data + i*zr->y_stride,
+ zr->u_data + i*zr->u_stride,
+ zr->v_data + i*zr->v_stride,
+ zr->buf+zr->frame*MJPEG_SIZE+k);
}
- k=0;
- for (i = 0; i < fields; i++)
- k+=jpeg_enc_frame(j, y_data + i*y_stride,
- u_data + i*u_stride, v_data + i*v_stride,
- buf+frame*zrq.size+k);
/* Warning: Only the first jpeg image contains huffman- and
* quantisation tables, so don't expect files other than
* test0001.jpg to be readable */
@@ -467,25 +514,31 @@ static void flip_page (void) {
fread(buf+frame*zrq.size, 1, 2126, fp);
fclose(fp);*/
- if (ioctl(vdes, MJPIOC_QBUF_PLAY, &frame) < 0)
- mp_msg(MSGT_VO, MSGL_ERR,
- "zr: error queueing buffer for playback\n");
- queue++;
+ for (j = 0; j < zr_count; j++) {
+ zr_info_t *zr = &zr_info[j];
+ if (ioctl(zr->vdes, MJPIOC_QBUF_PLAY, &zr->frame) < 0)
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: error queueing buffer for playback\n");
+ zr->queue++;
+ }
framenum++;
return;
}
static uint32_t draw_frame(uint8_t * src[]) {
- int i;
+ int i, j;
char *source, *dest;
//printf("draw frame called\n");
- source = src[0] + 2*g.yoff*vdec*stride + 2*g.xoff;
- dest = image + 2*off_y;
- for (i = 0; i < g.height/vdec; i++) {
- memcpy(dest, source, image_width*2);
- dest += 2*image_width;
- source += vdec*stride;
+ for (j = 0; j < zr_count; j++) {
+ zr_info_t *zr = &zr_info[j];
+ geo_t *g = &zr->g;
+ source = src[0] + 2*g->yoff*zr->vdec*zr->stride + 2*g->xoff;
+ dest = zr->image + 2*zr->off_y;
+ for (i = 0; i < g->height/zr->vdec; i++) {
+ memcpy(dest, source, zr->image_width*2);
+ dest += 2*zr->image_width;
+ source += zr->vdec*zr->stride;
+ }
}
return 0;
}
@@ -497,8 +550,12 @@ static uint32_t query_format(uint32_t format) {
}
static void uninit(void) {
- jpeg_enc_uninit(j);
- uninit_zoran();
+ int j;
+ mp_msg(MSGT_VO, MSGL_V, "zr: uninit called\n");
+ for (j = 0; j < zr_count; j++) {
+ jpeg_enc_uninit(zr_info[j].j);
+ uninit_zoran(&zr_info[j]);
+ }
}
static void check_events(void) {
@@ -506,70 +563,75 @@ 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;
+ int wf, int hf, int xf, int yf) {
+ int i, j, w, h, x, y;
/* 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];
-
- }
- if (!bw) {
- // copy U+V:
+ for (j = 0; j < zr_count; j++) {
+ uint8_t *src=srcimg[0];
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;
+ zr_info_t *zr = &zr_info[j];
+ geo_t *g = &zr->g;
+ w = wf; h = hf; x = xf; y = yf;
+ if (x < g->xoff) {
+ src += g->xoff - x;
+ src1 += (g->xoff - x)/2;
+ src2 += (g->xoff - x)/2;
+ w -= g->xoff - x;
+ if (w < 0) break; //return 0;
+ x = 0 /*g.xoff*/;
+ } else {
+ x -= g->xoff;
+ }
+ if (x + w > g->width) {
+ w = g->width - x;
+ if (w < 0) break; //return 0;
+ }
+ if (y < g->yoff) {
+ src += (g->yoff - y)*stride[0];
+ src1 += ((g->yoff - y)/2)*stride[1];
+ src2 += ((g->yoff - y)/2)*stride[2];
+ h -= g->yoff - y;
+ if (h < 0) break; //return 0;
+ y = 0;
+ } else {
+ y -= g->yoff;
+ }
+ if (y + h > g->height) {
+ h = g->height - y;
+ if (h < 0) break; //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=zr->image + zr->off_y + zr->image_width*(y/zr->vdec)+x;
+ // copy Y:
+ for (i = 0; i < h; i++) {
+ if ((i + x)%zr->vdec == 0) {
+ memcpy(dst,src,w);
+ dst+=zr->image_width;
}
- src1+=stride[1];
- src2+=stride[2];
+ src+=stride[0];
+
}
- }
+ if (!zr->bw) {
+ // copy U+V:
+ uint8_t *dst1=zr->image + zr->size + zr->off_c+ (y/(zr->vdec*2))*zr->image_width/2+(x/2);
+ uint8_t *dst2=zr->image + 3*zr->size/2 + zr->off_c +
+ (y/(zr->vdec*2))*
+ zr->image_width/2+(x/2);
+ for (i = 0; i< h/2; i++) {
+ if ((i+x/2)%zr->vdec == 0) {
+ memcpy(dst1,src1,w/2);
+ memcpy(dst2,src2,w/2);
+ dst1+=zr->image_width/2;
+ dst2+=zr->image_width/2;
+ }
+ src1+=stride[1];
+ src2+=stride[2];
+ }
+ }
+ }
return 0;
}
@@ -578,66 +640,86 @@ static uint32_t draw_slice(uint8_t *srcimg[], int stride[],
int
vo_zr_parseoption(struct config * conf, char *opt, char *param){
/* got an option starting with zr */
- char *x, *help;
+ zr_info_t *zr = &zr_info[zr_parsing];
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);
+ free(zr->device);
+ zr->device = malloc(strlen(param)+1);
+ strcpy(zr->device, param);
+ mp_msg(MSGT_VO, MSGL_V, "zr: using device %s\n", zr->device);
return 1;
} else if (!strcasecmp(opt, "zrbw")) {
if (param != NULL) {
return ERR_OUT_OF_RANGE;
}
- bw = 1;
+ zr->bw = 1;
return 1;
} else if (!strcasecmp(opt, "zrfd")) {
if (param != NULL) {
return ERR_OUT_OF_RANGE;
}
- zrfd = 1;
+ zr->fd = 1;
return 1;
} else if (!strcasecmp(opt, "zrcrop")){
+ geo_t *g = &zr->g;
+ if (g->set == 1) {
+ zr_parsing++;
+ zr_count++;
+ zr = &zr_info[zr_parsing];
+ g = &zr->g;
+ if (zr_count > 4) {
+ mp_msg(MSGT_VO, MSGL_ERR, "zr: too many simultaneus display devices requested (max. is 4)\n");
+ return ERR_OUT_OF_RANGE;
+ }
+ }
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) {
+ 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, "zr: argument to -zrcrop must be of the form 352x288+16+0\n");
return ERR_OUT_OF_RANGE;
}
}
- g.set = 1;
+ g->set = 1;
mp_msg(MSGT_VO, MSGL_V, "zr: cropping %s\n", param);
return 1;
}else if (!strcasecmp(opt, "zrhdec")) {
i = atoi(param);
if (i != 1 && i != 2 && i != 4) return ERR_OUT_OF_RANGE;
- hdec = i;
+ zr->hdec = i;
return 1;
}else if (!strcasecmp(opt, "zrvdec")) {
i = atoi(param);
if (i != 1 && i != 2 && i != 4) return ERR_OUT_OF_RANGE;
- vdec = i;
+ zr->vdec = i;
+ return 1;
+ }else if (!strcasecmp(opt, "zrxdoff")) {
+ i = atoi(param);
+ zr->xdoff = i;
+ return 1;
+ }else if (!strcasecmp(opt, "zrydoff")) {
+ i = atoi(param);
+ zr->ydoff = i;
return 1;
}else if (!strcasecmp(opt, "zrquality")) {
i = atoi(param);
if (i < 1 || i > 20) return ERR_OUT_OF_RANGE;
- quality = i;
+ zr->quality = i;
return 1;
}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;
+ zr->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;
+ zr->norm = VIDEO_MODE_PAL;
return 1;
} else {
return ERR_OUT_OF_RANGE;
@@ -658,10 +740,23 @@ vo_zr_parseoption(struct config * conf, char *opt, char *param){
" this switch allows you to see the effects\n"
" of too much decimation\n"
" -zrbw display in black&white (speed increase)\n"
+ " -zrxdoff x offset from upper-left of TV screen (default is 'centered')\n"
+ " -zrydoff y offset from upper-left of TV screen (default is 'centered')\n"
" -zrquality jpeg compression quality [BEST] 1 - 20 [VERY BAD]\n"
- " -zrdev playback device (example -zrdev /dev/video1\n"
- " -zrnorm specify norm PAL/NTSC [dev: leave at current setting]\n"
+ " -zrdev playback device (example -zrdev /dev/video1)\n"
+ " -zrnorm specify norm PAL/NTSC (default: leave at current setting)\n"
"\n"