Mercurial > mplayer.hg
changeset 4214:664984198aef
zr driver (tv-out for DC10/DC10+, iomega buz, LML33...) added - patch by Rik Snel <rsnel@cube.dyndns.org>
author | arpi |
---|---|
date | Thu, 17 Jan 2002 01:32:29 +0000 |
parents | f1e1b02314ef |
children | 14b8bc735bf5 |
files | libvo/video_out.c libvo/vo_zr.c libvo/zoran.h |
diffstat | 3 files changed, 1018 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/libvo/video_out.c Thu Jan 17 01:28:20 2002 +0000 +++ b/libvo/video_out.c Thu Jan 17 01:32:29 2002 +0000 @@ -64,6 +64,7 @@ extern vo_functions_t video_out_tdfxfb; extern vo_functions_t video_out_null; //extern vo_functions_t video_out_odivx; +extern vo_functions_t video_out_zr; extern vo_functions_t video_out_pgm; extern vo_functions_t video_out_md5; extern vo_functions_t video_out_syncfb; @@ -131,6 +132,9 @@ #ifdef HAVE_DXR3 &video_out_dxr3, #endif +#ifdef HAVE_ZR + &video_out_zr, +#endif #ifdef HAVE_PNG &video_out_png,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libvo/vo_zr.c Thu Jan 17 01:32:29 2002 +0000 @@ -0,0 +1,642 @@ +/* + * vo_zr.c - playback on zoran cards + * Copyright (C) Rik Snel 2001,2002, License GNU GPL v2 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.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 "zoran.h" + +#include "config.h" +#define ZR_USES_LIBJPEG + +#include "video_out.h" +#include "video_out_internal.h" +#include "../mp_msg.h" +#include "../cfgparser.h" + +LIBVO_EXTERN (zr) + +static vo_info_t vo_info = +{ + "Zoran ZR360[56]7/ZR36060 Driver (DC10(+)/buz/lml33/MatroxRR)", + "zr", + "Rik Snel <snel@phys.uu.nl>", + "" +}; + +/* General variables */ + +static int image_width; +static int image_height; +static int off_y, off_c, stride; /* for use by 'draw slice' */ +static int framenum; +static int fields = 1; /* currently no interlacing */ +static int forceinter = 0; +static int vdec = 1; +static int size; +static int quality = 70; + +typedef struct { + int width; + int height; + int xoff; + int yoff; + int set; +} geo; +geo g = {0, 0, 0, 0, 0}; + +static uint8_t *image=NULL; +static uint8_t *buf=NULL; + + +/* Variables needed for Zoran */ + +int vdes; /* the file descriptor of the video device */ +int frame = 0, synco = 0, queue = 0; /* buffer management */ +struct zoran_params zp; +struct zoran_requestbuffers zrq; +struct zoran_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; +char *device = "/dev/video"; + + +#ifdef ZR_USES_LIBJPEG +#include<jpeglib.h> +int ccount; +unsigned char *ccbuf; +struct jpeg_compress_struct cinfo; +struct jpeg_destination_mgr jdest; +struct jpeg_error_mgr jerr; + +/* minimal destination handler to output to buffer */ +METHODDEF(void) init_destination(struct jpeg_compress_struct *cinfo) { +// printf("init_destination called %p %d\n", ccbuf, ccount); + cinfo->dest->next_output_byte = (JOCTET*)(ccbuf+ccount); + cinfo->dest->free_in_buffer = MJPEG_SIZE - ccount; +} + +METHODDEF(boolean) empty_output_buffer(struct jpeg_compress_struct *cinfo) { +// printf("empty_output_buffer called\n"); + mp_msg(MSGT_VO, MSGL_ERR, "empty_output_buffer called, may not happen because buffer must me large enough\n"); + return(FALSE); +} + +METHODDEF(void) term_destination(struct jpeg_compress_struct *cinfo) { +// printf("term_destination called %p %d\n", ccbuf, ccount); + ccount = MJPEG_SIZE - cinfo->dest->free_in_buffer; +} +/* end of minimal destination handler */ + +JSAMPARRAY ***jsi; + +#else +#include "../libavcodec/avcodec.h" +AVCodec *codec; +AVCodecContext codec_context; +AVPicture picture; +#endif + +static int jpegdct = JDCT_IFAST; + +int init_codec() { +#ifdef ZR_USES_LIBJPEG + int i, j, k; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + cinfo.dest = &jdest; + cinfo.dest->init_destination = init_destination; + cinfo.dest->empty_output_buffer = empty_output_buffer; + cinfo.dest->term_destination = term_destination; + + cinfo.input_components = 3; + + jpeg_set_defaults(&cinfo); + + cinfo.image_width = image_width; + cinfo.image_height = image_height/fields; + cinfo.input_gamma = 1.0; + cinfo.in_color_space = JCS_YCbCr; + cinfo.raw_data_in = TRUE; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + cinfo.dct_method = jpegdct; + jpeg_set_quality(&cinfo, quality, FALSE); + jsi = malloc(sizeof(JSAMPARRAY**)*fields); + + /* Just some clutter to give libjpeg the pointers, + * and I don't want to recalculate everything everytime + * it is needed */ + for (k = 0; k < fields; k++) { + jsi[k] = malloc(sizeof(JSAMPARRAY*)*image_height/(8*fields)); + + for (i = 0; i < image_height/(8*fields); i++) { + jsi[k][i] = malloc(3*sizeof(JSAMPARRAY)); + jsi[k][i][0] = malloc(8*sizeof(JSAMPROW)); + jsi[k][i][1] = malloc(8*sizeof(JSAMPROW)); + jsi[k][i][2] = malloc(8*sizeof(JSAMPROW)); + for (j = 0; j < 8; j++) { + jsi[k][i][0][j] = (JSAMPROW)(image + + (fields*(8*i + j) + k)*image_width); + jsi[k][i][1][j] = (JSAMPROW)(image + size + + (fields*(8*i + j)/2)*image_width/2); + jsi[k][i][2][j] = (JSAMPROW)(image + 3*size/2 + + (fields*(8*i + j)/2)*image_width/2); + } + } + + } +#else + AVCodecContext *c = &codec_context; + codec = avcodec_find_encoder(CODEC_ID_MJPEG); + if (!codec) { + /* maybe libavcodec was not initialized */ + avcodec_init(); + avcodec_register_all(); + codec = avcodec_find_encoder(CODEC_ID_MJPEG); + if (!codec) { + mp_msg(MSGT_VO, MSGL_ERR, "MJPG codec not found in libavcodec\n"); + return 1; + } + } + /* put default values */ + memset(c, 0, sizeof(*c)); + + c->width = image_width; + c->height = image_height; + c->bit_rate = 4000000; + c->frame_rate = 25*FRAME_RATE_BASE; + //c->gop_size = 1; + c->pix_fmt = PIX_FMT_YUV422P; + + if (avcodec_open(c, codec) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "MJPG codec could not be opened\n"); + return 1; + } + + picture.data[0] = image; + picture.data[1] = image + size; + picture.data[2] = image + 3*size/2; + picture.linesize[0] = image_width; + picture.linesize[1] = image_width/2; + picture.linesize[2] = image_width/2; +#endif + return 0; +} + + +int zoran_getcap() { + vdes = open(device, O_RDWR); + /* before we can ask for the maximum resolution, we must set + * the correct tv norm */ + + if (ioctl(vdes, BUZIOC_G_PARAMS, &zp) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "device at %s is probably not a DC10(+)/buz/lml33\n", device); + return 1; + } + + if (zp.norm != norm && norm != VIDEO_MODE_AUTO) { + /* attempt to set requested norm */ + zp.norm = norm; + if (ioctl(vdes, BUZIOC_S_PARAMS, &zp) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, + "unable to change video norm, use another program to change it (XawTV)\n"); + return 1; + } + ioctl(vdes, BUZIOC_G_PARAMS, &zp); + if (norm != zp.norm) { + mp_msg(MSGT_VO, MSGL_ERR, + "unable to change video norm, use another program to change it (XawTV)\n"); + return 1; + } + } + + if (vdes < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "error opening %s\n", + device); + return 1; + } + + + if (ioctl(vdes, VIDIOCGCAP, &vc) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "error getting video capabilities from %s\n"); + return 1; + } + mp_msg(MSGT_VO, MSGL_V, "zr36067 reports: maxwidth=%d, maxheight=%d\n", vc.maxwidth, vc.maxheight); + + return 0; +} + +int init_zoran() { + /* 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, "movie to be played is too wide, max width currenty %d\n", vc.maxwidth); + return 1; + } + + if (image_height > vc.maxheight) { + mp_msg(MSGT_VO, MSGL_ERR, "movie to be played is too high, max height currenty %d\n", vc.maxheight); + return 1; + } + + zp.decimation = 0; + zp.HorDcm = (vc.maxwidth >= 2*(int)image_width) ? 2 : 1; + zp.VerDcm = 1; + if (zp.HorDcm == 2 && 4*image_width <= vc.maxwidth && + 4*image_height/fields <= vc.maxheight) { + zp.HorDcm = 4; + zp.VerDcm = 2; + } + if (((forceinter == 0 && vdec >= 2) || (forceinter == 1 && vdec == 4)) && 4*image_height/fields <= vc.maxheight) { + zp.VerDcm = 2; + } + zp.TmpDcm = 1; + zp.field_per_buff = fields; + zp.img_x = (vc.maxwidth - zp.HorDcm*(int)image_width)/2; + zp.img_y = (vc.maxheight - zp.VerDcm*(3-fields)*(int)image_height)/4; + zp.img_width = zp.HorDcm*image_width; + 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, zp.img_height, zp.img_x, zp.img_y, fields, image_width, image_height); + + if (ioctl(vdes, BUZIOC_S_PARAMS, &zp) < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "error setting display parameters\n"); + return 1; + } + + zrq.count = MJPEG_NBUFFERS; + zrq.size = MJPEG_SIZE; + + if (ioctl(vdes, BUZIOC_REQBUFS, &zrq)) { + mp_msg(MSGT_VO, MSGL_ERR, "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); + + if (buf == MAP_FAILED) { + mp_msg(MSGT_VO, MSGL_ERR, "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; + } + while (queue > synco + 1) { + if (ioctl(vdes, BUZIOC_SYNC, &zs) < 0) + mp_msg(MSGT_VO, MSGL_ERR, "error waiting for buffers to become free"); + synco++; + } + /* stop streaming */ + frame = -1; + if (ioctl(vdes, BUZIOC_QBUF_PLAY, &frame) < 0) + mp_msg(MSGT_VO, MSGL_ERR, "error stopping playback of last frame"); + close(vdes); +} + +static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width, + uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format) +{ + int j; + /* this allows to crop parts from incoming picture, + * for easy 512x240 -> 352x240 */ + /* These values must be multples of 2 */ + + 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, "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, "width and height must be positive and offset nonnegative\n"); + return 1; + } + if (g.width + g.xoff > width) { + mp_msg(MSGT_VO, MSGL_ERR, "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, "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; + } + /* 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 */ + if (g.height/vdec > vc.maxheight/2 || (forceinter == 1 && vdec == 1)) + fields = 2; + printf("fields=%d\n", fields); + /* 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 = 16*((g.width - 1)/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, "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, "Memory exhausted\n"); + return 1; + } + /* and make sure that the borders are _really_ black */ + 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); + + if (init_codec()) { + return 1; + } + + if (init_zoran()) { +#ifdef ZR_USES_LIBJPEG + jpeg_destroy_compress(&cinfo); +#else + avcodec_close(&codec_context); +#endif + return 1; + } + + return 0; +} + +static const vo_info_t* get_info(void) { + return &vo_info; +} + +static void draw_osd(void) { +} + +static void flip_page (void) { +#ifdef ZR_USES_LIBJPEG + int i, j, k; +#else + AVCodecContext *c = &codec_context; +#endif + + /* do we have a free buffer? */ + if (queue-synco < zrq.count) { + frame = queue; + } else { + if (ioctl(vdes, BUZIOC_SYNC, &zs) < 0) + mp_msg(MSGT_VO, MSGL_ERR, "error waiting for buffers to become free"); + frame = zs.frame; + synco++; + } + +#ifdef ZR_USES_LIBJPEG + ccbuf = buf + frame*zrq.size; + ccount = 0; + k = fields; + for (j=0; j < k; j++) { + + jpeg_start_compress(&cinfo, TRUE); + i=0; + while (cinfo.next_scanline < cinfo.image_height) { + jpeg_write_raw_data(&cinfo, jsi[j][i], 8); + i++; + } + jpeg_finish_compress(&cinfo); + + } +#else + avcodec_encode_video(c, buf + frame*zrq.size, MJPEG_SIZE, &picture); +#endif + + if (ioctl(vdes, BUZIOC_QBUF_PLAY, &frame) < 0) + mp_msg(MSGT_VO, MSGL_ERR, + "error queueing buffer for playback"); + queue++; + + framenum++; + return; +} + +static uint32_t draw_frame(uint8_t * src[]) { + return 0; +} + +static uint32_t query_format(uint32_t format) { + if(format==IMGFMT_YV12) return 1; + return 0; +} + +static void uninit(void) { + uninit_zoran(); + +#ifdef ZR_USES_LIBJPEG + jpeg_destroy_compress(&cinfo); +#else + avcodec_close(&codec_context); +#endif +} + +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; + /* 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]; + + } + { + // copy U+V: + 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; + } + src1+=stride[1]; + src2+=stride[2]; + } + } + return 0; +} + + +/* copied and adapted from vo_aa_parseoption */ +int +vo_zr_parseoption(struct config * conf, char *opt, char *param){ + /* got an option starting with zr */ + char *x, *help; + 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); + return 1; + } else if (!strcasecmp(opt, "zrfi")) { + if (param != NULL) { + return ERR_OUT_OF_RANGE; + } + forceinter = 1; + return 1; + } else if (!strcasecmp(opt, "zrcrop")){ + 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) { + mp_msg(MSGT_VO, MSGL_ERR, "argument to -zrcrop must be of the form 352x288+16+0\n"); + return ERR_OUT_OF_RANGE; + } + } + g.set = 1; + mp_msg(MSGT_VO, MSGL_V, "zr: cropping %s\n", param); + return 1; + }else if (!strcasecmp(opt, "zrvdec")) { + i = atoi(param); + if (i != 1 && i != 2 && i != 4) return ERR_OUT_OF_RANGE; + vdec = i; + return 1; + }else if (!strcasecmp(opt, "zrquality")) { + i = atoi(param); + if (i < 30 || i > 100) return ERR_OUT_OF_RANGE; + quality = i; + return 1; + }else if (!strcasecmp(opt, "zrdct")) { + if (param == NULL) return ERR_MISSING_PARAM; + if (!strcasecmp(param, "IFAST")) { + jpegdct = JDCT_IFAST; + return 1; + } else if (!strcasecmp(param, "ISLOW")) { + jpegdct = JDCT_ISLOW; + return 1; + } else if (!strcasecmp(param, "FLOAT")) { + jpegdct = JDCT_FLOAT; + return 1; + } else { + return ERR_OUT_OF_RANGE; + } + }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; + return 1; + } else if (!strcasecmp(param, "PAL")) { + mp_msg(MSGT_VO, MSGL_V, "zr: Norm set to PAL\n"); + norm = VIDEO_MODE_PAL; + return 1; + } else { + return ERR_OUT_OF_RANGE; + } + }else if (!strcasecmp(opt, "zrhelp")){ + printf("Help for -vo zr: Zoran ZR360[56]7/ZR36060 based MJPEG capture/playback cards\n"); + printf("\n"); + printf("Here are the zr options:\n"); + printf( + "\n" + " -zrcrop specify part of the input image that\n" + " you want to see as an x-style geometry string\n" + " example: -zrcrop 352x288+16+0\n" + " -zrvdec vertical decimation 1, 2 or 4\n" + " -zrfi force interlacing ('wide screen')\n" + " (by default we only interlace if the movie\n" + " is higher than half of the screen height)\n" + " -zrquality jpeg compression quality 30-100\n" + " -zrdct specify DCT method: IFAST, ISLOW or FLOAT\n" + " -zrdev playback device (example -zrdev /dev/video1\n" + " -zrnorm specify norm PAL/NTSC [dev: leave at current setting]\n" + "\n" + ); + exit(0); + + } + return ERR_NOT_AN_OPTION; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libvo/zoran.h Thu Jan 17 01:32:29 2002 +0000 @@ -0,0 +1,372 @@ +/* + zoran - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + + based on + + zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + and + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +#include <linux/config.h> + +#if LINUX_VERSION_CODE < 0x20212 +typedef struct wait_queue *wait_queue_head_t; +#endif + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +//#define XAWTV_HACK + +//#ifdef XAWTV_HACK +//#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#define BUZ_MAX_WIDTH (zr->timing->Wa) +//#else +//#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +//#endif +//#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MAX_HEIGHT (zr->timing->Ha) +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* +Private IOCTL to set up for displaying MJPEG +*/ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +# define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +# define V4L_MAX_FRAME 64 +#else +# error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum card_type { + UNKNOWN = 0, + DC10, + DC10plus, + LML33, + BUZ +}; + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct tvnorm { + u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + enum card_type card; + struct tvnorm *timing; + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock irq and hardware */ + struct semaphore sem; /* Guard parallel ioctls and mmap */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + wait_queue_head_t v4l_capq; + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + wait_queue_head_t jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + unsigned long jpg_err_seq; /* last seq_num before error */ + unsigned long jpg_err_shift; + unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ + + /* Additional stuff for testing */ + struct proc_dir_entry *zoran_proc; + + int testing; + int jpeg_error; + int intr_counter_GIRQ1; + int intr_counter_GIRQ0; + int intr_counter_CodRepIRQ; + int intr_counter_JPEGRepIRQ; + int field_counter; + int IRQ1_in; + int IRQ1_out; + int JPEG_in; + int JPEG_out; + int JPEG_0; + int JPEG_1; + int END_event_missed; + int JPEG_missed; + int JPEG_error; + int num_errors; + int JPEG_max_missed; + int JPEG_min_missed; + + u32 last_isr; + unsigned long frame_num; + + wait_queue_head_t test_q; +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile.*/ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7110 0x9c +#define I2C_SAA7185 0x88 +//#define I2C_ADV7175 0xd4 +#define I2C_ADV7175 0x54 + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif