Hi, I finally found some time to go over the v4l patch. I've cleaned it up a bit (move yuv detection stuff into a function, loop instead of cut+paste, ...). It survived the ItWorksForMe[tm] test, but I'd like to know whenever it still works for the dvb people before I send it the way to the xfree86 cvs ... Gerd ==============================[ cut here ]============================== diff -ur /home/my-cvs/xfree86/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c --- /home/my-cvs/xfree86/xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c Thu Nov 1 12:23:10 2001 +++ xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c Fri Mar 1 12:22:50 2002 @@ -132,7 +132,7 @@ XF86OffscreenImagePtr format; /* list */ int nformat; /* # if list entries */ XF86OffscreenImagePtr myfmt; /* which one is YUY2 (packed) */ - int have_yuv; + int yuv_format; int yuv_width,yuv_height; XF86SurfacePtr surface; @@ -286,7 +286,7 @@ return Success; } - if (pPPriv->have_yuv) { + if (0 != pPPriv->yuv_format) { 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 */ @@ -338,7 +338,7 @@ perror("ioctl VIDIOCSFBUF"); if (-1 == ioctl(V4L_FD,VIDIOCGPICT,&pPPriv->pict)) perror("ioctl VIDIOCGPICT"); - pPPriv->pict.palette = VIDEO_PALETTE_YUV422; + pPPriv->pict.palette = pPPriv->yuv_format; pPPriv->pict.depth = 16; if (-1 == ioctl(V4L_FD,VIDIOCSPICT,&pPPriv->pict)) perror("ioctl VIDIOCSPICT"); @@ -585,7 +585,7 @@ } else if (attribute == xvFreq) { if (-1 == ioctl(V4L_FD,VIDIOCSFREQ,&value)) perror("ioctl VIDIOCSFREQ"); - } else if (pPPriv->have_yuv && + } else if (0 != pPPriv->yuv_format && pPPriv->myfmt->setAttribute) { /* not mine -> pass to yuv scaler driver */ ret = pPPriv->myfmt->setAttribute(pScrn, attribute, value); @@ -636,7 +636,7 @@ } } else if (attribute == xvFreq) { ioctl(V4L_FD,VIDIOCGFREQ,value); - } else if (pPPriv->have_yuv && + } else if (0 != pPPriv->yuv_format && pPPriv->myfmt->getAttribute) { /* not mine -> pass to yuv scaler driver */ ret = pPPriv->myfmt->getAttribute(pScrn, attribute, value); @@ -660,7 +660,7 @@ int maxx = pPPriv->enc[pPPriv->cenc].width; int maxy = pPPriv->enc[pPPriv->cenc].height; - if (pPPriv->have_yuv) { + if (0 != pPPriv->yuv_format) { *p_w = pPPriv->myfmt->max_width; *p_h = pPPriv->myfmt->max_height; } else { @@ -838,10 +838,54 @@ (*count)++; } +/* setup yuv overlay + hw scaling: look if we find some common video + format which both v4l driver and the X-Server can handle */ +static void v4l_check_yuv(ScrnInfoPtr pScrn, PortPrivPtr pPPriv, + char *dev, int fd) +{ + static const struct { + unsigned int v4l_palette; + unsigned int v4l_depth; + unsigned int xv_id; + unsigned int xv_format; + } yuvlist[] = { + { VIDEO_PALETTE_YUV422, 16, 0x32595559, XvPacked }, + { VIDEO_PALETTE_UYVY, 16, 0x59565955, XvPacked }, + { 0 /* end of list */ }, + }; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + int fmt,i; + + pPPriv->format = xf86XVQueryOffscreenImages(pScreen,&pPPriv->nformat); + for (fmt = 0; yuvlist[fmt].v4l_palette != 0; fmt++) { + /* check v4l ... */ + ioctl(fd,VIDIOCGPICT,&pPPriv->pict); + pPPriv->pict.palette = yuvlist[fmt].v4l_palette; + pPPriv->pict.depth = yuvlist[fmt].v4l_depth; + if (-1 == ioctl(fd,VIDIOCSPICT,&pPPriv->pict)) + continue; + ioctl(fd,VIDIOCGPICT,&pPPriv->pict); + if (pPPriv->pict.palette != yuvlist[fmt].v4l_palette) + continue; + /* ... works, check available offscreen image formats now ... */ + for (i = 0; i < pPPriv->nformat; i++) { + if (pPPriv->format[i].image->id == yuvlist[fmt].xv_id && + pPPriv->format[i].image->format == yuvlist[fmt].xv_format) { + /* ... match found, good. */ + pPPriv->yuv_format = yuvlist[fmt].v4l_palette; + pPPriv->myfmt = pPPriv->format+i; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "v4l[%s]: using hw video scaling [%4.4s].\n", + dev,(char*)&(pPPriv->format[i].image->id)); + return; + } + } + } +} + static int V4LInit(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr **adaptors) { - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; PortPrivPtr pPPriv; DevUnion *Private; XF86VideoAdaptorPtr *VAR = NULL; @@ -880,35 +924,7 @@ V4LBuildEncodings(pPPriv,fd,pPPriv->cap.channels); if (NULL == pPPriv->enc) return FALSE; - -#if 1 - /* test v4l device for yuv support: check if the driver - accepts VIDEO_PALETTE_YUV422 */ - ioctl(fd,VIDIOCGPICT,&pPPriv->pict); - pPPriv->pict.palette = VIDEO_PALETTE_YUV422; - pPPriv->pict.depth = 16; - 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 + v4l_check_yuv(pScrn,pPPriv,dev,fd); /* alloc VideoAdaptorRec */ VAR = xrealloc(VAR,sizeof(XF86VideoAdaptorPtr)*(i+1)); @@ -938,7 +954,7 @@ v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes, &FreqAttr); } - if (pPPriv->have_yuv) { + if (0 != pPPriv->yuv_format) { /* pass throuth scaler attributes */ for (j = 0; j < pPPriv->myfmt->num_attributes; j++) { v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes,