vo_zr.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 827 行 · 第 1/2 页

C
827
字号
/*  * vo_zr.c - playback on zoran cards  * Copyright (C) Rik Snel 2001,2002, License GNU GPL v2 *//* $Id: vo_zr.c,v 1.2 2008/03/03 08:11:38 dsqiu Exp $ */#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <fcntl.h>#include <errno.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 "videodev_mjpeg.h"#include "config.h"#include "video_out.h"#include "video_out_internal.h"#include "mp_msg.h"#include "m_option.h"#include "fastmemcpy.h"#include "jpeg_enc.h"static vo_info_t info = {	"Zoran ZR360[56]7/ZR36060 Driver (DC10(+)/buz/lml33/MatroxRR)",	"zr",	"Rik Snel <rsnel@cube.dyndns.org>",	""};LIBVO_EXTERN (zr)#define	ZR_MAX_DEVICES 4/* General variables */typedef struct {	int width;	int height;	int xoff;	int yoff;	int set;} 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 mjpeg_requestbuffers zrq;	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, 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, 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, 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, 0, 0}};#define MJPEG_NBUFFERS	2#define MJPEG_SIZE	1024*256int zoran_getcap(zr_info_t *zr) {	char* dev = NULL;	if (zr->device)		dev = zr->device;	else {		struct stat vstat;		const char *devs[] = {		    "/dev/video",		    "/dev/video0",		    "/dev/v4l/video0",		    "/dev/v4l0",		    "/dev/v4l",		    NULL		};		int i = 0;				do		{		    if ((stat(devs[i], &vstat) == 0) && S_ISCHR(vstat.st_mode))		    {			dev = devs[i];			mp_msg(MSGT_VO, MSGL_V, "zr: found video device %s\n", dev);			break;		    }		} while (devs[++i] != NULL);		if (!dev)		{		    mp_msg(MSGT_VO, MSGL_ERR, "zr: unable to find video device\n");		    return 1;		}	}				zr->vdes = open(dev, O_RDWR);	if (zr->vdes < 0) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: error opening %s: %s\n", 		       dev, strerror(errno));		return 1;	}	/* before we can ask for the maximum resolution, we must set 	 * the correct tv norm */	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 (zr->p.norm != zr->norm && zr->norm != VIDEO_MODE_AUTO) {		/* attempt to set requested norm */		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(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(zr->vdes, VIDIOCGCAP, &zr->vc) < 0) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: error getting video capabilities from %s\n", dev);		return 1;	}	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(zr_info_t *zr, int stretchx, int stretchy) {	/* center the image, and stretch it as far as possible (try to keep	 * aspect) and check if it fits */	if (zr->image_width > zr->vc.maxwidth) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: movie to be played is too wide, max width currently %d\n", zr->vc.maxwidth);		return 1;	}	if (zr->image_height > zr->vc.maxheight) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: movie to be played is too high, max height currently %d\n", zr->vc.maxheight);		return 1;	}	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;	}	zr->zrq.count = MJPEG_NBUFFERS;	zr->zrq.size = MJPEG_SIZE;	if (ioctl(zr->vdes, MJPIOC_REQBUFS, &zr->zrq)) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: error requesting %d buffers of size %d\n", zr->zrq.count, zr->zrq.size);		return 1;	}	/* the buffer count allocated may be different to the request */	zr->buf = (unsigned char*)mmap(0, zr->zrq.count*zr->zrq.size, 			PROT_READ|PROT_WRITE, MAP_SHARED, zr->vdes, 0);	if (zr->buf == MAP_FAILED) {		mp_msg(MSGT_VO, MSGL_ERR, "zr: error requesting %d buffers of size %d\n", zr->zrq.count, zr->zrq.size);		return 1;	}		mp_msg(MSGT_VO, MSGL_V, "zr: got %d buffers of size %d (wanted %d buffers of size %d)\n", zr->zrq.count, zr->zrq.size, MJPEG_NBUFFERS, MJPEG_SIZE);	if (zr->zrq.count < MJPEG_NBUFFERS) {		mp_msg(MSGT_VO, MSGL_V, "zr: got not enough buffers\n");		return 1;	}	zr->queue = 0;	zr->synco = 0;	return 0;}void uninit_zoran(zr_info_t *zr) {	if (zr->image) {		free(zr->image);		zr->image=NULL;	}	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"); 		zr->synco++;	}	/* stop streaming */	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");	if (munmap(zr->buf,zr->zrq.count*zr->zrq.size))	   mp_msg(MSGT_VO, MSGL_ERR, "zr: error unmapping buffer\n");	close(zr->vdes);}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) {			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);			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);			return 1;		}	} else {		g->width = width;		g->height = height;		g->xoff = 0;		g->yoff = 0;		g->set = 1;	}	return 0;}static int config(uint32_t width, uint32_t height, uint32_t d_width, 	uint32_t d_height, uint32_t flags, char *title, uint32_t format){	int i, tmp, stretchx, stretchy;	framenum = 0;	if (format != IMGFMT_YV12 && format != IMGFMT_YUY2) {		printf("vo_zr called with wrong format");		return 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;			}			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;			}		}		/* 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*/		}		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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?