Mercurial > vloopback
comparison example/dummy.c @ 0:5f21a4dddc0c
Initial checkin
author | KennethLavrsen |
---|---|
date | Sun, 01 Apr 2007 05:22:43 +0000 |
parents | |
children | 2fce9e157b8d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5f21a4dddc0c |
---|---|
1 /* dummy.c | |
2 * | |
3 * Example program for using a videoloopback device in zero-copy mode. | |
4 * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) | |
5 * Copyright 2005 by Angel Carpintero (ack@telefonica.net) | |
6 * This software is distributed under the GNU public license version 2 | |
7 * See also the file 'COPYING'. | |
8 * | |
9 */ | |
10 | |
11 #include <unistd.h> | |
12 #include <stdlib.h> | |
13 #include <stdio.h> | |
14 #include <fcntl.h> | |
15 #include <string.h> | |
16 #include <errno.h> | |
17 #include <sys/ioctl.h> | |
18 #include <sys/mman.h> | |
19 #include <signal.h> | |
20 #include <sys/wait.h> | |
21 #include <sys/poll.h> | |
22 #include <dirent.h> | |
23 #include <sys/utsname.h> | |
24 #include <linux/videodev.h> | |
25 | |
26 /* all seem reasonable, or not? */ | |
27 #define MAXIOCTL 1024 | |
28 #define MAXWIDTH 640 | |
29 #define MAXHEIGHT 480 | |
30 int width; | |
31 int height; | |
32 int fmt=0; | |
33 char ioctlbuf[MAXIOCTL]; | |
34 int v4ldev; | |
35 char *image_out; | |
36 | |
37 | |
38 int get_frame(void) | |
39 { | |
40 int i; | |
41 char colour = 0; | |
42 | |
43 memset(image_out, 0x128, width*height*3); | |
44 | |
45 for (i=10; i<width-10; i++) { | |
46 image_out[10*width*3+i*3]=colour++; | |
47 image_out[10*width*3+i*3+1]=0; | |
48 image_out[10*width*3+i*3+2]=-colour; | |
49 } | |
50 for (i=10; i<width-10; i++) { | |
51 image_out[(height-10)*width*3+i*3]=colour; | |
52 image_out[(height-10)*width*3+i*3+1]=0; | |
53 image_out[(height-10)*width*3+i*3+2]=-colour++; | |
54 } | |
55 /* | |
56 */ | |
57 usleep(500); /* BIG XXX */ | |
58 return 0; | |
59 } | |
60 | |
61 char *v4l_create (int dev, int memsize) | |
62 { | |
63 char *map; | |
64 | |
65 map=mmap(0, memsize, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); | |
66 if ((unsigned char *)-1 == (unsigned char *)map) | |
67 return NULL; | |
68 return map; | |
69 } | |
70 | |
71 int v4l_ioctl(unsigned long int cmd, void *arg) | |
72 { | |
73 int i; | |
74 switch (cmd) { | |
75 case VIDIOCGCAP: | |
76 { | |
77 struct video_capability *vidcap=arg; | |
78 | |
79 sprintf(vidcap->name, "Jeroen's dummy v4l driver"); | |
80 vidcap->type= VID_TYPE_CAPTURE; | |
81 vidcap->channels=1; | |
82 vidcap->audios=0; | |
83 vidcap->maxwidth=MAXWIDTH; | |
84 vidcap->maxheight=MAXHEIGHT; | |
85 vidcap->minwidth=20; | |
86 vidcap->minheight=20; | |
87 return 0; | |
88 } | |
89 case VIDIOCGCHAN: | |
90 { | |
91 struct video_channel *vidchan= (struct video_channel *)arg; | |
92 | |
93 printf("VIDIOCGCHAN called\n"); | |
94 if (vidchan->channel!=0) | |
95 ;//return 1; | |
96 vidchan->channel=0; | |
97 vidchan->flags=0; | |
98 vidchan->tuners=0; | |
99 vidchan->norm=0; | |
100 vidchan->type=VIDEO_TYPE_CAMERA; | |
101 strcpy(vidchan->name, "Loopback"); | |
102 | |
103 return 0; | |
104 } | |
105 case VIDIOCSCHAN: | |
106 { | |
107 int *v=arg; | |
108 | |
109 if (v[0]!=0) | |
110 return 1; | |
111 return 0; | |
112 } | |
113 case VIDIOCGTUNER: | |
114 { | |
115 struct video_tuner *v = arg; | |
116 | |
117 if(v->tuner) { | |
118 printf("VIDIOCGTUNER: Invalid Tuner, was %d\n", v->tuner); | |
119 //return -EINVAL; | |
120 } | |
121 v->tuner=0; | |
122 strcpy(v->name, "Format"); | |
123 v->rangelow=0; | |
124 v->rangehigh=0; | |
125 v->flags=0; | |
126 v->mode=VIDEO_MODE_AUTO; | |
127 return 1; | |
128 } | |
129 case VIDIOCGPICT: | |
130 { | |
131 struct video_picture *vidpic=arg; | |
132 | |
133 vidpic->colour=0x8000; | |
134 vidpic->hue=0x8000; | |
135 vidpic->brightness=0x8000; | |
136 vidpic->contrast=0x8000; | |
137 vidpic->whiteness=0x8000; | |
138 vidpic->depth=0x8000; | |
139 vidpic->palette=fmt; | |
140 return 0; | |
141 } | |
142 case VIDIOCSPICT: | |
143 { | |
144 struct video_picture *vidpic=arg; | |
145 | |
146 if (vidpic->palette!=fmt) | |
147 return 1; | |
148 return 0; | |
149 } | |
150 case VIDIOCGWIN: | |
151 { | |
152 struct video_window *vidwin=arg; | |
153 | |
154 vidwin->x=0; | |
155 vidwin->y=0; | |
156 vidwin->width=width; | |
157 vidwin->height=height; | |
158 vidwin->chromakey=0; | |
159 vidwin->flags=0; | |
160 vidwin->clipcount=0; | |
161 return 0; | |
162 } | |
163 case VIDIOCSWIN: | |
164 { | |
165 struct video_window *vidwin=arg; | |
166 | |
167 if (vidwin->width > MAXWIDTH || | |
168 vidwin->height > MAXHEIGHT ) | |
169 return 1; | |
170 if (vidwin->flags) | |
171 return 1; | |
172 width=vidwin->width; | |
173 height=vidwin->height; | |
174 printf("new size: %dx%d\n", width, height); | |
175 return 0; | |
176 } | |
177 case VIDIOCGMBUF: | |
178 { | |
179 struct video_mbuf *vidmbuf=arg; | |
180 | |
181 vidmbuf->size=width*height*3; | |
182 vidmbuf->frames=1; | |
183 for (i=0; i<vidmbuf->frames; i++) | |
184 vidmbuf->offsets[i]=i*vidmbuf->size; | |
185 return 0; | |
186 } | |
187 case VIDIOCMCAPTURE: | |
188 { | |
189 struct video_mmap *vidmmap=arg; | |
190 | |
191 //return 0; | |
192 if (vidmmap->height>MAXHEIGHT || | |
193 vidmmap->width>MAXWIDTH || | |
194 vidmmap->format!=fmt ) | |
195 return 1; | |
196 if (vidmmap->height!=height || | |
197 vidmmap->width!=width) { | |
198 height=vidmmap->height; | |
199 width=vidmmap->width; | |
200 printf("new size: %dx%d\n", width, height); | |
201 } | |
202 // check if 'vidmmap->frame' is valid | |
203 // initiate capture for 'vidmmap->frame' frames | |
204 return 0; | |
205 } | |
206 case VIDIOCSYNC: | |
207 { | |
208 //struct video_mmap *vidmmap=arg; | |
209 | |
210 // check if frames are ready. | |
211 // wait until ready. | |
212 get_frame(); | |
213 return 0; | |
214 } | |
215 default: | |
216 { | |
217 printf("unknown ioctl: %ld\n", cmd & 0xff); | |
218 return 1; | |
219 } | |
220 } | |
221 return 0; | |
222 } | |
223 | |
224 #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) | |
225 | |
226 void sighandler(int signo) | |
227 { | |
228 int size, ret; | |
229 unsigned long int cmd; | |
230 struct pollfd ufds; | |
231 | |
232 if (signo!=SIGIO) | |
233 return; | |
234 ufds.fd=v4ldev; | |
235 ufds.events=POLLIN; | |
236 ufds.revents=0; | |
237 poll(&ufds, 1, 1000); | |
238 if (!ufds.revents & POLLIN) { | |
239 printf("Received signal but got negative on poll?!?!?!?\n"); | |
240 return; | |
241 } | |
242 size=read(v4ldev, ioctlbuf, MAXIOCTL); | |
243 if (size >= sizeof(unsigned long int)) { | |
244 memcpy(&cmd, ioctlbuf, sizeof(unsigned long int)); | |
245 if (cmd==0) { | |
246 printf("Client closed device\n"); | |
247 return; | |
248 } | |
249 ret=v4l_ioctl(cmd, ioctlbuf+sizeof(unsigned long int)); | |
250 if (ret) { | |
251 memset(ioctlbuf+sizeof(unsigned long int), MAXIOCTL-sizeof(unsigned long int), 0xff); | |
252 printf("ioctl %lx unsuccesfull, lets issue VIDIOCSINVALID (%x)\n", cmd, VIDIOCSINVALID); | |
253 ioctl(v4ldev, VIDIOCSINVALID); | |
254 } else | |
255 ioctl(v4ldev, cmd, ioctlbuf+sizeof(unsigned long int)); | |
256 } | |
257 return; | |
258 } | |
259 | |
260 int open_vidpipe(void) | |
261 { | |
262 int pipe_fd = -1; | |
263 FILE *vloopbacks; | |
264 char pipepath[255]; | |
265 char buffer[255]; | |
266 char *loop; | |
267 char *input; | |
268 char *istatus; | |
269 char *output; | |
270 char *ostatus; | |
271 char *major; | |
272 char *minor; | |
273 struct utsname uts; | |
274 | |
275 if (uname(&uts) < 0) { | |
276 printf("Unable to execute uname\nError[%s]\n",strerror(errno)); | |
277 return -1; | |
278 } | |
279 | |
280 major = strtok(uts.release, "."); | |
281 minor = strtok(NULL, "."); | |
282 if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) { | |
283 printf("Unable to decipher OS version\n"); | |
284 return -1; | |
285 } | |
286 | |
287 if (strcmp(minor, "5") < 0) { | |
288 | |
289 vloopbacks=fopen("/proc/video/vloopback/vloopbacks", "r"); | |
290 if (!vloopbacks) { | |
291 printf ("Failed to open '/proc/video/vloopback/vloopbacks"); | |
292 return -1; | |
293 } | |
294 /* Read vloopback version */ | |
295 fgets(buffer, 255, vloopbacks); | |
296 printf("%s", buffer); | |
297 /* Read explaination line */ | |
298 fgets(buffer, 255, vloopbacks); | |
299 while (fgets(buffer, 255, vloopbacks)) { | |
300 if (strlen(buffer)>1) { | |
301 buffer[strlen(buffer)-1]=0; | |
302 loop=strtok(buffer, "\t"); | |
303 input=strtok(NULL, "\t"); | |
304 istatus=strtok(NULL, "\t"); | |
305 output=strtok(NULL, "\t"); | |
306 ostatus=strtok(NULL, "\t"); | |
307 if (istatus[0]=='-') { | |
308 sprintf(pipepath, "/dev/%s", input); | |
309 pipe_fd=open(pipepath, O_RDWR); | |
310 if (pipe_fd>=0) { | |
311 printf("Input: /dev/%s\n", input); | |
312 printf("Output: /dev/%s\n", output); | |
313 return pipe_fd; | |
314 } | |
315 } | |
316 } | |
317 } | |
318 | |
319 }else{ | |
320 DIR *dir; | |
321 struct dirent *dirp; | |
322 const char prefix[]="/sys/class/video4linux/"; | |
323 char *ptr, *io; | |
324 int fd; | |
325 int low=9999; | |
326 int tfd; | |
327 int tnum; | |
328 | |
329 if ((dir=opendir(prefix))== NULL) { | |
330 printf( "Failed to open '%s'", prefix); | |
331 return -1; | |
332 } | |
333 | |
334 while ((dirp=readdir(dir)) != NULL) { | |
335 if (!strncmp(dirp->d_name, "video", 5)) { | |
336 strcpy(buffer, prefix); | |
337 strcat(buffer, dirp->d_name); | |
338 strcat(buffer, "/name"); | |
339 if ((fd=open(buffer, O_RDONLY)) >= 0) { | |
340 if ((read(fd, buffer, sizeof(buffer)-1))<0) { | |
341 close(fd); | |
342 continue; | |
343 } | |
344 ptr = strtok(buffer, " "); | |
345 if (strcmp(ptr,"Video")) { | |
346 close(fd); | |
347 continue; | |
348 } | |
349 major = strtok(NULL, " "); | |
350 minor = strtok(NULL, " "); | |
351 io = strtok(NULL, " \n"); | |
352 if (strcmp(major, "loopback") || strcmp(io, "input")) { | |
353 close(fd); | |
354 continue; | |
355 } | |
356 if ((ptr=strtok(buffer, " "))==NULL) { | |
357 close(fd); | |
358 continue; | |
359 } | |
360 tnum = atoi(minor); | |
361 if (tnum < low) { | |
362 strcpy(buffer, "/dev/"); | |
363 strcat(buffer, dirp->d_name); | |
364 if ((tfd=open(buffer, O_RDWR))>=0) { | |
365 strcpy(pipepath, buffer); | |
366 if (pipe_fd>=0) { | |
367 close(pipe_fd); | |
368 } | |
369 pipe_fd = tfd; | |
370 low = tnum; | |
371 } | |
372 } | |
373 close(fd); | |
374 } | |
375 } | |
376 } | |
377 | |
378 | |
379 closedir(dir); | |
380 if (pipe_fd >= 0) | |
381 printf("Opened input of %s", pipepath); | |
382 } | |
383 | |
384 return pipe_fd; | |
385 } | |
386 | |
387 int main (int argc, char **argv) | |
388 { | |
389 char palette[10]={'\0'}; | |
390 | |
391 if (argc != 3) { | |
392 printf("dummy.c\n"); | |
393 printf("A example for using a video4linux loopback in zero-copy mode\n"); | |
394 printf("Written by Jeroen Vreeken, 2000\n"); | |
395 printf("Updated to vloopback API v0.97\n\n"); | |
396 printf("Usage:\n\n"); | |
397 printf("dummy widthxheight rgb24|yuv420p\n\n"); | |
398 printf("example: dummy 352x288 yuv420p\n\n"); | |
399 exit(1); | |
400 } | |
401 | |
402 sscanf(argv[1], "%dx%d", &width, &height); | |
403 sscanf(argv[2], "%s", palette); | |
404 | |
405 if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24; | |
406 else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P; | |
407 else fmt = VIDEO_PALETTE_RGB24; | |
408 | |
409 /* Default startup values, nothing special | |
410 width=352; | |
411 height=288; | |
412 */ | |
413 | |
414 v4ldev=open_vidpipe(); | |
415 if (v4ldev < 0) { | |
416 printf ("Failed to open video loopback device\nError[%s]\n",strerror(errno)); | |
417 exit(1); | |
418 } | |
419 image_out=v4l_create(v4ldev, MAXWIDTH*MAXHEIGHT*3); | |
420 if (!image_out) { | |
421 exit(1); | |
422 printf ("Failed to set device to zero-copy mode\nError[%s]\n",strerror(errno)); | |
423 } | |
424 | |
425 signal (SIGIO, sighandler); | |
426 | |
427 printf("\nListening.\n"); | |
428 while (1) { | |
429 sleep(1000); | |
430 } | |
431 | |
432 close (v4ldev); | |
433 free(image_out); | |
434 exit(0); | |
435 } |