public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* V4l2 :: Debugging an issue with cx8800 card.
@ 2008-09-04 22:14 B. Bogart
  2008-09-04 22:51 ` Andy Walls
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-04 22:14 UTC (permalink / raw)
  To: video4linux-list; +Cc: gem-dev

[-- Attachment #1: Type: text/plain, Size: 3433 bytes --]

Hello all,

This issue has been lagging for years and I wanted to get some expert
advice on debugging it. It seems I'm the only one with a cx8800 card
that is having problems so I hope to take the challenge up and propose a
solution to the maintainer.

So the software I'm using is GEM. It has v4l2 support, and works fine
with my bt848 card. Problem is I can't get things working properly with
my cx8800 cards.

First HW info:

lspci reports my tuner as:

00:0d.0 Multimedia video controller: Conexant CX23880/1/2/3 PCI Video
and Audio Decoder (rev 05)

The card is branded as a Leadtek Winfast 2000XP Expert.

I'm sure the problem is with the v4l2 implementation in Gem as running
the following command gives me perfect video on this card at 640x480:

mplayer tv:// -tv driver=v4l2:device=/dev/video0:input=1:norm=NTSC-M

(the output follows this message).

So the card is capable of 640x480.

If I run Gem on this card as 320x240 all works fine. (pictured in
attachment 320x240.png)

As soon as I change the resolution to 640x480 I get the following errors
repeated:

VIDIOCMCAPTURE1: Invalid argument
VIDIOCMCAPTURE2: Invalid argument

And the image appears as in attachment 640x480.png

What should my steps for debugging be?

Is there dead-simple v4l2 example source (including output so I can
confirm its working) I can test with and compare with Gem sources?

Any advice appreciated.

B. Bogart


--
Here is the mplayer output:

MPlayer dev-SVN-r26940
CPU: AMD Athlon(tm) 64 Processor 3200+ (Family: 15, Model: 47, Stepping: 0)
CPUflags:  MMX: 1 MMX2: 1 3DNow: 1 3DNow2: 1 SSE: 1 SSE2: 1
Compiled with runtime CPU detection.
Can't open joystick device /dev/input/js0: No such file or directory
Can't init input joystick
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote
control.

Playing tv://.
TV file format detected.
Selected driver: v4l2
 name: Video 4 Linux 2 input
 author: Martin Olschewski <olschewski@zpr.uni-koeln.de>
 comment: first try, more to come ;-)
Selected device: Leadtek Winfast 2000XP Expert
 Tuner cap:
 Tuner rxs:
 Capabilites:  video capture  VBI capture device  tuner  read/write
streaming
 supported norms: 0 = PAL-BG; 1 = PAL-DK; 2 = PAL-I; 3 = PAL-M; 4 =
PAL-N; 5 = PAL-Nc; 6 = PAL-60; 7 = NTSC-M; 8 = NTSC-M-JP; 9 = NTSC-443;
10 = SECAM-DK; 11 = SECAM-L;
 inputs: 0 = Television; 1 = Composite1; 2 = S-Video;
 Current input: 1
 Current format: BGR24
v4l2: current audio mode is : MONO
v4l2: ioctl set format failed: Invalid argument
v4l2: ioctl set format failed: Invalid argument
open: No such file or directory
[MGA] Couldn't open: /dev/mga_vid
open: No such file or directory
[MGA] Couldn't open: /dev/mga_vid
[VO_TDFXFB] Can't open /dev/fb0: No such file or directory.
s3fb: can't open /dev/fb0: No such file or directory
==========================================================================
Opening video decoder: [raw] RAW Uncompressed Video
VDec: vo config request - 640 x 480 (preferred colorspace: Packed UYVY)
VDec: using Packed UYVY as output csp (no 0)
Movie-Aspect is undefined - no prescaling applied.
VO: [xv] 640x480 => 640x480 Packed UYVY
Selected video codec: [rawuyvy] vfm: raw (RAW UYVY)
==========================================================================
Audio: no sound
Starting playback...
v4l2: 40 frames successfully processed, -39 frames dropped.

Exiting... (Quit)


[-- Attachment #2: 320x240.png --]
[-- Type: image/png, Size: 184819 bytes --]

[-- Attachment #3: 640x480.png --]
[-- Type: image/png, Size: 134088 bytes --]

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 22:14 V4l2 :: Debugging an issue with cx8800 card B. Bogart
@ 2008-09-04 22:51 ` Andy Walls
  2008-09-04 23:16   ` B. Bogart
                     ` (2 more replies)
  2008-09-12  0:44 ` Broken gem support for UYVY V4L capture? WAS " B. Bogart
  2008-09-12  0:46 ` Sorry! B. Bogart
  2 siblings, 3 replies; 9+ messages in thread
From: Andy Walls @ 2008-09-04 22:51 UTC (permalink / raw)
  To: B. Bogart; +Cc: video4linux-list, gem-dev

[-- Attachment #1: Type: text/plain, Size: 4366 bytes --]

On Thu, 2008-09-04 at 15:14 -0700, B. Bogart wrote:
> Hello all,
> 
> This issue has been lagging for years and I wanted to get some expert
> advice on debugging it. It seems I'm the only one with a cx8800 card
> that is having problems so I hope to take the challenge up and propose a
> solution to the maintainer.
> 
> So the software I'm using is GEM. It has v4l2 support, and works fine
> with my bt848 card. Problem is I can't get things working properly with
> my cx8800 cards.
> 
> First HW info:
> 
> lspci reports my tuner as:
> 
> 00:0d.0 Multimedia video controller: Conexant CX23880/1/2/3 PCI Video
> and Audio Decoder (rev 05)
> 
> The card is branded as a Leadtek Winfast 2000XP Expert.
> 
> I'm sure the problem is with the v4l2 implementation in Gem as running
> the following command gives me perfect video on this card at 640x480:
> 
> mplayer tv:// -tv driver=v4l2:device=/dev/video0:input=1:norm=NTSC-M
> 
> (the output follows this message).
> 
> So the card is capable of 640x480.
> 
> If I run Gem on this card as 320x240 all works fine. (pictured in
> attachment 320x240.png)
> 
> As soon as I change the resolution to 640x480 I get the following errors
> repeated:
> 
> VIDIOCMCAPTURE1: Invalid argument
> VIDIOCMCAPTURE2: Invalid argument
> 
> And the image appears as in attachment 640x480.png
> 
> What should my steps for debugging be?
> 
> Is there dead-simple v4l2 example source (including output so I can
> confirm its working) I can test with and compare with Gem sources?

I am not a V4L2 app programmer.

However, I have attached a program I wrote a while ago to exercise the
cx18 driver and HVR-1600 as MythTV would opening an ivtv/cx18 based
card.  The cx88 probably won't support the MPEG ioctls but I think the
program is a pretty simple example of how to set up a v4l2 device and
capture data.

You might want to look at the set_picture_size() call.

The V4L2 API document can be found at linuxtv.org, if you need further
documentation on the ioctl()s.

Regards,
Andy

> Any advice appreciated.
> 
> B. Bogart
> 
> 
> --
> Here is the mplayer output:
> 
> MPlayer dev-SVN-r26940
> CPU: AMD Athlon(tm) 64 Processor 3200+ (Family: 15, Model: 47, Stepping: 0)
> CPUflags:  MMX: 1 MMX2: 1 3DNow: 1 3DNow2: 1 SSE: 1 SSE2: 1
> Compiled with runtime CPU detection.
> Can't open joystick device /dev/input/js0: No such file or directory
> Can't init input joystick
> mplayer: could not connect to socket
> mplayer: No such file or directory
> Failed to open LIRC support. You will not be able to use your remote
> control.
> 
> Playing tv://.
> TV file format detected.
> Selected driver: v4l2
>  name: Video 4 Linux 2 input
>  author: Martin Olschewski <olschewski@zpr.uni-koeln.de>
>  comment: first try, more to come ;-)
> Selected device: Leadtek Winfast 2000XP Expert
>  Tuner cap:
>  Tuner rxs:
>  Capabilites:  video capture  VBI capture device  tuner  read/write
> streaming
>  supported norms: 0 = PAL-BG; 1 = PAL-DK; 2 = PAL-I; 3 = PAL-M; 4 =
> PAL-N; 5 = PAL-Nc; 6 = PAL-60; 7 = NTSC-M; 8 = NTSC-M-JP; 9 = NTSC-443;
> 10 = SECAM-DK; 11 = SECAM-L;
>  inputs: 0 = Television; 1 = Composite1; 2 = S-Video;
>  Current input: 1
>  Current format: BGR24
> v4l2: current audio mode is : MONO
> v4l2: ioctl set format failed: Invalid argument
> v4l2: ioctl set format failed: Invalid argument
> open: No such file or directory
> [MGA] Couldn't open: /dev/mga_vid
> open: No such file or directory
> [MGA] Couldn't open: /dev/mga_vid
> [VO_TDFXFB] Can't open /dev/fb0: No such file or directory.
> s3fb: can't open /dev/fb0: No such file or directory
> ==========================================================================
> Opening video decoder: [raw] RAW Uncompressed Video
> VDec: vo config request - 640 x 480 (preferred colorspace: Packed UYVY)
> VDec: using Packed UYVY as output csp (no 0)
> Movie-Aspect is undefined - no prescaling applied.
> VO: [xv] 640x480 => 640x480 Packed UYVY
> Selected video codec: [rawuyvy] vfm: raw (RAW UYVY)
> ==========================================================================
> Audio: no sound
> Starting playback...
> v4l2: 40 frames successfully processed, -39 frames dropped.
> 
> Exiting... (Quit)
> 
> --
> video4linux-list mailing list
> Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list

[-- Attachment #2: pollcx18.c --]
[-- Type: text/x-csrc, Size: 12119 bytes --]

/*
 * pollcx18 - exercise the cx18 driver in a manner similar to MythTV
 * Copyright (C) 2008 Andy Walls
 *
 * 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.
 *
 * 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
 *
 * Author: Andy Walls <cwalls@radix.net>
 *
 * Compile: gcc -Wall -O2 -o pollcx18 pollcx18.c
 *
 * Invoke:  ./pollcx18 -d /dev/video1 -o foo.mpg
 *
 * To see the cx23418 encoder stall out for a while and a select() timeout,
 * cx18_v4l2_enc_poll() should be modified not to check q_io, and you should
 * tune to and away from a weak, snowy TV station (but not one that's all snow)
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

struct parsed_args
{
	char *devpath;
	char *outfile;
};

static int quit = 0;

void sig_handler (int signum, siginfo_t *info, void *ucontext)
{
	quit = 1;
}

int parse_args (int argc, char **argv, struct parsed_args *args)
{
	int c, retval;

	args->devpath = "/dev/video";
	args->outfile = NULL;
	retval = 0;
	while ((c = getopt(argc, argv, "d:o:")) != -1)
	{
		switch (c)
		{
			case 'd':
				args->devpath = optarg;
				break;
			case 'o':
				args->outfile = optarg;
				break;
			default:
				fprintf (stderr, "Usage:\npollcx18 [-d videodev] [-o outfile]\n");
				retval = -1;
				break;
		}
	}
	return retval;
}

void mainloop (int *readfd, int outfd, int *quit, char *devpath)
{
	const int bufsize = 4 * 1024; /* 4 kB is what MythTV uses */
	char buffer[bufsize];
	int bytesused, n;

	/* Set retry limit to > 0 to try a few times before closing and
	 * reopening the fd on a select() timeout */
	const int retry_limit = 0;
	int retries;
	int got_data;

	int nfds;
	struct timeval timeout;
	fd_set rfds;

	retries = 0;
	got_data = 0;
	bytesused = 0;
	while (!(*quit))
	{
		/* 
 		 * Attempt to reopen the capture device like MythTV, since
 		 * we may close it later in this loop on timeout, like MythTV
 		 *
 		 * We reopen it without O_NONBLOCK, as does MythTV,
 		 * but that's really a MythTV bug.  We should really reopen with
 		 * O_NONBLOCK set.
 		 *
 		 */
		if (*readfd < 0)
		{ 
			if ((*readfd =
			             open(devpath, O_RDWR /*|O_NONBLOCK*/)) < 0)
			{
				perror("open");
				fprintf(stderr,
			        "Unable to re-open video capture device: %s\n",
		                	devpath);
				*quit = 1;
				break;
			}
			else
			{
				got_data = 0;
				retries = 0;
			}
		}

		FD_ZERO(&rfds);
		FD_SET(*readfd, &rfds);
		timeout.tv_sec  = 5;  /* MythTV uses 5 seconds */
		timeout.tv_usec = 0;
		nfds = *readfd + 1;

		nfds = select (nfds, &rfds, NULL, NULL, &timeout);

		switch (nfds)
		{
			case -1:
				if (errno == EINTR)
					continue;

				perror("select");
				fprintf(stderr, "select failed on video "
				        "capture device: %s\n",
		                        devpath);
				*quit = 1;
				retries++; /* this doesn't matter for now */
				continue;

			case 0:
				fprintf(stderr, "select timeout on video "
				        "capture device: %s\n",
		                        devpath);
				/*
 				 * MythTV tries to fix things by closing and
 				 * reopening the readfd
 				 *
 				 * Well do few retries before doing so.
 				 */
				retries++;
				if (retries >= retry_limit)
				{
					close(*readfd);
					*readfd = -1;
					retries = 0;
					got_data = 0;
				}
				continue;

			default:
				break;
		}

		retries = 0;

		n = read(*readfd, &(buffer[bytesused]), bufsize-bytesused);
		if (n == -1 && errno != EAGAIN && errno != EINTR)
		{
			perror("read");
			fprintf(stderr,
			        "read failed on video capture device: %s\n",
		                devpath);
			*quit = 1;
		}
		if (n > 0)
		{
			bytesused += n;
			if (got_data == 0)
			{
				fprintf(stderr,
			          "received data on video capture device: %s\n",
		                  devpath);
				got_data = 1;
			}
				
		}
		if (bytesused >= bufsize)
		{
			if (outfd > -1)
				write(outfd, buffer, bufsize);
			bytesused = 0;
		}
	}

	/* write out the final partially filled buffer */
	if (bytesused > 0 && outfd > -1)
		write(outfd, buffer, bytesused);

	return;
}

int set_picture_size (int chanfd, int width, int height, char *devpath)
{
	struct v4l2_format f;

	memset (&f, 0, sizeof (f));
	f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (ioctl(chanfd, VIDIOC_G_FMT, &f) < 0)
	{
		perror ("ioctl");
		fprintf (stderr, "couldn't get video format for device %s\n",
		         devpath);
		return -1;
	}

	f.fmt.pix.width = width;
	f.fmt.pix.height = height;

	if (ioctl(chanfd, VIDIOC_S_FMT, &f) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't get video format for device %s\n",
		         devpath);
		return -1;
	}
	return 0;
}

int set_volume (int chanfd, int level, char *devpath)
{
	struct v4l2_control c;

	c.id = V4L2_CID_AUDIO_VOLUME;
	c.value = (65536*level)/100;
	if (ioctl(chanfd, VIDIOC_S_CTRL, &c) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set audio volume for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_audio_fs (int chanfd, int rate, char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
	switch (rate)
	{
		case 32000:
			c.value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
			break;
		case 44100:
			c.value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
			break;
		case 48000:
		default:
			c.value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
			break;
	}

	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr,
			"couldn't set audio sample rate for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_aspect_ratio (int chanfd, enum v4l2_mpeg_video_aspect aspect,
                      char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_VIDEO_ASPECT;
	c.value = aspect;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set aspect ratio for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_audio_encoding (int chanfd, enum v4l2_mpeg_audio_encoding encoding,
                        char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_AUDIO_ENCODING;
	c.value = encoding;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set audio encoding for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_audio_bitrate (int chanfd, enum v4l2_mpeg_audio_l2_bitrate rate,
                        char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_AUDIO_L2_BITRATE;
	c.value = rate;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set audio encoding for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_video_bitrates (int chanfd, int peak, int nominal, char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c[2];

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(struct v4l2_ext_control)*2);

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 2;
	e.controls = c;

	c[0].id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK;
	c[0].value = peak;
	c[1].id = V4L2_CID_MPEG_VIDEO_BITRATE;
	c[1].value = nominal;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set video bitrates for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int set_streamtype (int chanfd, enum v4l2_mpeg_stream_type type, char *devpath)
{
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_STREAM_TYPE;
	c.value = type;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't set stream type for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int setup_vbi (int chanfd, int vbitype, char *devpath)
{
	struct v4l2_format f;
	struct v4l2_ext_controls e;
	struct v4l2_ext_control c;

	memset (&f, 0, sizeof (f));

	f.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
	f.fmt.sliced.service_set = vbitype;
	if (ioctl(chanfd, VIDIOC_S_FMT, &f) < 0)
	{
		perror("ioctl");
		fprintf(stderr, "couldn't enable vbi for device %s\n",
		        devpath);
		return -1;
	}

	memset(&e, 0, sizeof(e));
	memset(&c, 0, sizeof(c));

	e.ctrl_class = V4L2_CTRL_CLASS_MPEG;
	e.count = 1;
	e.controls = &c;

	c.id = V4L2_CID_MPEG_STREAM_VBI_FMT;
	c.value = V4L2_MPEG_STREAM_VBI_FMT_IVTV;
	if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &e) < 0)
	{
		perror("ioctl");
		fprintf(stderr,
		        "couldn't set vbi stream format for device %s\n",
		        devpath);
		return -1;
	}
	return 0;
}

int main (int argc, char **argv)
{
	int chanfd, readfd, outfd;
	struct parsed_args args;
	struct sigaction sigact;

	if (parse_args(argc, argv, &args) < 0)
		exit(1);
	
	outfd = -1;
	if (args.outfile != NULL && 
	    (outfd = open(args.outfile, O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
	{
		perror("open");
		fprintf(stderr, "Unable to open output file: %s\n",
		        args.outfile);
	}

	/* MythTV would use this fd for controlling the capture device */
	if ((chanfd = open(args.devpath, O_RDWR)) < 0)
	{
		perror("open");
		fprintf(stderr, "Unable to open video control device: %s\n",
		        args.devpath);
		exit(2);
	}

	/* Setup like MythTV does on my NTSC-M system */
	set_picture_size   (chanfd, 704, 480,                   args.devpath);
	set_volume         (chanfd, 90,                         args.devpath);
	set_audio_fs       (chanfd, 48000,                      args.devpath);
	set_aspect_ratio   (chanfd, V4L2_MPEG_VIDEO_ASPECT_4x3, args.devpath);
	set_audio_encoding (chanfd, V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
	                                                        args.devpath);
	set_audio_bitrate  (chanfd, V4L2_MPEG_AUDIO_L2_BITRATE_384K,
	                                                        args.devpath);
	set_video_bitrates (chanfd, 6000000, 4500000,           args.devpath);
	set_streamtype     (chanfd, V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
	                                                        args.devpath);
	/*
  	 * This vbi setup makes the difference between the encoder permanently
  	 * stalling or not
	*/
	setup_vbi          (chanfd, V4L2_SLICED_VBI_525,        args.devpath);

	/* MythTV would use this fd for video capture */
	if ((readfd = open(args.devpath, O_RDWR|O_NONBLOCK)) < 0)
	{
		perror("open");
		fprintf(stderr, "Unable to open video capture device: %s\n",
		        args.devpath);
		exit(3);
	}

	sigact.sa_flags = SA_SIGINFO;
	sigact.sa_sigaction = sig_handler;
	sigemptyset(&(sigact.sa_mask));
	sigaction(SIGINT, &sigact, NULL);  /* handle ^C to do a graceful exit */

	quit = 0;
	mainloop(&readfd, outfd, &quit, args.devpath);

	close(readfd);
	close(chanfd);
	close(outfd);

	exit(0);
}

[-- Attachment #3: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 22:51 ` Andy Walls
@ 2008-09-04 23:16   ` B. Bogart
  2008-09-05  6:01     ` Jean-Francois Moine
  2008-09-12 19:19   ` B. Bogart
  2008-09-12 19:22   ` B. Bogart
  2 siblings, 1 reply; 9+ messages in thread
From: B. Bogart @ 2008-09-04 23:16 UTC (permalink / raw)
  To: Andy Walls; +Cc: video4linux-list, IOhannes m zmoelnig

[-- Attachment #1: Type: text/plain, Size: 5157 bytes --]

Hello Andy,

Thanks for your help.

I've not yet tried running your program, but did have some luck with:
http://moinejf.free.fr/svv.c

I managed to compile it and run it, I had to change the pixelformat to
YUVY. The resolution is correct, but the image looks like PAL.

How/where do I set the video format in V4l2?

I tried adding #define V4L2_STD_NTSC_M but that did not make any difference.

Attached is an image of the svv current output.

Oh and I'm currently looking at
http://v4l2spec.bytesex.org/spec-single/v4l2.html for reference, but
much of it is over my head.

I've only written a couple things in C.

Thanks for the pointers.
B. Bogart


Andy Walls wrote:
> On Thu, 2008-09-04 at 15:14 -0700, B. Bogart wrote:
>> Hello all,
>>
>> This issue has been lagging for years and I wanted to get some expert
>> advice on debugging it. It seems I'm the only one with a cx8800 card
>> that is having problems so I hope to take the challenge up and propose a
>> solution to the maintainer.
>>
>> So the software I'm using is GEM. It has v4l2 support, and works fine
>> with my bt848 card. Problem is I can't get things working properly with
>> my cx8800 cards.
>>
>> First HW info:
>>
>> lspci reports my tuner as:
>>
>> 00:0d.0 Multimedia video controller: Conexant CX23880/1/2/3 PCI Video
>> and Audio Decoder (rev 05)
>>
>> The card is branded as a Leadtek Winfast 2000XP Expert.
>>
>> I'm sure the problem is with the v4l2 implementation in Gem as running
>> the following command gives me perfect video on this card at 640x480:
>>
>> mplayer tv:// -tv driver=v4l2:device=/dev/video0:input=1:norm=NTSC-M
>>
>> (the output follows this message).
>>
>> So the card is capable of 640x480.
>>
>> If I run Gem on this card as 320x240 all works fine. (pictured in
>> attachment 320x240.png)
>>
>> As soon as I change the resolution to 640x480 I get the following errors
>> repeated:
>>
>> VIDIOCMCAPTURE1: Invalid argument
>> VIDIOCMCAPTURE2: Invalid argument
>>
>> And the image appears as in attachment 640x480.png
>>
>> What should my steps for debugging be?
>>
>> Is there dead-simple v4l2 example source (including output so I can
>> confirm its working) I can test with and compare with Gem sources?
> 
> I am not a V4L2 app programmer.
> 
> However, I have attached a program I wrote a while ago to exercise the
> cx18 driver and HVR-1600 as MythTV would opening an ivtv/cx18 based
> card.  The cx88 probably won't support the MPEG ioctls but I think the
> program is a pretty simple example of how to set up a v4l2 device and
> capture data.
> 
> You might want to look at the set_picture_size() call.
> 
> The V4L2 API document can be found at linuxtv.org, if you need further
> documentation on the ioctl()s.
> 
> Regards,
> Andy
> 
>> Any advice appreciated.
>>
>> B. Bogart
>>
>>
>> --
>> Here is the mplayer output:
>>
>> MPlayer dev-SVN-r26940
>> CPU: AMD Athlon(tm) 64 Processor 3200+ (Family: 15, Model: 47, Stepping: 0)
>> CPUflags:  MMX: 1 MMX2: 1 3DNow: 1 3DNow2: 1 SSE: 1 SSE2: 1
>> Compiled with runtime CPU detection.
>> Can't open joystick device /dev/input/js0: No such file or directory
>> Can't init input joystick
>> mplayer: could not connect to socket
>> mplayer: No such file or directory
>> Failed to open LIRC support. You will not be able to use your remote
>> control.
>>
>> Playing tv://.
>> TV file format detected.
>> Selected driver: v4l2
>>  name: Video 4 Linux 2 input
>>  author: Martin Olschewski <olschewski@zpr.uni-koeln.de>
>>  comment: first try, more to come ;-)
>> Selected device: Leadtek Winfast 2000XP Expert
>>  Tuner cap:
>>  Tuner rxs:
>>  Capabilites:  video capture  VBI capture device  tuner  read/write
>> streaming
>>  supported norms: 0 = PAL-BG; 1 = PAL-DK; 2 = PAL-I; 3 = PAL-M; 4 =
>> PAL-N; 5 = PAL-Nc; 6 = PAL-60; 7 = NTSC-M; 8 = NTSC-M-JP; 9 = NTSC-443;
>> 10 = SECAM-DK; 11 = SECAM-L;
>>  inputs: 0 = Television; 1 = Composite1; 2 = S-Video;
>>  Current input: 1
>>  Current format: BGR24
>> v4l2: current audio mode is : MONO
>> v4l2: ioctl set format failed: Invalid argument
>> v4l2: ioctl set format failed: Invalid argument
>> open: No such file or directory
>> [MGA] Couldn't open: /dev/mga_vid
>> open: No such file or directory
>> [MGA] Couldn't open: /dev/mga_vid
>> [VO_TDFXFB] Can't open /dev/fb0: No such file or directory.
>> s3fb: can't open /dev/fb0: No such file or directory
>> ==========================================================================
>> Opening video decoder: [raw] RAW Uncompressed Video
>> VDec: vo config request - 640 x 480 (preferred colorspace: Packed UYVY)
>> VDec: using Packed UYVY as output csp (no 0)
>> Movie-Aspect is undefined - no prescaling applied.
>> VO: [xv] 640x480 => 640x480 Packed UYVY
>> Selected video codec: [rawuyvy] vfm: raw (RAW UYVY)
>> ==========================================================================
>> Audio: no sound
>> Starting playback...
>> v4l2: 40 frames successfully processed, -39 frames dropped.
>>
>> Exiting... (Quit)
>>
>> --
>> video4linux-list mailing list
>> Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
>> https://www.redhat.com/mailman/listinfo/video4linux-list


[-- Attachment #2: Screenshot.png --]
[-- Type: image/png, Size: 746990 bytes --]

[-- Attachment #3: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 23:16   ` B. Bogart
@ 2008-09-05  6:01     ` Jean-Francois Moine
  2008-09-05 15:29       ` B. Bogart
  0 siblings, 1 reply; 9+ messages in thread
From: Jean-Francois Moine @ 2008-09-05  6:01 UTC (permalink / raw)
  To: B. Bogart; +Cc: video4linux-list, IOhannes m zmoelnig

On Thu, 2008-09-04 at 16:16 -0700, B. Bogart wrote:
> I've not yet tried running your program, but did have some luck with:
> http://moinejf.free.fr/svv.c

Hello B.,

It seems the driver cannot switch to 640x480. You may know it grabbing
images with svv. Try
	svv -rg -f 640x480
then
	svv -rg -f 320x240
and check each time the size of image.dat.

Best regards.

-- 
Ken ar c'hentañ |             ** Breizh ha Linux atav! **
Jef             |               http://moinejf.free.fr/


--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-05  6:01     ` Jean-Francois Moine
@ 2008-09-05 15:29       ` B. Bogart
  0 siblings, 0 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-05 15:29 UTC (permalink / raw)
  To: Jean-Francois Moine; +Cc: video4linux-list, IOhannes m zmoelnig

Hello Jean-Francois,

I don't believe this is a size issue with svv (but it does appear to be
one with Gem) but the image really looks like NTSC interpreted as PAL to
me, in particular the VBI noise at the bottom.

I ran your test to confirm and:

bbogart@insitu:~/tmp/svv$ ./svv -rg -f 320x240
raw pixfmt: UYVY 320x240
pixfmt: UYVY 320x240
mmap method
raw image dumped to 'image.dat'

bbogart@insitu:~/tmp/svv$ ls -l image.dat
-rw-r--r-- 1 bbogart bbogart 153600 2008-09-05 08:23 image.dat
bbogart@insitu:~/tmp/svv$ ./svv -rg -f 640x480
raw pixfmt: UYVY 640x480
pixfmt: UYVY 640x480
mmap method

raw image dumped to 'image.dat'
bbogart@insitu:~/tmp/svv$ ls -l image.dat
-rw-r--r-- 1 bbogart bbogart 614400 2008-09-05 08:24 image.dat

>From your message I assume a larger file means that indeed the image
format is 640x480. Also mplayer shows video from this device as 640x480.

Johannes,

I'd feel better about svv "working" once I get the normal thing going,
but what Gem files should I compare with svv for stuff like choosing the
pixel format and allocating the size? I took a crack yesterday but I
felt like I was following a string through a haystack through the
various levels of abstraction from pix_video to v4l... FYI the behaviour
is the same for Gem compiled with v4l2 and v4l.

Thanks all,
.b.

Jean-Francois Moine wrote:
> On Thu, 2008-09-04 at 16:16 -0700, B. Bogart wrote:
>> I've not yet tried running your program, but did have some luck with:
>> http://moinejf.free.fr/svv.c
> 
> Hello B.,
> 
> It seems the driver cannot switch to 640x480. You may know it grabbing
> images with svv. Try
> 	svv -rg -f 640x480
> then
> 	svv -rg -f 320x240
> and check each time the size of image.dat.
> 
> Best regards.
> 

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Broken gem support for UYVY V4L capture? WAS V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 22:14 V4l2 :: Debugging an issue with cx8800 card B. Bogart
  2008-09-04 22:51 ` Andy Walls
@ 2008-09-12  0:44 ` B. Bogart
  2008-09-12  0:46 ` Sorry! B. Bogart
  2 siblings, 0 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-12  0:44 UTC (permalink / raw)
  To: video4linux-list; +Cc: gem-dev

[-- Attachment #1: Type: text/plain, Size: 2080 bytes --]

Hey Johannes,

I've read through the v4l code in Gem and realized an important issue:

1. My previous post about resolution and problems with "VIDIOCMCAPTURE1:
Invalid argument" messages was due to me using v4l1 not 2!

2. As best as I can tell, while using v4l2, my UYVY card does not work
at all.

In the PD window I get:

video driver 0: video4linux2
video driver 1: ieee1394 for linux
v4l2: wanted 6408, got 'RGB4'
v4l2: GEM: pix_video: Opened video connection 0x12

STDERR gives me:

VIDIOC_DQBUF: stopping capture thread!: Resource temporarily unavailable

Resulting in an all black image.

I could not understand the reqFormat vs format stuff but I do know the
card produces V4L2_PIX_FMT_UYVY video.

I inserted a few statements at line 450 of videoV4L2.cpp (attached)

These statements result in:

bbogart: fmt.fmt.pix.pixelformat = 876758866
bbogart: m_reqFormat = 6408
bbogart: GL_YCBCR_422_GEM = 34233
bbogart: GL_LUMINANCE = 6409
bbogart: GL_RGB= 6407
bbogart: V4L2_PIX_FMT_UYVY = 1498831189
bbogart: V4L2_PIX_FMT_SBGGR8 = 825770306
bbogart: V4L2_PIX_FMT_GREY = 1497715271
bbogart: V4L2_PIX_FMT_YUYV = 1448695129
bbogart: V4L2_PIX_FMT_Y41P = 1345401945
bbogart: V4L2_PIX_FMT_YVU420 = 842094169
bbogart: V4L2_PIX_FMT_YVU410 = 961893977
bbogart: V4L2_PIX_FMT_YUV422P = 1345466932
bbogart: V4L2_PIX_FMT_YUV411P = 1345401140
bbogart: V4L2_PIX_FMT_NV12 = 842094158

Ok, so 6408 is RGBA.

So I send the "colorspace YUV" message to pix_video.

Now I see:

bbogart: fmt.fmt.pix.pixelformat = 1498831189
bbogart: m_reqFormat = 34233
bbogart: GL_YCBCR_422_GEM = 34233
bbogart: V4L2_PIX_FMT_UYVY = 1498831189

so that all looks correct fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY
and m_reqFormat = GL_YCBCR_422_GEM

BUT the PD console still prints:

v4l2: wanted 34233, got 'UYVY'
v4l2: GEM: pix_video: Opened video connection 0xE

But 34233 is a YUV format...

I still get the VIDIOC_DQBUF: stopping capture thread!: Resource
temporarily unavailable error.

So I'm stuck here, but I hope this helps enough that you can give me
more hints on what else to try.

Thanks,
B. Bogart

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: videoV4L2.cpp --]
[-- Type: text/x-c++src; name="videoV4L2.cpp", Size: 18942 bytes --]

////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    Copyright (c) Günther Geiger.
//    Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "videoV4L2.h"

#if 0
# define debugPost post
# define debugThread post
#else
# define debugPost
# define debugThread
#endif

/////////////////////////////////////////////////////////
//
// videoV4L2
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
videoV4L2 :: videoV4L2(int format) : video(format)
#ifdef HAVE_VIDEO4LINUX2
                                   , m_gotFormat(0), m_colorConvert(0),
                                     m_tvfd(0),
                                     m_buffers(NULL), m_nbuffers(0), 
                                     m_currentBuffer(NULL),
                                     m_frame(0), m_last_frame(0),
                                     m_maxwidth(844), m_minwidth(32),
                                     m_maxheight(650), m_minheight(32),
                                     m_thread_id(0), m_continue_thread(false), m_frame_ready(false),
                                     m_rendering(false)
{
  if (!m_width)m_width=320;
  if (!m_height)m_height=240;
  m_capturing=false;
  m_devicenum=V4L2_DEVICENO;
  post("video4linux2");
#else
{
#endif /* HAVE_VIDEO4LINUX2 */
}
  
////////////////////////////////////////////////////////
// Destructor
//
////////////////////////////////////////////////////////
videoV4L2 :: ~videoV4L2()
{
#ifdef HAVE_VIDEO4LINUX2
  if (m_haveVideo)stopTransfer();
#endif /* HAVE_VIDEO4LINUX2 */
}

#ifdef HAVE_VIDEO4LINUX2
static int xioctl(int                    fd,
                  int                    request,
                  void *                 arg)
{
  int r;
     
  do {
    r = ioctl (fd, request, arg);
    debugThread("V4L2: xioctl %d->%d\n", r, errno);
  }
  while (-1 == r && EINTR == errno);

  debugThread("V4L2: xioctl done %d\n", r);
   
  return r;
}
 
int videoV4L2::init_mmap (void)
{
  struct v4l2_requestbuffers req;
  char*devname=(char*)((m_devicename)?m_devicename:"device");

  memset (&(req), 0, sizeof (req));

  req.count               = V4L2_NBUF;
  req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory              = V4L2_MEMORY_MMAP;

  if (-1 == xioctl (m_tvfd, VIDIOC_REQBUFS, &req)) {
    if (EINVAL == errno) {
      error("%s does not support memory mapping", devname);
      return 0;
    } else {
      error ("VIDIOC_REQBUFS");
      return 0;
    }
  }

  if (req.count < V4L2_NBUF) {
    //error("Insufficient buffer memory on %s: %d", devname, req.count);
    //return(0);
  }

  m_buffers = (t_v4l2_buffer*)calloc (req.count, sizeof (*m_buffers));

  if (!m_buffers) {
    error("out of memory");
    return(0);
  }

  for (m_nbuffers = 0; m_nbuffers < req.count; ++m_nbuffers) {
    struct v4l2_buffer buf;

    memset (&(buf), 0, sizeof (buf));

    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = m_nbuffers;
    debugPost("v4l2: buf.index==%d", buf.index);

    if (-1 == xioctl (m_tvfd, VIDIOC_QUERYBUF, &buf)){
      error ("VIDIOC_QUERYBUF");
      return(0);
    }

    m_buffers[m_nbuffers].length = buf.length;
    m_buffers[m_nbuffers].start =
      mmap (NULL /* start anywhere */,
            buf.length,
            PROT_READ | PROT_WRITE /* required */,
            MAP_SHARED /* recommended */,
            m_tvfd, buf.m.offset);

    if (MAP_FAILED == m_buffers[m_nbuffers].start){
      error ("mmap");
      return 0;
    }
  }
  return 1;
}

/////////////////////////////////////////////////////////
// this is the work-horse
// a thread that does the capturing
//
/////////////////////////////////////////////////////////
void *videoV4L2 :: capturing(void*you)
{
  videoV4L2 *me=(videoV4L2 *)you;
  t_v4l2_buffer*buffers=me->m_buffers;

  struct v4l2_buffer buf;
  unsigned int i;
    
  fd_set fds;
  struct timeval tv;
  int r;

  int nbuf=me->m_nbuffers;
  int m_tvfd=me->m_tvfd;
  me->m_capturing=true;

  debugThread("V4L2: memset");
  memset(&(buf), 0, sizeof (buf));
  
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  buf.memory = V4L2_MEMORY_MMAP;

  while(me->m_continue_thread){
    FD_ZERO (&fds);
    FD_SET (m_tvfd, &fds);

    debugThread("V4L2: grab");

    me->m_frame++;
    me->m_frame%=nbuf;

    
    /* Timeout. */
    tv.tv_sec = 0;
    tv.tv_usec = 100;

#if 0
    r = select (m_tvfd + 1, &fds, NULL, NULL, &tv);
      if (0 == r) {
      error("select timeout");
      me->m_continue_thread=false;
      }
#else
    r = select(0,0,0,0,&tv);
#endif
    debugThread("V4L2: waited...");
    if (-1 == r) {
      if (EINTR == errno)
        continue;
      error ("select");//exit
    }

    memset(&(buf), 0, sizeof (buf));
    debugThread("V4L2: memset...");
  
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if (-1 == xioctl (m_tvfd, VIDIOC_DQBUF, &buf)) {
      switch (errno) {
      case EAGAIN:
        perror("VIDIOC_DQBUF: stopping capture thread!");
        goto stop_capturethread;
      case EIO:
        /* Could ignore EIO, see spec. */
        /* fall through */
      default:
        perror ("VIDIOC_DQBUF");
      }
    }

    debugThread("V4L2: grabbed %d", buf.index);

    me->m_currentBuffer=buffers[buf.index].start;
    //process_image (m_buffers[buf.index].start);

    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      perror ("VIDIOC_QBUF");
    }

    debugThread("V4L2: dequeueueeud");
    
    me->m_frame_ready = 1;
    me->m_last_frame=me->m_frame;
  }
 stop_capturethread:
  // stop capturing
  if(me->m_tvfd){
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == xioctl (me->m_tvfd, VIDIOC_STREAMOFF, &type)){
      perror ("VIDIOC_STREAMOFF");
    }
  }
  me->m_capturing=false;
  debugThread("V4L2: thread finished");
  return NULL;
}

//////////////////
// this reads the data that was captured by capturing() and returns it within a pixBlock
pixBlock *videoV4L2 :: getFrame(){
  if(!m_haveVideo)return NULL;
  //debugPost("v4l2: getting frame %d", m_frame_ready);
  m_image.newfilm=0;
  if (!m_frame_ready) m_image.newimage = 0;
  else {
    int i=0; // FIXME
    unsigned char*data=(unsigned char*)m_currentBuffer;
    if (m_colorConvert){
      m_image.image.notowned = false;
      switch(m_gotFormat){
      case V4L2_PIX_FMT_RGB24: m_image.image.fromRGB   (data); break;
      case V4L2_PIX_FMT_RGB32: m_image.image.fromRGBA  (data); break;
      case V4L2_PIX_FMT_GREY : m_image.image.fromGray  (data); break;
      case V4L2_PIX_FMT_UYVY : m_image.image.fromYUV422(data); break;
      case V4L2_PIX_FMT_YUV420:m_image.image.fromYU12(data); break;


      default: // ? what should we do ?
        m_image.image.data=data;
        m_image.image.notowned = true;
      }
    } else {
      m_image.image.data=data;
      m_image.image.notowned = true;
    }
    m_image.image.upsidedown=true;
    
    m_image.newimage = 1;
    m_frame_ready = false;
  }
  return &m_image;
}
/////////////////////////////////////////////////////////
// restartTransfer
//
/////////////////////////////////////////////////////////
void videoV4L2 :: restartTransfer()
{
  bool rendering=m_rendering;
  debugPost("v4l2: restart transfer");
  if(m_capturing)stopTransfer();
  debugPost("v4l2: restart stopped");
  if (rendering)startTransfer();
  debugPost("v4l2: restart started");
}


/////////////////////////////////////////////////////////
// startTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: startTransfer(int format)
{
  debugPost("v4l2: startTransfer: %d", m_capturing);
  if(m_capturing)stopTransfer(); // just in case we are already running!
  debugPost("v4l2: start transfer");
  m_rendering=true;
  if (format>1)m_reqFormat=format;
  //  verbose(1, "starting transfer");
  char buf[256];
  char*dev_name=m_devicename;
  int i;

  struct stat st; 
  struct v4l2_capability cap;
  struct v4l2_cropcap cropcap;
  struct v4l2_crop crop;
  struct v4l2_format fmt;
  unsigned int min;

  enum v4l2_buf_type type;

  m_frame = 0;
  m_last_frame = 0;


  /* check the device */

  // if we don't have a devicename, create one
  if(!dev_name){
    if (m_devicenum<0){
      sprintf(buf, "/dev/video");
    } else {
      sprintf(buf, "/dev/video%d", m_devicenum);
    }
    dev_name=buf;
  }

  // try to open the device
  debugPost("v4l2: device: %s", dev_name);
  
  m_tvfd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

  if (-1 == m_tvfd) {
    error("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (-1 == fstat (m_tvfd, &st)) {
    error("Cannot identify '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (!S_ISCHR (st.st_mode)) {
    error("%s is no device", dev_name);
    goto closit;
  }




  // by now, we have an open file-descriptor
  // check whether this is really a v4l2-device
  if (-1 == xioctl (m_tvfd, VIDIOC_QUERYCAP, &cap)) {
    if (EINVAL == errno) {
      error("%s is no V4L2 device",  dev_name);
      goto closit;
    } else {
      perror ("VIDIOC_QUERYCAP");//exit
      goto closit;
    }
  }

  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    error("%s is no video capture device", dev_name);
    goto closit;
  }

  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
    error("%s does not support streaming i/o", dev_name);
    goto closit;
  }

  /* Select video input, video standard and tune here. */

  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    /* Errors ignored. */
  }

  memset(&(cropcap), 0, sizeof (cropcap));
  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (0 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect; /* reset to default */

    if (-1 == xioctl (m_tvfd, VIDIOC_S_CROP, &crop)) {
      perror("vidioc_s_crop");
      switch (errno) {
      case EINVAL:
        /* Cropping not supported. */
        break;
      default:
        /* Errors ignored. */
        break;
      }
    }
  }


  if (-1 == xioctl (m_tvfd, VIDIOC_S_INPUT, &m_channel)) {
    perror("VIDIOC_S_INPUT"); /* exit */
  }

  memset (&(fmt), 0, sizeof (fmt));

  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.width       = m_width;
  fmt.fmt.pix.height      = m_height;

  switch(m_reqFormat){
  case GL_YCBCR_422_GEM: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 
    break;
  case GL_LUMINANCE: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; 
    break;
  case GL_RGB: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 
    break;
  default: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; 
    m_reqFormat=GL_RGBA;
    break;
  }
  fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

  post("v4l2: wanted %d, got '%c%c%c%c' ", m_reqFormat, 
	    (char)(fmt.fmt.pix.pixelformat),
	    (char)(fmt.fmt.pix.pixelformat>>8),
	    (char)(fmt.fmt.pix.pixelformat>>16),
	    (char)(fmt.fmt.pix.pixelformat>>24));
// bbogart
printf("bbogart: fmt.fmt.pix.pixelformat = %d\n", fmt.fmt.pix.pixelformat);
printf("bbogart: m_reqFormat = %d\n", m_reqFormat);
printf("bbogart: GL_YCBCR_422_GEM = %d\n", GL_YCBCR_422_GEM);
printf("bbogart: GL_LUMINANCE = %d\n", GL_LUMINANCE);
printf("bbogart: GL_RGB= %d\n", GL_RGB);
printf("bbogart: V4L2_PIX_FMT_UYVY = %d\n",V4L2_PIX_FMT_UYVY);
printf("bbogart: V4L2_PIX_FMT_SBGGR8 = %d\n",V4L2_PIX_FMT_SBGGR8);
printf("bbogart: V4L2_PIX_FMT_GREY = %d\n",V4L2_PIX_FMT_GREY);
printf("bbogart: V4L2_PIX_FMT_YUYV = %d\n",V4L2_PIX_FMT_YUYV);
printf("bbogart: V4L2_PIX_FMT_Y41P = %d\n",V4L2_PIX_FMT_Y41P);
printf("bbogart: V4L2_PIX_FMT_YVU420 = %d\n",V4L2_PIX_FMT_YVU420);
printf("bbogart: V4L2_PIX_FMT_YVU410 = %d\n",V4L2_PIX_FMT_YVU410);
printf("bbogart: V4L2_PIX_FMT_YUV422P = %d\n",V4L2_PIX_FMT_YUV422P);
printf("bbogart: V4L2_PIX_FMT_YUV411P = %d\n",V4L2_PIX_FMT_YUV411P);
printf("bbogart: V4L2_PIX_FMT_NV12 = %d\n",V4L2_PIX_FMT_NV12);


  if (-1 == xioctl (m_tvfd, VIDIOC_S_FMT, &fmt)){
    perror ("VIDIOC_S_FMT");//exit
    error("should exit!");
  }
  
  // query back what we have set
  if (-1 == xioctl (m_tvfd, VIDIOC_G_FMT, &fmt)){
    perror ("VIDIOC_G_FMT");//exit
    error("should exit!");
  }

  m_gotFormat=fmt.fmt.pix.pixelformat;
  switch(m_gotFormat){
  case V4L2_PIX_FMT_RGB32: debugPost("v4l2: RGBA");break;
  case V4L2_PIX_FMT_UYVY: debugPost("v4l2: YUV ");break;
  case V4L2_PIX_FMT_GREY: debugPost("v4l2: gray");break;
  case V4L2_PIX_FMT_YUV420: debugPost("v4l2: YUV 4:2:0");break;
  default: error("unknown format '%c%c%c%c'",
		(char)(fmt.fmt.pix.pixelformat),
		(char)(fmt.fmt.pix.pixelformat>>8),
		(char)(fmt.fmt.pix.pixelformat>>16),
		(char)(fmt.fmt.pix.pixelformat>>24));

  }

  /* Note VIDIOC_S_FMT may change width and height. */
  if(m_width!=fmt.fmt.pix.width||m_height!=fmt.fmt.pix.height){
    post("v4l2: changed size from %dx%d to %dx%d", 
	 m_width, m_height,
	 fmt.fmt.pix.width,fmt.fmt.pix.height);
  }
  m_width =fmt.fmt.pix.width;
  m_height=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;

  if(!init_mmap ())goto closit;

  for (i = 0; i < m_nbuffers; ++i) {
    struct v4l2_buffer buf;
    
    memset (&(buf), 0, sizeof (buf));
    
    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = i;
    
    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      perror ("VIDIOC_QBUF");//exit
    }
  }

  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_STREAMON, &type)){
    perror ("VIDIOC_STREAMON");//exit
  }
  
  /* fill in image specifics for Gem pixel object.  Could we have
     just used RGB, I wonder? */
  m_image.image.xsize = m_width;
  m_image.image.ysize = m_height;
  m_image.image.setCsizeByFormat(m_reqFormat);
  m_image.image.reallocate();
  
  debugPost("v4l2: format: %c%c%c%c -> %d", 
       (char)(m_gotFormat),
       (char)(m_gotFormat>>8),
       (char)(m_gotFormat>>16),
       (char)(m_gotFormat>>24),
       m_reqFormat);
  switch(m_gotFormat){
  case V4L2_PIX_FMT_GREY  : m_colorConvert=(m_reqFormat!=GL_LUMINANCE); break;
  case V4L2_PIX_FMT_RGB24 : m_colorConvert=(m_reqFormat!=GL_RGB); break;
  case V4L2_PIX_FMT_RGB32 : m_colorConvert=(m_reqFormat!=GL_RGBA); break;//RGB32!=RGBA; is it ARGB or ABGR?
  case V4L2_PIX_FMT_UYVY  : m_colorConvert=(m_reqFormat!=GL_YCBCR_422_GEM); break;
  case V4L2_PIX_FMT_YUV420: m_colorConvert=1; break;
  default: m_colorConvert=true;
  }
  
  debugPost("v4l2: colorconvert=%d", m_colorConvert);
  
  m_haveVideo = 1;
  
  /* create thread */
  m_continue_thread = 1;
  m_frame_ready = 0;
  pthread_create(&m_thread_id, 0, capturing, this);
  while(!m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to come up");
  }
  
  post("v4l2: GEM: pix_video: Opened video connection 0x%X", m_tvfd);
  
  return(1);
  
 closit:
  debugPost("v4l2: closing it!");
  stopTransfer();
  debugPost("v4l2: closed it");
  return(0);
}

/////////////////////////////////////////////////////////
// stopTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: stopTransfer()
{
  debugPost("v4l2: stoptransfer");
  int i=0;
  /* close the v4l2 device and dealloc buffer */
  /* terminate thread if there is one */
  if(m_continue_thread){
    void *dummy;
    m_continue_thread = 0;
    pthread_join (m_thread_id, &dummy);
  }
  while(m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to finish");
  }

  // unmap the mmap
  debugPost("v4l2: unmapping %d buffers: %x", m_nbuffers, m_buffers);
  if(m_buffers){
    for (i = 0; i < m_nbuffers; ++i)
      if (-1 == munmap (m_buffers[i].start, m_buffers[i].length)){
        // oops: couldn't unmap the memory
      }
    debugPost("v4l2: freeing buffers: %x", m_buffers);
    free (m_buffers);
  }
  m_buffers=NULL;
  debugPost("v4l2: freed");

  // close the file-descriptor
  if (m_tvfd) close(m_tvfd);

  m_tvfd = 0;
  m_haveVideo = 0;
  m_frame_ready = 0;
  m_rendering=false;
  return(1);
}

/////////////////////////////////////////////////////////
// dimenMess
//
/////////////////////////////////////////////////////////
int videoV4L2 :: setDimen(int x, int y, int leftmargin, int rightmargin,
                          int topmargin, int bottommargin)
{
  int xtotal = x + leftmargin + rightmargin;
  int ytotal = y + topmargin + bottommargin;
  if (xtotal > m_maxwidth) /* 844 */
    error("x dimensions too great");
  else if (xtotal < m_minwidth || x < 1 || leftmargin < 0 || rightmargin < 0)
    error("x dimensions too small");
  if (ytotal > m_maxheight)
    error("y dimensions too great");
  else if (ytotal < m_minheight || y < 1 ||
           topmargin < 0 || bottommargin < 0)
    error("y dimensions too small");

  m_width=x;
  m_height=y;
  m_image.image.xsize = x;
  m_image.image.ysize = y;

  m_image.image.reallocate();
  restartTransfer();
  return 0;
}

int videoV4L2 :: setNorm(char*norm)
{
  char c=*norm;
  int i_norm=-1;

  switch (c){
  case 'p': case 'P':
    i_norm = V4L2_STD_PAL;
    break;
  case 'n': case 'N':
    i_norm = V4L2_STD_NTSC;
    break;
  case 's': case 'S':
    i_norm = V4L2_STD_SECAM;
    break;
  default:
    error("pix_video: unknown norm");
    return -1;
    break;
  }
  //  if (i_norm==m_norm)return 0;
  m_norm=i_norm;
  restartTransfer();
  return 0;
}

int videoV4L2 :: setChannel(int c, t_float f){
  error("v4l2: oops, no channel selection! please report this as a bug!!!");
  
  m_channel=c;
  
  restartTransfer();

  return 0;
}

int videoV4L2 :: setDevice(int d)
{
  m_devicename=NULL;
  if (d==m_devicenum)return 0;
  m_devicenum=d;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}
int videoV4L2 :: setDevice(char*name)
{
  m_devicenum=-1;
  m_devicename=name;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}

int videoV4L2 :: setColor(int format)
{
  if (format<=0 || format==m_reqFormat)return -1;
  m_reqFormat=format;
  restartTransfer();
  return 0;
}
#endif /* HAVE_VIDEO4LINUX2 */

[-- Attachment #3: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Sorry!
  2008-09-04 22:14 V4l2 :: Debugging an issue with cx8800 card B. Bogart
  2008-09-04 22:51 ` Andy Walls
  2008-09-12  0:44 ` Broken gem support for UYVY V4L capture? WAS " B. Bogart
@ 2008-09-12  0:46 ` B. Bogart
  2 siblings, 0 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-12  0:46 UTC (permalink / raw)
  To: video4linux-list

Sorry,

The last message was meant only for the gem-dev mailinglist.

My apologies.

B. Bogart

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 22:51 ` Andy Walls
  2008-09-04 23:16   ` B. Bogart
@ 2008-09-12 19:19   ` B. Bogart
  2008-09-12 19:22   ` B. Bogart
  2 siblings, 0 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-12 19:19 UTC (permalink / raw)
  Cc: video4linux-list, gem-dev

I have made progress.

I've managed to get my card working in Gem with some minor changes to
the code. I'm not sure what this code does though, so I'm not sure what
the longer term effect will be.

I'm sending this to the v4l list as you all are the best to advice on a
proper solution to this issue.

I've attached the original, and the hacked version.

Basically the hacked version ignores all errors when running the
following command:

xioctl (m_tvfd, VIDIOC_DQBUF, &buf)

What does this command actually do? Why are there two instances in the
capture function?

I can use the card at 640x480.

The result is the frame-rate is horrid compared to mplayer (which I
suppose makes sense based on those removed error reports) and also using
the V4L1 w/ a bt8x8 card.

Does this change give a hint as to what is causing the problem?

What is the proper way to fix the issue, rather than commenting out
error codes?

Thanks all,
B. Bogart

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: V4l2 :: Debugging an issue with cx8800 card.
  2008-09-04 22:51 ` Andy Walls
  2008-09-04 23:16   ` B. Bogart
  2008-09-12 19:19   ` B. Bogart
@ 2008-09-12 19:22   ` B. Bogart
  2 siblings, 0 replies; 9+ messages in thread
From: B. Bogart @ 2008-09-12 19:22 UTC (permalink / raw)
  Cc: video4linux-list, gem-dev

[-- Attachment #1: Type: text/plain, Size: 937 bytes --]

I have made progress.

I've managed to get my card working in Gem with some minor changes to
the code. I'm not sure what this code does though, so I'm not sure what
the longer term effect will be.

I'm sending this to the v4l list as you all are the best to advice on a
proper solution to this issue.

I've attached the original, and the hacked version.

Basically the hacked version ignores all errors when running the
following command:

xioctl (m_tvfd, VIDIOC_DQBUF, &buf)

What does this command actually do? Why are there two instances in the
capture function?

I can use the card at 640x480.

The result is the frame-rate is horrid compared to mplayer (which I
suppose makes sense based on those removed error reports) and also using
the V4L1 w/ a bt8x8 card.

Does this change give a hint as to what is causing the problem?

What is the proper way to fix the issue, rather than commenting out
error codes?

Thanks all,
B. Bogart


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: videoV4L2.cpp --]
[-- Type: text/x-c++src; name="videoV4L2.cpp", Size: 17993 bytes --]

////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    Copyright (c) Günther Geiger.
//    Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "videoV4L2.h"

#if 0
# define debugPost post
# define debugThread post
#else
# define debugPost
# define debugThread
#endif

/////////////////////////////////////////////////////////
//
// videoV4L2
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
videoV4L2 :: videoV4L2(int format) : video(format)
#ifdef HAVE_VIDEO4LINUX2
                                   , m_gotFormat(0), m_colorConvert(0),
                                     m_tvfd(0),
                                     m_buffers(NULL), m_nbuffers(0), 
                                     m_currentBuffer(NULL),
                                     m_frame(0), m_last_frame(0),
                                     m_maxwidth(844), m_minwidth(32),
                                     m_maxheight(650), m_minheight(32),
                                     m_thread_id(0), m_continue_thread(false), m_frame_ready(false),
                                     m_rendering(false)
{
  if (!m_width)m_width=320;
  if (!m_height)m_height=240;
  m_capturing=false;
  m_devicenum=V4L2_DEVICENO;
  post("video4linux2");
#else
{
#endif /* HAVE_VIDEO4LINUX2 */
}
  
////////////////////////////////////////////////////////
// Destructor
//
////////////////////////////////////////////////////////
videoV4L2 :: ~videoV4L2()
{
#ifdef HAVE_VIDEO4LINUX2
  if (m_haveVideo)stopTransfer();
#endif /* HAVE_VIDEO4LINUX2 */
}

#ifdef HAVE_VIDEO4LINUX2
static int xioctl(int                    fd,
                  int                    request,
                  void *                 arg)
{
  int r;
     
  do {
    r = ioctl (fd, request, arg);
    debugThread("V4L2: xioctl %d->%d\n", r, errno);
  }
  while (-1 == r && EINTR == errno);

  debugThread("V4L2: xioctl done %d\n", r);
   
  return r;
}
 
int videoV4L2::init_mmap (void)
{
  struct v4l2_requestbuffers req;
  char*devname=(char*)((m_devicename)?m_devicename:"device");

  memset (&(req), 0, sizeof (req));

  req.count               = V4L2_NBUF;
  req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory              = V4L2_MEMORY_MMAP;

  if (-1 == xioctl (m_tvfd, VIDIOC_REQBUFS, &req)) {
    if (EINVAL == errno) {
      error("%s does not support memory mapping", devname);
      return 0;
    } else {
      error ("VIDIOC_REQBUFS");
      return 0;
    }
  }

  if (req.count < V4L2_NBUF) {
    //error("Insufficient buffer memory on %s: %d", devname, req.count);
    //return(0);
  }

  m_buffers = (t_v4l2_buffer*)calloc (req.count, sizeof (*m_buffers));

  if (!m_buffers) {
    error("out of memory");
    return(0);
  }

  for (m_nbuffers = 0; m_nbuffers < req.count; ++m_nbuffers) {
    struct v4l2_buffer buf;

    memset (&(buf), 0, sizeof (buf));

    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = m_nbuffers;
    debugPost("v4l2: buf.index==%d", buf.index);

    if (-1 == xioctl (m_tvfd, VIDIOC_QUERYBUF, &buf)){
      error ("VIDIOC_QUERYBUF");
      return(0);
    }

    m_buffers[m_nbuffers].length = buf.length;
    m_buffers[m_nbuffers].start =
      mmap (NULL /* start anywhere */,
            buf.length,
            PROT_READ | PROT_WRITE /* required */,
            MAP_SHARED /* recommended */,
            m_tvfd, buf.m.offset);

    if (MAP_FAILED == m_buffers[m_nbuffers].start){
      error ("mmap");
      return 0;
    }
  }
  return 1;
}

/////////////////////////////////////////////////////////
// this is the work-horse
// a thread that does the capturing
//
/////////////////////////////////////////////////////////
void *videoV4L2 :: capturing(void*you)
{
  videoV4L2 *me=(videoV4L2 *)you;
  t_v4l2_buffer*buffers=me->m_buffers;

  struct v4l2_buffer buf;
  unsigned int i;
    
  fd_set fds;
  struct timeval tv;
  int r;

  int nbuf=me->m_nbuffers;
  int m_tvfd=me->m_tvfd;
  me->m_capturing=true;

  debugThread("V4L2: memset");
  memset(&(buf), 0, sizeof (buf));
  
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  buf.memory = V4L2_MEMORY_MMAP;

  while(me->m_continue_thread){
    FD_ZERO (&fds);
    FD_SET (m_tvfd, &fds);

    debugThread("V4L2: grab");

    me->m_frame++;
    me->m_frame%=nbuf;

    
    /* Timeout. */
    tv.tv_sec = 0;
    tv.tv_usec = 100;

#if 0
    r = select (m_tvfd + 1, &fds, NULL, NULL, &tv);
      if (0 == r) {
      error("select timeout");
      me->m_continue_thread=false;
      }
#else
    r = select(0,0,0,0,&tv);
#endif
    debugThread("V4L2: waited...");
    if (-1 == r) {
      if (EINTR == errno)
        continue;
      error ("select");//exit
    }

    memset(&(buf), 0, sizeof (buf));
    debugThread("V4L2: memset...");
  
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if (-1 == xioctl (m_tvfd, VIDIOC_DQBUF, &buf)) {
      switch (errno) {
      case EAGAIN:
        perror("VIDIOC_DQBUF: stopping capture thread!");
        goto stop_capturethread;
      case EIO:
        /* Could ignore EIO, see spec. */
        /* fall through */
      default:
        perror ("VIDIOC_DQBUF");
      }
    }

    debugThread("V4L2: grabbed %d", buf.index);

    me->m_currentBuffer=buffers[buf.index].start;
    //process_image (m_buffers[buf.index].start);

    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      perror ("VIDIOC_QBUF");
    }

    debugThread("V4L2: dequeueueeud");
    
    me->m_frame_ready = 1;
    me->m_last_frame=me->m_frame;
  }
 stop_capturethread:
  // stop capturing
  if(me->m_tvfd){
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == xioctl (me->m_tvfd, VIDIOC_STREAMOFF, &type)){
      perror ("VIDIOC_STREAMOFF");
    }
  }
  me->m_capturing=false;
  debugThread("V4L2: thread finished");
  return NULL;
}

//////////////////
// this reads the data that was captured by capturing() and returns it within a pixBlock
pixBlock *videoV4L2 :: getFrame(){
  if(!m_haveVideo)return NULL;
  //debugPost("v4l2: getting frame %d", m_frame_ready);
  m_image.newfilm=0;
  if (!m_frame_ready) m_image.newimage = 0;
  else {
    int i=0; // FIXME
    unsigned char*data=(unsigned char*)m_currentBuffer;
    if (m_colorConvert){
      m_image.image.notowned = false;
      switch(m_gotFormat){
      case V4L2_PIX_FMT_RGB24: m_image.image.fromRGB   (data); break;
      case V4L2_PIX_FMT_RGB32: m_image.image.fromRGBA  (data); break;
      case V4L2_PIX_FMT_GREY : m_image.image.fromGray  (data); break;
      case V4L2_PIX_FMT_UYVY : m_image.image.fromYUV422(data); break;
      case V4L2_PIX_FMT_YUV420:m_image.image.fromYU12(data); break;


      default: // ? what should we do ?
        m_image.image.data=data;
        m_image.image.notowned = true;
      }
    } else {
      m_image.image.data=data;
      m_image.image.notowned = true;
    }
    m_image.image.upsidedown=true;
    
    m_image.newimage = 1;
    m_frame_ready = false;
  }
  return &m_image;
}
/////////////////////////////////////////////////////////
// restartTransfer
//
/////////////////////////////////////////////////////////
void videoV4L2 :: restartTransfer()
{
  bool rendering=m_rendering;
  debugPost("v4l2: restart transfer");
  if(m_capturing)stopTransfer();
  debugPost("v4l2: restart stopped");
  if (rendering)startTransfer();
  debugPost("v4l2: restart started");
}


/////////////////////////////////////////////////////////
// startTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: startTransfer(int format)
{
  debugPost("v4l2: startTransfer: %d", m_capturing);
  if(m_capturing)stopTransfer(); // just in case we are already running!
  debugPost("v4l2: start transfer");
  m_rendering=true;
  if (format>1)m_reqFormat=format;
  //  verbose(1, "starting transfer");
  char buf[256];
  char*dev_name=m_devicename;
  int i;

  struct stat st; 
  struct v4l2_capability cap;
  struct v4l2_cropcap cropcap;
  struct v4l2_crop crop;
  struct v4l2_format fmt;
  unsigned int min;

  enum v4l2_buf_type type;

  m_frame = 0;
  m_last_frame = 0;


  /* check the device */

  // if we don't have a devicename, create one
  if(!dev_name){
    if (m_devicenum<0){
      sprintf(buf, "/dev/video");
    } else {
      sprintf(buf, "/dev/video%d", m_devicenum);
    }
    dev_name=buf;
  }

  // try to open the device
  debugPost("v4l2: device: %s", dev_name);
  
  m_tvfd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

  if (-1 == m_tvfd) {
    error("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (-1 == fstat (m_tvfd, &st)) {
    error("Cannot identify '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (!S_ISCHR (st.st_mode)) {
    error("%s is no device", dev_name);
    goto closit;
  }




  // by now, we have an open file-descriptor
  // check whether this is really a v4l2-device
  if (-1 == xioctl (m_tvfd, VIDIOC_QUERYCAP, &cap)) {
    if (EINVAL == errno) {
      error("%s is no V4L2 device",  dev_name);
      goto closit;
    } else {
      perror ("VIDIOC_QUERYCAP");//exit
      goto closit;
    }
  }

  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    error("%s is no video capture device", dev_name);
    goto closit;
  }

  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
    error("%s does not support streaming i/o", dev_name);
    goto closit;
  }

  /* Select video input, video standard and tune here. */

  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    /* Errors ignored. */
  }

  memset(&(cropcap), 0, sizeof (cropcap));
  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (0 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect; /* reset to default */

    if (-1 == xioctl (m_tvfd, VIDIOC_S_CROP, &crop)) {
      perror("vidioc_s_crop");
      switch (errno) {
      case EINVAL:
        /* Cropping not supported. */
        break;
      default:
        /* Errors ignored. */
        break;
      }
    }
  }


  if (-1 == xioctl (m_tvfd, VIDIOC_S_INPUT, &m_channel)) {
    perror("VIDIOC_S_INPUT"); /* exit */
  }

  memset (&(fmt), 0, sizeof (fmt));

  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.width       = m_width;
  fmt.fmt.pix.height      = m_height;

  switch(m_reqFormat){
  case GL_YCBCR_422_GEM: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 
    break;
  case GL_LUMINANCE: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; 
    break;
  case GL_RGB: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 
    break;
  default: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; 
    m_reqFormat=GL_RGBA;
    break;
  }
  fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
  
  post("v4l2: wanted %d, got '%c%c%c%c' ", m_reqFormat, 
	    (char)(fmt.fmt.pix.pixelformat),
	    (char)(fmt.fmt.pix.pixelformat>>8),
	    (char)(fmt.fmt.pix.pixelformat>>16),
	    (char)(fmt.fmt.pix.pixelformat>>24));

  if (-1 == xioctl (m_tvfd, VIDIOC_S_FMT, &fmt)){
    perror ("VIDIOC_S_FMT");//exit
    error("should exit!");
  }
  
  // query back what we have set
  if (-1 == xioctl (m_tvfd, VIDIOC_G_FMT, &fmt)){
    perror ("VIDIOC_G_FMT");//exit
    error("should exit!");
  }

  m_gotFormat=fmt.fmt.pix.pixelformat;
  switch(m_gotFormat){
  case V4L2_PIX_FMT_RGB32: debugPost("v4l2: RGBA");break;
  case V4L2_PIX_FMT_UYVY: debugPost("v4l2: YUV ");break;
  case V4L2_PIX_FMT_GREY: debugPost("v4l2: gray");break;
  case V4L2_PIX_FMT_YUV420: debugPost("v4l2: YUV 4:2:0");break;
  default: error("unknown format '%c%c%c%c'",
		(char)(fmt.fmt.pix.pixelformat),
		(char)(fmt.fmt.pix.pixelformat>>8),
		(char)(fmt.fmt.pix.pixelformat>>16),
		(char)(fmt.fmt.pix.pixelformat>>24));

  }

  /* Note VIDIOC_S_FMT may change width and height. */
  if(m_width!=fmt.fmt.pix.width||m_height!=fmt.fmt.pix.height){
    post("v4l2: changed size from %dx%d to %dx%d", 
	 m_width, m_height,
	 fmt.fmt.pix.width,fmt.fmt.pix.height);
  }
  m_width =fmt.fmt.pix.width;
  m_height=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;

  if(!init_mmap ())goto closit;

  for (i = 0; i < m_nbuffers; ++i) {
    struct v4l2_buffer buf;
    
    memset (&(buf), 0, sizeof (buf));
    
    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = i;
    
    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      perror ("VIDIOC_QBUF");//exit
    }
  }

  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_STREAMON, &type)){
    perror ("VIDIOC_STREAMON");//exit
  }
  
  /* fill in image specifics for Gem pixel object.  Could we have
     just used RGB, I wonder? */
  m_image.image.xsize = m_width;
  m_image.image.ysize = m_height;
  m_image.image.setCsizeByFormat(m_reqFormat);
  m_image.image.reallocate();
  
  debugPost("v4l2: format: %c%c%c%c -> %d", 
       (char)(m_gotFormat),
       (char)(m_gotFormat>>8),
       (char)(m_gotFormat>>16),
       (char)(m_gotFormat>>24),
       m_reqFormat);
  switch(m_gotFormat){
  case V4L2_PIX_FMT_GREY  : m_colorConvert=(m_reqFormat!=GL_LUMINANCE); break;
  case V4L2_PIX_FMT_RGB24 : m_colorConvert=(m_reqFormat!=GL_RGB); break;
  case V4L2_PIX_FMT_RGB32 : m_colorConvert=(m_reqFormat!=GL_RGBA); break;//RGB32!=RGBA; is it ARGB or ABGR?
  case V4L2_PIX_FMT_UYVY  : m_colorConvert=(m_reqFormat!=GL_YCBCR_422_GEM); break;
  case V4L2_PIX_FMT_YUV420: m_colorConvert=1; break;
  default: m_colorConvert=true;
  }
  
  debugPost("v4l2: colorconvert=%d", m_colorConvert);
  
  m_haveVideo = 1;
  
  /* create thread */
  m_continue_thread = 1;
  m_frame_ready = 0;
  pthread_create(&m_thread_id, 0, capturing, this);
  while(!m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to come up");
  }
  
  post("v4l2: GEM: pix_video: Opened video connection 0x%X", m_tvfd);
  
  return(1);
  
 closit:
  debugPost("v4l2: closing it!");
  stopTransfer();
  debugPost("v4l2: closed it");
  return(0);
}

/////////////////////////////////////////////////////////
// stopTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: stopTransfer()
{
  debugPost("v4l2: stoptransfer");
  int i=0;
  /* close the v4l2 device and dealloc buffer */
  /* terminate thread if there is one */
  if(m_continue_thread){
    void *dummy;
    m_continue_thread = 0;
    pthread_join (m_thread_id, &dummy);
  }
  while(m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to finish");
  }

  // unmap the mmap
  debugPost("v4l2: unmapping %d buffers: %x", m_nbuffers, m_buffers);
  if(m_buffers){
    for (i = 0; i < m_nbuffers; ++i)
      if (-1 == munmap (m_buffers[i].start, m_buffers[i].length)){
        // oops: couldn't unmap the memory
      }
    debugPost("v4l2: freeing buffers: %x", m_buffers);
    free (m_buffers);
  }
  m_buffers=NULL;
  debugPost("v4l2: freed");

  // close the file-descriptor
  if (m_tvfd) close(m_tvfd);

  m_tvfd = 0;
  m_haveVideo = 0;
  m_frame_ready = 0;
  m_rendering=false;
  return(1);
}

/////////////////////////////////////////////////////////
// dimenMess
//
/////////////////////////////////////////////////////////
int videoV4L2 :: setDimen(int x, int y, int leftmargin, int rightmargin,
                          int topmargin, int bottommargin)
{
  int xtotal = x + leftmargin + rightmargin;
  int ytotal = y + topmargin + bottommargin;
  if (xtotal > m_maxwidth) /* 844 */
    error("x dimensions too great");
  else if (xtotal < m_minwidth || x < 1 || leftmargin < 0 || rightmargin < 0)
    error("x dimensions too small");
  if (ytotal > m_maxheight)
    error("y dimensions too great");
  else if (ytotal < m_minheight || y < 1 ||
           topmargin < 0 || bottommargin < 0)
    error("y dimensions too small");

  m_width=x;
  m_height=y;
  m_image.image.xsize = x;
  m_image.image.ysize = y;

  m_image.image.reallocate();
  restartTransfer();
  return 0;
}

int videoV4L2 :: setNorm(char*norm)
{
  char c=*norm;
  int i_norm=-1;

  switch (c){
  case 'p': case 'P':
    i_norm = V4L2_STD_PAL;
    break;
  case 'n': case 'N':
    i_norm = V4L2_STD_NTSC;
    break;
  case 's': case 'S':
    i_norm = V4L2_STD_SECAM;
    break;
  default:
    error("pix_video: unknown norm");
    return -1;
    break;
  }
  //  if (i_norm==m_norm)return 0;
  m_norm=i_norm;
  restartTransfer();
  return 0;
}

int videoV4L2 :: setChannel(int c, t_float f){
  error("v4l2: oops, no channel selection! please report this as a bug!!!");
  
  m_channel=c;
  
  restartTransfer();

  return 0;
}

int videoV4L2 :: setDevice(int d)
{
  m_devicename=NULL;
  if (d==m_devicenum)return 0;
  m_devicenum=d;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}
int videoV4L2 :: setDevice(char*name)
{
  m_devicenum=-1;
  m_devicename=name;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}

int videoV4L2 :: setColor(int format)
{
  if (format<=0 || format==m_reqFormat)return -1;
  m_reqFormat=format;
  restartTransfer();
  return 0;
}
#endif /* HAVE_VIDEO4LINUX2 */

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: videoV4L2-hacked.cpp --]
[-- Type: text/x-c++src; name="videoV4L2-hacked.cpp", Size: 18001 bytes --]

////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    Copyright (c) Günther Geiger.
//    Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "videoV4L2.h"

#if 0
# define debugPost post
# define debugThread post
#else
# define debugPost
# define debugThread
#endif

/////////////////////////////////////////////////////////
//
// videoV4L2
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
videoV4L2 :: videoV4L2(int format) : video(format)
#ifdef HAVE_VIDEO4LINUX2
                                   , m_gotFormat(0), m_colorConvert(0),
                                     m_tvfd(0),
                                     m_buffers(NULL), m_nbuffers(0), 
                                     m_currentBuffer(NULL),
                                     m_frame(0), m_last_frame(0),
                                     m_maxwidth(844), m_minwidth(32),
                                     m_maxheight(650), m_minheight(32),
                                     m_thread_id(0), m_continue_thread(false), m_frame_ready(false),
                                     m_rendering(false)
{
  if (!m_width)m_width=320;
  if (!m_height)m_height=240;
  m_capturing=false;
  m_devicenum=V4L2_DEVICENO;
  post("video4linux2");
#else
{
#endif /* HAVE_VIDEO4LINUX2 */
}
  
////////////////////////////////////////////////////////
// Destructor
//
////////////////////////////////////////////////////////
videoV4L2 :: ~videoV4L2()
{
#ifdef HAVE_VIDEO4LINUX2
  if (m_haveVideo)stopTransfer();
#endif /* HAVE_VIDEO4LINUX2 */
}

#ifdef HAVE_VIDEO4LINUX2
static int xioctl(int                    fd,
                  int                    request,
                  void *                 arg)
{
  int r;
     
  do {
    r = ioctl (fd, request, arg);
    debugThread("V4L2: xioctl %d->%d\n", r, errno);
  }
  while (-1 == r && EINTR == errno);

  debugThread("V4L2: xioctl done %d\n", r);
   
  return r;
}
 
int videoV4L2::init_mmap (void)
{
  struct v4l2_requestbuffers req;
  char*devname=(char*)((m_devicename)?m_devicename:"device");

  memset (&(req), 0, sizeof (req));

  req.count               = V4L2_NBUF;
  req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory              = V4L2_MEMORY_MMAP;

  if (-1 == xioctl (m_tvfd, VIDIOC_REQBUFS, &req)) {
    if (EINVAL == errno) {
      error("%s does not support memory mapping", devname);
      return 0;
    } else {
      error ("VIDIOC_REQBUFS");
      return 0;
    }
  }

  if (req.count < V4L2_NBUF) {
    //error("Insufficient buffer memory on %s: %d", devname, req.count);
    //return(0);
  }

  m_buffers = (t_v4l2_buffer*)calloc (req.count, sizeof (*m_buffers));

  if (!m_buffers) {
    error("out of memory");
    return(0);
  }

  for (m_nbuffers = 0; m_nbuffers < req.count; ++m_nbuffers) {
    struct v4l2_buffer buf;

    memset (&(buf), 0, sizeof (buf));

    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = m_nbuffers;
    debugPost("v4l2: buf.index==%d", buf.index);

    if (-1 == xioctl (m_tvfd, VIDIOC_QUERYBUF, &buf)){
      error ("VIDIOC_QUERYBUF");
      return(0);
    }

    m_buffers[m_nbuffers].length = buf.length;
    m_buffers[m_nbuffers].start =
      mmap (NULL /* start anywhere */,
            buf.length,
            PROT_READ | PROT_WRITE /* required */,
            MAP_SHARED /* recommended */,
            m_tvfd, buf.m.offset);

    if (MAP_FAILED == m_buffers[m_nbuffers].start){
      error ("mmap");
      return 0;
    }
  }
  return 1;
}

/////////////////////////////////////////////////////////
// this is the work-horse
// a thread that does the capturing
//
/////////////////////////////////////////////////////////
void *videoV4L2 :: capturing(void*you)
{
  videoV4L2 *me=(videoV4L2 *)you;
  t_v4l2_buffer*buffers=me->m_buffers;

  struct v4l2_buffer buf;
  unsigned int i;
    
  fd_set fds;
  struct timeval tv;
  int r;

  int nbuf=me->m_nbuffers;
  int m_tvfd=me->m_tvfd;
  me->m_capturing=true;

  debugThread("V4L2: memset");
  memset(&(buf), 0, sizeof (buf));
  
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  buf.memory = V4L2_MEMORY_MMAP;

  while(me->m_continue_thread){
    FD_ZERO (&fds);
    FD_SET (m_tvfd, &fds);

    debugThread("V4L2: grab");

    me->m_frame++;
    me->m_frame%=nbuf;

    
    /* Timeout. */
    tv.tv_sec = 0;
    tv.tv_usec = 100;

#if 0
    r = select (m_tvfd + 1, &fds, NULL, NULL, &tv);
      if (0 == r) {
      error("select timeout");
      me->m_continue_thread=false;
      }
#else
    r = select(0,0,0,0,&tv);
#endif
    debugThread("V4L2: waited...");
    if (-1 == r) {
      if (EINTR == errno)
        continue;
      error ("select");//exit
    }

    memset(&(buf), 0, sizeof (buf));
    debugThread("V4L2: memset...");
  
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if (-1 == xioctl (m_tvfd, VIDIOC_DQBUF, &buf)) {
/*      switch (errno) {
      case EAGAIN:
        perror("VIDIOC_DQBUF: stopping capture thread!");
        goto stop_capturethread;
      case EIO:
        /* Could ignore EIO, see spec. bb/
        /* fall through bb/
      default:
        perror ("VIDIOC_DQBUF");
      }*/
    }

    debugThread("V4L2: grabbed %d", buf.index);

    me->m_currentBuffer=buffers[buf.index].start;
    //process_image (m_buffers[buf.index].start);

    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      //perror ("VIDIOC_QBUF");
    }

    debugThread("V4L2: dequeueueeud");
    
    me->m_frame_ready = 1;
    me->m_last_frame=me->m_frame;
  }
 stop_capturethread:
  // stop capturing
  if(me->m_tvfd){
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == xioctl (me->m_tvfd, VIDIOC_STREAMOFF, &type)){
      perror ("VIDIOC_STREAMOFF");
    }
  }
  me->m_capturing=false;
  debugThread("V4L2: thread finished");
  return NULL;
}

//////////////////
// this reads the data that was captured by capturing() and returns it within a pixBlock
pixBlock *videoV4L2 :: getFrame(){
  if(!m_haveVideo)return NULL;
  //debugPost("v4l2: getting frame %d", m_frame_ready);
  m_image.newfilm=0;
  if (!m_frame_ready) m_image.newimage = 0;
  else {
    int i=0; // FIXME
    unsigned char*data=(unsigned char*)m_currentBuffer;
    if (m_colorConvert){
      m_image.image.notowned = false;
      switch(m_gotFormat){
      case V4L2_PIX_FMT_RGB24: m_image.image.fromRGB   (data); break;
      case V4L2_PIX_FMT_RGB32: m_image.image.fromRGBA  (data); break;
      case V4L2_PIX_FMT_GREY : m_image.image.fromGray  (data); break;
      case V4L2_PIX_FMT_UYVY : m_image.image.fromYUV422(data); break;
      case V4L2_PIX_FMT_YUV420:m_image.image.fromYU12(data); break;


      default: // ? what should we do ?
        m_image.image.data=data;
        m_image.image.notowned = true;
      }
    } else {
      m_image.image.data=data;
      m_image.image.notowned = true;
    }
    m_image.image.upsidedown=true;
    
    m_image.newimage = 1;
    m_frame_ready = false;
  }
  return &m_image;
}
/////////////////////////////////////////////////////////
// restartTransfer
//
/////////////////////////////////////////////////////////
void videoV4L2 :: restartTransfer()
{
  bool rendering=m_rendering;
  debugPost("v4l2: restart transfer");
  if(m_capturing)stopTransfer();
  debugPost("v4l2: restart stopped");
  if (rendering)startTransfer();
  debugPost("v4l2: restart started");
}


/////////////////////////////////////////////////////////
// startTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: startTransfer(int format)
{
  debugPost("v4l2: startTransfer: %d", m_capturing);
  if(m_capturing)stopTransfer(); // just in case we are already running!
  debugPost("v4l2: start transfer");
  m_rendering=true;
  if (format>1)m_reqFormat=format;
  //  verbose(1, "starting transfer");
  char buf[256];
  char*dev_name=m_devicename;
  int i;

  struct stat st; 
  struct v4l2_capability cap;
  struct v4l2_cropcap cropcap;
  struct v4l2_crop crop;
  struct v4l2_format fmt;
  unsigned int min;

  enum v4l2_buf_type type;

  m_frame = 0;
  m_last_frame = 0;


  /* check the device */

  // if we don't have a devicename, create one
  if(!dev_name){
    if (m_devicenum<0){
      sprintf(buf, "/dev/video");
    } else {
      sprintf(buf, "/dev/video%d", m_devicenum);
    }
    dev_name=buf;
  }

  // try to open the device
  debugPost("v4l2: device: %s", dev_name);
  
  m_tvfd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

  if (-1 == m_tvfd) {
    error("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (-1 == fstat (m_tvfd, &st)) {
    error("Cannot identify '%s': %d, %s", dev_name, errno, strerror (errno));
    goto closit;
  }

  if (!S_ISCHR (st.st_mode)) {
    error("%s is no device", dev_name);
    goto closit;
  }




  // by now, we have an open file-descriptor
  // check whether this is really a v4l2-device
  if (-1 == xioctl (m_tvfd, VIDIOC_QUERYCAP, &cap)) {
    if (EINVAL == errno) {
      error("%s is no V4L2 device",  dev_name);
      goto closit;
    } else {
      perror ("VIDIOC_QUERYCAP");//exit
      goto closit;
    }
  }

  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    error("%s is no video capture device", dev_name);
    goto closit;
  }

  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
    error("%s does not support streaming i/o", dev_name);
    goto closit;
  }

  /* Select video input, video standard and tune here. */

  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    /* Errors ignored. */
  }

  memset(&(cropcap), 0, sizeof (cropcap));
  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (0 == xioctl (m_tvfd, VIDIOC_CROPCAP, &cropcap)) {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect; /* reset to default */

    if (-1 == xioctl (m_tvfd, VIDIOC_S_CROP, &crop)) {
      perror("vidioc_s_crop");
      switch (errno) {
      case EINVAL:
        /* Cropping not supported. */
        break;
      default:
        /* Errors ignored. */
        break;
      }
    }
  }


  if (-1 == xioctl (m_tvfd, VIDIOC_S_INPUT, &m_channel)) {
    perror("VIDIOC_S_INPUT"); /* exit */
  }

  memset (&(fmt), 0, sizeof (fmt));

  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.width       = m_width;
  fmt.fmt.pix.height      = m_height;

  switch(m_reqFormat){
  case GL_YCBCR_422_GEM: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 
    break;
  case GL_LUMINANCE: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; 
    break;
  case GL_RGB: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 
    break;
  default: 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; 
    m_reqFormat=GL_RGBA;
    break;
  }
  fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
  
  post("v4l2: wanted %d, got '%c%c%c%c' ", m_reqFormat, 
	    (char)(fmt.fmt.pix.pixelformat),
	    (char)(fmt.fmt.pix.pixelformat>>8),
	    (char)(fmt.fmt.pix.pixelformat>>16),
	    (char)(fmt.fmt.pix.pixelformat>>24));

  if (-1 == xioctl (m_tvfd, VIDIOC_S_FMT, &fmt)){
    perror ("VIDIOC_S_FMT");//exit
    error("should exit!");
  }
  
  // query back what we have set
  if (-1 == xioctl (m_tvfd, VIDIOC_G_FMT, &fmt)){
    perror ("VIDIOC_G_FMT");//exit
    error("should exit!");
  }

  m_gotFormat=fmt.fmt.pix.pixelformat;
  switch(m_gotFormat){
  case V4L2_PIX_FMT_RGB32: debugPost("v4l2: RGBA");break;
  case V4L2_PIX_FMT_UYVY: debugPost("v4l2: YUV ");break;
  case V4L2_PIX_FMT_GREY: debugPost("v4l2: gray");break;
  case V4L2_PIX_FMT_YUV420: debugPost("v4l2: YUV 4:2:0");break;
  default: error("unknown format '%c%c%c%c'",
		(char)(fmt.fmt.pix.pixelformat),
		(char)(fmt.fmt.pix.pixelformat>>8),
		(char)(fmt.fmt.pix.pixelformat>>16),
		(char)(fmt.fmt.pix.pixelformat>>24));

  }

  /* Note VIDIOC_S_FMT may change width and height. */
  if(m_width!=fmt.fmt.pix.width||m_height!=fmt.fmt.pix.height){
    post("v4l2: changed size from %dx%d to %dx%d", 
	 m_width, m_height,
	 fmt.fmt.pix.width,fmt.fmt.pix.height);
  }
  m_width =fmt.fmt.pix.width;
  m_height=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;

  if(!init_mmap ())goto closit;

  for (i = 0; i < m_nbuffers; ++i) {
    struct v4l2_buffer buf;
    
    memset (&(buf), 0, sizeof (buf));
    
    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory      = V4L2_MEMORY_MMAP;
    buf.index       = i;
    
    if (-1 == xioctl (m_tvfd, VIDIOC_QBUF, &buf)){
      perror ("VIDIOC_QBUF");//exit
    }
  }

  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if (-1 == xioctl (m_tvfd, VIDIOC_STREAMON, &type)){
    perror ("VIDIOC_STREAMON");//exit
  }
  
  /* fill in image specifics for Gem pixel object.  Could we have
     just used RGB, I wonder? */
  m_image.image.xsize = m_width;
  m_image.image.ysize = m_height;
  m_image.image.setCsizeByFormat(m_reqFormat);
  m_image.image.reallocate();
  
  debugPost("v4l2: format: %c%c%c%c -> %d", 
       (char)(m_gotFormat),
       (char)(m_gotFormat>>8),
       (char)(m_gotFormat>>16),
       (char)(m_gotFormat>>24),
       m_reqFormat);
  switch(m_gotFormat){
  case V4L2_PIX_FMT_GREY  : m_colorConvert=(m_reqFormat!=GL_LUMINANCE); break;
  case V4L2_PIX_FMT_RGB24 : m_colorConvert=(m_reqFormat!=GL_RGB); break;
  case V4L2_PIX_FMT_RGB32 : m_colorConvert=(m_reqFormat!=GL_RGBA); break;//RGB32!=RGBA; is it ARGB or ABGR?
  case V4L2_PIX_FMT_UYVY  : m_colorConvert=(m_reqFormat!=GL_YCBCR_422_GEM); break;
  case V4L2_PIX_FMT_YUV420: m_colorConvert=1; break;
  default: m_colorConvert=true;
  }
  
  debugPost("v4l2: colorconvert=%d", m_colorConvert);
  
  m_haveVideo = 1;
  
  /* create thread */
  m_continue_thread = 1;
  m_frame_ready = 0;
  pthread_create(&m_thread_id, 0, capturing, this);
  while(!m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to come up");
  }
  
  post("v4l2: GEM: pix_video: Opened video connection 0x%X", m_tvfd);
  
  return(1);
  
 closit:
  debugPost("v4l2: closing it!");
  stopTransfer();
  debugPost("v4l2: closed it");
  return(0);
}

/////////////////////////////////////////////////////////
// stopTransfer
//
/////////////////////////////////////////////////////////
int videoV4L2 :: stopTransfer()
{
  debugPost("v4l2: stoptransfer");
  int i=0;
  /* close the v4l2 device and dealloc buffer */
  /* terminate thread if there is one */
  if(m_continue_thread){
    void *dummy;
    m_continue_thread = 0;
    pthread_join (m_thread_id, &dummy);
  }
  while(m_capturing){
    struct timeval sleep;
    sleep.tv_sec=0;  sleep.tv_usec=10; /* 10us */
    select(0,0,0,0,&sleep);
    debugPost("v4l2: waiting for thread to finish");
  }

  // unmap the mmap
  debugPost("v4l2: unmapping %d buffers: %x", m_nbuffers, m_buffers);
  if(m_buffers){
    for (i = 0; i < m_nbuffers; ++i)
      if (-1 == munmap (m_buffers[i].start, m_buffers[i].length)){
        // oops: couldn't unmap the memory
      }
    debugPost("v4l2: freeing buffers: %x", m_buffers);
    free (m_buffers);
  }
  m_buffers=NULL;
  debugPost("v4l2: freed");

  // close the file-descriptor
  if (m_tvfd) close(m_tvfd);

  m_tvfd = 0;
  m_haveVideo = 0;
  m_frame_ready = 0;
  m_rendering=false;
  return(1);
}

/////////////////////////////////////////////////////////
// dimenMess
//
/////////////////////////////////////////////////////////
int videoV4L2 :: setDimen(int x, int y, int leftmargin, int rightmargin,
                          int topmargin, int bottommargin)
{
  int xtotal = x + leftmargin + rightmargin;
  int ytotal = y + topmargin + bottommargin;
  if (xtotal > m_maxwidth) /* 844 */
    error("x dimensions too great");
  else if (xtotal < m_minwidth || x < 1 || leftmargin < 0 || rightmargin < 0)
    error("x dimensions too small");
  if (ytotal > m_maxheight)
    error("y dimensions too great");
  else if (ytotal < m_minheight || y < 1 ||
           topmargin < 0 || bottommargin < 0)
    error("y dimensions too small");

  m_width=x;
  m_height=y;
  m_image.image.xsize = x;
  m_image.image.ysize = y;

  m_image.image.reallocate();
  restartTransfer();
  return 0;
}

int videoV4L2 :: setNorm(char*norm)
{
  char c=*norm;
  int i_norm=-1;

  switch (c){
  case 'p': case 'P':
    i_norm = V4L2_STD_PAL;
    break;
  case 'n': case 'N':
    i_norm = V4L2_STD_NTSC;
    break;
  case 's': case 'S':
    i_norm = V4L2_STD_SECAM;
    break;
  default:
    error("pix_video: unknown norm");
    return -1;
    break;
  }
  //  if (i_norm==m_norm)return 0;
  m_norm=i_norm;
  restartTransfer();
  return 0;
}

int videoV4L2 :: setChannel(int c, t_float f){
  error("v4l2: oops, no channel selection! please report this as a bug!!!");
  
  m_channel=c;
  
  restartTransfer();

  return 0;
}

int videoV4L2 :: setDevice(int d)
{
  m_devicename=NULL;
  if (d==m_devicenum)return 0;
  m_devicenum=d;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}
int videoV4L2 :: setDevice(char*name)
{
  m_devicenum=-1;
  m_devicename=name;
  restartTransfer();
  //  verbose(1, "new device set %d", m_devicenum);
  return 0;
}

int videoV4L2 :: setColor(int format)
{
  if (format<=0 || format==m_reqFormat)return -1;
  m_reqFormat=format;
  restartTransfer();
  return 0;
}
#endif /* HAVE_VIDEO4LINUX2 */

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2008-09-12 19:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-04 22:14 V4l2 :: Debugging an issue with cx8800 card B. Bogart
2008-09-04 22:51 ` Andy Walls
2008-09-04 23:16   ` B. Bogart
2008-09-05  6:01     ` Jean-Francois Moine
2008-09-05 15:29       ` B. Bogart
2008-09-12 19:19   ` B. Bogart
2008-09-12 19:22   ` B. Bogart
2008-09-12  0:44 ` Broken gem support for UYVY V4L capture? WAS " B. Bogart
2008-09-12  0:46 ` Sorry! B. Bogart

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox