diff options
Diffstat (limited to 'xc/programs/Xserver/hw/xfree86/drivers/v4l')
-rw-r--r-- | xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c | 448 | ||||
-rw-r--r-- | xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp | 20 |
2 files changed, 361 insertions, 107 deletions
diff --git a/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c b/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c index 6ef875e7f..065df36c3 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c @@ -2,7 +2,7 @@ * video4linux Xv Driver * based on Michael Schimek's permedia 2 driver. */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c,v 1.16 2000/02/22 02:00:54 mvojkovi Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c,v 1.19 2000/06/13 02:28:34 dawes Exp $ */ #include "videodev.h" #include "xf86.h" @@ -25,7 +25,11 @@ typedef unsigned long ulong; /* XXX Lots of xalloc() calls don't check for failure. */ -#define DEBUG(x) (x) +#if 0 +# define DEBUG(x) (x) +#else +# define DEBUG(x) +#endif static void V4LIdentify(int flags); static Bool V4LProbe(DriverPtr drv, int flags); @@ -100,20 +104,27 @@ v4lSetup(pointer module, pointer opts, int *errmaj, int *errmin) #endif +#define VIDEO_OFF 0 /* really off */ +#define VIDEO_RGB 1 /* rgb overlay (directly to fb) */ +#define VIDEO_YUV 2 /* yuv overlay (to offscreen memory + hw scaling) */ +#define VIDEO_RECLIP 3 /* temporarly off, window clipping changes */ + typedef struct _PortPrivRec { ScrnInfoPtr pScrn; FBAreaPtr pFBArea[2]; - int VideoOn; /* yes/no */ + int VideoOn; Bool StreamOn; /* file handle */ int fd; char devname[16]; int useCount; + struct video_capability cap; - /* overlay */ - struct video_buffer ov_fbuf; - struct video_window ov_win; + /* RGB overlay */ + struct video_buffer rgb_fbuf; + struct video_window rgb_win; + int rgbpalette; /* attributes */ struct video_picture pict; @@ -121,6 +132,17 @@ typedef struct _PortPrivRec { XF86VideoEncodingPtr enc; int nenc,cenc; + + /* yuv to offscreen */ + XF86OffscreenImagePtr format; /* list */ + int nformat; /* # if list entries */ + XF86OffscreenImagePtr myfmt; /* which one is YUY2 (packed) */ + int have_yuv; + + int yuv_width,yuv_height; + XF86SurfacePtr surface; + struct video_buffer yuv_fbuf; + struct video_window yuv_win; } PortPrivRec, *PortPrivPtr; #define XV_ENCODING "XV_ENCODING" @@ -143,8 +165,24 @@ InputVideoFormats[] = { { 15, TrueColor }, { 16, TrueColor }, { 24, TrueColor }, + { 32, TrueColor }, }; +#define V4L_ATTR (sizeof(Attributes) / sizeof(XF86AttributeRec)) + +static XF86AttributeRec Attributes[] = { + {XvSettable | XvGettable, -1000, 1000, XV_ENCODING}, + {XvSettable | XvGettable, -1000, 1000, XV_BRIGHTNESS}, + {XvSettable | XvGettable, -1000, 1000, XV_CONTRAST}, + {XvSettable | XvGettable, -1000, 1000, XV_SATURATION}, + {XvSettable | XvGettable, -1000, 1000, XV_HUE}, + {XvSettable | XvGettable, 0, 1, XV_MUTE}, + {XvSettable | XvGettable, 0, 16*1000, XV_FREQ}, +}; +static XF86AttributeRec VolumeAttr = + {XvSettable | XvGettable, -1000, 1000, XV_VOLUME}; + + /* ---------------------------------------------------------------------- */ /* forward decl */ @@ -172,14 +210,26 @@ static int V4lOpenDevice(PortPrivPtr pPPriv, ScrnInfoPtr pScrn) if (pPPriv->fd == -1) { pPPriv->fd = open(pPPriv->devname, O_RDWR, 0); - pPPriv->ov_fbuf.width = pScrn->virtualX; - pPPriv->ov_fbuf.height = pScrn->virtualY; - pPPriv->ov_fbuf.depth = pScrn->bitsPerPixel; - pPPriv->ov_fbuf.bytesperline = pScrn->displayWidth * ((pScrn->bitsPerPixel + 7)/8); - pPPriv->ov_fbuf.base = (pointer)(pScrn->memPhysBase + pScrn->fbOffset); + pPPriv->rgb_fbuf.width = pScrn->virtualX; + pPPriv->rgb_fbuf.height = pScrn->virtualY; + pPPriv->rgb_fbuf.depth = pScrn->bitsPerPixel; + pPPriv->rgb_fbuf.bytesperline = pScrn->displayWidth * ((pScrn->bitsPerPixel + 7)/8); + pPPriv->rgb_fbuf.base = (pointer)(pScrn->memPhysBase + pScrn->fbOffset); - if (-1 == ioctl(pPPriv->fd,VIDIOCSFBUF,&(pPPriv->ov_fbuf))) - perror("ioctl VIDIOCSFBUF"); + switch (pScrn->bitsPerPixel) { + case 16: + if (pScrn->weight.green == 5) + pPPriv->rgbpalette = VIDEO_PALETTE_RGB555; + else + pPPriv->rgbpalette = VIDEO_PALETTE_RGB565; + break; + case 24: + pPPriv->rgbpalette = VIDEO_PALETTE_RGB24; + break; + case 32: + pPPriv->rgbpalette = VIDEO_PALETTE_RGB32; + break; + } } if (pPPriv->fd == -1) @@ -200,7 +250,6 @@ static void V4lCloseDevice(PortPrivPtr pPPriv) } } - static int V4lPutVideo(ScrnInfoPtr pScrn, short vid_x, short vid_y, short drw_x, short drw_y, @@ -210,13 +259,133 @@ V4lPutVideo(ScrnInfoPtr pScrn, PortPrivPtr pPPriv = (PortPrivPtr) data; struct video_clip *clip; BoxPtr pBox; + RegionRec newReg; + BoxRec newBox; unsigned int i,dx,dy,dw,dh; + int width,height; int one=1; - DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PV\n")); + /* Open a file handle to the device */ + if (VIDEO_OFF == pPPriv->VideoOn) { + if (V4lOpenDevice(pPPriv, pScrn)) + return BadAccess; + } + + if (pPPriv->have_yuv) { + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PV yuv\n")); + width = pPPriv->enc[pPPriv->cenc].width; + height = pPPriv->enc[pPPriv->cenc].height/2; /* no interlace */ + if (drw_w < width) + width = drw_w; + if (drw_h < height) + height = drw_h; + if ((height != pPPriv->yuv_height) || (width != pPPriv->yuv_width)) { + /* new size -- free old surface */ + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " surface resize\n")); + if (pPPriv->surface) { + pPPriv->VideoOn = VIDEO_OFF; + pPPriv->myfmt->stop(pPPriv->surface); + pPPriv->myfmt->free_surface(pPPriv->surface); + xfree(pPPriv->surface); + pPPriv->surface = NULL; + } + pPPriv->yuv_width = width; + pPPriv->yuv_height = height; + } + if (!pPPriv->surface) { + /* allocate + setup offscreen surface */ + if (NULL == (pPPriv->surface = xalloc(sizeof(XF86SurfaceRec)))) + return FALSE; + if (Success != pPPriv->myfmt->alloc_surface + (pScrn,pPPriv->myfmt->image->id, + pPPriv->yuv_width,pPPriv->yuv_height,pPPriv->surface)) { + xfree(pPPriv->surface); + pPPriv->surface = NULL; + goto fallback_to_rgb; + } + pPPriv->yuv_fbuf.width = pPPriv->surface->width; + pPPriv->yuv_fbuf.height = pPPriv->surface->height; + pPPriv->yuv_fbuf.depth = 16; + pPPriv->yuv_fbuf.bytesperline = pPPriv->surface->pitches[0]; + pPPriv->yuv_fbuf.base = + (pointer)(pScrn->memPhysBase + pPPriv->surface->offsets[0]); + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " surface: %p+%d = %p, %dx%d, pitch %d\n", + pScrn->memPhysBase,pPPriv->surface->offsets[0], + pScrn->memPhysBase+pPPriv->surface->offsets[0], + pPPriv->surface->width,pPPriv->surface->height, + pPPriv->surface->pitches[0])); + pPPriv->yuv_win.width = pPPriv->surface->width; + pPPriv->yuv_win.height = pPPriv->surface->height; + } + + /* program driver */ + if (VIDEO_YUV != pPPriv->VideoOn) { + if (-1 == ioctl(pPPriv->fd,VIDIOCSFBUF,&(pPPriv->yuv_fbuf))) + perror("ioctl VIDIOCSFBUF"); + if (-1 == ioctl(pPPriv->fd,VIDIOCGPICT,&pPPriv->pict)) + perror("ioctl VIDIOCGPICT"); + pPPriv->pict.palette = VIDEO_PALETTE_YUV422; + if (-1 == ioctl(pPPriv->fd,VIDIOCSPICT,&pPPriv->pict)) + perror("ioctl VIDIOCSPICT"); + if (-1 == ioctl(pPPriv->fd,VIDIOCSWIN,&(pPPriv->yuv_win))) + perror("ioctl VIDIOCSWIN"); + if (-1 == ioctl(pPPriv->fd, VIDIOCCAPTURE, &one)) + perror("ioctl VIDIOCCAPTURE(1)"); + } + + if (0 == (pPPriv->myfmt->flags & VIDEO_INVERT_CLIPLIST)) { + /* invert cliplist */ + newBox.x1 = drw_x; + newBox.y1 = drw_y; + newBox.x2 = drw_x + drw_w; + newBox.y2 = drw_y + drw_h; + + if (pPPriv->myfmt->flags & VIDEO_CLIP_TO_VIEWPORT) { + /* trim to the viewport */ + if(newBox.x1 < pScrn->frameX0) + newBox.x1 = pScrn->frameX0; + if(newBox.x2 > pScrn->frameX1) + newBox.x2 = pScrn->frameX1; + + if(newBox.y1 < pScrn->frameY0) + newBox.y1 = pScrn->frameY0; + if(newBox.y2 > pScrn->frameY1) + newBox.y2 = pScrn->frameY1; + } + + REGION_INIT(pScrn->pScreen, &newReg, &newBox, 1); + REGION_SUBTRACT(pScrn->pScreen, &newReg, &newReg, clipBoxes); + clipBoxes = &newReg; + } + + /* start overlay */ + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, + "over: - %d,%d -> %d,%d (%dx%d) (yuv=%dx%d)\n", + drw_x, drw_y, + drw_x+drw_w, drw_y+drw_h, + drw_w, drw_h, + pPPriv->surface->width,pPPriv->surface->height)); + pPPriv->myfmt->display(pPPriv->surface, + 0, 0, drw_x, drw_y, + pPPriv->surface->width, + pPPriv->surface->height, + drw_w, drw_h, + clipBoxes); + if (0 == (pPPriv->myfmt->flags & VIDEO_INVERT_CLIPLIST)) { + REGION_UNINIT(pScrn->pScreen, &newReg); + } + pPPriv->VideoOn = VIDEO_YUV; + return Success; + } + + fallback_to_rgb: + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/PV rgb\n")); /* FIXME: vid-* is ignored for now, not supported by v4l */ - V4lQueryBestSize(pScrn, 0, vid_w, vid_h, drw_w, drw_h, &dw, &dh, data); + dw = (drw_w < pPPriv->enc[pPPriv->cenc].width) ? + drw_w : pPPriv->enc[pPPriv->cenc].width; + dh = (drw_h < pPPriv->enc[pPPriv->cenc].height) ? + drw_h : pPPriv->enc[pPPriv->cenc].height; /* if the window is too big, center the video */ dx = drw_x + (drw_w - dw)/2; dy = drw_y + (drw_h - dh)/2; @@ -230,25 +399,25 @@ V4lPutVideo(ScrnInfoPtr pScrn, drw_w,drw_h,drw_x,drw_y)); DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, " use: %dx%d+%d+%d\n", dw,dh,dx,dy)); - pPPriv->ov_win.x = dx; - pPPriv->ov_win.y = dy; - pPPriv->ov_win.width = dw; - pPPriv->ov_win.height = dh; - pPPriv->ov_win.flags = 0; + pPPriv->rgb_win.x = dx; + pPPriv->rgb_win.y = dy; + pPPriv->rgb_win.width = dw; + pPPriv->rgb_win.height = dh; + pPPriv->rgb_win.flags = 0; /* clipping */ - if (pPPriv->ov_win.clips) { - xfree(pPPriv->ov_win.clips); - pPPriv->ov_win.clips = NULL; + if (pPPriv->rgb_win.clips) { + xfree(pPPriv->rgb_win.clips); + pPPriv->rgb_win.clips = NULL; } - pPPriv->ov_win.clipcount = REGION_NUM_RECTS(clipBoxes); + pPPriv->rgb_win.clipcount = REGION_NUM_RECTS(clipBoxes); DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2," clip: have #%d\n", - pPPriv->ov_win.clipcount)); - if (0 != pPPriv->ov_win.clipcount) { - pPPriv->ov_win.clips = xalloc(pPPriv->ov_win.clipcount*sizeof(struct video_clip)); - memset(pPPriv->ov_win.clips,0,pPPriv->ov_win.clipcount*sizeof(struct video_clip)); + pPPriv->rgb_win.clipcount)); + if (0 != pPPriv->rgb_win.clipcount) { + pPPriv->rgb_win.clips = xalloc(pPPriv->rgb_win.clipcount*sizeof(struct video_clip)); + memset(pPPriv->rgb_win.clips,0,pPPriv->rgb_win.clipcount*sizeof(struct video_clip)); pBox = REGION_RECTS(clipBoxes); - clip = pPPriv->ov_win.clips; + clip = pPPriv->rgb_win.clips; for (i = 0; i < REGION_NUM_RECTS(clipBoxes); i++, pBox++, clip++) { clip->x = pBox->x1 - dx; clip->y = pBox->y1 - dy; @@ -257,20 +426,21 @@ V4lPutVideo(ScrnInfoPtr pScrn, } } - /* Open a file handle to the device */ - - if (!pPPriv->VideoOn) { - if (V4lOpenDevice(pPPriv, pScrn)) - return BadAccess; - pPPriv->VideoOn = 1; - } - /* start */ - - if (-1 == ioctl(pPPriv->fd,VIDIOCSWIN,&(pPPriv->ov_win))) + if (VIDEO_RGB != pPPriv->VideoOn) { + if (-1 == ioctl(pPPriv->fd,VIDIOCSFBUF,&(pPPriv->rgb_fbuf))) + perror("ioctl VIDIOCSFBUF"); + if (-1 == ioctl(pPPriv->fd,VIDIOCGPICT,&pPPriv->pict)) + perror("ioctl VIDIOCGPICT"); + pPPriv->pict.palette = pPPriv->rgbpalette; + if (-1 == ioctl(pPPriv->fd,VIDIOCSPICT,&pPPriv->pict)) + perror("ioctl VIDIOCSPICT"); + } + if (-1 == ioctl(pPPriv->fd,VIDIOCSWIN,&(pPPriv->rgb_win))) perror("ioctl VIDIOCSWIN"); if (-1 == ioctl(pPPriv->fd, VIDIOCCAPTURE, &one)) perror("ioctl VIDIOCCAPTURE(1)"); + pPPriv->VideoOn = VIDEO_RGB; return Success; } @@ -295,18 +465,34 @@ V4lStopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit) PortPrivPtr pPPriv = (PortPrivPtr) data; int zero=0; - if (!pPPriv->VideoOn) { + if (VIDEO_OFF == pPPriv->VideoOn) { DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/StopVideo called with video already off\n")); return; } - DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/StopVideo\n")); - - if (-1 == ioctl(pPPriv->fd, VIDIOCCAPTURE, &zero)) - perror("ioctl VIDIOCCAPTURE(0)"); - - V4lCloseDevice(pPPriv); - pPPriv->VideoOn = 0; + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/StopVideo exit=%d\n",exit)); + + if (!exit) { + /* just reclipping, we have to stop DMA transfers to the visible screen */ + if (VIDEO_RGB == pPPriv->VideoOn) { + if (-1 == ioctl(pPPriv->fd, VIDIOCCAPTURE, &zero)) + perror("ioctl VIDIOCCAPTURE(0)"); + pPPriv->VideoOn = VIDEO_RECLIP; + } + } else { + /* video stop - turn off and free everything */ + if (VIDEO_YUV == pPPriv->VideoOn) { + pPPriv->myfmt->stop(pPPriv->surface); + pPPriv->myfmt->free_surface(pPPriv->surface); + xfree(pPPriv->surface); + pPPriv->surface = NULL; + } + if (-1 == ioctl(pPPriv->fd, VIDIOCCAPTURE, &zero)) + perror("ioctl VIDIOCCAPTURE(0)"); + + V4lCloseDevice(pPPriv); + pPPriv->VideoOn = VIDEO_OFF; + } } /* v4l uses range 0 - 65535; Xv uses -1000 - 1000 */ @@ -333,12 +519,12 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, struct video_channel chan; int ret = Success; - DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/SPA %d, %d\n", - attribute, value)); - if (V4lOpenDevice(pPPriv, pScrn)) return BadAccess; + DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/SPA %d, %d\n", + attribute, value)); + if (-1 == pPPriv->fd) { ret = Success /* FIXME: EBUSY/ENODEV ?? */; } else if (attribute == xvEncoding) { @@ -370,8 +556,9 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, pPPriv->audio.flags |= VIDEO_AUDIO_MUTE; else pPPriv->audio.flags &= ~VIDEO_AUDIO_MUTE; - } else if (attribute == xvVolume && (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME)) { - pPPriv->audio.volume = xv_to_v4l(value); + } else if (attribute == xvVolume) { + if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME) + pPPriv->audio.volume = xv_to_v4l(value); } else { ret = BadValue; } @@ -381,6 +568,10 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, } else if (attribute == xvFreq) { if (-1 == ioctl(pPPriv->fd,VIDIOCSFREQ,&value)) perror("ioctl VIDIOCSFREQ"); + } else if (pPPriv->have_yuv && + pPPriv->myfmt->setAttribute) { + /* not mine -> pass to yuv scaler driver */ + ret = pPPriv->myfmt->setAttribute(pScrn, attribute, value); } else { ret = BadValue; } @@ -417,13 +608,18 @@ V4lGetPortAttribute(ScrnInfoPtr pScrn, ioctl(pPPriv->fd,VIDIOCGAUDIO,&pPPriv->audio); if (attribute == xvMute) { *value = (pPPriv->audio.flags & VIDEO_AUDIO_MUTE) ? 1 : 0; - } else if (attribute == xvVolume && (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME)) { - *value = v4l_to_xv(pPPriv->audio.volume); + } else if (attribute == xvVolume) { + if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME) + *value = v4l_to_xv(pPPriv->audio.volume); } else { ret = BadValue; } } else if (attribute == xvFreq) { ioctl(pPPriv->fd,VIDIOCGFREQ,value); + } else if (pPPriv->have_yuv && + pPPriv->myfmt->getAttribute) { + /* not mine -> pass to yuv scaler driver */ + ret = pPPriv->myfmt->getAttribute(pScrn, attribute, value); } else { ret = BadValue; } @@ -444,8 +640,13 @@ V4lQueryBestSize(ScrnInfoPtr pScrn, Bool motion, int maxx = pPPriv->enc[pPPriv->cenc].width; int maxy = pPPriv->enc[pPPriv->cenc].height; - *p_w = (drw_w < maxx) ? drw_w : maxx; - *p_h = (drw_h < maxy) ? drw_h : maxy; + if (pPPriv->have_yuv) { + *p_w = pPPriv->myfmt->max_width; + *p_h = pPPriv->myfmt->max_height; + } else { + *p_w = (drw_w < maxx) ? drw_w : maxx; + *p_h = (drw_h < maxy) ? drw_h : maxy; + } DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv/BS %d %dx%d %dx%d\n", pPPriv->cenc,drw_w,drw_h,*p_w,*p_h)); @@ -467,32 +668,28 @@ V4LIdentify(int flags) static char* fixname(char *str) { - int s,d; - for (s=0, d=0;; s++) { - if (str[s] == '-') - continue; - str[d++] = tolower(str[s]); - if (0 == str[s]) - break; - } - return str; + int s,d; + for (s=0, d=0;; s++) { + if (str[s] == '-') + continue; + str[d++] = tolower(str[s]); + if (0 == str[s]) + break; + } + return str; } static XF86VideoEncodingPtr -V4LBuildEncodings(int fd, int *count) +V4LBuildEncodings(int fd, int *count, int channels) { - static struct video_capability cap; static struct video_channel channel; XF86VideoEncodingPtr enc; int i; - if (-1 == ioctl(fd,VIDIOCGCAP,&cap)) - return NULL; - - enc = xalloc(sizeof(XF86VideoEncodingRec)*3*cap.channels); - memset(enc,0,sizeof(XF86VideoEncodingRec)*3*cap.channels); + enc = xalloc(sizeof(XF86VideoEncodingRec)*3*channels); + memset(enc,0,sizeof(XF86VideoEncodingRec)*3*channels); - for (i = 0; i < 3*cap.channels; ) { + for (i = 0; i < 3*channels; ) { channel.channel = i/3; if (-1 == ioctl(fd,VIDIOCGCHAN,&channel)) { perror("ioctl VIDIOCGCHAN"); @@ -533,38 +730,28 @@ V4LBuildEncodings(int fd, int *count) return enc; } - -static XF86AttributeRec Attributes[8] = { - {XvSettable | XvGettable, -1000, 1000, XV_ENCODING}, - {XvSettable | XvGettable, -1000, 1000, XV_BRIGHTNESS}, - {XvSettable | XvGettable, -1000, 1000, XV_CONTRAST}, - {XvSettable | XvGettable, -1000, 1000, XV_SATURATION}, - {XvSettable | XvGettable, -1000, 1000, XV_HUE}, - {XvSettable | XvGettable, -1000, 1000, XV_VOLUME}, - {XvSettable | XvGettable, 0, 1, XV_MUTE}, - {XvSettable | XvGettable, 0, 16*1000, XV_FREQ}, -}; - - static int V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors) { + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; PortPrivPtr pPPriv; DevUnion *Private; XF86VideoAdaptorPtr *VAR = NULL; XF86VideoEncodingPtr enc; - char dev[16]; - int fd,i,nenc; + char dev[18]; + int fd,i,j,nenc; DEBUG(xf86Msg(X_INFO, "v4l: init start\n")); for (i = 0; i < 4; i++) { - sprintf(dev,"/dev/video%d",i); + sprintf(dev, "/dev/video%d", i); fd = open(dev, O_RDWR, 0); - if (fd == -1) - break; - if (NULL == (enc = V4LBuildEncodings(fd,&nenc))) - break; + if (fd == -1) { + sprintf(dev, "/dev/v4l/video%d", i); + fd = open(dev, O_RDWR, 0); + if (fd == -1) + break; + } DEBUG(xf86Msg(X_INFO, "v4l: %s ok\n",dev)); @@ -576,9 +763,44 @@ V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors) pPPriv->fd = -1; strncpy(pPPriv->devname, dev, 16); pPPriv->useCount=0; + + /* check device */ + if (-1 == ioctl(fd,VIDIOCGCAP,&pPPriv->cap) || + NULL == (enc = V4LBuildEncodings + (fd,&nenc,pPPriv->cap.channels))) { + xfree(pPPriv); + break; + } pPPriv->enc = enc; pPPriv->nenc = nenc; +#if 1 + /* check for yuv (see if the driver accepts VIDEO_PALETTE_YUV422) */ + ioctl(fd,VIDIOCGPICT,&pPPriv->pict); + pPPriv->pict.palette = VIDEO_PALETTE_YUV422; + if (0 == ioctl(fd,VIDIOCSPICT,&pPPriv->pict)) { + ioctl(fd,VIDIOCGPICT,&pPPriv->pict); + if (VIDEO_PALETTE_YUV422 == pPPriv->pict.palette) { + /* works, check screen capabilities */ + DEBUG(xf86Msg(X_INFO, "v4l: kernel driver supports yuv422.\n")); + pPPriv->format = xf86XVQueryOffscreenImages + (pScreen,&pPPriv->nformat); + DEBUG(xf86Msg(X_INFO, "v4l: screen driver supports %d yuv formats (%p)\n", + pPPriv->nformat,pPPriv->format)); + for (j = 0; j < pPPriv->nformat; j++) { + DEBUG(xf86Msg(X_INFO, "v4l: yuv format: %4.4s\n", + (char*)&(pPPriv->format[j].image->id))); + if (pPPriv->format[j].image->id == 0x32595559 && + pPPriv->format[j].image->format == XvPacked) { + pPPriv->have_yuv = 1; + pPPriv->myfmt = pPPriv->format+j; + DEBUG(xf86Msg(X_INFO, "v4l: matching format found, offscreen yuv enabled.\n")); + } + } + } + } +#endif + /* alloc VideoAdaptorRec */ VAR = xrealloc(VAR,sizeof(XF86VideoAdaptorPtr)*(i+1)); VAR[i] = xalloc(sizeof(XF86VideoAdaptorRec)); @@ -587,8 +809,18 @@ V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors) memset(VAR[i],0,sizeof(XF86VideoAdaptorRec)); /* add attribute lists */ - VAR[i]->nAttributes = 8; - VAR[i]->pAttributes = Attributes; + if (pPPriv->have_yuv) { + VAR[i]->nAttributes = V4L_ATTR + pPPriv->myfmt->num_attributes; + VAR[i]->pAttributes = xalloc(VAR[i]->nAttributes * + sizeof(XF86AttributeRec)); + memcpy(VAR[i]->pAttributes, Attributes, + sizeof(XF86AttributeRec) * V4L_ATTR); + memcpy(VAR[i]->pAttributes+V4L_ATTR, pPPriv->myfmt->attributes, + sizeof(XF86AttributeRec) * pPPriv->myfmt->num_attributes); + } else { + VAR[i]->nAttributes = V4L_ATTR; + VAR[i]->pAttributes = Attributes; + } /* hook in private data */ Private = xalloc(sizeof(DevUnion)); @@ -616,6 +848,27 @@ V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors) VAR[i]->nFormats = sizeof(InputVideoFormats) / sizeof(InputVideoFormats[0]); VAR[i]->pFormats = InputVideoFormats; + + /* Check whether we have VIDEO_AUDIO_VOLUME */ + if (!ioctl(pPPriv->fd,VIDIOCGAUDIO,&pPPriv->audio) && + pPPriv->audio.flags & VIDEO_AUDIO_VOLUME) { + XF86AttributeRec *oldattrs = VAR[i]->pAttributes; + int nattrs = VAR[i]->nAttributes; + + DEBUG(xf86Msg(X_INFO, "v4l: Volume supported, adding XV_VOLUME to attribute list\n")); + + VAR[i]->pAttributes = xalloc((nattrs + 1) * + sizeof(XF86AttributeRec)); + memcpy(VAR[i]->pAttributes, oldattrs, + sizeof(XF86AttributeRec) * nattrs); + memcpy(VAR[i]->pAttributes+nattrs, &VolumeAttr, + sizeof(XF86AttributeRec)); + VAR[i]->nAttributes++; + } else { + DEBUG(xf86Msg(X_INFO, "v4l: Volume not supported\n")); + } + + if (fd != -1) close(fd); } @@ -640,8 +893,9 @@ static Bool V4LProbe(DriverPtr drv, int flags) { if (flags & PROBE_DETECT) - return FALSE; + return TRUE; xf86XVRegisterGenericAdaptorDriver(V4LInit); + drv->refCount++; return TRUE; } diff --git a/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp b/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp index a2bf9f4b3..fb06a6567 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp +++ b/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp @@ -1,17 +1,17 @@ -.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp,v 1.1 2000/03/03 01:05:45 dawes Exp $ -.TH V4L __drivermansuffix__ "Version 4.0" "XFree86" +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.cpp,v 1.4 2000/06/14 02:13:16 dawes Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH V4L __drivermansuffix__ "Version 4.0.1" "XFree86" .SH NAME v4l \- Video 4 Linux driver .SH SYNOPSIS -.B "Section ""Device""" -.br -.BI " Identifier """ devname """" -.br -.B " Driver ""v4l""" -.br +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qv4l\*q" \ \ ... -.br .B EndSection +.fi .SH DESCRIPTION .B v4l is an XFree86 driver for Video 4 Linux. @@ -25,6 +25,6 @@ Please refer to XF86Config(__filemansuffix__) for general configuration details. This section only covers configuration details specific to this driver. .SH "SEE ALSO" -XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(1) +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) .SH AUTHORS Authors include: ... |