diff example/dummy.c @ 0:5f21a4dddc0c

Initial checkin
author KennethLavrsen
date Sun, 01 Apr 2007 05:22:43 +0000
parents
children 2fce9e157b8d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/dummy.c	Sun Apr 01 05:22:43 2007 +0000
@@ -0,0 +1,435 @@
+/*	dummy.c
+ *
+ *	Example program for using a videoloopback device in zero-copy mode.
+ *	Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org)
+ *	Copyright 2005 by Angel Carpintero (ack@telefonica.net)
+ *	This software is distributed under the GNU public license version 2
+ *	See also the file 'COPYING'.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/poll.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <linux/videodev.h>
+
+/* all seem reasonable, or not? */
+#define MAXIOCTL 1024
+#define MAXWIDTH 640
+#define MAXHEIGHT 480
+int width;
+int height;
+int fmt=0;
+char ioctlbuf[MAXIOCTL];
+int v4ldev;
+char *image_out;
+	
+
+int get_frame(void)
+{
+	int i;
+	char colour = 0;
+
+	memset(image_out, 0x128, width*height*3);
+	
+	for (i=10; i<width-10; i++) {
+		image_out[10*width*3+i*3]=colour++;
+		image_out[10*width*3+i*3+1]=0;
+		image_out[10*width*3+i*3+2]=-colour;
+	}
+	for (i=10; i<width-10; i++) {
+		image_out[(height-10)*width*3+i*3]=colour;
+		image_out[(height-10)*width*3+i*3+1]=0;
+		image_out[(height-10)*width*3+i*3+2]=-colour++;
+	}
+	/*
+	*/
+	usleep(500); /* BIG XXX */
+	return 0;
+}
+
+char *v4l_create (int dev, int memsize)
+{
+	char *map;
+	
+	map=mmap(0, memsize, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0);
+	if ((unsigned char *)-1 == (unsigned char *)map)
+		return NULL;
+	return map;	
+}
+
+int v4l_ioctl(unsigned long int cmd, void *arg)
+{
+	int i;
+	switch (cmd) {
+		case VIDIOCGCAP:
+		{
+			struct video_capability *vidcap=arg;
+
+			sprintf(vidcap->name, "Jeroen's dummy v4l driver");
+			vidcap->type= VID_TYPE_CAPTURE;
+			vidcap->channels=1;
+			vidcap->audios=0;
+			vidcap->maxwidth=MAXWIDTH;
+			vidcap->maxheight=MAXHEIGHT;
+			vidcap->minwidth=20;
+			vidcap->minheight=20;
+			return 0;
+		}
+		case VIDIOCGCHAN:
+		{
+			struct video_channel *vidchan= (struct video_channel *)arg;
+			
+			printf("VIDIOCGCHAN called\n");
+			if (vidchan->channel!=0)
+				;//return 1;
+			vidchan->channel=0;
+			vidchan->flags=0;
+			vidchan->tuners=0;
+			vidchan->norm=0;
+			vidchan->type=VIDEO_TYPE_CAMERA;
+			strcpy(vidchan->name, "Loopback");
+			
+			return 0;
+		}
+		case VIDIOCSCHAN:
+		{
+			int *v=arg;
+			
+			if (v[0]!=0)
+				return 1;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner *v = arg;
+
+			if(v->tuner) {
+				printf("VIDIOCGTUNER: Invalid Tuner, was %d\n", v->tuner);
+				//return -EINVAL;
+			}
+			v->tuner=0;
+			strcpy(v->name, "Format");
+			v->rangelow=0;
+			v->rangehigh=0;
+			v->flags=0;
+			v->mode=VIDEO_MODE_AUTO;
+			return 1;
+		}
+		case VIDIOCGPICT:
+		{
+			struct video_picture *vidpic=arg;
+
+			vidpic->colour=0x8000;
+			vidpic->hue=0x8000;
+			vidpic->brightness=0x8000;
+			vidpic->contrast=0x8000;
+			vidpic->whiteness=0x8000;
+			vidpic->depth=0x8000;
+			vidpic->palette=fmt;
+			return 0;
+		}
+		case VIDIOCSPICT:
+		{
+			struct video_picture *vidpic=arg;
+			
+			if (vidpic->palette!=fmt)
+				return 1;
+			return 0;
+		}
+		case VIDIOCGWIN:
+		{
+			struct video_window *vidwin=arg;
+
+			vidwin->x=0;
+			vidwin->y=0;
+			vidwin->width=width;
+			vidwin->height=height;
+			vidwin->chromakey=0;
+			vidwin->flags=0;
+			vidwin->clipcount=0;
+			return 0;
+		}
+		case VIDIOCSWIN:
+		{
+			struct video_window *vidwin=arg;
+			
+			if (vidwin->width > MAXWIDTH ||
+			    vidwin->height > MAXHEIGHT )
+				return 1;
+			if (vidwin->flags)
+				return 1;
+			width=vidwin->width;
+			height=vidwin->height;
+			printf("new size: %dx%d\n", width, height);
+			return 0;
+		}
+		case VIDIOCGMBUF:
+		{
+			struct video_mbuf *vidmbuf=arg;
+
+			vidmbuf->size=width*height*3;
+			vidmbuf->frames=1;
+			for (i=0; i<vidmbuf->frames; i++)
+				vidmbuf->offsets[i]=i*vidmbuf->size;
+			return 0;
+		}
+		case VIDIOCMCAPTURE:
+		{
+			struct video_mmap *vidmmap=arg;
+
+			//return 0;
+			if (vidmmap->height>MAXHEIGHT ||
+			    vidmmap->width>MAXWIDTH ||
+			    vidmmap->format!=fmt )
+				return 1;
+			if (vidmmap->height!=height ||
+			    vidmmap->width!=width) {
+				height=vidmmap->height;
+				width=vidmmap->width;
+				printf("new size: %dx%d\n", width, height);
+			}
+			// check if 'vidmmap->frame' is valid
+			// initiate capture for 'vidmmap->frame' frames
+			return 0;
+		}
+		case VIDIOCSYNC:
+		{
+			//struct video_mmap *vidmmap=arg;
+
+			// check if frames are ready.
+			// wait until ready.
+			get_frame();
+			return 0;
+		}
+		default:
+		{
+			printf("unknown ioctl: %ld\n", cmd & 0xff);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+#define VIDIOCSINVALID	_IO('v',BASE_VIDIOCPRIVATE+1)
+
+void sighandler(int signo)
+{
+	int size, ret;
+	unsigned long int cmd;
+	struct pollfd ufds;
+
+	if (signo!=SIGIO)
+		return;
+	ufds.fd=v4ldev;
+	ufds.events=POLLIN;
+	ufds.revents=0;
+	poll(&ufds, 1, 1000);
+	if (!ufds.revents & POLLIN) {
+		printf("Received signal but got negative on poll?!?!?!?\n");
+		return;
+	}
+	size=read(v4ldev, ioctlbuf, MAXIOCTL);
+	if (size >= sizeof(unsigned long int)) {
+		memcpy(&cmd, ioctlbuf, sizeof(unsigned long int));
+		if (cmd==0) {
+			printf("Client closed device\n");
+			return;
+		}
+		ret=v4l_ioctl(cmd, ioctlbuf+sizeof(unsigned long int));
+		if (ret) {
+			memset(ioctlbuf+sizeof(unsigned long int), MAXIOCTL-sizeof(unsigned long int), 0xff);
+			printf("ioctl %lx unsuccesfull, lets issue VIDIOCSINVALID (%x)\n", cmd, VIDIOCSINVALID);
+			ioctl(v4ldev, VIDIOCSINVALID);
+		} else
+			ioctl(v4ldev, cmd, ioctlbuf+sizeof(unsigned long int));
+	}
+	return;
+}
+
+int open_vidpipe(void)
+{
+	int pipe_fd = -1;
+	FILE *vloopbacks;
+	char pipepath[255];
+	char buffer[255];
+	char *loop;
+	char *input;
+	char *istatus;
+	char *output;
+	char *ostatus;
+	char *major;
+	char *minor;
+	struct utsname uts;
+
+	if (uname(&uts) < 0) {
+		printf("Unable to execute uname\nError[%s]\n",strerror(errno));
+		return -1;
+	}
+	
+	major = strtok(uts.release, ".");
+	minor = strtok(NULL, ".");
+	if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) {
+		printf("Unable to decipher OS version\n");
+		return -1;
+	}
+
+	if (strcmp(minor, "5") < 0) {
+	
+		vloopbacks=fopen("/proc/video/vloopback/vloopbacks", "r");
+		if (!vloopbacks) {
+			printf ("Failed to open '/proc/video/vloopback/vloopbacks");
+			return -1;
+		}
+		/* Read vloopback version */
+		fgets(buffer, 255, vloopbacks);
+		printf("%s", buffer);
+		/* Read explaination line */
+		fgets(buffer, 255, vloopbacks);
+		while (fgets(buffer, 255, vloopbacks)) {
+			if (strlen(buffer)>1) {
+				buffer[strlen(buffer)-1]=0;
+				loop=strtok(buffer, "\t");
+				input=strtok(NULL, "\t");
+				istatus=strtok(NULL, "\t");
+				output=strtok(NULL, "\t");
+				ostatus=strtok(NULL, "\t");
+				if (istatus[0]=='-') {
+					sprintf(pipepath, "/dev/%s", input);
+					pipe_fd=open(pipepath, O_RDWR);
+					if (pipe_fd>=0) {
+						printf("Input: /dev/%s\n", input);
+						printf("Output: /dev/%s\n", output);
+						return pipe_fd;
+					}
+				}
+			} 
+		}
+
+	}else{
+		DIR *dir;
+		struct dirent *dirp;
+		const char prefix[]="/sys/class/video4linux/";
+		char *ptr, *io;
+		int fd;
+		int low=9999;
+		int tfd;
+		int tnum;
+
+		if ((dir=opendir(prefix))== NULL) {
+			printf( "Failed to open '%s'", prefix);
+			return -1;
+		}
+
+		while ((dirp=readdir(dir)) != NULL) {
+                        if (!strncmp(dirp->d_name, "video", 5)) {
+                                strcpy(buffer, prefix);
+                                strcat(buffer, dirp->d_name);
+                                strcat(buffer, "/name");
+                                if ((fd=open(buffer, O_RDONLY)) >= 0) {
+                                        if ((read(fd, buffer, sizeof(buffer)-1))<0) {
+                                                close(fd);
+                                                continue;
+                                        }
+                                        ptr = strtok(buffer, " ");
+                                        if (strcmp(ptr,"Video")) {
+                                                close(fd);
+                                                continue;
+                                        }
+                                        major = strtok(NULL, " ");
+                                        minor = strtok(NULL, " ");
+                                        io  = strtok(NULL, " \n");
+                                        if (strcmp(major, "loopback") || strcmp(io, "input")) {
+                                                close(fd);
+                                                continue;
+                                        }
+                                        if ((ptr=strtok(buffer, " "))==NULL) {
+                                                close(fd);
+                                                continue;
+                                        }
+                                        tnum = atoi(minor);
+                                        if (tnum < low) {
+                                                strcpy(buffer, "/dev/");
+                                                strcat(buffer, dirp->d_name);
+                                                if ((tfd=open(buffer, O_RDWR))>=0) {
+                                                        strcpy(pipepath, buffer);
+                                                        if (pipe_fd>=0) {
+                                                                close(pipe_fd);
+                                                        }
+                                                        pipe_fd = tfd;
+                                                        low = tnum;
+                                                }
+                                        }
+                                        close(fd);
+                                }
+                        }
+                }
+		
+
+		closedir(dir);
+                if (pipe_fd >= 0)
+                        printf("Opened input of %s", pipepath);
+        }
+	
+	return pipe_fd;
+}
+
+int main (int argc, char **argv)
+{
+	char palette[10]={'\0'};
+
+	if (argc != 3) {
+		printf("dummy.c\n");
+		printf("A example for using a video4linux loopback in zero-copy mode\n");
+		printf("Written by Jeroen Vreeken, 2000\n");
+		printf("Updated to vloopback API v0.97\n\n");
+		printf("Usage:\n\n");
+		printf("dummy widthxheight rgb24|yuv420p\n\n");
+		printf("example: dummy 352x288 yuv420p\n\n");
+		exit(1);
+	}
+	
+	sscanf(argv[1], "%dx%d", &width, &height);
+	sscanf(argv[2], "%s", palette);
+
+	if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24;
+	else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P;
+	else fmt = VIDEO_PALETTE_RGB24;
+	
+	/* Default startup values, nothing special 
+	width=352;
+	height=288;
+	*/
+
+	v4ldev=open_vidpipe();
+	if (v4ldev < 0) {
+		printf ("Failed to open video loopback device\nError[%s]\n",strerror(errno));
+		exit(1);
+	}
+	image_out=v4l_create(v4ldev, MAXWIDTH*MAXHEIGHT*3);
+	if (!image_out) {
+		exit(1);
+		printf ("Failed to set device to zero-copy mode\nError[%s]\n",strerror(errno));
+	}
+
+	signal (SIGIO, sighandler);
+
+	printf("\nListening.\n");
+	while (1) {
+		sleep(1000);
+	}
+
+	close (v4ldev);
+	free(image_out);
+	exit(0);
+}