vo_zr2.c

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

C
485
字号
/*  * vo_zr2.c - playback on zoran cards  * Based on vo_zr.c,v 1.27 * Copyright (C) Rik Snel 2001-2005, License GNU GPL v2 *//* $Id: vo_zr2.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 "subopt-helper.h"#include "fastmemcpy.h"static vo_info_t info = {	"Zoran ZR360[56]7/ZR36060 Driver (DC10(+)/buz/lml33/MatroxRR)",	"zr2",	"Rik Snel <rsnel@cube.dyndns.org>",	""};LIBVO_EXTERN(zr2)typedef struct {	/* options */	char *subdevice;	/* information for (and about) the zoran card */	unsigned char *buf; 		 /* the JPEGs will be placed here */	struct mjpeg_requestbuffers zrq; /* info about this buffer */	int vdes;			 /* file descriptor of card */	int playing;                     /* 0 or 1 */	int frame, sync, queue; 	 /* buffer management */	struct mjpeg_sync zs;		 /* state information */	struct mjpeg_params zp;	struct video_capability vc;	 /* max resolution and so on */} vo_zr2_priv_t;static vo_zr2_priv_t priv;#define ZR2_MJPEG_NBUFFERS	2#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__)static void stop_playing(vo_zr2_priv_t *p) {	if (p->playing) {		p->frame = -1;		if (ioctl(p->vdes, MJPIOC_QBUF_PLAY, &p->frame) < 0)  			ERROR("error stopping playback\n");		p->playing = 0;		p->sync = 0;		p->queue = 0;		p->frame = 0;	}}static const char *guess_device(const char *suggestion, int inform) {	struct stat vstat;	int res;	char *devs[] = {		"/dev/video",		"/dev/video0",		"/dev/v4l/video0",		"/dev/v4l0",		"/dev/v4l",		NULL	};	char **dev = devs;	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)) {			if (inform) 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)) {			VERBOSE("guessed video device %s\n", *dev);			return *dev;		}		dev++;	}	ERROR("unable to find video device\n");	return NULL;}static int query_format(uint32_t format) {	if (format==IMGFMT_ZRMJPEGNI ||			format==IMGFMT_ZRMJPEGIT ||			format==IMGFMT_ZRMJPEGIB)		return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;	return 0;}static uint32_t draw_image(mp_image_t *mpi) {	vo_zr2_priv_t *p = &priv;	int size = (int)mpi->planes[1];	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 < (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");			return VO_FALSE;		}		p->frame = p->zs.frame;		p->sync++;	}	/* copy the jpeg image to the buffer which we acquired */	fast_memcpy(p->buf + p->zrq.size*p->frame, mpi->planes[0], size);				return VO_TRUE;}static const 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 int get_norm(const char *n) {	if (!strcmp(n, "PAL")) return VIDEO_MODE_PAL;	if (!strcmp(n, "NTSC")) return VIDEO_MODE_NTSC;	if (!strcmp(n, "SECAM")) return VIDEO_MODE_SECAM;	if (!strcmp(n, "auto")) return VIDEO_MODE_AUTO;	return -1; /* invalid */}static int nc(const char **norm) {	if (get_norm(*norm) == -1) {		ERROR("norm \"%s\" is not supported, choose from PAL, NTSC, SECAM and auto\n", *norm);		return 0;	} else return 1;}static int pbc(int *prebuf) {	if (*prebuf) WARNING("prebuffering is not yet supported\n");	return 1;}static int preinit(const char *arg) {	vo_zr2_priv_t *p = &priv;	const char *dev = NULL;	char *dev_arg = NULL, *norm_arg = NULL;	int norm = VIDEO_MODE_AUTO, prebuf = 0;	opt_t subopts[] = { /* don't want warnings with -Wall... */		{ "dev",    OPT_ARG_MSTRZ, &dev_arg,   NULL, 	        0 },		{ "prebuf", OPT_ARG_BOOL,  &prebuf,    (opt_test_f)pbc, 0 },		{ "norm",   OPT_ARG_MSTRZ, &norm_arg,  (opt_test_f)nc,  0 },		{ NULL,     0, 		   NULL,       NULL, 	        0 }	};	VERBOSE("preinit() called with arg: %s\n", arg);	memset(p, 0, sizeof(*p)); /* set defaults */	p->vdes = -1;	if (subopt_parse(arg, subopts)) {		mp_msg(MSGT_VO, MSGL_FATAL,				"Allowed suboptions for -vo zr2 are:\n"				"-  dev=DEVICE               (default: %s)\n"				"-  norm=PAL|NTSC|SECAM|auto (default: auto)\n"				"-  prebuf/noprebuf          (default:"				" noprebuf)\n"				"\n"				"Example: mplayer -vo zr2:dev=/dev/video1:"				"norm=PAL movie.avi\n\n"				, guess_device(NULL, 0));		free(norm_arg);		free(dev_arg);		return -1;	}					/* interpret the strings we got from subopt_parse */	if (norm_arg) {		norm = get_norm(norm_arg);		free(norm_arg);	}	if (dev_arg) dev = dev_arg;	dev = guess_device(dev, 1);	if (!dev) {		free(dev_arg);		uninit();		return 1;	}	p->vdes = open(dev, O_RDWR);	if (p->vdes < 0) {		ERROR("error opening %s: %s\n", dev, strerror(errno));		free(dev_arg);		uninit();		return 1;	}		free(dev_arg);	/* 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,			normstring(p->zp.norm));	/* changing the norm in the zoran_params and MJPIOC_S_PARAMS	 * does nothing the last time I tried, so bail out if the norm 	 * is not correct */	if (norm != VIDEO_MODE_AUTO &&  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;	}		VERBOSE("got %ld buffers of size %ld (wanted %d buffers of size %d)\n",			p->zrq.count, p->zrq.size, ZR2_MJPEG_NBUFFERS,			ZR2_MJPEG_SIZE);		p->buf = (unsigned char*)mmap(0, p->zrq.count*p->zrq.size,			PROT_READ|PROT_WRITE, MAP_SHARED, p->vdes, 0);	if (p->buf == MAP_FAILED) {		ERROR("error mapping requested buffers: %s", strerror(errno));		uninit();		return 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 fields = 1, top_first = 1, err = 0;	int stretchx = 1, stretchy = 1;	struct mjpeg_params zptmp;	vo_zr2_priv_t *p = &priv;	VERBOSE("config() called\n");	/* paranoia check */	if (!query_format(format)) {		ERROR("called with wrong format, should be impossible\n");		return 1;	}	if ((int)height > p->vc.maxheight) {		ERROR("input height %d is too large, maxheight=%d\n",				height, p->vc.maxheight);		err = 1;	}	if (format != IMGFMT_ZRMJPEGNI) {		fields = 2;		if (format == IMGFMT_ZRMJPEGIB)			top_first = 0;	} else if ((int)height > p->vc.maxheight/2) {		ERROR("input is too high (%d) for non-interlaced playback"				"max=%d\n", height, p->vc.maxheight);		err = 1;	}	if (width%16 != 0) {		ERROR("input width=%d, must be multiple of 16\n", width);		err = 1;	}		if (height%(fields*8) != 0) {		ERROR("input height=%d, must be multiple of %d\n", 				height, 2*fields);		err = 1;	}	/* we assume sample_aspect = 1 */	if (fields == 1) {		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 "					"too small\n");	}	if (d_width == width) stretchx = 1;	else if (d_width == 2*width) stretchx = 2;#if 0 /* do minimal stretching for now */	else if (d_width == 4*width) stretchx = 4;	else WARNING("d_width must be {1,2,4}*width, using defaults\n");	if (d_height == height) stretchy = 1;	else if (d_height == 2*height) stretchy = 2;	else if (d_height == 4*height) stretchy = 4;	else WARNING("d_height must be {1,2,4}*height, using defaults\n");#endif	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 > (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;	}	if (err == 1) return 1;	/* some video files (eg. concatenated MPEG files), make MPlayer	 * call config() during playback while no parameters have changed.	 * We make configuration changes to a temporary params structure,	 * compare it with the old params structure and only apply the new	 * config if it is different from the old one. */	memcpy(&zptmp, &p->zp, sizeof(zptmp));	/* translate the configuration to zoran understandable format */	zptmp.decimation = 0;	zptmp.HorDcm = stretchx;	zptmp.VerDcm = stretchy;	zptmp.TmpDcm = 1;	zptmp.field_per_buff = fields;	zptmp.odd_even = top_first;	/* center the image on screen */	zptmp.img_x = (p->vc.maxwidth - width*stretchx)/2;	zptmp.img_y = (p->vc.maxheight - height*stretchy*(3-fields))/4;	zptmp.img_width = stretchx*width;	zptmp.img_height = stretchy*height/fields;	VERBOSE("tv: %dx%d, out: %dx%d+%d+%d, in: %ux%u %s%s%s\n",			p->vc.maxwidth, p->vc.maxheight,			zptmp.img_width, 2*zptmp.img_height,			zptmp.img_x, 2*zptmp.img_y,			width, height, (fields == 1) ? "non-interlaced" : "",			(fields == 2 && top_first == 1) 			?  "interlaced top first" : "",			(fields == 2 && top_first == 0) 			? "interlaced bottom first" : "");	if (memcmp(&zptmp, &p->zp, sizeof(zptmp))) {		/* config differs, we must update */		memcpy(&p->zp, &zptmp, sizeof(zptmp));		stop_playing(p);		if (ioctl(p->vdes, MJPIOC_S_PARAMS, &p->zp) < 0) {			ERROR("error writing display params to card\n");			return 1;		}		VERBOSE("successfully written display parameters to card\n");	} else VERBOSE("config didn't change, no need to write it to card\n");	return 0;}static int control(uint32_t request, void *data, ...) {	switch (request) {  		case VOCTRL_QUERY_FORMAT:			return query_format(*((uint32_t*)data));		case VOCTRL_DRAW_IMAGE:			return draw_image(data);  	}	return VO_NOTIMPL;}static int draw_frame(uint8_t *src[]) {	return 0;}static int draw_slice(uint8_t *image[], int stride[],		int w, int h, int x, int y) { 	return 0;}static void draw_osd(void) {}static void flip_page(void) {	vo_zr2_priv_t *p = &priv;	/* queueing the buffer for playback */	/* queueing the first buffer automatically starts playback */	if (p->playing == 0) p->playing = 1;	if (ioctl(p->vdes, MJPIOC_QBUF_PLAY, &p->frame) < 0) 		ERROR("error queueing buffer for playback\n");	else p->queue++;}static void check_events(void) {}static void uninit(void) {	vo_zr2_priv_t *p = &priv;	VERBOSE("uninit() called (may be called from preinit() on error)\n");	stop_playing(p);	if (p->buf && munmap(p->buf, p->zrq.size*p->zrq.count)) 		ERROR("error munmapping buffer: %s\n", strerror(errno));	if (p->vdes >= 0) close(p->vdes);	free(p->subdevice);}

⌨️ 快捷键说明

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