#include #include #include #include #include extern const char *__progname; #include "readloop-cvt.h" #include "readloop-X.h" 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 long int *imgdata; static XImage *img; static unsigned int (*rgb_to_pixel)(RGB); static int rshift; static int gshift; static int bshift; 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(640*480*4); img = XCreateImage(disp,visinfo.visual,depth,ZPixmap,0,(void *)imgdata,640,480,32,640*4); img->byte_order = LSBFirst; img->bitmap_unit = 32; img->bitmap_bit_order = LSBFirst; img->bitmap_pad = 32; } 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,640,480,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(void) { disp = XOpenDisplay(0); if (disp == 0) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } 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); } void display_frame(const unsigned char *dbuf) { int x; int y; unsigned long int *ip; ip = imgdata; for (y=0;y<480-1;y++) { for (x=0;x<640;x+=2) { *ip++ = (*rgb_to_pixel)(cvt_YCbCr_to_RGB(dbuf[0],dbuf[1],dbuf[3])); *ip++ = (*rgb_to_pixel)(cvt_YCbCr_to_RGB(dbuf[2],dbuf[1],dbuf[3])); dbuf += 4; } } for (x=0;x<128;x++) *ip++ = (*rgb_to_pixel)((RGB){.r=x*2,.g=0,.b=0}); for (x=0;x<128;x++) *ip++ = (*rgb_to_pixel)((RGB){.r=0,.g=x*2,.b=0}); for (x=0;x<128;x++) *ip++ = (*rgb_to_pixel)((RGB){.r=0,.g=0,.b=x*2}); for (x=128*3;x<640;x++) *ip++ = (*rgb_to_pixel)((RGB){.r=0,.g=0,.b=0}); await_ping(); XPutImage(disp,win,gc,img,0,0,0,0,640,480); ping_myself(); XFlush(disp); }