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 + -
显示快捷键?