woops, i forgot to attach the code..... here it is attached.

To re-capitulate: XvShmPutImage seems to be slow, can anyone see why that might be so, am I initiating Xv and its buffers correctly?

(p4 2ghz, 512 MB ram, 32Mb nvideo gforce go, calling XvShmPutImage on a 512x256 YUV422 image takes around 4msecs)

etienne



/*
 * jMax
 * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou,
Paris, France.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * See file LICENSE for further informations on licensing terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Based on Max/ISPW by Miller Puckette.
 *
 * Author: Etienne Deleflie based 
 *
 */


#include <fts/fts.h>
#include <sys/time.h>
#include "../../vdsp/h/vdsp.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#include <X11/extensions/XShm.h>

#include "split_channel.h"

#define vmonitor_VERSION "0.1"

#define DOUBLEW
#define YV12 0x32315659 //(YV12) PLANAR
#define I420 0x30323449	//(I420) PLANAR

#define YUY2 0x32595559	//(YUY2) PACKED
#define UYVY 0x59565955	//(UYVY) PACKED

extern int 	XShmQueryExtension(Display*);
extern int 	XShmGetEventBase(Display*);
extern XvImage  *XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*);
static void vmonitor_drawTestPattern(XvImage *img);
static void vmonitor_send_drawable(fts_object_t *o);


/* ---------------------------------------------------------------------- */
/* The fts_videoport_t derived class                                      */
/* ---------------------------------------------------------------------- */

typedef struct
{
	fts_videoport_t head;

	// X object attributes 
	Display		*dpy;
	Window		window, _dw;
	int		_d, _w, _h;
	int		xv_port;
	GC		gc;
	XvImage		*yuv_image;
	XShmSegmentInfo	yuv_shminfo;
	char		constrained;
	char		centered;
	char		scaled;

	// on off
	int run;

	// flag if output image proportions have changed (in which case we have to background colour)
	int 		image_parameters_changed;

	// the default background image
	unsigned char *background_image;

	// whether the X stuff has been called or not
	char 		x_has_been_setup;

	
} vmonitor_t;

static void vmonitor_output( fts_word_t *argv)
{
	// this next line is for timing exclusively
	struct timeval tv_s, tv_e, result;
	
	vmonitor_t *this = (vmonitor_t *)fts_word_get_ptr( argv+0);
	long n = fts_word_get_int(argv + 1);
	char *in_Y = (char *) fts_word_get_ptr( argv + 2);
	char *in_UV = (char *) fts_word_get_ptr( argv + 3);
	long i;
	
	// (OLD VERSION) copy the current incoming data to the buffer
	//v_byte_copy(in_Y, (this->yuv_image->data) + pdata[0].count*4, VTICK_SIZE*4);

	// START TIMING CODE
	gettimeofday(&tv_s, NULL);
	// END TIMING CODE

	/* begin SSE2 assembly function call */
	// asm_interleave(in_Y, in_UV, this->yuv_image->data, /* size */);
	/* begin SSE2 assembly function call */
	
	n = n*4;
	for(i=0; i<n; i+=2)	//n is 1 pixel
	{
		this->yuv_image->data[i*2] = in_Y[i];
		this->yuv_image->data[(i+1)*2] = in_Y[i+1];		
	}

	for(i=0; i<n; i+=2)	//n is 1 pixel
	{
		this->yuv_image->data[i*2 + 1] = in_UV[i];
		this->yuv_image->data[(i+1)*2 + 1] = in_UV[i+1];		
	}
	
	// START TIMING CODE
	gettimeofday(&tv_e, NULL);
	timeval_subtract (&result, &tv_e, &tv_s);
	fprintf(stderr, "Took %d micro seconds to write data into Hardware buffer.\n", (&result)->tv_usec );
	// END TIMING CODE

	
	// START TIMING CODE
	gettimeofday(&tv_s, NULL);
	// END TIMING CODE

	vmonitor_send_drawable(this);

	// START TIMING CODE
	gettimeofday(&tv_e, NULL);
	timeval_subtract (&result, &tv_e, &tv_s);
	fprintf(stderr, "Took %d micro seconds to send drawable to Xv.\n", (&result)->tv_usec );
	// END TIMING CODE
	
	//XFlush(this->dpy);
}


static void vmonitor_nullinput( fts_word_t *argv)
{
	vmonitor_t *port = (vmonitor_t *)fts_word_get_ptr( argv+0);
	int32 *out = (int32 *) fts_word_get_ptr( argv + 2);

	//v_vec_const(out, 0x00FF0000, VTICK_SIZE);
}

////////////////////////////////////////////////////////////////
//////////////			2		////////////////
////////////////////////////////////////////////////////////////
static void vmonitor_init( fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *att)
{
	vmonitor_t *this = (vmonitor_t *)o;
	fts_symbol_t which_display;
	
	// variables necessary for checking x windows and the like
	int			screen, encodings, attributes, formats;	
	XSizeHints		hint;
	XSetWindowAttributes	xswa;
	XVisualInfo		vinfo;
	unsigned long		mask;
	XEvent			event;

	/** for shm */
	int 			shmem_flag = 0;
	int			CompletionType;

	/** for xv */
	int			ret, i, p, j;
	unsigned int		p_version, p_release,p_request_base, p_event_base, p_error_base;
	int			p_num_adaptors;
	
	XvAdaptorInfo		*ai;
	XvEncodingInfo		*ei;
	XvAttribute		*at;
	XvImageFormatValues	*fo;

	/** for user defnied parameters */
	fts_symbol_t first_arg;		//geometry string 	
	fts_symbol_t second_arg;	//scalable or not	
	fts_symbol_t third_arg;		//centered or not	
	fts_symbol_t fourth_arg;	//scaled or not	
	fts_symbol_t fifth_arg;		//name of window	
	char *	window_name = "video monitor";	//name as string	

	/** for printing out the first image */
	int drawable_width, drawable_height, drawable_origin_x, drawable_origin_y;	
	
	/** for window geometry */
	char * mainGeometry="";
	char defaultMainGeometry[13] = "";
	struct coordinates {  int x, y; };
	struct coordinates total_size;
        int x_negative = 0;
        int y_negative = 0;
	int result = 0;
	int gravity = 0;
	total_size.x = total_size.y = 54;

	// initiate some of the basic variables
	this->constrained = 0;
	this->centered = 0;
	this->scaled = 0;
	this->xv_port = -1;

	this->x_has_been_setup=0;

	// the flag
	this->image_parameters_changed = 0;
	
	fts_videoport_init( &this->head);
	
	// retrieve user defined variables (window size + scalable)
	first_arg = fts_get_symbol_arg(ac, att, 1, 0);
	if (first_arg)
	{
		mainGeometry = 	fts_symbol_name(first_arg);
	}
	
	second_arg = fts_get_symbol_arg(ac, att, 2, 0);
	if (second_arg)
		this->constrained = 1;

	third_arg = fts_get_symbol_arg(ac, att, 3, 0);
	if (third_arg)
		this->centered = 1;

	fourth_arg =  fts_get_symbol_arg(ac, att, 4, 0);
	if (fourth_arg)
		this->scaled = 1;

	fifth_arg =  fts_get_symbol_arg(ac, att, 5, 0);
	if (fifth_arg)
		window_name = fts_symbol_name (fifth_arg);

	// set up and test what is available for X

	// can we open an X display ?
	this->dpy = XOpenDisplay(NULL);
	//this->dpy = XOpenDisplay(":1.0");
	if (this->dpy == NULL)
	{
		post("Cannot open X Display.\n");
		return;
	}

	screen = DefaultScreen(this->dpy);
	
	/** find best display */
	if (XMatchVisualInfo(this->dpy, screen, 24, TrueColor, &vinfo)) {post("vmonitor found 24bit TrueColor display\n");} 
	else if (XMatchVisualInfo(this->dpy, screen, 16, TrueColor, &vinfo)) {post("vmonitor found 16bit TrueColor display\n");}
	else if (XMatchVisualInfo(this->dpy, screen, 15, TrueColor, &vinfo)) {post("vmonitor found 15bit TrueColor display\n");}
	else if (XMatchVisualInfo(this->dpy, screen, 8, PseudoColor, &vinfo)) {post("vmonitor found 8bit PseudoColor display\n");}
	else if (XMatchVisualInfo(this->dpy, screen, 8, GrayScale, &vinfo)) {post("vmonitor found 8bit GrayScale display\n");}
	else if (XMatchVisualInfo(this->dpy, screen, 8, StaticGray, &vinfo)) {post("vmonitor found 8bit StaticGray display\n");}
	else if (XMatchVisualInfo(this->dpy, screen, 1, StaticGray, &vinfo)) {post("vmonitor found 1bit StaticGray display\n");}
	else { post("requires 16 bit display\n"); return ;}
  
	CompletionType = -1;	
	
	/** hints **/ // window size and position.
	if (!strlen(mainGeometry))
	{
		char width[4], height[4];
		char by[] = "x";
		char position[] = "+20+60";
		sprintf (width, "%d",V_WIDTH);
		sprintf (height, "%d",V_HEIGHT);
		//post ("width is -%s-\n", width);
		strcat (defaultMainGeometry, width);
		strcat (defaultMainGeometry, by);
		strcat (defaultMainGeometry, height);
		strcat (defaultMainGeometry, position);
		
		mainGeometry = defaultMainGeometry;
	}
	
		// set up and test what is available for X

		// can we open an X display ?
		this->dpy = XOpenDisplay(NULL);
		//this->dpy = XOpenDisplay(":1.0");
		if (this->dpy == NULL)
		{
			post("Cannot open X Display.\n");
			return;
		}

		screen = DefaultScreen(this->dpy);
		
		/** find best display */
		if (XMatchVisualInfo(this->dpy, screen, 24, TrueColor, &vinfo)) {post("vmonitor found 24bit TrueColor display\n");} 
		else if (XMatchVisualInfo(this->dpy, screen, 16, TrueColor, &vinfo)) {post("vmonitor found 16bit TrueColor display\n");}
		else if (XMatchVisualInfo(this->dpy, screen, 15, TrueColor, &vinfo)) {post("vmonitor found 15bit TrueColor display\n");}
		else if (XMatchVisualInfo(this->dpy, screen, 8, PseudoColor, &vinfo)) {post("vmonitor found 8bit PseudoColor display\n");}
		else if (XMatchVisualInfo(this->dpy, screen, 8, GrayScale, &vinfo)) {post("vmonitor found 8bit GrayScale display\n");}
		else if (XMatchVisualInfo(this->dpy, screen, 8, StaticGray, &vinfo)) {post("vmonitor found 8bit StaticGray display\n");}
		else if (XMatchVisualInfo(this->dpy, screen, 1, StaticGray, &vinfo)) {post("vmonitor found 1bit StaticGray display\n");}
		else { post("requires 16 bit display\n"); return ;}
  
		CompletionType = -1;	
	
		/** hints **/ // window size and position.
		// Check the user-specified size
		result = XParseGeometry(mainGeometry,
					&hint.x,
					&hint.y,
					&hint.width,
					&hint.height);
		if (result & WidthValue)
			total_size.x = hint.width;
		if (result & HeightValue)
			total_size.y = hint.height;
		if (result & XNegative)
			x_negative = 1;
		if (result & YNegative)
			y_negative = 1;

		hint.flags = USSize | USPosition;
		
		hint.x = 0;
		hint.y = 0;
		hint.width = V_WIDTH;
		hint.height = V_HEIGHT;
		XWMGeometry(this->dpy, screen, mainGeometry, NULL, 0,
       	             &hint, &hint.x, &hint.y,
       	             &hint.width, &hint.height, &gravity);
	
		/** take care of the gravity */
		hint.win_gravity = StaticGravity;
		hint.flags |= PWinGravity;
	
		/** set some X window attributes **/
		xswa.colormap =  XCreateColormap(this->dpy, DefaultRootWindow(this->dpy), vinfo.visual, AllocNone);
		xswa.event_mask = StructureNotifyMask | ExposureMask;
		xswa.background_pixel = 0;
		xswa.border_pixel = 0;
	
		/** some mask business **/
		mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;

		/** initialise the window **/
		this->window = XCreateWindow(	this->dpy, DefaultRootWindow(this->dpy),
				hint.x, hint.y,
				hint.width,
				hint.height,
				0, vinfo.depth,
				InputOutput,
				vinfo.visual,
				mask, &xswa);
		/** set the window manager hints */
		XSetWMNormalHints(this->dpy, this->window, &hint);
	 
		/** a bit more about the window **/
		XStoreName(this->dpy, this->window, window_name);
 		XSetIconName(this->dpy, this->window, window_name);
	
		XSelectInput(this->dpy, this->window, StructureNotifyMask);
	
		/** Map window */
		XMapWindow(this->dpy, this->window);
	
		/** Wait for map. (this opens an X window) */
		do
		{
			XNextEvent(this->dpy, &event);
		} while (event.type != MapNotify || event.xmap.event != this->window);
	
		/** test that Shm is ready ?**/
		if (XShmQueryExtension(this->dpy)) shmem_flag = 1;
		if (!shmem_flag)
		{
			printf("no shmem available.\n");
			return;
		}
 	 
		if (shmem_flag==1) CompletionType = XShmGetEventBase(this->dpy) + ShmCompletion;
	
		/**--------------------------------- XV ------------------------------------*/
	
		/** query Xvideo Extension */
		ret = XvQueryExtension(this->dpy, &p_version, &p_release, &p_request_base, &p_event_base, &p_error_base);
		
		if (ret != Success)
		{
			if (ret == XvBadExtension)
				post ("XvBadExtension returned at XvQueryExtension.\n");
			else if (ret == XvBadAlloc)
				post ("XvBadAlloc returned at XvQueryExtension.\n");
			else post ("other error happened at XvQueryExtension.\n");
		}
	
/*
	post("========================================\n");
	post("XvQueryExtension returned the following:\n");
	post("p_version      : %u\n", p_version);
	post("p_release      : %u\n", p_release);
	post("p_request_base : %u\n", p_request_base);
	post("p_event_base   : %u\n", p_event_base);
	post("p_error_base   : %u\n", p_error_base);
	post("========================================\n");
*/

		/** query Xvideo Adaptors */
		ret = XvQueryAdaptors(this->dpy, DefaultRootWindow(this->dpy), &p_num_adaptors, &ai);
	
		if (ret != Success)
		{
			if (ret == XvBadExtension)
				post("XvBadExtension returned at XvQueryExtension.\n");
			else if (ret == XvBadAlloc)
				post("XvBadAlloc returned at XvQueryExtension.\n");
			else 
				post("other error happaned at XvQueryAdaptors.\n");
		}
	
		// post ("%d xv adaptors available.\n", p_num_adaptors);
		
		/** loop through all the adaptors */
		for (i = 0; i < p_num_adaptors; i++)
		{
			this->xv_port = ai[i].base_id;
    			for (p = ai[i].base_id; p < ai[i].base_id+ai[i].num_ports; p++)
   			{
				if (XvQueryEncodings(this->dpy, p, &encodings, &ei) != Success)
					continue;
				
				XvFreeEncodingInfo(ei);
				
				at = XvQueryPortAttributes(this->dpy, p, &attributes);
      				if (at)
					XFree(at);
				
				fo = XvListImageFormats(this->dpy, p, &formats);
				
				/* UNCOMMENT TO FIND OUT WHAT COLOUR MODELS THE GRAPHICS CARD CAN HANDLE
				// to find out what colour models the card accepts
				for (j = 0; j < formats; j++)
				{
					post("  0x%x (%4.4s) %s\n",
							fo[j].id,
							(char *)&fo[j].id,
							(fo[j].format == XvPacked) ? "packed" : "planar");
				}
				*/
      				if (fo)
					XFree(fo);
			}
		}
	
		if (p_num_adaptors > 0)
			XvFreeAdaptorInfo(ai);
		
		if (this->xv_port == -1)
		{
			post ("could not find any xv_ports ..... does your graphics card have overlay support?");
    			return;
		}

		this->gc = XCreateGC(this->dpy, this->window, 0, 0);
		
		// create the Xv image
		this->yuv_image = XvShmCreateImage(this->dpy, this->xv_port, YUY2 , 0, V_WIDTH, V_HEIGHT, &(this->yuv_shminfo));
		this->yuv_shminfo.shmid = shmget(IPC_PRIVATE, this->yuv_image->data_size, IPC_CREAT | 0777);
		this->yuv_shminfo.shmaddr = this->yuv_image->data = shmat(this->yuv_shminfo.shmid, 0, 0);
		this->yuv_shminfo.readOnly = True;
		XSync (this->dpy, False);
	    
		if (!XShmAttach(this->dpy, &(this->yuv_shminfo)))
		{
    			post("XShmAttach failed !\n");
    			return;
		}
		

		// TODO: the background image needs to be an XV image
		// 
		// allocate space for the background image that will be re-drawn any time the aspect ratio of the image changes.
		// this image is the size of the X output window
		this->background_image = (unsigned char *)  fts_malloc( (size_t)(this->_w * this->_h * 2)*sizeof(unsigned char *));
		// populate it with black (for now)
		for (i = (this->_w * this->_h * 2) -1 ; i >= 0; i-- )
		{
			this->background_image[i] = 100;
		}
		
		//vmonitor_setup_X_window_geometry(this);
		// print out a default image
		vmonitor_drawTestPattern(this->yuv_image);

		// set up the window geometry
		vmonitor_send_drawable(this);

		XFlush(this->dpy);
		
		// object is on by default
		this->run = 1;

		// define the number of input channels (which is 2 in the case of YUV)
		fts_videoport_set_output_function( (fts_videoport_t *)this, vmonitor_output);
		fts_videoport_set_output_channels( (fts_videoport_t *)this, 2);
		fts_videoport_set_input_channels( (fts_videoport_t *)this, 2);
		fts_videoport_set_input_function( (fts_videoport_t *)this, vmonitor_nullinput);
}

/* CLEAN RESOURCES */
static void vmonitor_delete( fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at)
{
	vmonitor_t *this = (vmonitor_t *)o;

	free(this->background_image);
	
	if (&(this->yuv_shminfo))
	{
		//fprintf(stderr, "cleaning, found some shminfo");
		XShmDetach(this->dpy, &(this->yuv_shminfo));
		XFree(this->yuv_image);
		this->yuv_image = NULL;
		shmdt( this->yuv_shminfo.shmaddr);
		shmctl( this->yuv_shminfo.shmid, IPC_RMID, 0);
	} else
		XFree(this->yuv_image);	

	XCloseDisplay(this->dpy);
	
	fts_videoport_delete( (fts_videoport_t *)o);
}

/* GET STATE (?) */
static void vmonitor_get_state( fts_daemon_action_t action, fts_object_t *o, fts_symbol_t property, fts_atom_t *value)
{
	fts_set_object( value, o);
}

static void vmonitor_constrained( fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at)
{
  vmonitor_t *this = (vmonitor_t *)o;
  this->constrained = fts_get_int_arg( ac, at, 0, 0); //fts_get_number_int(at);
  this->image_parameters_changed = 1;
}

static void vmonitor_centered( fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at)
{
  vmonitor_t *this = (vmonitor_t *)o;
  this->centered = fts_get_int_arg( ac, at, 0, 0); //fts_get_number_int(at);
  this->image_parameters_changed = 1;
}

static void vmonitor_scaled( fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at)
{
  vmonitor_t *this = (vmonitor_t *)o;
  this->scaled = fts_get_int_arg( ac, at, 0, 0); //fts_get_number_int(at);
  this->image_parameters_changed = 1;
}

////////////////////////////////////////////////////////////////
//////////////			1		////////////////
////////////////////////////////////////////////////////////////
static fts_status_t vmonitor_instantiate(fts_class_t *cl, int ac, const fts_atom_t *at)
{
  	fts_symbol_t a[6];
	a[0] = fts_s_symbol; 	/* class */
	a[1] = fts_s_symbol; 	/* X11 params */
	a[2] = fts_s_int; 	/* constrained or not */
	a[3] = fts_s_int; 	/* cenetered or not */
	a[4] = fts_s_int; 	/* scaled or not */
	a[5] = fts_s_symbol; 	/* name of output window */
	
	fts_class_init( cl, sizeof( vmonitor_t), 1, 0, 0);
	
	// takes up to 5 arguments ......... but at least 2 are required
	fts_method_define_optargs( cl, fts_SystemInlet,  fts_s_init,   vmonitor_init, 6, a, 1);	
	fts_method_define_varargs( cl, fts_SystemInlet,  fts_s_delete, vmonitor_delete);

	// user methods
	a[0] = fts_t_int;
	
	fts_method_define_optargs(cl, 0, fts_new_symbol("constrained"), vmonitor_constrained, 1, a, 1);
	fts_method_define_optargs(cl, 0, fts_new_symbol("centered"), vmonitor_centered, 1, a, 1);
	fts_method_define_optargs(cl, 0, fts_new_symbol("scaled"), vmonitor_scaled, 1, a, 1);

	fts_class_add_daemon     ( cl, obj_property_get, fts_s_state,  vmonitor_get_state);

	/*
	 * NOTE: there are no vdsp inlets decalred, because this cass uses a metaclass (is that what they are called ?)
	 *
	 */
	
	return fts_Success;
}

static void vmonitor_drawTestPattern(XvImage *img)
{
	int i,j, n;
	int unit, num_in_width;
	int last_width, last_height;
	n = V_SIZE*2;			
	
	for(i=0; i<n; i+=4)	//n is 1 pixel
	{
		img->data[i] = 0;	// Y1
		img->data[i+2] = 255;	// Y2
		img->data[i+1] = 100;	// U 
		img->data[i+3] = 100;	// V 
	}
}

static void vmonitor_send_drawable(fts_object_t *o)
{
	vmonitor_t *this = (vmonitor_t *)o;

	int drawable_width, drawable_height, drawable_origin_x, drawable_origin_y;
	
	XGetGeometry(this->dpy, this->window, &(this->_dw), &(this->_d), &(this->_d), &(this->_w),  &(this->_h),  &(this->_d),  &(this->_d));
    
	if (this->image_parameters_changed)
	{
		// TODO: if the image parameters change, make screen go back to black, to avoid part of the image lying around.
		this->image_parameters_changed = o;
	}
	
	// now work out what is the drawable area within the X window
	if (this->scaled)
	{
		if (this->constrained)
		{
			// check to see if the shortest side is length or height
			float proport_w = (float)this->_w / this->_h;
			float proport_v = (float)V_WIDTH / V_HEIGHT;
			if (proport_w < proport_v)
			{
				// if we get here then the window width is skinny.... we have to scale down height
				drawable_width = this->_w;
				drawable_height = (rint)(drawable_width / proport_v);
				// position
				if (this->centered)
				{
					drawable_origin_x = 0;
					drawable_origin_y =  (this->_h - drawable_height)/2;
				} else
					drawable_origin_x = drawable_origin_y = 0;
			}
			else
			{
				// if we get here then the window height is skinny
				drawable_height = this->_h;
				drawable_width = (int)(drawable_height * proport_v);
				// position
				if (this->centered)
				{
					drawable_origin_y = 0;
					drawable_origin_x = (this->_w - drawable_width)/2;
				} else
					drawable_origin_x = drawable_origin_y = 0;
			}
		}
		else
		{
			// if we get here then we are scaled but not constrained.
			drawable_width = this->_w;
			drawable_height = this->_h;
			drawable_origin_x = drawable_origin_y = 0;
		}
	}
	else 
	{
		// if we get here then we are not constrained
		drawable_width = V_WIDTH;
		drawable_height = V_HEIGHT;

		if (this->centered)
		{
			drawable_origin_x = (this->_w - V_WIDTH)/2;
			drawable_origin_y = (this->_h - V_HEIGHT)/2;
		}
		else
		{
			drawable_origin_x = 0;
			drawable_origin_y = 0;
		}
	}

	XvShmPutImage(
			this->dpy			//The connection to the X-Server
			, this->xv_port			//The port id of a port on an XvImage capable adaptor
			, this->window			//The target drawable
			, this->gc			//the graphics context specifying the clip mask to use, if any.
			, this->yuv_image		//A pointer to the XvImage to be displayed
			, 0, 0				//The portion of the XvImage to be displayed.
			, this->yuv_image->width	
			, this->yuv_image->height	
			, drawable_origin_x		//The portion of the destination drawable to be filled by the image.
			, drawable_origin_y	
			, drawable_width, drawable_height
			, True);			//Indicates whether or not an XShmCompletionEvent should be sent. 

}

void vmonitor_config( void)
{
	fts_class_install( fts_new_symbol("monitor*"), vmonitor_instantiate);
}

Reply via email to