view libvo/vo_xv.c @ 732:e14114170e01

applied 'fakemono' patch by Bryan Chan scorpio@acm.org
author arpi_esp
date Tue, 08 May 2001 21:49:00 +0000
parents c3e0bdb64027
children 108ea5157cbc
line wrap: on
line source


#define NUM_BUFFERS 1

/*
 * vo_xv.c, X11 Xv interface
 *
 * Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved.
 *
 * Hacked into mpeg2dec by
 *
 * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
 *
 * Xv image suuport by Gerd Knorr <kraxel@goldbach.in-berlin.de>
 */

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

#include "config.h"
#include "video_out.h"
#include "video_out_internal.h"

LIBVO_EXTERN(xv)

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <errno.h>

#include "x11_common.h"

#include "fastmemcpy.h"
#include "sub.h"

static vo_info_t vo_info =
{
        "X11/Xv",
        "xv",
        "Gerd Knorr <kraxel@goldbach.in-berlin.de>",
        ""
};

/* since it doesn't seem to be defined on some platforms */
int XShmGetEventBase(Display*);

/* local data */
static unsigned char *ImageData;

/* X11 related variables */
static Display *mydisplay;
static Window mywindow;
static GC mygc;
static XImage *myximage;
static int depth, bpp, mode;
static XWindowAttributes attribs;

#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
// FIXME: dynamically allocate this stuff
static void allocate_xvimage(int);
static unsigned int ver,rel,req,ev,err;
static unsigned int formats, adaptors,i,xv_port,xv_format;
static XvAdaptorInfo        *ai;
static XvImageFormatValues  *fo;

static int current_buf=0;
static XvImage* xvimage[NUM_BUFFERS];

#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>

static int Shmem_Flag;
static int Quiet_Flag;
static XShmSegmentInfo Shminfo[NUM_BUFFERS];
static int gXErrorFlag;
static int CompletionType = -1;

static uint32_t image_width;
static uint32_t image_height;
static uint32_t image_format;

static Window                 mRoot;
static uint32_t               drwX,drwY,drwWidth,drwHeight,drwBorderWidth,drwDepth;
static uint32_t               drwcX,drwcY,dwidth,dheight,mFullscreen;

#ifdef HAVE_GUI
 static uint32_t               mdwidth,mdheight;
#endif

/*
 * connect to server, create and map window,
 * allocate colors and (shared) memory
 */
static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format)
{
 int screen;
 char *hello = (title == NULL) ? "Xv render" : title;
 char *name = ":0.0";
 XSizeHints hint;
 XVisualInfo vinfo;
 XEvent xev;

 XGCValues xgcv;
 XSetWindowAttributes xswa;
 unsigned long xswamask;

 image_height = height;
 image_width = width;
 image_format=format;

 mFullscreen=fullscreen;
 dwidth=d_width; dheight=d_height;

 if(getenv("DISPLAY")) name = getenv("DISPLAY");

 mydisplay = XOpenDisplay(name);

 if (mydisplay == NULL)
  {
   printf("Can't open display\n");
   return -1;
  }

 screen = DefaultScreen(mydisplay);

#ifdef HAVE_GUI
 if ( vo_window == None )
  {
#endif
   hint.x = 0;
   hint.y = 0;
   hint.width = d_width;
   hint.height = d_height;
   if ( fullscreen )
    {
     hint.width=vo_screenwidth;
     hint.height=vo_screenheight;
    }
   hint.flags = PPosition | PSize;
   XGetWindowAttributes(mydisplay, DefaultRootWindow(mydisplay), &attribs);
   depth=attribs.depth;
   if (depth != 15 && depth != 16 && depth != 24 && depth != 32) depth = 24;
   XMatchVisualInfo(mydisplay, screen, depth, TrueColor, &vinfo);

   xswa.background_pixel = 0;
   xswa.border_pixel     = 0;
   xswamask = CWBackPixel | CWBorderPixel;

   mywindow = XCreateWindow(mydisplay, RootWindow(mydisplay,screen),
   hint.x, hint.y, hint.width, hint.height,
   0, depth,CopyFromParent,vinfo.visual,xswamask,&xswa);
   vo_hidecursor(mydisplay,mywindow);

   XSelectInput(mydisplay, mywindow, StructureNotifyMask | KeyPressMask );
   XSetStandardProperties(mydisplay, mywindow, hello, hello, None, NULL, 0, &hint);
   if ( fullscreen ) vo_x11_decoration( mydisplay,mywindow,0 );
   XMapWindow(mydisplay, mywindow);
   XFlush(mydisplay);
   XSync(mydisplay, False);
#ifdef HAVE_GUI
  }
  else
    {
     mywindow=vo_window;
     mygc=vo_gc;
     if ( vo_screenwidth != d_width )
      {
       XMoveWindow( mydisplay,mywindow,( vo_screenwidth - d_width ) / 2,( vo_screenheight - d_height ) / 2 );
       XResizeWindow( mydisplay,mywindow,d_width,d_height );
      }
      else mFullscreen=1;
    }
#endif

 mygc = XCreateGC(mydisplay, mywindow, 0L, &xgcv);

 xv_port = 0;
 if (Success == XvQueryExtension(mydisplay,&ver,&rel,&req,&ev,&err))
  {
   /* check for Xvideo support */
   if (Success != XvQueryAdaptors(mydisplay,DefaultRootWindow(mydisplay), &adaptors,&ai))
    {
     printf("Xv: XvQueryAdaptors failed");
     return -1;
    }
   /* check adaptors */
   for (i = 0; i < adaptors; i++)
    {
     if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask) && (xv_port == 0)) xv_port = ai[i].base_id;
    }
   /* check image formats */
   if (xv_port != 0)
    {
     fo = XvListImageFormats(mydisplay, xv_port, (int*)&formats);
     xv_format=0;
     for(i = 0; i < formats; i++)
      {
       printf("Xvideo image format: 0x%x (%4.4s) %s\n", fo[i].id,(char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar");

       if (fo[i].id == format)
        {
         xv_format = fo[i].id;
        }
      }
     if (!xv_format) xv_port = 0;
    }

   if (xv_port != 0)
    {
     printf( "using Xvideo port %d for hw scaling\n",xv_port );

     for(current_buf=0;current_buf<NUM_BUFFERS;++current_buf)
       allocate_xvimage(current_buf);

     current_buf=0;

     XGetGeometry( mydisplay,mywindow,&mRoot,&drwX,&drwY,&drwWidth,&drwHeight,&drwBorderWidth,&drwDepth );
     drwX=0; drwY=0;
     XTranslateCoordinates( mydisplay,mywindow,mRoot,0,0,&drwcX,&drwcY,&mRoot );
     printf( "[xv] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",drwcX,drwcY,drwX,drwY,drwWidth,drwHeight );

     if ( mFullscreen )
      {
       drwX=( vo_screenwidth - (dwidth > vo_screenwidth?vo_screenwidth:dwidth) ) / 2;
       drwcX+=drwX;
       drwY=( vo_screenheight - (dheight > vo_screenheight?vo_screenheight:dheight) ) / 2;
       drwcY+=drwY;
       drwWidth=(dwidth > vo_screenwidth?vo_screenwidth:dwidth);
       drwHeight=(dheight > vo_screenheight?vo_screenheight:dheight);
       printf( "[xv-fs] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",drwcX,drwcY,drwX,drwY,drwWidth,drwHeight );
      }

     saver_off(mydisplay);  // turning off screen saver
     return 0;
    }
  }

 printf("Sorry, Xv not supported by this X11 version/driver\n");
 printf("******** Try with  -vo x11  or  -vo sdl  *********\n");
 return 1;
}

static const vo_info_t * get_info(void)
{ return &vo_info; }

static void allocate_xvimage(int foo)
{
 /*
  * allocate XvImages.  FIXME: no error checking, without
  * mit-shm this will bomb...
  */
 xvimage[foo] = XvShmCreateImage(mydisplay, xv_port, xv_format, 0, image_width, image_height, &Shminfo[foo]);

 Shminfo[foo].shmid    = shmget(IPC_PRIVATE, xvimage[foo]->data_size, IPC_CREAT | 0777);
 Shminfo[foo].shmaddr  = (char *) shmat(Shminfo[foo].shmid, 0, 0);
 Shminfo[foo].readOnly = False;

 xvimage[foo]->data = Shminfo[foo].shmaddr;
 XShmAttach(mydisplay, &Shminfo[foo]);
 XSync(mydisplay, False);
 shmctl(Shminfo[foo].shmid, IPC_RMID, 0);
 memset(xvimage[foo]->data,128,xvimage[foo]->data_size);
 return;
}

static void check_events(void)
{
 int e=vo_x11_check_events(mydisplay);
 if(e&VO_EVENT_RESIZE)
  {
   XGetGeometry( mydisplay,mywindow,&mRoot,&drwX,&drwY,&drwWidth,&drwHeight,&drwBorderWidth,&drwDepth );
   drwX=0; drwY=0;
   XTranslateCoordinates( mydisplay,mywindow,mRoot,0,0,&drwcX,&drwcY,&mRoot );
   printf( "[xv] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",drwcX,drwcY,drwX,drwY,drwWidth,drwHeight );

   #ifdef HAVE_GUI
    if ( vo_window != None )
     {
      mFullscreen=0;
      dwidth=mdwidth; dheight=mdheight;
      if ( ( drwWidth == vo_screenwidth )&&( drwHeight == vo_screenheight ) )
       {
        mFullscreen=1;
        dwidth=vo_screenwidth;
        dheight=vo_screenwidth * mdheight / mdwidth;
       }
     }
   #endif

   if ( mFullscreen )
    {
     drwX=( vo_screenwidth - (dwidth > vo_screenwidth?vo_screenwidth:dwidth) ) / 2;
     drwcX+=drwX;
     drwY=( vo_screenheight - (dheight > vo_screenheight?vo_screenheight:dheight) ) / 2;
     drwcY+=drwY;
     drwWidth=(dwidth > vo_screenwidth?vo_screenwidth:dwidth);
     drwHeight=(dheight > vo_screenheight?vo_screenheight:dheight);
     printf( "[xv-fs] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",drwcX,drwcY,drwX,drwY,drwWidth,drwHeight );
    }
  }
}


static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    int x,y;

  switch (xv_format) {
	case IMGFMT_YV12:  
	case IMGFMT_I420:
        case IMGFMT_IYUV:
    		vo_draw_alpha_yv12(w,h,src,srca,stride,xvimage[current_buf]->data+image_width*y0+x0,image_width);
	break;
	case IMGFMT_YUY2:
        case IMGFMT_YVYU:	
    		vo_draw_alpha_yuy2(w,h,src,srca,stride,xvimage[current_buf]->data+2*(image_width*y0+x0),2*image_width);
	break;
        case IMGFMT_UYVY:
    		vo_draw_alpha_yuy2(w,h,src,srca,stride,xvimage[current_buf]->data+2*(image_width*y0+x0)+1,2*image_width);
	break;
  }		

}

static void flip_page(void)
{
 vo_draw_text(image_width,image_height,draw_alpha);
 check_events();
 XvShmPutImage(mydisplay, xv_port, mywindow, mygc, xvimage[current_buf],
         0, 0,  image_width, image_height,
         drwX,drwY,drwWidth,(mFullscreen?drwHeight - 1:drwHeight),
         False);
 XFlush(mydisplay);
 current_buf=(current_buf+1)%NUM_BUFFERS;
 return;
}



static uint32_t draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
{
 uint8_t *src;
 uint8_t *dst;
 int i;

 dst = xvimage[current_buf]->data + image_width * y + x;
 src = image[0];
 if(w==stride[0] && w==image_width) memcpy(dst,src,w*h);
   else
    for(i=0;i<h;i++)
     {
      memcpy(dst,src,w);
      src+=stride[0];
      dst+=image_width;
     }

 x/=2;y/=2;w/=2;h/=2;

 dst = xvimage[current_buf]->data + image_width * image_height + image_width/2 * y + x;
 src = image[2];
 if(w==stride[2] && w==image_width/2) memcpy(dst,src,w*h);
  else
   for(i=0;i<h;i++)
    {
     memcpy(dst,src,w);
     src+=stride[2];
     dst+=image_width/2;
   }
 dst = xvimage[current_buf]->data + image_width * image_height * 5 / 4 + image_width/2 * y + x;
 src = image[1];
 if(w==stride[1] && w==image_width/2) memcpy(dst,src,w*h);
  else
   for(i=0;i<h;i++)
    {
     memcpy(dst,src,w);
     src+=stride[1];
     dst+=image_width/2;
    }
 return 0;
}

static uint32_t draw_frame(uint8_t *src[])
{
 int foo;

 switch (xv_format) {
 case IMGFMT_YUY2:
 case IMGFMT_UYVY:
 case IMGFMT_YVYU:

     // YUY2 packed, flipped
#if 0
     int i;
     unsigned short *s=(unsigned short *)src[0];
     unsigned short *d=(unsigned short *)xvimage[current_buf]->data;
     s+=image_width*image_height;
     for(i=0;i<image_height;i++) {
	 s-=image_width;
	 memcpy(d,s,image_width*2);
	 d+=image_width;
     }
#else
     memcpy(xvimage[current_buf]->data,src[0],image_width*image_height*2);
#endif
     break;

 case IMGFMT_YV12:
 case IMGFMT_I420:
 case IMGFMT_IYUV:

     // YV12 planar
     memcpy(xvimage[current_buf]->data,src[0],image_width*image_height);
     memcpy(xvimage[current_buf]->data+image_width*image_height,src[2],image_width*image_height/4);
     memcpy(xvimage[current_buf]->data+image_width*image_height*5/4,src[1],image_width*image_height/4);
     break;
 }

  return 0;
}

static uint32_t query_format(uint32_t format)
{

// umm, this is a kludge, we need to ask the server.. (see init function above)
    return 1;
/*
 switch(format)
  {
   case IMGFMT_YV12:
   case IMGFMT_YUY2: 
       return 1;
  }
 return 0;
*/
}

static void uninit(void) {
    saver_on(mydisplay); // screen saver back on
}