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 } |
