<commit_before>/*
    videodevice.cpp  -  Kopete Video Device Low-level Support

    Copyright (c) 2005-2006 by <NAME>   <<EMAIL>>
    Copyright (c) 2010      by <NAME>                 <<EMAIL>>

    Kopete    (c) 2002-2003      by the Kopete developers  <<EMAIL>>

    *************************************************************************
    *                                                                       *
    * This library is free software; you can redistribute it and/or         *
    * modify it under the terms of the GNU Lesser General Public            *
    * License as published by the Free Software Foundation; either          *
    * version 2 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#define ENABLE_AV

#include <cstdlib>
#include <cerrno>
#include <cstring>

#include <kdebug.h>

#include "videoinput.h"
#include "videodevice.h"

#include "bayer.h"
#include "sonix_compress.h"

#define CLEAR(x) memset (&(x), 0, sizeof (x))

namespace Kopete {

namespace AV {

VideoDevice::VideoDevice()
{
	descriptor = -1;
	m_streambuffers  = 0;
	m_current_input = 0;
}


VideoDevice::~VideoDevice()
{
	close();
}

/*!
    \fn void VideoDevice::setupControls()
    \brief Sets up the supported video-controls for the current input
    
    Determines which video-controls are supported for the current input,
    reads all needed informations about them and stores the data to the local members
 */
void VideoDevice::setupControls()
{
#if defined(__linux__) && defined(ENABLE_AV)
	bool driver_vflip = false;
	bool driver_hflip = false;
#endif
	m_numericCtrls.clear();
	m_booleanCtrls.clear();
	m_menuCtrls.clear();
	m_actionCtrls.clear();

	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
			struct v4l2_queryctrl qctrl;
			CLEAR (qctrl);
			// Get standard controls:
			for (quint32 k = V4L2_CID_BASE; k < V4L2_CID_LASTP1; k++) // NOTE: DO NOT USE qctrl.id DIRECTLY !
			{
				qctrl.id = k;
				if (0 == xioctl(VIDIOC_QUERYCTRL, &qctrl))
				{
					if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
						continue;
					if (qctrl.id == V4L2_CID_VFLIP)
						driver_vflip = true;
					if (qctrl.id == V4L2_CID_HFLIP)
						driver_hflip = true;
					const char *name_uni = getUnifiedV4L2StdCtrlName(qctrl.id);
					if (name_uni && strlen(name_uni))
						strncpy((char*)qctrl.name, name_uni, 32); // NOTE: v4l2_queryctrl.name is _u8[32]
					saveV4L2ControlData(qctrl);
				}
				else
				{
					if (errno == EINVAL)
						continue;
					kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ").";
				}
			}
			// Get custom controls:
			for (quint32 k = V4L2_CID_PRIVATE_BASE; ; k++)
			{
				qctrl.id = k;
				if (0 == xioctl(VIDIOC_QUERYCTRL, &qctrl))
				{
					if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
						continue;
					saveV4L2ControlData(qctrl);
				}
				else
				{
					if (errno == EINVAL)
						break;
					kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ").";
				}
			}
			break;
#endif
		VIDEODEV_DRIVER_V4L:
			{
				NumericVideoControl numCtrl;
				numCtrl.value_min = 0;
				numCtrl.value_max = 65535;
				numCtrl.value_step = 1;
				numCtrl.value_default = 32767;
				numCtrl.id = IMGCTRL_ID_V4L1_BRIGHTNESS;
				numCtrl.name = i18n("Brightness");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_HUE;
				numCtrl.name = i18n("Hue");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_COLOR;
				numCtrl.name = i18n("Color");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_CONTRAST;
				numCtrl.name = i18n("Contrast");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_WHITENESS;
				numCtrl.name = i18n("Whiteness");
				m_numericCtrls.push_back( numCtrl );
			}
			break;
#endif
		VIDEODEV_DRIVER_NONE:
		default:
			break;
	}
	
#if defined(__linux__) && defined(ENABLE_AV)
	// Software controls:
	BooleanVideoControl boolCtrl;
	boolCtrl.value_default = 0;
	boolCtrl.id = IMGCTRL_ID_SOFT_AUTOBRIGHTNESSCONTRASTCORR;
	boolCtrl.name = i18n("Automatic Brightness/Contrast Correction");
	m_booleanCtrls.push_back( boolCtrl );
	boolCtrl.id = IMGCTRL_ID_SOFT_AUTOCOLORCORR;
	boolCtrl.name = i18n("Automatic Color Correction");
	m_booleanCtrls.push_back( boolCtrl );
	if (!driver_vflip)
	{
		boolCtrl.id = IMGCTRL_ID_SOFT_VFLIP;
		boolCtrl.name = i18n("Vertical Flip");
		m_booleanCtrls.push_back( boolCtrl );
	}
	if (!driver_hflip)
	{
		boolCtrl.id = IMGCTRL_ID_SOFT_HFLIP;
		boolCtrl.name = i18n("Horizontal Flip");
		m_booleanCtrls.push_back( boolCtrl );
	}
#endif
}

#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
/*!
    \fn bool VideoDevice::getMenuCtrlOptions(quint32 id, quint32 maxindex, QStringList * options)
    \param id ID of the video-control
    \param maxindex Highest menu index
    \param options Pointer to the QStringList which will recieve the option-strings of the video-control
    \return The success of the operation
    \brief Reads the available options provided by a menu-video-control
 */
bool VideoDevice::getMenuCtrlOptions(quint32 id, quint32 maxindex, QStringList * options)
{
	QStringList opt;
	struct v4l2_querymenu ctrlmenu;
	CLEAR (ctrlmenu);
	options->clear();
	ctrlmenu.id = id;
	for (quint32 k = 0; k <= maxindex; k++)	// DO NOT USE ctrlmenu.index DIRECTLY !
	{
		ctrlmenu.index = k;
		if (0 == xioctl(VIDIOC_QUERYMENU, &ctrlmenu))
		{
			opt.push_back( i18n( (char*)(ctrlmenu.name) ) );
			kDebug() << "option" << k << ":" << (char*)(ctrlmenu.name);
		}
		else
		{
			kDebug() << "VIDIOC_QUERYMENU failed (" << errno << ").";
			return false;
		}
	}
	*options = opt;
	return true;
	/* NOTE: According to V4L2-spec v0.24:
	         v4l2_querymenu.minimum = start-index = 0, v4l2_querymenu.maximum = last index
	         => DO DRIVERS REALLY SET THESE VALUES CORRECTLY ???
	 */
}


/*!
    \fn void VideoDevice::saveV4L2ControlData(struct v4l2_queryctrl qctrl)
    \param qctrl The struct v4l2_queryctrl of the V4L2-control that should be saved
    \brief Saves the data of a V4L2-video-control
 */
void VideoDevice::saveV4L2ControlData(struct v4l2_queryctrl qctrl)
{
	NumericVideoControl numericCtrl;
	BooleanVideoControl booleanCtrl;
	MenuVideoControl menuCtrl;
	ActionVideoControl actionCtrl;
	QStringList options;
	switch (qctrl.type)
	{
		case V4L2_CTRL_TYPE_INTEGER:
			numericCtrl.id = qctrl.id;
			numericCtrl.name = i18n((char*)qctrl.name);
			numericCtrl.value_min = qctrl.minimum;
			numericCtrl.value_max = qctrl.maximum;
			numericCtrl.value_default = qctrl.default_value;
			numericCtrl.value_step = qctrl.step;
			m_numericCtrls.push_back( numericCtrl );
			break;
		case V4L2_CTRL_TYPE_BOOLEAN:
			booleanCtrl.id = qctrl.id;
			booleanCtrl.name = i18n((char*)qctrl.name);
			booleanCtrl.value_default = qctrl.default_value;
			m_booleanCtrls.push_back( booleanCtrl );
			break;
		case V4L2_CTRL_TYPE_MENU:
			if (getMenuCtrlOptions( qctrl.id, qctrl.maximum, &options ))
			{
				menuCtrl.id = qctrl.id;
				menuCtrl.name = i18n((char*)qctrl.name);
				menuCtrl.index_default = qctrl.default_value;
				menuCtrl.options = options;
				m_menuCtrls.push_back( menuCtrl );
			}
			break;
		case V4L2_CTRL_TYPE_BUTTON:
			actionCtrl.id = qctrl.id;
			actionCtrl.name = i18n((char*)qctrl.name);
			m_actionCtrls.push_back( actionCtrl );
			break;
		// Since kernel 2.6.18:
#ifdef V4L2_CTRL_TYPE_INTEGER64
		case V4L2_CTRL_TYPE_INTEGER64:
#endif
#ifdef V4L2_CTRL_TYPE_CTRL_CLASS
		case V4L2_CTRL_TYPE_CTRL_CLASS:
#endif
		default:
			break;
	}
// TODO	V4L2_CTRL_TYPE_INTEGER64, V4L2_CTRL_TYPE_CTRL_CLASS
}
#endif
#endif

/*!
    \fn VideoDevice::xioctl(int fd, int request, void *arg)
 */
int VideoDevice::xioctl(int request, void *arg)
{
	int r;

#ifdef HAVE_LIBV4L2
	do r = v4l2_ioctl (descriptor, request, arg);
#else
	do r = ioctl (descriptor, request, arg);
#endif
	while (-1 == r && EINTR == errno);
	return r;
}

/*!
    \fn VideoDevice::errnoReturn(const char* s)
 */
int VideoDevice::errnoReturn(const char* s)
{
    /// @todo implement me
	fprintf (stderr, "%s error %d, %s\n",s, errno, strerror (errno));
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::setFileName(QString name)
 */
int VideoDevice::setFileName(QString filename)
{
    /// @todo implement me
	full_filename=filename;
	return EXIT_SUCCESS;
}

/*!
    \fn QString VideoDevice::fileName()
 */
QString VideoDevice::fileName()
{
	return full_filename;
}

/*!
    \fn VideoDevice::open()
 */
int VideoDevice::open()
{
    /// @todo implement me

	kDebug() << "called";
	if(-1 != descriptor)
	{
		kDebug() << "Device is already open";
		return EXIT_SUCCESS;
	}
#ifdef HAVE_LIBV4L2
	descriptor = ::v4l2_open (QFile::encodeName(full_filename), O_RDWR, 0);
#else
	descriptor = ::open (QFile::encodeName(full_filename), O_RDWR, 0);
#endif
	if(isOpen())
	{
		kDebug() << "File " << full_filename << " was opened successfuly";
		if(EXIT_FAILURE==checkDevice())
		{
			kDebug() << "File " << full_filename << " could not be opened";
			close();
			return EXIT_FAILURE;
		}
	}
	else
	{
		kDebug() << "Unable to open file " << full_filename << "Err: "<< errno;
		return EXIT_FAILURE;
	}

	initDevice();
	selectInput(m_current_input);
	kDebug() << "exited successfuly";
	return EXIT_SUCCESS;
}

bool VideoDevice::isOpen()
{
	if(-1 == descriptor)
	{
//		kDebug() << "VideoDevice::isOpen() File is not open";
		return false;
	}
//	kDebug() << "VideoDevice::isOpen() File is open";
	return true;
}

int VideoDevice::checkDevice()
{
	kDebug() << "checkDevice() called.";
	if(isOpen())
	{
		m_videocapture=false;
		m_videochromakey=false;
		m_videoscale=false;
		m_videooverlay=false;
		m_videoread=false;
		m_videoasyncio=false;
		m_videostream=false;

		m_driver=VIDEODEV_DRIVER_NONE;
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE

		CLEAR(V4L2_capabilities);

		if (-1 != xioctl (VIDIOC_QUERYCAP, &V4L2_capabilities))
		{
			if (!(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE))
			{
				kDebug() << "checkDevice(): " << full_filename << " is not a video capture device.";
				m_driver = VIDEODEV_DRIVER_NONE;
				return EXIT_FAILURE;
			}
			m_videocapture=true;
			kDebug() << "checkDevice(): " << full_filename << " is a V4L2 device.";
			m_driver = VIDEODEV_DRIVER_V4L2;
			m_model=QString::fromLocal8Bit((const char*)V4L2_capabilities.card);


// Detect maximum and minimum resolution supported by the V4L2 device. VIDIOC_ENUM_FRAMESIZES is still experimental.
			CLEAR (fmt);
			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
			{
				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").";
			}
			fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			fmt.fmt.pix.width       = 32767;
			fmt.fmt.pix.height      = 32767;
			fmt.fmt.pix.field       = V4L2_FIELD_ANY;
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
				kDebug() << "Detecting maximum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				// Note VIDIOC_S_FMT may change width and height.
			}
			else
			{
				maxwidth  = fmt.fmt.pix.width;
				maxheight = fmt.fmt.pix.height;
			}
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
			{
				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").";
			}
			fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			fmt.fmt.pix.width       = 1;
			fmt.fmt.pix.height      = 1;
			fmt.fmt.pix.field       = V4L2_FIELD_ANY;
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
				kDebug() << "Detecting minimum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				// Note VIDIOC_S_FMT may change width and height.
			}
			else
			{
				minwidth  = fmt.fmt.pix.width;
				minheight = fmt.fmt.pix.height;
			}

// Buggy driver paranoia
/*				min = fmt.fmt.pix.width * 2;
				if (fmt.fmt.pix.bytesperline < min)
					fmt.fmt.pix.bytesperline = min;
				min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
				if (fmt.fmt.pix.sizeimage < min)
					fmt.fmt.pix.sizeimage = min;
				m_buffer_size=fmt.fmt.pix.sizeimage ;*/

			int inputisok=EXIT_SUCCESS;
			m_input.clear();
			for(unsigned int loop=0; inputisok==EXIT_SUCCESS; loop++)
			{
				struct v4l2_input videoinput;
				CLEAR(videoinput);
				videoinput.index = loop;
				inputisok=xioctl(VIDIOC_ENUMINPUT, &videoinput);
				if(inputisok==EXIT_SUCCESS)
				{
					VideoInput tempinput;
					tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name);
					tempinput.hastuner = videoinput.type & V4L2_INPUT_TYPE_TUNER;
detectSignalStandards();
					tempinput.m_standards = videoinput.std;
					m_input.push_back(tempinput);
					kDebug() << "Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0) << ")";
					if((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0)
					{
//						_tunerForInput[name] = desc.tuner;
//						_isTuner = true;
					}
					else
					{
//						_tunerForInput[name] = -1;
					}
				}
			}
		}
		else
		{
// V4L-only drivers should return an EINVAL in errno to indicate they cannot handle V4L2 calls. Not every driver is compliant, so
// it will try the V4L api even if the error code is different than expected.
			kDebug() << "checkDevice(): " << full_filename << " is not a V4L2 device.";
		}

#endif

		CLEAR(V4L_capabilities);

		if(m_driver==VIDEODEV_DRIVER_NONE)
		{
			kDebug() << "checkDevice(): " << full_filename << " Trying V4L API.";
			if (-1 == xioctl (VIDIOCGCAP, &V4L_capabilities))
			{
				perror ("ioctl (VIDIOCGCAP)");
				m_driver = VIDEODEV_DRIVER_NONE;
				return EXIT_FAILURE;
			}
			else
			{
				kDebug() << full_filename << " is a V4L device.";
				m_driver = VIDEODEV_DRIVER_V4L;
				m_model=QString::fromLocal8Bit((const char*)V4L_capabilities.name);
				if(V4L_capabilities.type & VID_TYPE_CAPTURE)
					m_videocapture=true;
				if(V4L_capabilities.type & VID_TYPE_CHROMAKEY)
					m_videochromakey=true;
				if(V4L_capabilities.type & VID_TYPE_SCALES)
					m_videoscale=true;	
				if(V4L_capabilities.type & VID_TYPE_OVERLAY)
					m_videooverlay=true;
//				kDebug() << "libkopete (avdevice):     Inputs : " << V4L_capabilities.channels;
//				kDebug() << "libkopete (avdevice):     Audios : " << V4L_capabilities.audios;
				minwidth  = V4L_capabilities.minwidth;
				maxwidth  = V4L_capabilities.maxwidth;
				minheight = V4L_capabilities.minheight;
				maxheight = V4L_capabilities.maxheight;


				int inputisok=EXIT_SUCCESS;
				m_input.clear();
				for(int loop=0; loop < V4L_capabilities.channels; loop++)
				{
					struct video_channel videoinput;
					CLEAR(videoinput);
					videoinput.channel = loop;
					videoinput.norm    = 1;
					inputisok=xioctl(VIDIOCGCHAN, &videoinput);
					if(inputisok==EXIT_SUCCESS)
					{
						VideoInput tempinput;
						tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name);
						tempinput.hastuner=videoinput.flags & VIDEO_VC_TUNER;
// TODO: The routine to detect the appropriate video standards for V4L must be placed here
						m_input.push_back(tempinput);
//						kDebug() << "libkopete (avdevice): Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.flags & VIDEO_VC_TUNER) != 0) << ")";
/*						if((input.type & V4L2_INPUT_TYPE_TUNER) != 0)
						{
//							_tunerForInput[name] = desc.tuner;
//							_isTuner = true;
						}
						else
						{
//							_tunerForInput[name] = -1;
						}
*/					}
				}

			}
		}
#endif
		m_name=m_model; // Take care about changing the name to be different from the model itself...

		detectPixelFormats();
// TODO: Now we must execute the proper initialization according to the type of the driver.
		kDebug() << "checkDevice() exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}


/*!
    \fn VideoDevice::showDeviceCapabilities()
 */
int VideoDevice::showDeviceCapabilities()
{
	kDebug() << "showDeviceCapabilities() called.";
	if(isOpen())
	{
/*		kDebug() << "libkopete (avdevice): Driver: " << (const char*)V4L2_capabilities.driver << " "
			<< ((V4L2_capabilities.version>>16) & 0xFF) << "."
			<< ((V4L2_capabilities.version>> 8) & 0xFF) << "."
			<< ((V4L2_capabilities.version    ) & 0xFF) << endl;
		kDebug() << "libkopete (avdevice): Device: " << name;
		kDebug() << "libkopete (avdevice): Capabilities:";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE)
			kDebug() << "libkopete (avdevice):     Video capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OUTPUT)
			kDebug() << "libkopete (avdevice):     Video output";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OVERLAY)
			kDebug() << "libkopete (avdevice):     Video overlay";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_CAPTURE)
			kDebug() << "libkopete (avdevice):     VBI capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_OUTPUT)
			kDebug() << "libkopete (avdevice):     VBI output";
		if(V4L2_capabilities.capabilities & V4L2_CAP_RDS_CAPTURE)
			kDebug() << "libkopete (avdevice):     RDS capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_TUNER)
			kDebug() << "libkopete (avdevice):     Tuner IO";
		if(V4L2_capabilities.capabilities & V4L2_CAP_AUDIO)
			kDebug() << "libkopete (avdevice):     Audio IO";
;*/
		kDebug() << "Device model: " << m_model;
		kDebug() << "Device name : " << m_name;
		kDebug() << "Capabilities:";
		if(canCapture())
		{
			kDebug() << "    Video capture";
		}
		if(canRead())
		{
			kDebug() << "        Read";
		}
		if(canAsyncIO())
		{
			kDebug() << "        Asynchronous input/output";
		}
		if(canStream())
		{
			kDebug() << "        Streaming";
		}
		if(canChromakey())
		{
			kDebug() << "    Video chromakey";
		}
		if(canScale())
		{
			kDebug() << "    Video scales";
		}
		if(canOverlay())
		{
			kDebug() << "    Video overlay";
		}
//		kDebug() << "libkopete (avdevice):     Audios : " << V4L_capabilities.audios;
		kDebug() << "    Max res: " << maxWidth() << " x " << maxHeight();
		kDebug() << "    Min res: " << minWidth() << " x " << minHeight();
		kDebug() << "    Inputs : " << inputs();
		for (int loop=0; loop < inputs(); loop++)
			kDebug() << "Input " << loop << ": " << m_input[loop].name << " (tuner: " << m_input[loop].hastuner << ")";
		kDebug() << "showDeviceCapabilities() exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevicePool::initDevice()
 */
int VideoDevice::initDevice()
{
    /// @todo implement me
	kDebug() << "initDevice() started";
	if(-1 == descriptor)
	{
		kDebug() << "initDevice() Device is not open";
		return EXIT_FAILURE;
	}
	m_io_method = IO_METHOD_NONE;
	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
			if(V4L2_capabilities.capabilities & V4L2_CAP_READWRITE)
			{
				m_videoread=true;
				m_io_method = IO_METHOD_READ;
				kDebug() << "    Read/Write interface";
			}
			if(V4L2_capabilities.capabilities & V4L2_CAP_ASYNCIO)
			{
				m_videoasyncio=true;
				kDebug() << "    Async IO interface";
			}
			if(V4L2_capabilities.capabilities & V4L2_CAP_STREAMING)
			{
				m_videostream=true;
				m_io_method = IO_METHOD_MMAP;
//				m_io_method = IO_METHOD_USERPTR;
				kDebug() << "    Streaming interface";
			}
			if(m_io_method==IO_METHOD_NONE)
			{
				kDebug() << "initDevice() Found no suitable input/output method for " << full_filename;
				return EXIT_FAILURE;
			}
			break;
#endif
		case VIDEODEV_DRIVER_V4L:
			m_videoread=true;
			m_io_method=IO_METHOD_READ;
			if(-1 != xioctl(VIDIOCGFBUF,&V4L_videobuffer))
			{
//				m_videostream=true;
//				m_io_method = IO_METHOD_MMAP;
				kDebug() << "    Streaming interface";
			}
			break;
#endif
		case VIDEODEV_DRIVER_NONE:
		default:

			break;
	}

// Select video input, video standard and tune here.
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
	struct v4l2_cropcap cropcap;
	struct v4l2_crop crop;
	CLEAR (cropcap);
	CLEAR (crop);
	
	cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (-1 == xioctl (VIDIOC_CROPCAP, &cropcap))
	{ // Errors ignored.
	}
	crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	crop.c = cropcap.defrect; // reset to default
	if (-1 == xioctl (VIDIOC_S_CROP, &crop))
	{
		switch (errno)
		{
			case EINVAL: break;  // Cropping not supported.
			default:     break;  // Errors ignored.
		}
	}
#endif
#endif

	showDeviceCapabilities();
	kDebug() << "initDevice() exited successfuly";
	return EXIT_SUCCESS;
}

int VideoDevice::inputs()
{
	return m_input.size();
}


int VideoDevice::width()
{
	return currentwidth;
}

int VideoDevice::minWidth()
{
	return minwidth;
}

int VideoDevice::maxWidth()
{
	return maxwidth;
}

int VideoDevice::height()
{
	return currentheight;
}

int VideoDevice::minHeight()
{
	return minheight;
}

int VideoDevice::maxHeight()
{
	return maxheight;
}

int VideoDevice::setSize( int newwidth, int newheight)
{
kDebug() << "setSize(" << newwidth << ", " << newheight << ") called.";
	if(isOpen())
	{
// It should not be there. It must remain in a completely distict place, cause this method should not change the pixelformat.
// It shouldn't try to find a suitable pixel format this way. It should use values discovered by - detectPixelFormats() - to choose a valid one.
		kDebug() <<  "Trying YUY422P";
		errno = 0;
		if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV422P) && errno != EBUSY)
		{
			kDebug() <<  "Device doesn't seem to support YUV422P format. Trying YUYV.";
			if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUYV) && errno != EBUSY)
			{
				kDebug() <<  "Device doesn't seem to support YUYV format. Trying UYVY.";
				if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_UYVY) && errno != EBUSY)
				{
					kDebug() <<  "Device doesn't seem to support UYVY format. Trying YUV420P.";
					if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV420P) && errno != EBUSY)
					{
						kDebug() <<  "Device doesn't seem to support YUV420P format. Trying RGB24.";
						if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB24) && errno != EBUSY)
						{
							kDebug() <<  "Device doesn't seem to support RGB24 format. Trying BGR24.";
							if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR24) && errno != EBUSY)
							{
								kDebug() <<  "Device doesn't seem to support RGB24 format. Trying RGB32.";
								if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB32) && errno != EBUSY)
								{
									kDebug() <<  "Device doesn't seem to support RGB32 format. Trying BGR32.";
									if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR32) && errno != EBUSY)
									{
										kDebug() <<  "Device doesn't seem to support BGR32 format. Trying SBGGR8.";
										if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SBGGR8) && errno != EBUSY)
										{
											kDebug() <<  "Device doesn't seem to support SBGGR8 format. Trying SN9C10X.";
											if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SN9C10X) && errno != EBUSY)
											{
												kDebug() <<  "Device doesn't seem to support BGR32 format. Fallback to it is not yet implemented.";
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		if (errno == EBUSY) {
			kDebug() << "Can't change the video size: device in use";
			return EXIT_FAILURE;
		}

		if(newwidth  > maxwidth ) newwidth  = maxwidth;
		if(newheight > maxheight) newheight = maxheight;
		if(newwidth  < minwidth ) newwidth  = minwidth;
		if(newheight < minheight) newheight = minheight;

		currentwidth  = newwidth;
		currentheight = newheight;

//kDebug() << "width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << width() << "x" << height();
// Change resolution for the video device
		switch(m_driver)
		{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
			case VIDEODEV_DRIVER_V4L2:
//				CLEAR (fmt);
				if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
				{
					kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				}
				fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
				fmt.fmt.pix.width       = width();
				fmt.fmt.pix.height      = height();
				fmt.fmt.pix.field       = V4L2_FIELD_ANY;
				if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
				{
					kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
					// Note VIDIOC_S_FMT may change width and height.
				}
				else
				{
// Buggy driver paranoia.
kDebug() << "VIDIOC_S_FMT worked (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
					unsigned int min = fmt.fmt.pix.width * 2;
					if (fmt.fmt.pix.bytesperline < min)
					{
						fmt.fmt.pix.bytesperline = min;
					}
					min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
					if (fmt.fmt.pix.sizeimage < min)
					{
						fmt.fmt.pix.sizeimage = min;
					}
					m_buffer_size=fmt.fmt.pix.sizeimage ;
				}
				break;
#endif
			case VIDEODEV_DRIVER_V4L:
				{
					struct video_window V4L_videowindow;

				if (xioctl (VIDIOCGWIN, &V4L_videowindow)== -1)
				{
					perror ("ioctl VIDIOCGWIN");
//					return (NULL);
				}
				V4L_videowindow.width  = width();
				V4L_videowindow.height = height();
				V4L_videowindow.clipcount=0;
				if (xioctl (VIDIOCSWIN, &V4L_videowindow)== -1)
				{
					perror ("ioctl VIDIOCSWIN");
//					return (NULL);
				}
kDebug() << "------------- width: " << V4L_videowindow.width << " Height: " << V4L_videowindow.height << " Clipcount: " << V4L_videowindow.clipcount << " -----------------";

//				kDebug() << "libkopete (avdevice): V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;

/*				if(-1 == xioctl(VIDIOCGFBUF,&V4L_videobuffer))
					kDebug() << "libkopete (avdevice): VIDIOCGFBUF failed (" << errno << "): Device cannot stream";*/

				}
				break;
#endif
			case VIDEODEV_DRIVER_NONE:
			default:
				break;
		}
		m_buffer_size = width() * height() * pixelFormatDepth(m_pixelformat) / 8;
kDebug() << "------------------------- ------- -- m_buffer_size: " << m_buffer_size << " !!! -- ------- -----------------------------------------";

		m_currentbuffer.pixelformat=m_pixelformat;
		m_currentbuffer.data.resize(m_buffer_size);

		switch (m_io_method)
		{
			case IO_METHOD_NONE:                    break;
			case IO_METHOD_READ:    initRead ();    break;
			case IO_METHOD_MMAP:    initMmap ();    break;
			case IO_METHOD_USERPTR: initUserptr (); break;
		}

kDebug() << "setSize(" << newwidth << ", " << newheight << ") exited successfuly.";
		return EXIT_SUCCESS;
	}
kDebug() << "setSize(" << newwidth << ", " << newheight << ") Device is not open.";
	return EXIT_FAILURE;
}













pixel_format VideoDevice::setPixelFormat(pixel_format newformat)
{
	pixel_format ret = PIXELFORMAT_NONE;
//kDebug() << "called.";
// Change the pixel format for the video device
	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
//			CLEAR (fmt);
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
                        {
//				return errnoReturn ("VIDIOC_S_FMT");
//				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
			}
			else
				m_pixelformat = pixelFormatForPalette(fmt.fmt.pix.pixelformat);
		
			fmt.fmt.pix.pixelformat = pixelFormatCode(newformat);
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
//				kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
			}
			else
			{
				if (fmt.fmt.pix.pixelformat == (unsigned int) pixelFormatCode(newformat)) // Thih "if" (not what is contained within) is a fix for a bug in sn9c102 driver.
				{
					m_pixelformat = newformat;
					ret = m_pixelformat;
				}
			}
			break;
#endif
		case VIDEODEV_DRIVER_V4L:
			{
			struct video_picture V4L_picture;
			if(-1 == xioctl(VIDIOCGPICT, &V4L_picture))
			{
				kDebug() << "VIDIOCGPICT failed (" << errno << ").";
			}
//			kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;
			V4L_picture.palette = pixelFormatCode(newformat);
			V4L_picture.depth   = pixelFormatDepth(newformat);
			if(-1 == xioctl(VIDIOCSPICT,&V4L_picture))
			{
//				kDebug() << "Device seems to not support " << pixelFormatName(newformat) << " format. Fallback to it is not yet implemented.";
			}

			if(-1 == xioctl(VIDIOCGPICT, &V4L_picture))
			{
				kDebug() << "VIDIOCGPICT failed (" << errno << ").";
			}

//			kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;
			m_pixelformat=pixelFormatForPalette(V4L_picture.palette);
			if (m_pixelformat == newformat)
				ret = newformat;

			}
			break;
#endif
		case VIDEODEV_DRIVER_NONE:
		default:
			break;
	}
	return ret;
}






/*!
    \fn Kopete::AV::VideoDevice::currentInput()
 */
int VideoDevice::currentInput()
{
    /// @todo implement me
	if(isOpen())
	{
		return m_current_input;
	}
	return 0;
}

/*!
    \fn Kopete::AV::VideoDevice::selectInput(int input)
 */
int VideoDevice::selectInput(int newinput)
{
    /// @todo implement me
	if(m_current_input >= inputs())
		return EXIT_FAILURE;

	if(isOpen())
	{
		switch (m_driver)
		{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
			case VIDEODEV_DRIVER_V4L2:
				if (-1 == ioctl (descriptor, VIDIOC_S_INPUT, &newinput))
				{
					perror ("VIDIOC_S_INPUT");
					return EXIT_FAILURE;
				}
				setupControls();
				break;
#endif
			case VIDEODEV_DRIVER_V4L:
				struct video_channel V4L_input;
				V4L_input.channel=newinput;
				V4L_input.norm=4; // Hey, it's plain wrong! It should be input's signal standard!
				if (-1 == ioctl (descriptor, VIDIOCSCHAN, &V4L_input))
				{
					perror ("ioctl (VIDIOCSCHAN)");
					return EXIT_FAILURE;
				}
				setupControls();
				break;
#endif
			case VIDEODEV_DRIVER_NONE:
			default:
				break;
		}
		kDebug() << "Selected input " << newinput << " (" << m_input[newinput].name << ")";
		m_current_input = newinput;
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::startCapturing()
 */
int VideoDevice::startCapturing()
{

	kDebug() << "called.";
	if(isOpen())
	{
		switch (m_io_method)
		{
			case IO_METHOD_NONE: // Device cannot capture frames
				return EXIT_FAILURE;
				break;
			case IO_METHOD_READ: // Nothing to do
				break;
			case IO_METHOD_MMAP:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				{
					unsigned int loop;
					for (loop = 0; loop < m_streambuffers; ++loop)
					{
						struct v4l2_buffer buf;
						CLEAR (buf);
						buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
						buf.memory = V4L2_MEMORY_MMAP;
						buf.index  = loop;
						if (-1 == xioctl (VIDIOC_QBUF, &buf))
							return errnoReturn ("VIDIOC_QBUF");
					}
					enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
					if (-1 == xioctl (VIDIOC_STREAMON, &type))
						return errnoReturn ("VIDIOC_STREAMON");
				}
#endif
#endif
				break;
			case IO_METHOD_USERPTR:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				{
					unsigned int loop;
					for (loop = 0; loop < m_streambuffers; ++loop)
					{
						struct v4l2_buffer buf;
						CLEAR (buf);
						buf.type      = V4L2_BUF_TYPE_VIDEO_CAPTURE;
						buf.memory    = V4L2_MEMORY_USERPTR;
						buf.m.userptr = (unsigned long) m_rawbuffers[loop].start;
						buf.length    = m_rawbuffers[loop].length;
						if (-1 == xioctl (VIDIOC_QBUF, &buf))
							return errnoReturn ("VIDIOC_QBUF");
					}
					enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
					if (-1 == xioctl (VIDIOC_STREAMON, &type))
						return errnoReturn ("VIDIOC_STREAMON");
				}
#endif
#endif
				break;
		}

		kDebug() << "exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::getFrame()
 */
int VideoDevice::getFrame()
{
    /// @todo implement me
	ssize_t bytesread;

#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
	struct v4l2_buffer v4l2buffer;
#endif
#endif
// 	kDebug() << "getFrame() called.";
	if(isOpen())
	{
		switch (m_io_method)
		{
			case IO_METHOD_NONE: // Device cannot capture frames
				return EXIT_FAILURE;
				break;
			case IO_METHOD_READ:
// 				kDebug() << "Using IO_METHOD_READ.File descriptor: " << descriptor << " Buffer address: " << &m_currentbuffer.data[0] << " Size: " << m_currentbuffer.data.size();
				if (m_currentbuffer.data.isEmpty())
					return EXIT_FAILURE;

#ifdef HAVE_LIBV4L2
				bytesread = v4l2_read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size());
#else
				bytesread = read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size());
#endif
				if (-1 == bytesread) // must verify this point with ov511 driver.
				{
					kDebug() << "IO_METHOD_READ failed.";
					switch (errno)
					{
						case EAGAIN:
							return EXIT_FAILURE;
						case EIO: /* Could ignore EIO, see spec. fall through */
						default:
						return errnoReturn ("read");
					}
				}
				if((int)m_currentbuffer.data.size() < bytesread)
				{
					kDebug() << "IO_METHOD_READ returned less bytes (" << bytesread << ") than it was asked for (" << m_currentbuffer.data.size() <<").";
				}
				break;
			case IO_METHOD_MMAP:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				CLEAR (v4l2buffer);
				v4l2buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
				v4l2buffer.memory = V4L2_MEMORY_MMAP;
				if (-1 == xioctl (VIDIOC_DQBUF, &v4l2buffer))
				{
					kDebug() << full_filename << " MMAPed getFrame failed.";
					switch (errno)
					{
						case EAGAIN:
						{
							kDebug() << full_filename << " MMAPed getFrame failed: EAGAIN. Pointer: ";
							return EXIT_FAILURE;
						}
						case EIO: /* Could ignore EIO, see spec. fall through */
						default:
							return errnoReturn ("VIDIOC_DQBUF");
					}
				}
/*				if (v4l2buffer.index < m_streambuffers)
					return EXIT_FAILURE;*/ //it was an assert()
// kDebug() << "m_rawbuffers[" << v4l2buffer.index << "].start: " << (void *)m_rawbuffers[v4l2buffer.index].start << "   Size: " << m_currentbuffer.data.size();
				if (m_currentbuffer.data.isEmpty() ||
//					v4l2buffer.index < 0 ||  	// is always false: v4l2buffer.index is unsigned
					(uint) m_rawbuffers.size() <= v4l2buffer.index)
					return EXIT_FAILURE;

				if (m_rawbuffers[v4l2buffer.index].length < m_currentbuffer.data.size())
				{
					kDebug() <<  "Buffer size mismatch: expecting raw buffer length to be" << m_currentbuffer.data.size() << "but it was" << m_rawbuffers[v4l2buffer.index].length;
					return EXIT_FAILURE;
				}

				memcpy(&m_currentbuffer.data[0], m_rawbuffers[v4l2buffer.index].start, m_currentbuffer.data.size());
				if (-1 == xioctl (VIDIOC_QBUF, &v4l2buffer))
					return errnoReturn ("VIDIOC_QBUF");<commit_msg>videodevice: fix some compilation warnings<commit_after>/*
    videodevice.cpp  -  Kopete Video Device Low-level Support

    Copyright (c) 2005-2006 by <NAME>   <<EMAIL>>
    Copyright (c) 2010      by <NAME>                 <<EMAIL>>

    Kopete    (c) 2002-2003      by the Kopete developers  <<EMAIL>>

    *************************************************************************
    *                                                                       *
    * This library is free software; you can redistribute it and/or         *
    * modify it under the terms of the GNU Lesser General Public            *
    * License as published by the Free Software Foundation; either          *
    * version 2 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#define ENABLE_AV

#include <cstdlib>
#include <cerrno>
#include <cstring>

#include <kdebug.h>

#include "videoinput.h"
#include "videodevice.h"

#include "bayer.h"
#include "sonix_compress.h"

#define CLEAR(x) memset (&(x), 0, sizeof (x))

namespace Kopete {

namespace AV {

VideoDevice::VideoDevice()
{
	descriptor = -1;
	m_streambuffers  = 0;
	m_current_input = 0;
}


VideoDevice::~VideoDevice()
{
	close();
}

/*!
    \fn void VideoDevice::setupControls()
    \brief Sets up the supported video-controls for the current input
    
    Determines which video-controls are supported for the current input,
    reads all needed informations about them and stores the data to the local members
 */
void VideoDevice::setupControls()
{
#if defined(__linux__) && defined(ENABLE_AV)
	bool driver_vflip = false;
	bool driver_hflip = false;
#endif
	m_numericCtrls.clear();
	m_booleanCtrls.clear();
	m_menuCtrls.clear();
	m_actionCtrls.clear();

	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
			struct v4l2_queryctrl qctrl;
			CLEAR (qctrl);
			// Get standard controls:
			for (quint32 k = V4L2_CID_BASE; k < V4L2_CID_LASTP1; k++) // NOTE: DO NOT USE qctrl.id DIRECTLY !
			{
				qctrl.id = k;
				if (0 == xioctl(VIDIOC_QUERYCTRL, &qctrl))
				{
					if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
						continue;
					if (qctrl.id == V4L2_CID_VFLIP)
						driver_vflip = true;
					if (qctrl.id == V4L2_CID_HFLIP)
						driver_hflip = true;
					const char *name_uni = getUnifiedV4L2StdCtrlName(qctrl.id);
					if (name_uni && strlen(name_uni))
						strncpy((char*)qctrl.name, name_uni, 32); // NOTE: v4l2_queryctrl.name is _u8[32]
					saveV4L2ControlData(qctrl);
				}
				else
				{
					if (errno == EINVAL)
						continue;
					kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ").";
				}
			}
			// Get custom controls:
			for (quint32 k = V4L2_CID_PRIVATE_BASE; ; k++)
			{
				qctrl.id = k;
				if (0 == xioctl(VIDIOC_QUERYCTRL, &qctrl))
				{
					if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
						continue;
					saveV4L2ControlData(qctrl);
				}
				else
				{
					if (errno == EINVAL)
						break;
					kDebug() << "VIDIOC_QUERYCTRL failed (" << errno << ").";
				}
			}
			break;
#endif
		case VIDEODEV_DRIVER_V4L:
			{
				NumericVideoControl numCtrl;
				numCtrl.value_min = 0;
				numCtrl.value_max = 65535;
				numCtrl.value_step = 1;
				numCtrl.value_default = 32767;
				numCtrl.id = IMGCTRL_ID_V4L1_BRIGHTNESS;
				numCtrl.name = i18n("Brightness");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_HUE;
				numCtrl.name = i18n("Hue");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_COLOR;
				numCtrl.name = i18n("Color");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_CONTRAST;
				numCtrl.name = i18n("Contrast");
				m_numericCtrls.push_back( numCtrl );
				numCtrl.id = IMGCTRL_ID_V4L1_WHITENESS;
				numCtrl.name = i18n("Whiteness");
				m_numericCtrls.push_back( numCtrl );
			}
			break;
#endif
		case VIDEODEV_DRIVER_NONE:
		default:
			break;
	}
	
#if defined(__linux__) && defined(ENABLE_AV)
	// Software controls:
	BooleanVideoControl boolCtrl;
	boolCtrl.value_default = 0;
	boolCtrl.id = IMGCTRL_ID_SOFT_AUTOBRIGHTNESSCONTRASTCORR;
	boolCtrl.name = i18n("Automatic Brightness/Contrast Correction");
	m_booleanCtrls.push_back( boolCtrl );
	boolCtrl.id = IMGCTRL_ID_SOFT_AUTOCOLORCORR;
	boolCtrl.name = i18n("Automatic Color Correction");
	m_booleanCtrls.push_back( boolCtrl );
	if (!driver_vflip)
	{
		boolCtrl.id = IMGCTRL_ID_SOFT_VFLIP;
		boolCtrl.name = i18n("Vertical Flip");
		m_booleanCtrls.push_back( boolCtrl );
	}
	if (!driver_hflip)
	{
		boolCtrl.id = IMGCTRL_ID_SOFT_HFLIP;
		boolCtrl.name = i18n("Horizontal Flip");
		m_booleanCtrls.push_back( boolCtrl );
	}
#endif
}

#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
/*!
    \fn bool VideoDevice::getMenuCtrlOptions(quint32 id, quint32 maxindex, QStringList * options)
    \param id ID of the video-control
    \param maxindex Highest menu index
    \param options Pointer to the QStringList which will recieve the option-strings of the video-control
    \return The success of the operation
    \brief Reads the available options provided by a menu-video-control
 */
bool VideoDevice::getMenuCtrlOptions(quint32 id, quint32 maxindex, QStringList * options)
{
	QStringList opt;
	struct v4l2_querymenu ctrlmenu;
	CLEAR (ctrlmenu);
	options->clear();
	ctrlmenu.id = id;
	for (quint32 k = 0; k <= maxindex; k++)	// DO NOT USE ctrlmenu.index DIRECTLY !
	{
		ctrlmenu.index = k;
		if (0 == xioctl(VIDIOC_QUERYMENU, &ctrlmenu))
		{
			opt.push_back( i18n( (char*)(ctrlmenu.name) ) );
			kDebug() << "option" << k << ":" << (char*)(ctrlmenu.name);
		}
		else
		{
			kDebug() << "VIDIOC_QUERYMENU failed (" << errno << ").";
			return false;
		}
	}
	*options = opt;
	return true;
	/* NOTE: According to V4L2-spec v0.24:
	         v4l2_querymenu.minimum = start-index = 0, v4l2_querymenu.maximum = last index
	         => DO DRIVERS REALLY SET THESE VALUES CORRECTLY ???
	 */
}


/*!
    \fn void VideoDevice::saveV4L2ControlData(struct v4l2_queryctrl qctrl)
    \param qctrl The struct v4l2_queryctrl of the V4L2-control that should be saved
    \brief Saves the data of a V4L2-video-control
 */
void VideoDevice::saveV4L2ControlData(struct v4l2_queryctrl qctrl)
{
	NumericVideoControl numericCtrl;
	BooleanVideoControl booleanCtrl;
	MenuVideoControl menuCtrl;
	ActionVideoControl actionCtrl;
	QStringList options;
	switch (qctrl.type)
	{
		case V4L2_CTRL_TYPE_INTEGER:
			numericCtrl.id = qctrl.id;
			numericCtrl.name = i18n((char*)qctrl.name);
			numericCtrl.value_min = qctrl.minimum;
			numericCtrl.value_max = qctrl.maximum;
			numericCtrl.value_default = qctrl.default_value;
			numericCtrl.value_step = qctrl.step;
			m_numericCtrls.push_back( numericCtrl );
			break;
		case V4L2_CTRL_TYPE_BOOLEAN:
			booleanCtrl.id = qctrl.id;
			booleanCtrl.name = i18n((char*)qctrl.name);
			booleanCtrl.value_default = qctrl.default_value;
			m_booleanCtrls.push_back( booleanCtrl );
			break;
		case V4L2_CTRL_TYPE_MENU:
			if (getMenuCtrlOptions( qctrl.id, qctrl.maximum, &options ))
			{
				menuCtrl.id = qctrl.id;
				menuCtrl.name = i18n((char*)qctrl.name);
				menuCtrl.index_default = qctrl.default_value;
				menuCtrl.options = options;
				m_menuCtrls.push_back( menuCtrl );
			}
			break;
		case V4L2_CTRL_TYPE_BUTTON:
			actionCtrl.id = qctrl.id;
			actionCtrl.name = i18n((char*)qctrl.name);
			m_actionCtrls.push_back( actionCtrl );
			break;
		// Since kernel 2.6.18:
#ifdef V4L2_CTRL_TYPE_INTEGER64
		case V4L2_CTRL_TYPE_INTEGER64:
#endif
#ifdef V4L2_CTRL_TYPE_CTRL_CLASS
		case V4L2_CTRL_TYPE_CTRL_CLASS:
#endif
		default:
			break;
	}
// TODO	V4L2_CTRL_TYPE_INTEGER64, V4L2_CTRL_TYPE_CTRL_CLASS
}
#endif
#endif

/*!
    \fn VideoDevice::xioctl(int fd, int request, void *arg)
 */
int VideoDevice::xioctl(int request, void *arg)
{
	int r;

#ifdef HAVE_LIBV4L2
	do r = v4l2_ioctl (descriptor, request, arg);
#else
	do r = ioctl (descriptor, request, arg);
#endif
	while (-1 == r && EINTR == errno);
	return r;
}

/*!
    \fn VideoDevice::errnoReturn(const char* s)
 */
int VideoDevice::errnoReturn(const char* s)
{
    /// @todo implement me
	fprintf (stderr, "%s error %d, %s\n",s, errno, strerror (errno));
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::setFileName(QString name)
 */
int VideoDevice::setFileName(QString filename)
{
    /// @todo implement me
	full_filename=filename;
	return EXIT_SUCCESS;
}

/*!
    \fn QString VideoDevice::fileName()
 */
QString VideoDevice::fileName()
{
	return full_filename;
}

/*!
    \fn VideoDevice::open()
 */
int VideoDevice::open()
{
    /// @todo implement me

	kDebug() << "called";
	if(-1 != descriptor)
	{
		kDebug() << "Device is already open";
		return EXIT_SUCCESS;
	}
#ifdef HAVE_LIBV4L2
	descriptor = ::v4l2_open (QFile::encodeName(full_filename), O_RDWR, 0);
#else
	descriptor = ::open (QFile::encodeName(full_filename), O_RDWR, 0);
#endif
	if(isOpen())
	{
		kDebug() << "File " << full_filename << " was opened successfuly";
		if(EXIT_FAILURE==checkDevice())
		{
			kDebug() << "File " << full_filename << " could not be opened";
			close();
			return EXIT_FAILURE;
		}
	}
	else
	{
		kDebug() << "Unable to open file " << full_filename << "Err: "<< errno;
		return EXIT_FAILURE;
	}

	initDevice();
	selectInput(m_current_input);
	kDebug() << "exited successfuly";
	return EXIT_SUCCESS;
}

bool VideoDevice::isOpen()
{
	if(-1 == descriptor)
	{
//		kDebug() << "VideoDevice::isOpen() File is not open";
		return false;
	}
//	kDebug() << "VideoDevice::isOpen() File is open";
	return true;
}

int VideoDevice::checkDevice()
{
	kDebug() << "checkDevice() called.";
	if(isOpen())
	{
		m_videocapture=false;
		m_videochromakey=false;
		m_videoscale=false;
		m_videooverlay=false;
		m_videoread=false;
		m_videoasyncio=false;
		m_videostream=false;

		m_driver=VIDEODEV_DRIVER_NONE;
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE

		CLEAR(V4L2_capabilities);

		if (-1 != xioctl (VIDIOC_QUERYCAP, &V4L2_capabilities))
		{
			if (!(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE))
			{
				kDebug() << "checkDevice(): " << full_filename << " is not a video capture device.";
				m_driver = VIDEODEV_DRIVER_NONE;
				return EXIT_FAILURE;
			}
			m_videocapture=true;
			kDebug() << "checkDevice(): " << full_filename << " is a V4L2 device.";
			m_driver = VIDEODEV_DRIVER_V4L2;
			m_model=QString::fromLocal8Bit((const char*)V4L2_capabilities.card);


// Detect maximum and minimum resolution supported by the V4L2 device. VIDIOC_ENUM_FRAMESIZES is still experimental.
			CLEAR (fmt);
			fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
			{
				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").";
			}
			fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			fmt.fmt.pix.width       = 32767;
			fmt.fmt.pix.height      = 32767;
			fmt.fmt.pix.field       = V4L2_FIELD_ANY;
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
				kDebug() << "Detecting maximum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				// Note VIDIOC_S_FMT may change width and height.
			}
			else
			{
				maxwidth  = fmt.fmt.pix.width;
				maxheight = fmt.fmt.pix.height;
			}
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
			{
				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").";
			}
			fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			fmt.fmt.pix.width       = 1;
			fmt.fmt.pix.height      = 1;
			fmt.fmt.pix.field       = V4L2_FIELD_ANY;
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
				kDebug() << "Detecting minimum size with VIDIOC_S_FMT failed (" << errno << ").Returned maxwidth: " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				// Note VIDIOC_S_FMT may change width and height.
			}
			else
			{
				minwidth  = fmt.fmt.pix.width;
				minheight = fmt.fmt.pix.height;
			}

// Buggy driver paranoia
/*				min = fmt.fmt.pix.width * 2;
				if (fmt.fmt.pix.bytesperline < min)
					fmt.fmt.pix.bytesperline = min;
				min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
				if (fmt.fmt.pix.sizeimage < min)
					fmt.fmt.pix.sizeimage = min;
				m_buffer_size=fmt.fmt.pix.sizeimage ;*/

			int inputisok=EXIT_SUCCESS;
			m_input.clear();
			for(unsigned int loop=0; inputisok==EXIT_SUCCESS; loop++)
			{
				struct v4l2_input videoinput;
				CLEAR(videoinput);
				videoinput.index = loop;
				inputisok=xioctl(VIDIOC_ENUMINPUT, &videoinput);
				if(inputisok==EXIT_SUCCESS)
				{
					VideoInput tempinput;
					tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name);
					tempinput.hastuner = videoinput.type & V4L2_INPUT_TYPE_TUNER;
detectSignalStandards();
					tempinput.m_standards = videoinput.std;
					m_input.push_back(tempinput);
					kDebug() << "Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0) << ")";
					if((videoinput.type & V4L2_INPUT_TYPE_TUNER) != 0)
					{
//						_tunerForInput[name] = desc.tuner;
//						_isTuner = true;
					}
					else
					{
//						_tunerForInput[name] = -1;
					}
				}
			}
		}
		else
		{
// V4L-only drivers should return an EINVAL in errno to indicate they cannot handle V4L2 calls. Not every driver is compliant, so
// it will try the V4L api even if the error code is different than expected.
			kDebug() << "checkDevice(): " << full_filename << " is not a V4L2 device.";
		}

#endif

		CLEAR(V4L_capabilities);

		if(m_driver==VIDEODEV_DRIVER_NONE)
		{
			kDebug() << "checkDevice(): " << full_filename << " Trying V4L API.";
			if (-1 == xioctl (VIDIOCGCAP, &V4L_capabilities))
			{
				perror ("ioctl (VIDIOCGCAP)");
				m_driver = VIDEODEV_DRIVER_NONE;
				return EXIT_FAILURE;
			}
			else
			{
				kDebug() << full_filename << " is a V4L device.";
				m_driver = VIDEODEV_DRIVER_V4L;
				m_model=QString::fromLocal8Bit((const char*)V4L_capabilities.name);
				if(V4L_capabilities.type & VID_TYPE_CAPTURE)
					m_videocapture=true;
				if(V4L_capabilities.type & VID_TYPE_CHROMAKEY)
					m_videochromakey=true;
				if(V4L_capabilities.type & VID_TYPE_SCALES)
					m_videoscale=true;	
				if(V4L_capabilities.type & VID_TYPE_OVERLAY)
					m_videooverlay=true;
//				kDebug() << "libkopete (avdevice):     Inputs : " << V4L_capabilities.channels;
//				kDebug() << "libkopete (avdevice):     Audios : " << V4L_capabilities.audios;
				minwidth  = V4L_capabilities.minwidth;
				maxwidth  = V4L_capabilities.maxwidth;
				minheight = V4L_capabilities.minheight;
				maxheight = V4L_capabilities.maxheight;


				int inputisok=EXIT_SUCCESS;
				m_input.clear();
				for(int loop=0; loop < V4L_capabilities.channels; loop++)
				{
					struct video_channel videoinput;
					CLEAR(videoinput);
					videoinput.channel = loop;
					videoinput.norm    = 1;
					inputisok=xioctl(VIDIOCGCHAN, &videoinput);
					if(inputisok==EXIT_SUCCESS)
					{
						VideoInput tempinput;
						tempinput.name = QString::fromLocal8Bit((const char*)videoinput.name);
						tempinput.hastuner=videoinput.flags & VIDEO_VC_TUNER;
// TODO: The routine to detect the appropriate video standards for V4L must be placed here
						m_input.push_back(tempinput);
//						kDebug() << "libkopete (avdevice): Input " << loop << ": " << tempinput.name << " (tuner: " << ((videoinput.flags & VIDEO_VC_TUNER) != 0) << ")";
/*						if((input.type & V4L2_INPUT_TYPE_TUNER) != 0)
						{
//							_tunerForInput[name] = desc.tuner;
//							_isTuner = true;
						}
						else
						{
//							_tunerForInput[name] = -1;
						}
*/					}
				}

			}
		}
#endif
		m_name=m_model; // Take care about changing the name to be different from the model itself...

		detectPixelFormats();
// TODO: Now we must execute the proper initialization according to the type of the driver.
		kDebug() << "checkDevice() exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}


/*!
    \fn VideoDevice::showDeviceCapabilities()
 */
int VideoDevice::showDeviceCapabilities()
{
	kDebug() << "showDeviceCapabilities() called.";
	if(isOpen())
	{
/*		kDebug() << "libkopete (avdevice): Driver: " << (const char*)V4L2_capabilities.driver << " "
			<< ((V4L2_capabilities.version>>16) & 0xFF) << "."
			<< ((V4L2_capabilities.version>> 8) & 0xFF) << "."
			<< ((V4L2_capabilities.version    ) & 0xFF) << endl;
		kDebug() << "libkopete (avdevice): Device: " << name;
		kDebug() << "libkopete (avdevice): Capabilities:";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_CAPTURE)
			kDebug() << "libkopete (avdevice):     Video capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OUTPUT)
			kDebug() << "libkopete (avdevice):     Video output";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VIDEO_OVERLAY)
			kDebug() << "libkopete (avdevice):     Video overlay";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_CAPTURE)
			kDebug() << "libkopete (avdevice):     VBI capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_VBI_OUTPUT)
			kDebug() << "libkopete (avdevice):     VBI output";
		if(V4L2_capabilities.capabilities & V4L2_CAP_RDS_CAPTURE)
			kDebug() << "libkopete (avdevice):     RDS capture";
		if(V4L2_capabilities.capabilities & V4L2_CAP_TUNER)
			kDebug() << "libkopete (avdevice):     Tuner IO";
		if(V4L2_capabilities.capabilities & V4L2_CAP_AUDIO)
			kDebug() << "libkopete (avdevice):     Audio IO";
;*/
		kDebug() << "Device model: " << m_model;
		kDebug() << "Device name : " << m_name;
		kDebug() << "Capabilities:";
		if(canCapture())
		{
			kDebug() << "    Video capture";
		}
		if(canRead())
		{
			kDebug() << "        Read";
		}
		if(canAsyncIO())
		{
			kDebug() << "        Asynchronous input/output";
		}
		if(canStream())
		{
			kDebug() << "        Streaming";
		}
		if(canChromakey())
		{
			kDebug() << "    Video chromakey";
		}
		if(canScale())
		{
			kDebug() << "    Video scales";
		}
		if(canOverlay())
		{
			kDebug() << "    Video overlay";
		}
//		kDebug() << "libkopete (avdevice):     Audios : " << V4L_capabilities.audios;
		kDebug() << "    Max res: " << maxWidth() << " x " << maxHeight();
		kDebug() << "    Min res: " << minWidth() << " x " << minHeight();
		kDebug() << "    Inputs : " << inputs();
		for (int loop=0; loop < inputs(); loop++)
			kDebug() << "Input " << loop << ": " << m_input[loop].name << " (tuner: " << m_input[loop].hastuner << ")";
		kDebug() << "showDeviceCapabilities() exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevicePool::initDevice()
 */
int VideoDevice::initDevice()
{
    /// @todo implement me
	kDebug() << "initDevice() started";
	if(-1 == descriptor)
	{
		kDebug() << "initDevice() Device is not open";
		return EXIT_FAILURE;
	}
	m_io_method = IO_METHOD_NONE;
	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
			if(V4L2_capabilities.capabilities & V4L2_CAP_READWRITE)
			{
				m_videoread=true;
				m_io_method = IO_METHOD_READ;
				kDebug() << "    Read/Write interface";
			}
			if(V4L2_capabilities.capabilities & V4L2_CAP_ASYNCIO)
			{
				m_videoasyncio=true;
				kDebug() << "    Async IO interface";
			}
			if(V4L2_capabilities.capabilities & V4L2_CAP_STREAMING)
			{
				m_videostream=true;
				m_io_method = IO_METHOD_MMAP;
//				m_io_method = IO_METHOD_USERPTR;
				kDebug() << "    Streaming interface";
			}
			if(m_io_method==IO_METHOD_NONE)
			{
				kDebug() << "initDevice() Found no suitable input/output method for " << full_filename;
				return EXIT_FAILURE;
			}
			break;
#endif
		case VIDEODEV_DRIVER_V4L:
			m_videoread=true;
			m_io_method=IO_METHOD_READ;
			if(-1 != xioctl(VIDIOCGFBUF,&V4L_videobuffer))
			{
//				m_videostream=true;
//				m_io_method = IO_METHOD_MMAP;
				kDebug() << "    Streaming interface";
			}
			break;
#endif
		case VIDEODEV_DRIVER_NONE:
		default:

			break;
	}

// Select video input, video standard and tune here.
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
	struct v4l2_cropcap cropcap;
	struct v4l2_crop crop;
	CLEAR (cropcap);
	CLEAR (crop);
	
	cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (-1 == xioctl (VIDIOC_CROPCAP, &cropcap))
	{ // Errors ignored.
	}
	crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	crop.c = cropcap.defrect; // reset to default
	if (-1 == xioctl (VIDIOC_S_CROP, &crop))
	{
		switch (errno)
		{
			case EINVAL: break;  // Cropping not supported.
			default:     break;  // Errors ignored.
		}
	}
#endif
#endif

	showDeviceCapabilities();
	kDebug() << "initDevice() exited successfuly";
	return EXIT_SUCCESS;
}

int VideoDevice::inputs()
{
	return m_input.size();
}


int VideoDevice::width()
{
	return currentwidth;
}

int VideoDevice::minWidth()
{
	return minwidth;
}

int VideoDevice::maxWidth()
{
	return maxwidth;
}

int VideoDevice::height()
{
	return currentheight;
}

int VideoDevice::minHeight()
{
	return minheight;
}

int VideoDevice::maxHeight()
{
	return maxheight;
}

int VideoDevice::setSize( int newwidth, int newheight)
{
kDebug() << "setSize(" << newwidth << ", " << newheight << ") called.";
	if(isOpen())
	{
// It should not be there. It must remain in a completely distict place, cause this method should not change the pixelformat.
// It shouldn't try to find a suitable pixel format this way. It should use values discovered by - detectPixelFormats() - to choose a valid one.
		kDebug() <<  "Trying YUY422P";
		errno = 0;
		if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV422P) && errno != EBUSY)
		{
			kDebug() <<  "Device doesn't seem to support YUV422P format. Trying YUYV.";
			if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUYV) && errno != EBUSY)
			{
				kDebug() <<  "Device doesn't seem to support YUYV format. Trying UYVY.";
				if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_UYVY) && errno != EBUSY)
				{
					kDebug() <<  "Device doesn't seem to support UYVY format. Trying YUV420P.";
					if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_YUV420P) && errno != EBUSY)
					{
						kDebug() <<  "Device doesn't seem to support YUV420P format. Trying RGB24.";
						if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB24) && errno != EBUSY)
						{
							kDebug() <<  "Device doesn't seem to support RGB24 format. Trying BGR24.";
							if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR24) && errno != EBUSY)
							{
								kDebug() <<  "Device doesn't seem to support RGB24 format. Trying RGB32.";
								if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_RGB32) && errno != EBUSY)
								{
									kDebug() <<  "Device doesn't seem to support RGB32 format. Trying BGR32.";
									if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_BGR32) && errno != EBUSY)
									{
										kDebug() <<  "Device doesn't seem to support BGR32 format. Trying SBGGR8.";
										if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SBGGR8) && errno != EBUSY)
										{
											kDebug() <<  "Device doesn't seem to support SBGGR8 format. Trying SN9C10X.";
											if(PIXELFORMAT_NONE == setPixelFormat(PIXELFORMAT_SN9C10X) && errno != EBUSY)
											{
												kDebug() <<  "Device doesn't seem to support BGR32 format. Fallback to it is not yet implemented.";
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		if (errno == EBUSY) {
			kDebug() << "Can't change the video size: device in use";
			return EXIT_FAILURE;
		}

		if(newwidth  > maxwidth ) newwidth  = maxwidth;
		if(newheight > maxheight) newheight = maxheight;
		if(newwidth  < minwidth ) newwidth  = minwidth;
		if(newheight < minheight) newheight = minheight;

		currentwidth  = newwidth;
		currentheight = newheight;

//kDebug() << "width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << width() << "x" << height();
// Change resolution for the video device
		switch(m_driver)
		{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
			case VIDEODEV_DRIVER_V4L2:
//				CLEAR (fmt);
				if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
				{
					kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
				}
				fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
				fmt.fmt.pix.width       = width();
				fmt.fmt.pix.height      = height();
				fmt.fmt.pix.field       = V4L2_FIELD_ANY;
				if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
				{
					kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
					// Note VIDIOC_S_FMT may change width and height.
				}
				else
				{
// Buggy driver paranoia.
kDebug() << "VIDIOC_S_FMT worked (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
					unsigned int min = fmt.fmt.pix.width * 2;
					if (fmt.fmt.pix.bytesperline < min)
					{
						fmt.fmt.pix.bytesperline = min;
					}
					min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
					if (fmt.fmt.pix.sizeimage < min)
					{
						fmt.fmt.pix.sizeimage = min;
					}
					m_buffer_size=fmt.fmt.pix.sizeimage ;
				}
				break;
#endif
			case VIDEODEV_DRIVER_V4L:
				{
					struct video_window V4L_videowindow;

				if (xioctl (VIDIOCGWIN, &V4L_videowindow)== -1)
				{
					perror ("ioctl VIDIOCGWIN");
//					return (NULL);
				}
				V4L_videowindow.width  = width();
				V4L_videowindow.height = height();
				V4L_videowindow.clipcount=0;
				if (xioctl (VIDIOCSWIN, &V4L_videowindow)== -1)
				{
					perror ("ioctl VIDIOCSWIN");
//					return (NULL);
				}
kDebug() << "------------- width: " << V4L_videowindow.width << " Height: " << V4L_videowindow.height << " Clipcount: " << V4L_videowindow.clipcount << " -----------------";

//				kDebug() << "libkopete (avdevice): V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;

/*				if(-1 == xioctl(VIDIOCGFBUF,&V4L_videobuffer))
					kDebug() << "libkopete (avdevice): VIDIOCGFBUF failed (" << errno << "): Device cannot stream";*/

				}
				break;
#endif
			case VIDEODEV_DRIVER_NONE:
			default:
				break;
		}
		m_buffer_size = width() * height() * pixelFormatDepth(m_pixelformat) / 8;
kDebug() << "------------------------- ------- -- m_buffer_size: " << m_buffer_size << " !!! -- ------- -----------------------------------------";

		m_currentbuffer.pixelformat=m_pixelformat;
		m_currentbuffer.data.resize(m_buffer_size);

		switch (m_io_method)
		{
			case IO_METHOD_NONE:                    break;
			case IO_METHOD_READ:    initRead ();    break;
			case IO_METHOD_MMAP:    initMmap ();    break;
			case IO_METHOD_USERPTR: initUserptr (); break;
		}

kDebug() << "setSize(" << newwidth << ", " << newheight << ") exited successfuly.";
		return EXIT_SUCCESS;
	}
kDebug() << "setSize(" << newwidth << ", " << newheight << ") Device is not open.";
	return EXIT_FAILURE;
}













pixel_format VideoDevice::setPixelFormat(pixel_format newformat)
{
	pixel_format ret = PIXELFORMAT_NONE;
//kDebug() << "called.";
// Change the pixel format for the video device
	switch(m_driver)
	{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
		case VIDEODEV_DRIVER_V4L2:
//			CLEAR (fmt);
			if (-1 == xioctl (VIDIOC_G_FMT, &fmt))
                        {
//				return errnoReturn ("VIDIOC_S_FMT");
//				kDebug() << "VIDIOC_G_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
			}
			else
				m_pixelformat = pixelFormatForPalette(fmt.fmt.pix.pixelformat);
		
			fmt.fmt.pix.pixelformat = pixelFormatCode(newformat);
			if (-1 == xioctl (VIDIOC_S_FMT, &fmt))
			{
//				kDebug() << "VIDIOC_S_FMT failed (" << errno << ").Returned width: " << pixelFormatName(fmt.fmt.pix.pixelformat) << " " << fmt.fmt.pix.width << "x" << fmt.fmt.pix.height;
			}
			else
			{
				if (fmt.fmt.pix.pixelformat == (unsigned int) pixelFormatCode(newformat)) // Thih "if" (not what is contained within) is a fix for a bug in sn9c102 driver.
				{
					m_pixelformat = newformat;
					ret = m_pixelformat;
				}
			}
			break;
#endif
		case VIDEODEV_DRIVER_V4L:
			{
			struct video_picture V4L_picture;
			if(-1 == xioctl(VIDIOCGPICT, &V4L_picture))
			{
				kDebug() << "VIDIOCGPICT failed (" << errno << ").";
			}
//			kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;
			V4L_picture.palette = pixelFormatCode(newformat);
			V4L_picture.depth   = pixelFormatDepth(newformat);
			if(-1 == xioctl(VIDIOCSPICT,&V4L_picture))
			{
//				kDebug() << "Device seems to not support " << pixelFormatName(newformat) << " format. Fallback to it is not yet implemented.";
			}

			if(-1 == xioctl(VIDIOCGPICT, &V4L_picture))
			{
				kDebug() << "VIDIOCGPICT failed (" << errno << ").";
			}

//			kDebug() << "V4L_picture.palette: " << V4L_picture.palette << " Depth: " << V4L_picture.depth;
			m_pixelformat=pixelFormatForPalette(V4L_picture.palette);
			if (m_pixelformat == newformat)
				ret = newformat;

			}
			break;
#endif
		case VIDEODEV_DRIVER_NONE:
		default:
			break;
	}
	return ret;
}






/*!
    \fn Kopete::AV::VideoDevice::currentInput()
 */
int VideoDevice::currentInput()
{
    /// @todo implement me
	if(isOpen())
	{
		return m_current_input;
	}
	return 0;
}

/*!
    \fn Kopete::AV::VideoDevice::selectInput(int input)
 */
int VideoDevice::selectInput(int newinput)
{
    /// @todo implement me
	if(m_current_input >= inputs())
		return EXIT_FAILURE;

	if(isOpen())
	{
		switch (m_driver)
		{
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
			case VIDEODEV_DRIVER_V4L2:
				if (-1 == ioctl (descriptor, VIDIOC_S_INPUT, &newinput))
				{
					perror ("VIDIOC_S_INPUT");
					return EXIT_FAILURE;
				}
				setupControls();
				break;
#endif
			case VIDEODEV_DRIVER_V4L:
				struct video_channel V4L_input;
				V4L_input.channel=newinput;
				V4L_input.norm=4; // Hey, it's plain wrong! It should be input's signal standard!
				if (-1 == ioctl (descriptor, VIDIOCSCHAN, &V4L_input))
				{
					perror ("ioctl (VIDIOCSCHAN)");
					return EXIT_FAILURE;
				}
				setupControls();
				break;
#endif
			case VIDEODEV_DRIVER_NONE:
			default:
				break;
		}
		kDebug() << "Selected input " << newinput << " (" << m_input[newinput].name << ")";
		m_current_input = newinput;
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::startCapturing()
 */
int VideoDevice::startCapturing()
{

	kDebug() << "called.";
	if(isOpen())
	{
		switch (m_io_method)
		{
			case IO_METHOD_NONE: // Device cannot capture frames
				return EXIT_FAILURE;
				break;
			case IO_METHOD_READ: // Nothing to do
				break;
			case IO_METHOD_MMAP:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				{
					unsigned int loop;
					for (loop = 0; loop < m_streambuffers; ++loop)
					{
						struct v4l2_buffer buf;
						CLEAR (buf);
						buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
						buf.memory = V4L2_MEMORY_MMAP;
						buf.index  = loop;
						if (-1 == xioctl (VIDIOC_QBUF, &buf))
							return errnoReturn ("VIDIOC_QBUF");
					}
					enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
					if (-1 == xioctl (VIDIOC_STREAMON, &type))
						return errnoReturn ("VIDIOC_STREAMON");
				}
#endif
#endif
				break;
			case IO_METHOD_USERPTR:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				{
					unsigned int loop;
					for (loop = 0; loop < m_streambuffers; ++loop)
					{
						struct v4l2_buffer buf;
						CLEAR (buf);
						buf.type      = V4L2_BUF_TYPE_VIDEO_CAPTURE;
						buf.memory    = V4L2_MEMORY_USERPTR;
						buf.m.userptr = (unsigned long) m_rawbuffers[loop].start;
						buf.length    = m_rawbuffers[loop].length;
						if (-1 == xioctl (VIDIOC_QBUF, &buf))
							return errnoReturn ("VIDIOC_QBUF");
					}
					enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
					if (-1 == xioctl (VIDIOC_STREAMON, &type))
						return errnoReturn ("VIDIOC_STREAMON");
				}
#endif
#endif
				break;
		}

		kDebug() << "exited successfuly.";
		return EXIT_SUCCESS;
	}
	return EXIT_FAILURE;
}

/*!
    \fn VideoDevice::getFrame()
 */
int VideoDevice::getFrame()
{
    /// @todo implement me
	ssize_t bytesread;

#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
	struct v4l2_buffer v4l2buffer;
#endif
#endif
// 	kDebug() << "getFrame() called.";
	if(isOpen())
	{
		switch (m_io_method)
		{
			case IO_METHOD_NONE: // Device cannot capture frames
				return EXIT_FAILURE;
				break;
			case IO_METHOD_READ:
// 				kDebug() << "Using IO_METHOD_READ.File descriptor: " << descriptor << " Buffer address: " << &m_currentbuffer.data[0] << " Size: " << m_currentbuffer.data.size();
				if (m_currentbuffer.data.isEmpty())
					return EXIT_FAILURE;

#ifdef HAVE_LIBV4L2
				bytesread = v4l2_read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size());
#else
				bytesread = read (descriptor, &m_currentbuffer.data[0], m_currentbuffer.data.size());
#endif
				if (-1 == bytesread) // must verify this point with ov511 driver.
				{
					kDebug() << "IO_METHOD_READ failed.";
					switch (errno)
					{
						case EAGAIN:
							return EXIT_FAILURE;
						case EIO: /* Could ignore EIO, see spec. fall through */
						default:
						return errnoReturn ("read");
					}
				}
				if((int)m_currentbuffer.data.size() < bytesread)
				{
					kDebug() << "IO_METHOD_READ returned less bytes (" << bytesread << ") than it was asked for (" << m_currentbuffer.data.size() <<").";
				}
				break;
			case IO_METHOD_MMAP:
#if defined(__linux__) && defined(ENABLE_AV)
#ifdef V4L2_CAP_VIDEO_CAPTURE
				CLEAR (v4l2buffer);
				v4l2buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
				v4l2buffer.memory = V4L2_MEMORY_MMAP;
				if (-1 == xioctl (VIDIOC_DQBUF, &v4l2buffer))
				{
					kDebug() << full_filename << " MMAPed getFrame failed.";
					switch (errno)
					{
						case EAGAIN:
						{
							kDebug() << full_filename << " MMAPed getFrame failed: EAGAIN. Pointer: ";
							return EXIT_FAILURE;
						}
						case EIO: /* Could ignore EIO, see spec. fall through */
						default:
							return errnoReturn ("VIDIOC_DQBUF");
					}
				}
/*				if (v4l2buffer.index < m_streambuffers)
					return EXIT_FAILURE;*/ //it was an assert()
// kDebug() << "m_rawbuffers[" << v4l2buffer.index << "].start: " << (void *)m_rawbuffers[v4l2buffer.index].start << "   Size: " << m_currentbuffer.data.size();
				if (m_currentbuffer.data.isEmpty() ||
//					v4l2buffer.index < 0 ||  	// is always false: v4l2buffer.index is unsigned
					(uint) m_rawbuffers.size() <= v4l2buffer.index)
					return EXIT_FAILURE;

				if (m_rawbuffers[v4l2buffer.index].length < (uint)m_currentbuffer.data.size())
				{
					kDebug() <<  "Buffer size mismatch: expecting raw buffer length to be" << m_currentbuffer.data.size() << "but it was" << m_rawbuffers[v4l2buffer.index].length;
					return EXIT_FAILURE;
				}

				memcpy(&m_currentbuffer.data[0], m_rawbuffers[v4l2buffer.index].start, m_currentbuffer.data.size());
				if (-1 == xioctl (VIDIOC_QBUF, &v4l2buffer))
					return errnoReturn ("VIDIOC_QBUF");
{'fraction_non_alphanumeric': 0.14381166744525134, 'fraction_numerical': 0.016505995101994592, 'mean_word_length': 3.2563113815749833, 'pattern_counts': {'":': 8, '<': 1205, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5982132', 'n_tokens_mistral': 30663, 'n_tokens_neox': 26394, 'n_words': 5205}