/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
                          gui_xv.cpp  -  description
                             -------------------

	This part is strongly derivated from xine/mplayer/mpeg2dec

    begin                : Tue Jan 1 2002
    copyright            : (C) 2002 by mean
    email                : fixounet@free.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#include "xvaccelrenderer.h"

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

#include <QX11Info>

// Use this define for verbose output
#define VERBOSE_XV

//________________Wrapper around Xv_______________
XvAccelRender::XvAccelRender(QWidget *window, uint32_t w, uint32_t h)
{
	xvimage = NULL;

#ifdef VERBOSE_XV
	printf("Xv start\n");
#endif
	width = w;
	height = h;
  GUI_XvInit(window, w, h);
}

XvAccelRender::~XvAccelRender()
{
	GUI_XvEnd( );
#ifdef VERBOSE_XV
	printf("Xv end\n");
#endif
}

char *XvAccelRender::getDisplayData()
{
  if(xvimage) return xvimage->data;
  else return NULL;
}

uint8_t XvAccelRender::display(uint32_t w, uint32_t h)
{
	return GUI_XvDisplay(w, h);
}
//________________Wrapper around Xv_______________


//
//	Free all ressources allocated by xv
//


void XvAccelRender::GUI_XvEnd( void )
{
	ADM_assert(xv_port);
 	ADM_assert(xv_display);


#ifdef VERBOSE_XV
	printf("\n Releasing Xv Port\n");
#endif
	XLockDisplay (xv_display);
	if(XvUngrabPort(xv_display,xv_port,0)!=Success)
		printf("\n Trouble releasing port...\n");
	XUnlockDisplay (xv_display);


	xvimage=NULL;
	xv_display=NULL;
	xv_port=0;

}

//------------------------------------
uint8_t XvAccelRender::GUI_XvDisplay(uint32_t w, uint32_t h)
{

	if (xvimage)
		{

			// put image in shared segment

			// for YV12, 4 bits for Y 4 bits for u, 4 bits for v
			// total 1.5*

      //      memcpy(xvimage->data, src, (w*h*3)>>1);
      //memcpy(xvimage->data, src, (w*h*4)>>1); // We decodee directly to the buffer, so we don't need to copy it.

			XLockDisplay (xv_display);
			// And display it !
#if 1
			XvShmPutImage(xv_display, xv_port, xv_win, xv_gc, xvimage, 
										0, 0, w, h, // src
										//										0, 0, w / 4, h / 4, // dst
										0, 0, width, height, // dst
										False);
#else
			XvPutImage(xv_display, xv_port, xv_win, xv_gc, xvimage, 
								 0, 0, w, h,	// src
								 0, 0, w, h	// dst
								 );

#endif
			//XSetForeground (xv_display, xv_gc, 0);

			XSync(xv_display, False);
			XUnlockDisplay (xv_display);
			//GUI_XvExpose();

		}
	return 1;

}
/*
uint8_t XvAccelRender::GUI_XvSync(void)
{
	if(xv_display)
		XSync(xv_display, False);
	return 1;		
}
*/
//------------------------------------
//
//------------------------------------
uint8_t XvAccelRender::GUI_XvInit(QWidget * window, uint32_t w, uint32_t h)
{
	unsigned int ver, rel, req, ev, err;
	unsigned int port, adaptors;
	static XvAdaptorInfo *ai;
	static XvAdaptorInfo *curai;
   

	//    win = gtk_widget_get_parent_window(window);
	xv_display = window->x11Info().display();//GDK_WINDOW_XDISPLAY(win);
	//      xv_win= RootWindow(xv_display,0);
	xv_win = window->winId();//GDK_WINDOW_XWINDOW(GTK_WIDGET(window)->window);
#define WDN xv_display
	xv_port = 0;

	if (Success != XvQueryExtension(WDN, &ver, &rel, &req, &ev, &err))
		{
			printf("\n Query Extension failed\n");
			goto failed;
		}
	/* check for Xvideo support */
	if (Success != XvQueryAdaptors(WDN,
																 DefaultRootWindow(WDN), &adaptors, &ai))
		{
			printf("\n Query Adaptor failed\n");
			goto failed;
		}
	curai = ai;
	XvFormat *formats;
	// Dump infos
	port = 0;
	for (uint16_t i = 0; (!port) && (i < adaptors); i++)
		{
			/*
				XvPortID base_id;
				unsigned long num_ports;
				char type;
				char *name;
				unsigned long num_formats;
				XvFormat *formats;
				unsigned long num_adaptors;
			*/
#ifdef VERBOSE_XV
			printf("\n_______________________________\n");
			printf("\n Adaptator  : %d", i);
			printf("\n Base ID    : %ld", curai->base_id);
			printf("\n Nb Port    : %lu", curai->num_ports);
			printf("\n Type       : %d,", curai->type);

#define CHECK(x) if(curai->type & x) printf("|"#x);
			CHECK(XvInputMask);
			CHECK(XvOutputMask);
			CHECK(XvVideoMask);
			CHECK(XvStillMask);
			CHECK(XvImageMask);

			printf("\n Name       : %s", curai->name);
			printf("\n Num Adap   : %lu", curai->num_adaptors);
			printf("\n Num fmt    : %lu", curai->num_formats);
#endif	  
			formats = curai->formats;

			//
			uint16_t k;

			for (k = 0; (k < curai->num_ports) && !port; k++)
				{
					if (GUI_XvList(WDN, k + curai->base_id, &xv_format))
						port = k + curai->base_id;
				}


			curai++;
		}
	//
	if (!port)
		{
			printf("\n no port found");
			goto failed;
		}
#ifdef 	COLORSPACE_YV12
#ifdef VERBOSE_XV
	printf("\n Xv YV12 found at port :%d, format : %d", port, xv_format);
#endif
#else
#ifdef VERBOSE_XV
	printf("\n Xv YUY2 found at port :%d, format : %d", port, xv_format);
#endif
#endif

	if (Success != XvGrabPort(WDN, port, 0))
		goto failed;
	{
	
		xv_port = port;
		/*
			Display *display,
			XvPortID port,
			int id,
			char* data,
			int width,
			int height,
			XShmSegmentInfo *shminfo

		*/
		xvimage = XvShmCreateImage(WDN, xv_port,
															 xv_format, 0, w, h, &Shminfo);

		Shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size,
													 IPC_CREAT | 0777);
		Shminfo.shmaddr = (char *) shmat(Shminfo.shmid, 0, 0);
		Shminfo.readOnly = False;
		xvimage->data = Shminfo.shmaddr;
		XShmAttach(WDN, &Shminfo);
		XSync(WDN, False);
		shmctl(Shminfo.shmid, IPC_RMID, 0);
		memset(xvimage->data, 0, xvimage->data_size);

		xv_xgc.graphics_exposures = False;

		xv_gc = XCreateGC(xv_display, xv_win, 0L, &xv_xgc);
	
		//ADM_assert(BadWindow!=XSelectInput(xv_display, xv_win, ExposureMask | VisibilityChangeMask));

	}
#ifdef VERBOSE_XV
	printf("\n Xv init succeedeed\n");
#endif
	return 1;
 failed:
	printf("\n Xv init failed..\n");
	return 0;
}

// _________________________________________________
//
// _________________________________________________
uint8_t XvAccelRender::GUI_XvList(Display * dis, uint32_t port, uint32_t * fmt)
{
	XvImageFormatValues *formatValues;
	int imgfmt;
	int k, f = 0;

	formatValues = XvListImageFormats(dis, port, &imgfmt);
	if (formatValues)
		for (k = 0; !f || (k < imgfmt); k++)
			{
#ifdef VERVOSE_XV
	      printf("\n %lx %d --> %s", port, formatValues[k].id,
							 formatValues[k].guid);
#endif
#ifdef 	COLORSPACE_YV12
	      if (!strcmp(formatValues[k].guid, "YV12"))
#else
					if (!strcmp(formatValues[k].guid, "YUY2"))
#endif
						{
							f = 1;
							*fmt = formatValues[k].id;
						}
			} else
				f = 0;
	XFree(formatValues);
	return f;
}