#include #include #include #include #include #include extern const char *__progname; #include "ycbcr-rgb-cvt.h" #include "display-X.h" static unsigned int ixsize; static unsigned int iysize; static unsigned int dxsize; static unsigned int dysize; static DX_FMT fmt; static unsigned int rot; static Display *disp; static Screen *scr; static int depth; static Window rootwin; static Colormap wincmap; static int defcmap; static GC gc; static XVisualInfo visinfo; static Window win; static unsigned int *imgdata; static XImage *img; static unsigned int (*rgb_to_pixel)(RGB); static int rshift; static int gshift; static int bshift; static void (*overlay)(void *, XImage *); static void *overlay_cookie; static unsigned int rgb_to_pixel_24rgb(RGB rgb) { return((rgb.r*0x010000)+(rgb.g*0x0100)+rgb.b); } static unsigned int rgb_to_pixel_24bgr(RGB rgb) { return((rgb.b*0x010000)+(rgb.g*0x0100)+rgb.r); } static unsigned int rgb_to_pixel_8bgr(RGB rgb) { return((rgb.b&0xc0)+((rgb.g>>2)&0x38)+(rgb.r>>5)); } static unsigned int rgb_to_pixel_general(RGB rgb) { return( (((rshift < 0) ? (rgb.r << -rshift) : (rgb.r >> rshift)) & visinfo.red_mask) | (((gshift < 0) ? (rgb.g << -gshift) : (rgb.g >> gshift)) & visinfo.green_mask) | (((bshift < 0) ? (rgb.b << -bshift) : (rgb.b >> bshift)) & visinfo.blue_mask) ); } static int mask_to_shift(unsigned int mask) { unsigned int s; if (mask < 0x80) { for (s=1;(mask<>s)>0xff;s++) ; return(s); } static void find_visual(void) { XVisualInfo *xvi; int nvi; XVisualInfo template; int i; int best; int best_onscr; template.class = TrueColor; xvi = XGetVisualInfo(disp,VisualClassMask,&template,&nvi); best = -1; best_onscr = -1; for (i=0;i xvi[best_onscr].depth) || ( (xvi[i].depth == xvi[best_onscr].depth) && (xvi[i].visual == XDefaultVisual(disp,xvi[i].screen)) ) ) { best_onscr = i; } } if ( (best < 0) || (xvi[i].depth > xvi[best].depth) || ( (xvi[i].depth == xvi[best].depth) && (xvi[i].visual == XDefaultVisual(disp,xvi[i].screen)) ) ) { best = i; } } if (best < 0) { fprintf(stderr,"%s: no TrueColor visual available\n",__progname); exit(1); } if (best_onscr < 0) { fprintf(stderr,"%s: no TrueColor visual on screen %d, using screen %d\n",__progname,XDefaultScreen(disp),xvi[best].screen); } else { best = best_onscr; } visinfo = xvi[best]; if ( (visinfo.red_mask == 0x00ff0000) && (visinfo.green_mask == 0x0000ff00) && (visinfo.blue_mask == 0x000000ff) ) { rgb_to_pixel = &rgb_to_pixel_24rgb; } else if ( (visinfo.red_mask == 0x000000ff) && (visinfo.green_mask == 0x0000ff00) && (visinfo.blue_mask == 0x00ff0000) ) { rgb_to_pixel = &rgb_to_pixel_24bgr; } else if ( (visinfo.red_mask == 0x07) && (visinfo.green_mask == 0x38) && (visinfo.blue_mask == 0xc0) ) { rgb_to_pixel = &rgb_to_pixel_8bgr; } else { rgb_to_pixel = &rgb_to_pixel_general; rshift = mask_to_shift(visinfo.red_mask); gshift = mask_to_shift(visinfo.green_mask); bshift = mask_to_shift(visinfo.blue_mask); } } static void setup_gc(void) { if (depth == XDefaultDepthOfScreen(scr)) { gc = XDefaultGCOfScreen(scr); } else { Pixmap p; p = XCreatePixmap(disp,rootwin,1,1,depth); gc = XCreateGC(disp,p,0,0); XFreePixmap(disp,p); } } static void setup_cmap(void) { if (visinfo.visual == XDefaultVisualOfScreen(scr)) { wincmap = XDefaultColormapOfScreen(scr); defcmap = 1; } else { wincmap = XCreateColormap(disp,rootwin,visinfo.visual,AllocNone); defcmap = 0; } } static void setup_image(void) { imgdata = malloc(dxsize*dysize*4); img = XCreateImage(disp,visinfo.visual,depth,ZPixmap,0,(void *)imgdata,dxsize,dysize,32,dxsize*4); } static void setup_window(void) { unsigned long int attrmask; XSetWindowAttributes attr; attrmask = 0; attr.background_pixel = ~0U; attrmask |= CWBackPixel; attr.border_pixel = 0; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = 0; attrmask |= CWEventMask; attr.colormap = wincmap; attrmask |= CWColormap; win = XCreateWindow(disp,rootwin,0,0,dxsize,dysize,0,depth,InputOutput,visinfo.visual,attrmask,&attr); XMapRaised(disp,win); } static void ping_myself(void) { XEvent e; e.type = ClientMessage; e.xclient.send_event = True; e.xclient.window = win; e.xclient.message_type = XA_X_HEIGHT; e.xclient.format = 8; XSendEvent(disp,win,False,0,&e); } static void await_ping(void) { XEvent e; do { XNextEvent(disp,&e); } while (e.type != ClientMessage); } void setup_X(unsigned int x, unsigned int y, DX_FMT f, unsigned int flags, ...) { va_list ap; ixsize = x; iysize = y; fmt = f; switch (f) { case DX_FMT_RGB888: break; case DX_FMT_YCbCr422: if (x & 1) { fprintf(stderr,"%s: 4:2:2 with odd width\n",__progname); exit(1); } break; default: fprintf(stderr,"%s: unknown image format\n",__progname); exit(1); break; } rot = flags & DXF_ROT_MASK; switch (rot) { case DXF_ROT_NONE: case DXF_ROT_180: dxsize = ixsize; dysize = iysize; break; case DXF_ROT_CW: case DXF_ROT_CCW: dxsize = iysize; dysize = ixsize; break; default: abort(); break; } disp = XOpenDisplay(0); if (disp == 0) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } va_start(ap,flags); if (flags & DXF_OVERLAY) { overlay = va_arg(ap,__typeof__(void (*)(void *, XImage *))); overlay_cookie = va_arg(ap,void *); } else { overlay = 0; } va_end(ap); find_visual(); scr = XScreenOfDisplay(disp,visinfo.screen); depth = visinfo.depth; rootwin = XRootWindowOfScreen(scr); setup_gc(); setup_cmap(); setup_image(); setup_window(); ping_myself(); XFlush(disp); } static void copy_data_rgb888_none(const unsigned char *dbuf) { int x; int y; for (y=0;y=0;y--) { for (x=ixsize-1;x>=0;x--) { XPutPixel(img,x,y,(*rgb_to_pixel)((RGB){.r=dbuf[0],.g=dbuf[1],.b=dbuf[2]})); dbuf += 3; } } } static void copy_data_rgb888_ccw(const unsigned char *dbuf) { int x; int y; for (y=0;y=0;y--) { for (x=ixsize-2;x>=0;x-=2) { XPutPixel(img,x,y,(*rgb_to_pixel)(cvt_YCbCr_to_RGB(dbuf[0],dbuf[1],dbuf[3]))); XPutPixel(img,x+1,y,(*rgb_to_pixel)(cvt_YCbCr_to_RGB(dbuf[2],dbuf[1],dbuf[3]))); dbuf += 4; } } } static void copy_data_ycbcr422_ccw(const unsigned char *dbuf) { int x; int y; for (y=0;y