Source

hakanardo / video / xvview.c

Full commit
Hakan Ardo edbd398 






























































































































































































































#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xvlib.h>
#include <X11/keysym.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>


/* ok the following constant should be by right included thru in Xvlib.h */
#ifndef XV_YV12
#define XV_YV12 0x32315659
#endif

#ifndef XV_YUY2
#define XV_YUY2 0x32595559
#endif

#ifndef XV_UYVY
#define XV_UYVY 0x59565955
#endif


#define RGB2YUV(r, g, b, y, u, v)\
  y = (9798*r + 19235*g + 3736*b)  / 32768;\
  u = (-4784*r - 9437*g + 14221*b)  / 32768 + 128;\
  v = (20218*r - 16941*g - 3277*b) / 32768 + 128;\
  y = y < 0 ? 0 : y;\
  u = u < 0 ? 0 : u;\
  v = v < 0 ? 0 : v;\
  y = y > 255 ? 255 : y;\
  u = u > 255 ? 255 : u;\
  v = v > 255 ? 255 : v

static inline
void rgb2yuy2 (unsigned char *RGB, unsigned char *YUV, int NumPixels) {
  int i, j;
  register int y0, y1, u0, u1, v0, v1 ;
  register int r, g, b;

  for (i = 0, j = 0; i < 3 * NumPixels; i += 6, j += 4)
    {
      r = RGB[i + 0];
      g = RGB[i + 1];
      b = RGB[i + 2];
      RGB2YUV (r, g, b, y0, u0 , v0);
      r = RGB[i + 3];
      g = RGB[i + 4];
      b = RGB[i + 5];
      RGB2YUV (r, g, b, y1, u1 , v1);
      YUV[j + 0] = y0;
      YUV[j + 1] = (u0+u1)/2;
      YUV[j + 2] = y1;
      YUV[j + 3] = (v0+v1)/2;
    }
}

static inline
void bgr2yuy2 (unsigned char *RGB, unsigned char *YUV, int NumPixels) {
  int i, j;
  register int y0, y1, u0, u1, v0, v1 ;
  register int r, g, b;

  for (i = 0, j = 0; i < 3 * NumPixels; i += 6, j += 4)
    {
      r = RGB[i + 2];
      g = RGB[i + 1];
      b = RGB[i + 0];
      RGB2YUV (r, g, b, y0, u0 , v0);
      r = RGB[i + 5];
      g = RGB[i + 4];
      b = RGB[i + 3];
      RGB2YUV (r, g, b, y1, u1 , v1);
      YUV[j + 0] = y0;
      YUV[j + 1] = (u0+u1)/2;
      YUV[j + 2] = y1;
      YUV[j + 3] = (v0+v1)/2;
    }
}

static inline
void yuv2yuy2 (unsigned char *YUV, unsigned char *YUV2, int NumPixels) {
  int i, j;
  //register int y0, y1, u0, u1, v0, v1 ;
  //register int r, g, b;

  for (i = 0, j = 0; i < 3 * NumPixels; i += 6, j += 4)
    {
      YUV2[j + 0] = YUV[i+2];
      YUV2[j + 1] = (YUV[i+1]+YUV[i+4])/2;
      YUV2[j + 2] = YUV[i+5];
      YUV2[j + 3] = (YUV[i+0]+YUV[i+3])/2;
    }
}

static inline
void y2yuy2 (unsigned char *Y, unsigned char *YUV2, int NumPixels) {
  int i, j;
  //register int y0, y1, u0, u1, v0, v1 ;
  //register int r, g, b;

  for (i = 0, j = 0; i < NumPixels; i += 2, j += 4)
    {
      YUV2[j + 0] = Y[i+0];
      YUV2[j + 1] = 127;
      YUV2[j + 2] = Y[i+1];
      YUV2[j + 3] = 127;
    }
}

int xvview(int w, int h, char *data, int color, char typecode) {
  static Display *display=NULL;
  static int adaptor=-1;
  static XvAdaptorInfo *info;
  static const long format=XV_YUY2;
  static unsigned char  *frame_buffer;

  static Window window;
  static XvImage *xv_image;
  static GC gc;
  static XShmSegmentInfo Shminfo;
  static XGCValues xgcv;

  static int paused = 0;

  if (!display) {
    int num_adaptors;
    int num_formats;
    XvImageFormatValues *formats=NULL;
    int i,j;
    char xv_name[5];

    display=XOpenDisplay(getenv("DISPLAY"));
    if(display==NULL) {
      fprintf(stderr, "Could not open display \"%s\"\n",getenv("DISPLAY"));
      return 0;
    }
  
    XvQueryAdaptors(display,DefaultRootWindow(display),&num_adaptors,&info);
        
    for(i=0;i<num_adaptors;i++) {
      formats=XvListImageFormats(display,info[i].base_id,&num_formats);
      for(j=0;j<num_formats;j++) {
	xv_name[4]=0;
	memcpy(xv_name,&formats[j].id,4);
	if(formats[j].id==format) {
	  fprintf(stderr, "using Xv format 0x%x %s %s\n",formats[j].id,xv_name,
		 (formats[j].format==XvPacked)?"packed":"planar");
	  if(adaptor<0)adaptor=i;
	}
      }
    }
    XFree(formats);
    if(adaptor<0) {
      fprintf(stderr, "No suitable Xv adaptor found"); 
      return 0;
    }

    long background=0x010203;

    frame_buffer=(unsigned char *)malloc(w*h*2);
    window=XCreateSimpleWindow(display,DefaultRootWindow(display),0,0,
			       w,h,0,
			       WhitePixel(display,DefaultScreen(display)),
			       background);
    XSelectInput(display,window,
		 StructureNotifyMask|KeyPressMask|ButtonPressMask);
    XMapWindow(display,window);
    gc=XCreateGC(display,window,0,&xgcv);
    if (!XShmQueryExtension(display)) 
      fprintf(stderr,"Shared memory not supported\n");

    Atom att=XInternAtom(display, "XV_SET_DEFAULTS", True);
    if (att!=None) XvSetPortAttribute(display,info[adaptor].base_id,att,1);
    xv_image = (XvImage *) XvShmCreateImage(display, info[adaptor].base_id, 
					    format, NULL, w, h, &Shminfo);
    Shminfo.shmid    = shmget(IPC_PRIVATE, xv_image->data_size, 
			      IPC_CREAT | 0777);
    Shminfo.shmaddr  = (char *) shmat(Shminfo.shmid, 0, 0);
    Shminfo.readOnly = False;
    xv_image->data = Shminfo.shmaddr;
    XShmAttach(display, &Shminfo);
    XSync(display, False);
    shmctl(Shminfo.shmid, IPC_RMID, 0);
  }

  if (color && typecode == 'B') {
    rgb2yuy2(data, xv_image->data, w*h);
  } else if (!color && typecode == 'B') {
    y2yuy2(data, xv_image->data, w*h);
  } else {
    fprintf(stderr, "Unknown image format: %c color=%d\n", typecode, color);
    return 0;
  }

  XvShmPutImage(display,info[adaptor].base_id,window,gc,xv_image,
		0,0,w,h,
		0,0,w,h,
		False);
  XFlush(display);
  
  XEvent xev;
  do {
    while(XPending(display)>0) {
      XNextEvent(display,&xev);
      if (xev.type == KeyPress) {
	char key[1];
	XLookupString(&xev.xkey, key, 1, NULL, NULL);
	if (key[0]==' ') paused=~paused;
	else if (key[0] == 27) exit(0);
      } else if (xev.type == ButtonPress) {
	if (xev.xbutton.button==1) 
	  printf("Click: (%d,%d)\n",xev.xbutton.x,xev.xbutton.y);
      }
    }
  } while (paused);

  
  return 1;
}