# HG changeset patch # User AngelCarpintero # Date 1219544451 0 # Node ID 2fce9e157b8da16d0d5e5d968d9cd06290ef68f6 # Parent d3fdefea8bce1e2e61c3b43073fb2e3bd401f56c Added some work around to work with kernel 2.6.27-rc3, added debug param. diff -r d3fdefea8bce -r 2fce9e157b8d FAQ --- a/FAQ Sat Jul 12 17:12:25 2008 +0000 +++ b/FAQ Sun Aug 24 02:20:51 2008 +0000 @@ -37,4 +37,11 @@ You need to use Coriander (http://damien.douxchamps.net/ieee1394/coriander/ ) and set on services tab V4L (http://damien.douxchamps.net/ieee1394/coriander/win_v4l.png). -And then you will have a V4L in /dev/video1. +And then you will have a V4L in /dev/video1. + +* Having problems running vloopback ? + +load vloopback with debug : + + modprobe vloopback debug=3 + diff -r d3fdefea8bce -r 2fce9e157b8d example/dummy.c --- a/example/dummy.c Sat Jul 12 17:12:25 2008 +0000 +++ b/example/dummy.c Sun Aug 24 02:20:51 2008 +0000 @@ -29,31 +29,31 @@ #define MAXHEIGHT 480 int width; int height; -int fmt=0; +int fmt = 0; char ioctlbuf[MAXIOCTL]; int v4ldev; char *image_out; - +int noexit = 1; int get_frame(void) { int i; char colour = 0; - memset(image_out, 0x128, width*height*3); + memset(image_out, 0x128, width * height * 3); - for (i=10; iname, "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; + 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; - 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; + 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 (vidpic->palette!=fmt) - return 1; - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vidwin=arg; + if (v[0] != 0) + return 1; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner *v = arg; - vidwin->x=0; - vidwin->y=0; - vidwin->width=width; - vidwin->height=height; - vidwin->chromakey=0; - vidwin->flags=0; - vidwin->clipcount=0; - return 0; + if (v->tuner) { + printf("VIDIOCGTUNER: Invalid Tuner, was %d\n", v->tuner); + //return -EINVAL; } - 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; + 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; - vidmbuf->size=width*height*3; - vidmbuf->frames=1; - for (i=0; iframes; i++) - vidmbuf->offsets[i]=i*vidmbuf->size; - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vidmmap=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; - //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; + 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); } - case VIDIOCSYNC: - { - //struct video_mmap *vidmmap=arg; + // 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; - } + // 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_exit(int signo) +{ + noexit = 0; +} + void sighandler(int signo) { int size, ret; unsigned long int cmd; struct pollfd ufds; - if (signo!=SIGIO) + if (signo != SIGIO) return; - ufds.fd=v4ldev; - ufds.events=POLLIN; - ufds.revents=0; + + 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); + + size = read(v4ldev, ioctlbuf, MAXIOCTL); + if (size >= sizeof(unsigned long int)) { memcpy(&cmd, ioctlbuf, sizeof(unsigned long int)); - if (cmd==0) { + if (cmd == 0) { printf("Client closed device\n"); return; } - ret=v4l_ioctl(cmd, ioctlbuf+sizeof(unsigned long int)); + ret = v4l_ioctl(cmd, ioctlbuf+sizeof(unsigned long int)); if (ret) { - memset(ioctlbuf+sizeof(unsigned long int), MAXIOCTL-sizeof(unsigned long int), 0xff); + 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)); + } else { + ioctl(v4ldev, cmd, ioctlbuf + sizeof(unsigned long int)); + } } return; } + int open_vidpipe(void) { int pipe_fd = -1; @@ -273,7 +285,7 @@ struct utsname uts; if (uname(&uts) < 0) { - printf("Unable to execute uname\nError[%s]\n",strerror(errno)); + printf("Unable to execute uname\nError[%s]\n", strerror(errno)); return -1; } @@ -285,29 +297,34 @@ } if (strcmp(minor, "5") < 0) { - - vloopbacks=fopen("/proc/video/vloopback/vloopbacks", "r"); + 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]=='-') { + + 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) { + 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; @@ -315,84 +332,90 @@ } } } - - }else{ + } else { DIR *dir; struct dirent *dirp; - const char prefix[]="/sys/class/video4linux/"; + const char prefix[] = "/sys/class/video4linux/"; char *ptr, *io; int fd; - int low=9999; + int low = 9999; int tfd; int tnum; - if ((dir=opendir(prefix))== NULL) { + 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); - } + 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); - } + if (pipe_fd >= 0) + printf("Opened input of %s", pipepath); + } return pipe_fd; } int main (int argc, char **argv) { - char palette[10]={'\0'}; + 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("Updated to vloopback API v1.1\n\n"); printf("Usage:\n\n"); printf("dummy widthxheight rgb24|yuv420p\n\n"); printf("example: dummy 352x288 yuv420p\n\n"); @@ -402,8 +425,10 @@ 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; + 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 @@ -411,25 +436,33 @@ height=288; */ - v4ldev=open_vidpipe(); + v4ldev = open_vidpipe(); + if (v4ldev < 0) { - printf ("Failed to open video loopback device\nError[%s]\n",strerror(errno)); + printf ("Failed to open video loopback device\nError[%s]\n", strerror(errno)); exit(1); } - image_out=v4l_create(v4ldev, MAXWIDTH*MAXHEIGHT*3); + + 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)); + printf ("Failed to set device to zero-copy mode\nError[%s]\n", strerror(errno)); } - signal (SIGIO, sighandler); + signal(SIGIO, sighandler); + signal(SIGTERM, sighandler_exit); + signal(SIGINT, sighandler_exit); printf("\nListening.\n"); - while (1) { + + while (noexit) sleep(1000); - } + + close(v4ldev); + munmap(image_out, MAXWIDTH * MAXHEIGHT * 3); - close (v4ldev); - free(image_out); + printf("\nBye Bye ...\n"); + exit(0); } diff -r d3fdefea8bce -r 2fce9e157b8d example/feed.c --- a/example/feed.c Sat Jul 12 17:12:25 2008 +0000 +++ b/example/feed.c Sun Aug 24 02:20:51 2008 +0000 @@ -20,52 +20,61 @@ #include -int fmt=0; +int fmt = 0; int noexit = 1; -int read_img=0; +int read_img = 0; char *start_capture (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_mbuf vid_buf; char *map; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); + if (ioctl(dev, VIDIOCGCAP, &vid_caps) == -1) { + printf ("ioctl (VIDIOCGCAP)\nError[%s]\n", strerror(errno)); return (NULL); } - if (vid_caps.type & VID_TYPE_MONOCHROME) fmt=VIDEO_PALETTE_GREY; + + if (vid_caps.type & VID_TYPE_MONOCHROME) + fmt=VIDEO_PALETTE_GREY; + if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { fprintf(stderr, "no mmap falling back on read\n"); + if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno)); return (NULL); } - vid_win.width=width; - vid_win.height=height; + + vid_win.width = width; + vid_win.height = height; + if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno)); return (NULL); } - read_img=1; - map=malloc(width*height*3); + + read_img = 1; + map = malloc(width * height * 3); return (map); } + /* If we are going to capture greyscale we need room to blow the image up */ - if (fmt==VIDEO_PALETTE_GREY) - map=mmap(0, vid_buf.size*3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + if (fmt == VIDEO_PALETTE_GREY) + map = mmap(0, vid_buf.size * 3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); else - map=mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + map = mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); if ((unsigned char *)-1 == (unsigned char *)map) return (NULL); + return map; } int start_pipe (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_picture vid_pic; @@ -73,22 +82,28 @@ printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); return (1); } - if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) { + + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) { printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno)); return (1); } - vid_pic.palette=fmt; - if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) { + + vid_pic.palette = fmt; + + if (ioctl (dev, VIDIOCSPICT, &vid_pic) == -1) { printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno)); return (1); } - if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { + + if (ioctl (dev, VIDIOCGWIN, &vid_win) == -1) { printf ("ioctl VIDIOCGWIN"); return (1); } - vid_win.width=width; - vid_win.height=height; - if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { + + vid_win.width = width; + vid_win.height = height; + + if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) { printf ("ioctl VIDIOCSWIN"); return (1); } @@ -101,47 +116,52 @@ char *grey, *rgb; struct video_mmap vid_mmap; - sigset_t set, old; + sigset_t set, old; if (read_img) { - if (fmt==VIDEO_PALETTE_GREY) { - if (read(dev, map, width*height) != width*height) + + if (fmt == VIDEO_PALETTE_GREY) { + size_t size = width * height; + if (read(dev, map, size) != size) return NULL; } else { - if (read(dev, map, width*height*3) != width*height*3) + size_t size = width * height * 3; + if (read(dev, map, size) != size) return NULL; } } else { - vid_mmap.format=fmt; - vid_mmap.frame=0; - vid_mmap.width=width; - vid_mmap.height=height; + vid_mmap.format = fmt; + vid_mmap.frame = 0; + vid_mmap.width = width; + vid_mmap.height = height; - sigemptyset (&set); //BTTV hates signals during IOCTL - sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM - sigaddset (&set, SIGALRM); //for the time of ioctls - sigprocmask (SIG_BLOCK, &set, &old); + sigemptyset (&set); //BTTV hates signals during IOCTL + sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM + sigaddset (&set, SIGALRM); //for the time of ioctls + sigprocmask (SIG_BLOCK, &set, &old); if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } + if (ioctl(dev, VIDIOCSYNC, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } - sigprocmask (SIG_UNBLOCK, &old, NULL); //undo the signal blocking + sigprocmask(SIG_UNBLOCK, &old, NULL); //undo the signal blocking } /* Blow up a grey */ - if (fmt==VIDEO_PALETTE_GREY) { - i=width*height; - grey=map+i-1; - rgb=map+i*3; - for (; i>=0; i--, grey--) { - *(rgb--)=*grey; - *(rgb--)=*grey; - *(rgb--)=*grey; + if (fmt == VIDEO_PALETTE_GREY) { + i= width * height; + grey=map + i - 1; + rgb=map + i * 3; + + for (; i >= 0; i--, grey--) { + *(rgb--) =*grey; + *(rgb--) =*grey; + *(rgb--) =*grey; } } return map; @@ -149,10 +169,13 @@ int put_image(int dev, char *image, int width, int height) { - if (write(dev, image, width*height*3)!=width*height*3) { - printf("Error writing image to pipe!\nError[%s]\n",strerror(errno)); + size_t size = width * height * 3; + + if (write(dev, image, size) != size) { + printf("Error writing image to pipe!\nError[%s]\n", strerror(errno)); return 0; } + return 1; } @@ -168,7 +191,7 @@ int width; int height; char *image_new; - char palette[10]={'\0'}; + char palette[10] = {'\0'}; if (argc != 5) { printf("Usage:\n\n"); @@ -176,28 +199,34 @@ printf("example: feed /dev/video0 /dev/video1 352x288 yuv420p\n\n"); exit(1); } + sscanf(argv[3], "%dx%d", &width, &height); sscanf(argv[4], "%s", palette); - if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24; - else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P; + if (!strcmp(palette,"rgb24")) + fmt = VIDEO_PALETTE_RGB24; + else if (!strcmp(palette,"yuv420p")) + fmt = VIDEO_PALETTE_YUV420P; else fmt = VIDEO_PALETTE_RGB24; - devin=open (argv[1], O_RDWR); + devin = open (argv[1], O_RDWR); + if (devin < 0) { - printf ("Failed to open video device %s\nError[%s]\n",argv[1],strerror(errno)); + printf ("Failed to open video device %s\nError[%s]\n", argv[1], strerror(errno)); exit(1); } - devout=open (argv[2], O_RDWR); + devout = open (argv[2], O_RDWR); + if (devout < 0) { - printf ("Failed to open video device%s \nError[%s]\n",argv[2],strerror(errno)); + printf ("Failed to open video device%s \nError[%s]\n", argv[2], strerror(errno)); exit(1); } - image_new=start_capture (devin, width, height); + image_new = start_capture(devin, width, height); + if (!image_new) { - printf("Capture error\nError[%s]\n",strerror(errno)); + printf("Capture error\nError[%s]\n", strerror(errno)); exit(1); } @@ -206,12 +235,25 @@ signal(SIGTERM, sig_handler); printf("Starting video stream.\n"); - while ( (next_capture(devin, image_new, width, height)) && (noexit)) { - if (put_image(devout, image_new, width, height)==0) + + while ((next_capture(devin, image_new, width, height)) && (noexit)) { + if (put_image(devout, image_new, width, height) == 0) exit(1); + } - printf("You bought vaporware!\nError[%s]\n",strerror(errno)); - close (devin); - close (devout); + + printf("You bought vaporware!\nError[%s]\n", strerror(errno)); + + close(devin); + close(devout); + + if ((read_img) && (image_new)) + free(image_new); + else if (fmt == VIDEO_PALETTE_GREY) + munmap(image_new, width * height * 3); + else + munmap(image_new, width * height); + + exit(0); } diff -r d3fdefea8bce -r 2fce9e157b8d example/invert.c --- a/example/invert.c Sat Jul 12 17:12:25 2008 +0000 +++ b/example/invert.c Sun Aug 24 02:20:51 2008 +0000 @@ -21,76 +21,89 @@ #include -int fmt=0; +int fmt = 0; int noexit = 1; -int read_img=0; +int read_img = 0; char *start_capture (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_mbuf vid_buf; char *map; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); + if (ioctl(dev, VIDIOCGCAP, &vid_caps) == -1) { + printf ("ioctl (VIDIOCGCAP)\nError[%s]\n", strerror(errno)); return (NULL); } - if (vid_caps.type & VID_TYPE_MONOCHROME) fmt=VIDEO_PALETTE_GREY; - if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { + if (vid_caps.type & VID_TYPE_MONOCHROME) + fmt = VIDEO_PALETTE_GREY; + + if (ioctl(dev, VIDIOCGMBUF, &vid_buf) == -1) { fprintf(stderr, "no mmap falling back on read\n"); - if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno)); + + if (ioctl(dev, VIDIOCGWIN, &vid_win) == -1) { + printf ("ioctl VIDIOCGWIN\nError[%s]\n", strerror(errno)); return (NULL); } - vid_win.width=width; - vid_win.height=height; - if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno)); + + vid_win.width = width; + vid_win.height = height; + + if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) { + printf ("ioctl VIDIOCSWIN\nError[%s]\n", strerror(errno)); return (NULL); } - read_img=1; - map=malloc(width*height*3); + + read_img = 1; + map = malloc(width * height * 3); return (map); } /* If we are going to capture greyscale we need room to blow the image up */ - if (fmt==VIDEO_PALETTE_GREY) - map=mmap(0, vid_buf.size*3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + if (fmt == VIDEO_PALETTE_GREY) + map = mmap(0, vid_buf.size * 3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); else - map=mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + map = mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); if ((unsigned char *)-1 == (unsigned char *)map) return (NULL); + return map; } int start_pipe (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_picture vid_pic; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); + if (ioctl(dev, VIDIOCGCAP, &vid_caps) == -1) { + printf ("ioctl (VIDIOCGCAP)\nError[%s]\n", strerror(errno)); return (1); } - if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) { - printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno)); + + if (ioctl(dev, VIDIOCGPICT, &vid_pic)== -1) { + printf ("ioctl VIDIOCGPICT\nError[%s]\n", strerror(errno)); return (1); } - vid_pic.palette=fmt; - if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) { - printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno)); + + vid_pic.palette = fmt; + + if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) { + printf ("ioctl VIDIOCSPICT\nError[%s]\n", strerror(errno)); return (1); } - if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno)); + + if (ioctl (dev, VIDIOCGWIN, &vid_win) == -1) { + printf ("ioctl VIDIOCGWIN\nError[%s]\n", strerror(errno)); return (1); } - vid_win.width=width; - vid_win.height=height; - if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno)); + + vid_win.width = width; + vid_win.height = height; + + if (ioctl(dev, VIDIOCSWIN, &vid_win)== -1) { + printf ("ioctl VIDIOCSWIN\nError[%s]\n", strerror(errno)); return (1); } return 0; @@ -102,47 +115,50 @@ char *grey, *rgb; struct video_mmap vid_mmap; - sigset_t set, old; + sigset_t set, old; if (read_img) { - if (fmt==VIDEO_PALETTE_GREY) { - if (read(dev, map, width*height) != width*height) + if (fmt == VIDEO_PALETTE_GREY) { + size_t size = width * height; + if (read(dev, map, size) != size) return NULL; } else { - if (read(dev, map, width*height*3) != width*height*3) + size_t size = width * height * 3; + if (read(dev, map, size) != size) return NULL; } } else { - vid_mmap.format=fmt; - vid_mmap.frame=0; - vid_mmap.width=width; - vid_mmap.height=height; + vid_mmap.format = fmt; + vid_mmap.frame = 0; + vid_mmap.width = width; + vid_mmap.height = height; - sigemptyset (&set); //BTTV hates signals during IOCTL - sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM - sigaddset (&set, SIGALRM); //for the time of ioctls - sigprocmask (SIG_BLOCK, &set, &old); + sigemptyset (&set); //BTTV hates signals during IOCTL + sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM + sigaddset (&set, SIGALRM); //for the time of ioctls + sigprocmask (SIG_BLOCK, &set, &old); if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } + if (ioctl(dev, VIDIOCSYNC, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } - sigprocmask (SIG_UNBLOCK, &old, NULL); //undo the signal blocking + sigprocmask (SIG_UNBLOCK, &old, NULL); //undo the signal blocking } /* Blow up a grey */ - if (fmt==VIDEO_PALETTE_GREY) { - i=width*height; - grey=map+i-1; - rgb=map+i*3; - for (; i>=0; i--, grey--) { - *(rgb--)=*grey; - *(rgb--)=*grey; - *(rgb--)=*grey; + if (fmt == VIDEO_PALETTE_GREY) { + i = width * height; + grey =map + i - 1; + rgb = map + i * 3; + for (; i >= 0; i--, grey--) { + *(rgb--) =*grey; + *(rgb--) =*grey; + *(rgb--) =*grey; } } return map; @@ -150,10 +166,11 @@ int put_image(int dev, char *image, int width, int height) { - if (write(dev, image, width*height*3)!=width*height*3) { - printf("Error writing image to pipe!\nError[%s]\n",strerror(errno)); + if (write(dev, image, width * height * 3) != width * height * 3) { + printf("Error writing image to pipe!\nError[%s]\n", strerror(errno)); return 0; } + return 1; } @@ -169,7 +186,7 @@ int width; int height; char *image_out, *image_new; - char palette[10]={'\0'}; + char palette[10] = {'\0'}; if (argc != 5) { printf("Usage:\n\n"); @@ -180,28 +197,33 @@ sscanf(argv[3], "%dx%d", &width, &height); sscanf(argv[4], "%s", palette); - if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24; - else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P; + if (!strcmp(palette,"rgb24")) + fmt = VIDEO_PALETTE_RGB24; + else if (!strcmp(palette,"yuv420p")) + fmt = VIDEO_PALETTE_YUV420P; else fmt = VIDEO_PALETTE_RGB24; - image_out=malloc(width*height*3); + image_out = malloc(width * height * 3); - devin=open (argv[1], O_RDWR); + devin = open (argv[1], O_RDWR); + if (devin < 0) { - printf("Failed to open input video device [%s]\nError:[%s]\n",argv[1],strerror(errno)); + printf("Failed to open input video device [%s]\nError:[%s]\n", argv[1], strerror(errno)); exit(1); } - devout=open (argv[2], O_RDWR); + devout = open (argv[2], O_RDWR); + if (devout < 0) { - printf ("Failed to open output video device [%s]\nError:[%s]\n",argv[2],strerror(errno)); + printf ("Failed to open output video device [%s]\nError:[%s]\n", argv[2], strerror(errno)); exit(1); } - image_new=start_capture (devin, width, height); + image_new = start_capture(devin, width, height); + if (!image_new) { - printf("Capture error \n Error[%s]\n",strerror(errno)); + printf("Capture error \n Error[%s]\n", strerror(errno)); exit(1); } @@ -210,14 +232,36 @@ signal(SIGTERM, sig_handler); printf("Starting video stream.\n"); - while ( (next_capture(devin, image_new, width, height)) && (noexit) ){ - for (i=width*height*3; i>=0; i--) image_out[i]=-image_new[i]; - if (put_image(devout, image_out, width, height)==0) + + while ( (next_capture(devin, image_new, width, height)) && (noexit) ) { + for (i = width * height * 3; i >= 0; i--) + image_out[i] =-image_new[i]; + + if (put_image(devout, image_out, width, height) == 0) { + if ((read_img) && (image_new)) + free(image_new); + else if (fmt == VIDEO_PALETTE_GREY) + munmap(image_new, width * height * 3); + else + munmap(image_new, width * height); + free(image_out); exit(1); + } } - printf("You bought vaporware!\nError[%s]\n",strerror(errno)); + + printf("You bought vaporware!\nError[%s]\n", strerror(errno)); + close (devin); close (devout); + + if ((read_img) && (image_new)) + free(image_new); + else if (fmt == VIDEO_PALETTE_GREY) + munmap(image_new, width * height * 3); + else + munmap(image_new, width * height); + free(image_out); + exit(0); } diff -r d3fdefea8bce -r 2fce9e157b8d example/resize.c --- a/example/resize.c Sat Jul 12 17:12:25 2008 +0000 +++ b/example/resize.c Sun Aug 24 02:20:51 2008 +0000 @@ -21,41 +21,49 @@ #include -int fmt=0; +int fmt = 0; int noexit = 1; -int read_img=0; +int read_img = 0; char *start_capture (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_mbuf vid_buf; char *map; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); + if (ioctl(dev, VIDIOCGCAP, &vid_caps) == -1) { + printf ("ioctl (VIDIOCGCAP)\nError[%s]\n", strerror(errno)); return (NULL); } - if (vid_caps.type & VID_TYPE_MONOCHROME) fmt=VIDEO_PALETTE_GREY; - if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { + + if (vid_caps.type & VID_TYPE_MONOCHROME) + fmt = VIDEO_PALETTE_GREY; + + if (ioctl(dev, VIDIOCGMBUF, &vid_buf) == -1) { fprintf(stderr, "no mmap falling back on read\n"); - if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno)); + + if (ioctl(dev, VIDIOCGWIN, &vid_win)== -1) { + printf ("ioctl VIDIOCGWIN\nError[%s]\n", strerror(errno)); return (NULL); } - vid_win.width=width; - vid_win.height=height; - if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { - printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno)); + + vid_win.width = width; + vid_win.height = height; + + if (ioctl(dev, VIDIOCSWIN, &vid_win)== -1) { + printf ("ioctl VIDIOCSWIN\nError[%s]\n", strerror(errno)); return (NULL); } - read_img=1; - map=malloc(width*height*3); + + read_img = 1; + map = malloc(width * height * 3); + return (map); } /* If we are going to capture greyscale we need room to blow the image up */ - if (fmt==VIDEO_PALETTE_GREY) - map=mmap(0, vid_buf.size*3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + if (fmt == VIDEO_PALETTE_GREY) + map=mmap(0, vid_buf.size * 3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); else map=mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); @@ -66,33 +74,40 @@ int start_pipe (int dev, int width, int height) { - struct video_capability vid_caps; + struct video_capability vid_caps; struct video_window vid_win; struct video_picture vid_pic; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno)); + if (ioctl(dev, VIDIOCGCAP, &vid_caps) == -1) { + printf ("ioctl (VIDIOCGCAP)\nError[%s]\n", strerror(errno)); + return (1); + } + + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) { + printf ("ioctl VIDIOCGPICT\nError[%s]\n", strerror(errno)); return (1); } - if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) { - printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno)); + + vid_pic.palette = fmt; + + if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) { + printf ("ioctl VIDIOCSPICT\nError[%s]\n", strerror(errno)); return (1); } - vid_pic.palette=fmt; - if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) { - printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno)); - return (1); - } - if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) { + + if (ioctl(dev, VIDIOCGWIN, &vid_win) == -1) { printf ("ioctl VIDIOCGWIN"); return (1); } - vid_win.width=width; - vid_win.height=height; - if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) { + + vid_win.width = width; + vid_win.height = height; + + if (ioctl(dev, VIDIOCSWIN, &vid_win)== -1) { printf ("ioctl VIDIOCSWIN"); return (1); } + return 0; } @@ -102,47 +117,49 @@ char *grey, *rgb; struct video_mmap vid_mmap; - sigset_t set, old; + sigset_t set, old; if (read_img) { - if (fmt==VIDEO_PALETTE_GREY) { - if (read(dev, map, width*height) != width*height) + if (fmt == VIDEO_PALETTE_GREY) { + size_t size = width * height; + if (read(dev, map, size) != size) return NULL; } else { - if (read(dev, map, width*height*3) != width*height*3) + size_t size = width * height * 3; + if (read(dev, map, size) != size) return NULL; } } else { - vid_mmap.format=fmt; - vid_mmap.frame=0; - vid_mmap.width=width; - vid_mmap.height=height; + vid_mmap.format = fmt; + vid_mmap.frame = 0; + vid_mmap.width = width; + vid_mmap.height = height; - sigemptyset (&set); //BTTV hates signals during IOCTL - sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM - sigaddset (&set, SIGALRM); //for the time of ioctls - sigprocmask (SIG_BLOCK, &set, &old); + sigemptyset (&set); //BTTV hates signals during IOCTL + sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM + sigaddset (&set, SIGALRM); //for the time of ioctls + sigprocmask (SIG_BLOCK, &set, &old); if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } if (ioctl(dev, VIDIOCSYNC, &vid_mmap) == -1) { - sigprocmask (SIG_UNBLOCK, &old, NULL); + sigprocmask (SIG_UNBLOCK, &old, NULL); return (NULL); } - sigprocmask (SIG_UNBLOCK, &old, NULL); //undo the signal blocking + sigprocmask(SIG_UNBLOCK, &old, NULL); //undo the signal blocking } /* Blow up a grey */ - if (fmt==VIDEO_PALETTE_GREY) { - i=width*height; - grey=map+i-1; - rgb=map+i*3; - for (; i>=0; i--, grey--) { - *(rgb--)=*grey; - *(rgb--)=*grey; - *(rgb--)=*grey; + if (fmt == VIDEO_PALETTE_GREY) { + i = width * height; + grey = map + i - 1; + rgb = map + i * 3; + for (; i >= 0; i--, grey--) { + *(rgb--) =*grey; + *(rgb--) =*grey; + *(rgb--) =*grey; } } return map; @@ -150,8 +167,8 @@ int put_image(int dev, char *image, int width, int height) { - if (write(dev, image, width*height*3)!=width*height*3) { - printf("Error writing image to pipe!\nError[%s]\n",strerror(errno)); + if (write(dev, image, width * height * 3) != width * height * 3) { + printf("Error writing image to pipe!\nError[%s]\n", strerror(errno)); return 0; } return 1; @@ -171,7 +188,7 @@ int heightout; int **newy, **newx, **line; char *image_out, *image_new; - char palette[10]={'\0'}; + char palette[10] = {'\0'}; if (argc != 6) { printf("Usage:\n\n"); @@ -179,81 +196,88 @@ printf("example: resize /dev/video0 /dev/video1 352x288 176x144 yuv420p\n\n"); exit(1); } + sscanf(argv[3], "%dx%d", &width, &height); sscanf(argv[4], "%dx%d", &widthout, &heightout); sscanf(argv[5], "%s", palette); - if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24; - else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P; + if (!strcmp(palette,"rgb24")) + fmt = VIDEO_PALETTE_RGB24; + else if (!strcmp(palette,"yuv420p")) + fmt = VIDEO_PALETTE_YUV420P; else fmt = VIDEO_PALETTE_RGB24; - realwidth=width*3; - realwidthout=widthout*3; + realwidth = width * 3; + realwidthout = widthout * 3; + + image_out = malloc(widthout * heightout * 3); + line = malloc(sizeof(int*) * heightout); + newy = malloc(sizeof(int*) * heightout); + newx = malloc(sizeof(int*) * realwidthout); - image_out=malloc(widthout*heightout*3); - line=malloc(sizeof(int*)*heightout); - newy=malloc(sizeof(int*)*heightout); - newx=malloc(sizeof(int*)*realwidthout); - for (y=0; y #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) -#include + #include #endif #include @@ -183,12 +187,24 @@ #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) -#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" "", ## arg) +#define verbose(format, arg...) if (printk_ratelimit()) \ + printk(KERN_INFO "[%s] %s: " format "\n" "", \ + __FUNCTION__, __FILE__, ## arg) + +#define info(format, arg...) if (printk_ratelimit()) \ + printk(KERN_INFO "[%s] : " format "\n" "", \ + __FUNCTION__, ## arg) + +#define LOG_NODEBUG 0 +#define LOG_FUNCTIONS 1 +#define LOG_IOCTL 2 +#define LOG_VERBOSE 3 struct vloopback_private { int pipenr; - int in; /* bool */ + int in; /* bool , is being feed ? */ }; + typedef struct vloopback_private *priv_ptr; struct vloopback_pipe { @@ -206,7 +222,11 @@ struct semaphore lock; wait_queue_head_t wait; unsigned int frame; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) unsigned int pid; +#else + struct pid *pid; +#endif unsigned int zerocopy; unsigned long int ioctlnr; unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ @@ -219,11 +239,12 @@ #define N_BUFFS 2 /* Number of buffers used for pipes */ static struct vloopback_pipe *loops[MAX_PIPES]; -static int nr_o_pipes=0; -static int pipes=-1; -static int spares=0; -static int pipesused=0; -static int dev_offset=-1; +static int nr_o_pipes = 0; +static int pipes = -1; +static int spares = 0; +static int pipesused = 0; +static int dev_offset = -1; +static unsigned int debug = LOG_NODEBUG; /********************************************************************** * @@ -237,7 +258,7 @@ */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long kva; + unsigned long kva; kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); kva |= adr & (PAGE_SIZE-1); /* restore the offset */ @@ -303,14 +324,23 @@ static int fake_ioctl(int nr, unsigned long int cmd, void *arg) { unsigned long fw; - - loops[nr]->ioctlnr=cmd; + + if (debug > LOG_NODEBUG) + info("Video loopback %d cmd %lu", nr, cmd); + + loops[nr]->ioctlnr = cmd; memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); - loops[nr]->ioctllength=_IOC_SIZE(cmd); - kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ + loops[nr]->ioctllength = _IOC_SIZE(cmd); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ +#else + kill_pid(loops[nr]->pid, SIGIO, 1); +#endif + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) fw = loops[nr]->frameswrite; - wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else interruptible_sleep_on(&loops[nr]->wait); #endif @@ -325,28 +355,31 @@ static int vloopback_open(struct inode *inod, struct file *f) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; - + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + + if (debug > LOG_NODEBUG) + info("Video loopback %d", nr); /* Only allow a output to be opened if there is someone feeding * the pipe. */ if (!ptr->in) { - if (loops[nr]->buffer==NULL) { + if (loops[nr]->buffer == NULL) return -EINVAL; - } - loops[nr]->framesread=0; - loops[nr]->ropen=1; + + loops[nr]->framesread = 0; + loops[nr]->ropen = 1; } else { if (loops[nr]->ropen || loops[nr]->wopen) return -EBUSY; - loops[nr]->framesdumped=0; - loops[nr]->frameswrite=0; - loops[nr]->wopen=1; - loops[nr]->zerocopy=0; - loops[nr]->ioctlnr=-1; + + loops[nr]->framesdumped = 0; + loops[nr]->frameswrite = 0; + loops[nr]->wopen = 1; + loops[nr]->zerocopy = 0; + loops[nr]->ioctlnr = -1; pipesused++; if (nr_o_pipes-pipesusedpid=current->pid; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + loops[nr]->pid = current->pid; +#else + // TODO : Check in stable 2.6.27 + loops[nr]->pid = task_pid(find_task_by_vpid(current->pid)); + //loops[nr]->pid = task_pid(current); +#endif + + if (debug > LOG_NODEBUG) + info("Current pid %d", current->pid); } return 0; } static int vloopback_release(struct inode * inod, struct file *f) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; - + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + + if (debug > LOG_NODEBUG) + info("Video loopback %d", nr); + if (ptr->in) { down(&loops[nr]->lock); if (loops[nr]->buffer && !loops[nr]->ropen) { - rvfree(loops[nr]->buffer, - loops[nr]->buflength*N_BUFFS); - loops[nr]->buffer=NULL; + rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); + loops[nr]->buffer = NULL; } up(&loops[nr]->lock); loops[nr]->frameswrite++; if (waitqueue_active(&loops[nr]->wait)) wake_up(&loops[nr]->wait); - loops[nr]->width=0; - loops[nr]->height=0; - loops[nr]->palette=0; - loops[nr]->wopen=0; + loops[nr]->width = 0; + loops[nr]->height = 0; + loops[nr]->palette = 0; + loops[nr]->wopen = 0; pipesused--; } else { down(&loops[nr]->lock); if (loops[nr]->buffer && !loops[nr]->wopen) { - rvfree(loops[nr]->buffer, - loops[nr]->buflength*N_BUFFS); - loops[nr]->buffer=NULL; + rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); + loops[nr]->buffer = NULL; } up(&loops[nr]->lock); - loops[nr]->ropen=0; + loops[nr]->ropen = 0; if (loops[nr]->zerocopy && loops[nr]->buffer) { - loops[nr]->ioctlnr=0; - loops[nr]->ioctllength=0; - kill_proc(loops[nr]->pid, SIGIO, 1); + loops[nr]->ioctlnr = 0; + loops[nr]->ioctllength = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + kill_proc(loops[nr]->pid, SIGIO, 1); +#else + kill_pid(loops[nr]->pid, SIGIO, 1); +#endif } } @@ -407,22 +454,25 @@ } static ssize_t vloopback_write(struct file *f, const char *buf, - size_t count, loff_t *offset) + size_t count, loff_t *offset) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; - unsigned long realcount=count; - + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + unsigned long realcount = count; + + if (debug > LOG_IOCTL) + info("Video loopback %d", nr); + if (!ptr->in) return -EINVAL; + if (loops[nr]->zerocopy) return -EINVAL; - if (loops[nr]->buffer==NULL) { + if (loops[nr]->buffer == NULL) return -EINVAL; - } - + /* Anybody want some pictures??? */ if (!waitqueue_active(&loops[nr]->wait)) { loops[nr]->framesdumped++; @@ -434,17 +484,18 @@ up(&loops[nr]->lock); return -EINVAL; } + if (realcount > loops[nr]->buflength) { realcount = loops[nr]->buflength; - info("Too much data! Only %ld bytes used.", realcount); + info("Too much data for Video loopback %d ! Only %ld bytes used.", + nr, realcount); } - if (copy_from_user( - loops[nr]->buffer+loops[nr]->frame*loops[nr]->buflength, - buf, realcount - )) return -EFAULT; + if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, + buf, realcount)) + return -EFAULT; - loops[nr]->frame=0; + loops[nr]->frame = 0; up(&loops[nr]->lock); loops[nr]->frameswrite++; @@ -453,24 +504,32 @@ return realcount; } -static ssize_t vloopback_read (struct file * f, char * buf, size_t count, loff_t *offset) +static ssize_t vloopback_read(struct file * f, char * buf, size_t count, + loff_t *offset) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; - unsigned long realcount=count; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + unsigned long realcount = count; + + if (debug > LOG_IOCTL) + info("Video loopback %d", nr); if (loops[nr]->zerocopy) { if (ptr->in) { - if (realcount > loops[nr]->ioctllength+sizeof(unsigned long int)) - realcount=loops[nr]->ioctllength+sizeof(unsigned long int); + if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int)) + realcount = loops[nr]->ioctllength + sizeof(unsigned long int); + if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) return -EFAULT; - if (copy_to_user(buf+sizeof(unsigned long int) , loops[nr]->ioctldata, - realcount-sizeof(unsigned long int))) + + if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, + realcount - sizeof(unsigned long int))) return -EFAULT; - if (loops[nr]->ioctlnr==0) - loops[nr]->ioctlnr=-1; + + if (loops[nr]->ioctlnr == 0) + loops[nr]->ioctlnr = -1; + return realcount; } else { struct video_window vidwin; @@ -480,30 +539,34 @@ fake_ioctl(nr, VIDIOCGWIN, &vidwin); fake_ioctl(nr, VIDIOCGPICT, &vidpic); - vidmmap.height=vidwin.height; - vidmmap.width=vidwin.width; - vidmmap.format=vidpic.palette; - vidmmap.frame=0; + vidmmap.height = vidwin.height; + vidmmap.width = vidwin.width; + vidmmap.format = vidpic.palette; + vidmmap.frame = 0; + if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) return 0; + if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) return 0; - realcount=vidwin.height*vidwin.width*vidpic.depth; + + realcount = vidwin.height * vidwin.width * vidpic.depth; } } + if (ptr->in) return -EINVAL; if (realcount > loops[nr]->buflength) { realcount = loops[nr]->buflength; - info("Not so much data in buffer!"); + info("Not so much data in buffer! for Video loopback %d", nr); } if (!loops[nr]->zerocopy) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - unsigned long fw=loops[nr]->frameswrite; + unsigned long fw = loops[nr]->frameswrite; - wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else interruptible_sleep_on(&loops[nr]->wait); #endif @@ -514,8 +577,10 @@ up(&loops[nr]->lock); return 0; } + if (copy_to_user(buf, loops[nr]->buffer, realcount)) return -EFAULT; + up(&loops[nr]->lock); loops[nr]->framesread++; @@ -524,95 +589,118 @@ static int vloopback_mmap(struct file *f, struct vm_area_struct *vma) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; unsigned long start = (unsigned long)vma->vm_start; long size = vma->vm_end - vma->vm_start; unsigned long page, pos; + if (debug > LOG_NODEBUG) + info("Video loopback %d", nr); + down(&loops[nr]->lock); + if (ptr->in) { - loops[nr]->zerocopy=1; + loops[nr]->zerocopy = 1; + if (loops[nr]->ropen) { - info("Can't change size while opened for read"); - up(&loops[nr]->lock); - return -EINVAL; - } - if (!size) { + info("Can't change size while opened for read in Video loopback %d", + nr); up(&loops[nr]->lock); return -EINVAL; } + + if (!size) { + up(&loops[nr]->lock); + info("Invalid size Video loopback %d", nr); + return -EINVAL; + } + if (loops[nr]->buffer) - rvfree(loops[nr]->buffer, loops[nr]->buflength*N_BUFFS); - loops[nr]->buflength=size; - loops[nr]->buffer=rvmalloc(loops[nr]->buflength*N_BUFFS); - } - if (loops[nr]->buffer == NULL) { - up(&loops[nr]->lock); - return -EINVAL; + rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); + + loops[nr]->buflength = size; + loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); } - if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { + if (loops[nr]->buffer == NULL) { up(&loops[nr]->lock); - return -EINVAL; + return -EINVAL; } - pos = (unsigned long)loops[nr]->buffer; - while (size > 0) { + if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1) + & ~(PAGE_SIZE - 1))) { + up(&loops[nr]->lock); + return -EINVAL; + } + + pos = (unsigned long)loops[nr]->buffer; + + while (size > 0) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) - page = kvirt_to_pa(pos); - if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { + page = kvirt_to_pa(pos); + if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { #else page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, - PAGE_SHARED)) { + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { #endif - up(&loops[nr]->lock); - return -EAGAIN; + up(&loops[nr]->lock); + return -EAGAIN; } - start += PAGE_SIZE; - pos += PAGE_SIZE; + start += PAGE_SIZE; + pos += PAGE_SIZE; size -= PAGE_SIZE; - } + } + up(&loops[nr]->lock); return 0; } -static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, unsigned long arg) +static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, + unsigned long arg) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; int i; + if (debug > LOG_NODEBUG) + info("Video loopback %d cmd %u", nr, cmd); + if (loops[nr]->zerocopy) { if (!ptr->in) { - loops[nr]->ioctlnr=cmd; - loops[nr]->ioctllength=_IOC_SIZE(cmd); + loops[nr]->ioctlnr = cmd; + loops[nr]->ioctllength = _IOC_SIZE(cmd); /* info("DEBUG: vl_ioctl: !loop->in"); */ /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ - if(copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) + if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) return -EFAULT; - kill_proc(loops[nr]->pid, SIGIO, 1); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + kill_proc(loops[nr]->pid, SIGIO, 1); +#else + kill_pid(loops[nr]->pid, SIGIO, 1); +#endif + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr==-1); + wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); #else interruptible_sleep_on(&loops[nr]->wait); #endif if (loops[nr]->invalid_ioctl) { - //info ("DEBUG: There was an invalid ioctl"); - loops[nr]->invalid_ioctl = 0; + info ("There was an invalid ioctl in Video loopback %d", nr); + loops[nr]->invalid_ioctl = 0; return -ENOTTY; } + if (cmd & IOC_IN && !(cmd & IOC_OUT)) { //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); - if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) { + if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) return -EINVAL; - } + //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); return 0; } else { @@ -622,309 +710,366 @@ return 0; } } else { - if ( (loops[nr]->ioctlnr!=cmd) && (cmd != (VIDIOCSINVALID))) { + if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) { /* wrong ioctl */ - info("DEBUG: vo_ioctl: Wrong IOCTL"); - return 0; + info("Wrong IOCTL %u in Video loopback %d", cmd, nr); + return 0; } + if (cmd == VIDIOCSINVALID) { loops[nr]->invalid_ioctl = 1; - } else { - if (copy_from_user(loops[nr]->ioctlretdata, (void*)arg, loops[nr]->ioctllength)) - return -EFAULT; + } else if (copy_from_user(loops[nr]->ioctlretdata, + (void*)arg, loops[nr]->ioctllength)) { + return -EFAULT; } - loops[nr]->ioctlnr=-1; + + loops[nr]->ioctlnr = -1; + if (waitqueue_active(&loops[nr]->wait)) wake_up(&loops[nr]->wait); + return 0; } } + switch(cmd) { - /* Get capabilities */ - case VIDIOCGCAP: - { - struct video_capability b; - if (ptr->in) { - sprintf(b.name, "Video loopback %d input", - ptr->pipenr); - b.type = 0; - } else { - sprintf(b.name, "Video loopback %d output", - ptr->pipenr); - b.type = VID_TYPE_CAPTURE; - } - b.channels=1; - b.audios=0; - b.maxwidth=loops[nr]->width; - b.maxheight=loops[nr]->height; - b.minwidth=20; - b.minheight=20; - if(copy_to_user((void*)arg, &b, sizeof(b))) - return -EFAULT; - return 0; + /* Get capabilities */ + case VIDIOCGCAP: + { + struct video_capability b; + if (ptr->in) { + sprintf(b.name, "Video loopback %d input", nr); + b.type = 0; + } else { + sprintf(b.name, "Video loopback %d output", nr); + b.type = VID_TYPE_CAPTURE; + } + + b.channels = 1; + b.audios = 0; + b.maxwidth = loops[nr]->width; + b.maxheight = loops[nr]->height; + b.minwidth = 20; + b.minheight = 20; + + if (copy_to_user((void*)arg, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + /* Get channel info (sources) */ + case VIDIOCGCHAN: + { + struct video_channel v; + if (copy_from_user(&v, (void*)arg, sizeof(v))) + return -EFAULT; + + if (v.channel != 0) { + info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); + v.channel = 0; + //return -EINVAL; } - /* Get channel info (sources) */ - case VIDIOCGCHAN: - { - struct video_channel v; - if(copy_from_user(&v, (void*)arg, sizeof(v))) - return -EFAULT; - if(v.channel!=0) { - info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); - v.channel=0; - //return -EINVAL; - } - v.flags=0; - v.tuners=0; - v.norm=0; - v.type = VIDEO_TYPE_CAMERA; - /*strcpy(v.name, "Loopback"); -- tibit */ - strcpy(v.name, "Composite1"); - if(copy_to_user((void*)arg, &v, sizeof(v))) - return -EFAULT; - return 0; + + v.flags = 0; + v.tuners = 0; + v.norm = 0; + v.type = VIDEO_TYPE_CAMERA; + /*strcpy(v.name, "Loopback"); -- tibit */ + strcpy(v.name, "Composite1"); + + if (copy_to_user((void*)arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + /* Set channel */ + case VIDIOCSCHAN: + { + int v; + + if (copy_from_user(&v, (void*)arg, sizeof(v))) + return -EFAULT; + + if (v != 0) { + info("VIDIOCSCHAN: Invalid Channel, was %d", v); + return -EINVAL; + } + + return 0; + } + /* Get tuner abilities */ + case VIDIOCGTUNER: + { + struct video_tuner v; + + if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0) + return -EFAULT; + + if (v.tuner) { + info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); + return -EINVAL; } - /* Set channel */ - case VIDIOCSCHAN: - { - int v; - if(copy_from_user(&v, (void*)arg, sizeof(v))) - return -EFAULT; - if(v!=0) { - info("VIDIOCSCHAN: Invalid Channel, was %d", v); - return -EINVAL; - } - return 0; - } - /* Get tuner abilities */ - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, (void*)arg, sizeof(v))!=0) - return -EFAULT; - if(v.tuner) { - info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); + + strcpy(v.name, "Format"); + v.rangelow = 0; + v.rangehigh = 0; + v.flags = 0; + v.mode = VIDEO_MODE_AUTO; + + if (copy_to_user((void*)arg,&v, sizeof(v)) != 0) + return -EFAULT; + + return 0; + } + /* Get picture properties */ + case VIDIOCGPICT: + { + struct video_picture p; + + p.colour = 0x8000; + p.hue = 0x8000; + p.brightness = 0x8000; + p.contrast = 0x8000; + p.whiteness = 0x8000; + p.depth = 0x8000; + p.palette = loops[nr]->palette; + + if (copy_to_user((void*)arg, &p, sizeof(p))) + return -EFAULT; + + return 0; + } + /* Set picture properties */ + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, (void*)arg, sizeof(p))) + return -EFAULT; + + if (!ptr->in) { + if (p.palette != loops[nr]->palette) return -EINVAL; - } - strcpy(v.name, "Format"); - v.rangelow=0; - v.rangehigh=0; - v.flags=0; - v.mode=VIDEO_MODE_AUTO; - if(copy_to_user((void*)arg,&v, sizeof(v))!=0) - return -EFAULT; - return 0; - } - /* Get picture properties */ - case VIDIOCGPICT: - { - struct video_picture p; - p.colour=0x8000; - p.hue=0x8000; - p.brightness=0x8000; - p.contrast=0x8000; - p.whiteness=0x8000; - p.depth=0x8000; - p.palette=loops[nr]->palette; - if(copy_to_user((void*)arg, &p, sizeof(p))) - return -EFAULT; + } else { + loops[nr]->palette = p.palette; + } + + return 0; + } + /* Get the video overlay window */ + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.width = loops[nr]->width; + vw.height = loops[nr]->height; + vw.chromakey = 0; + vw.flags = 0; + vw.clipcount = 0; + + if (copy_to_user((void*)arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, (void*)arg, sizeof(vw))) + return -EFAULT; + + if (vw.flags) + return -EINVAL; + + if (vw.clipcount) + return -EINVAL; + + if (loops[nr]->height == vw.height && + loops[nr]->width == vw.width) return 0; - } - /* Set picture properties */ - case VIDIOCSPICT: - { - struct video_picture p; - if(copy_from_user(&p, (void*)arg, sizeof(p))) - return -EFAULT; - if (!ptr->in) { - if (p.palette!=loops[nr]->palette) - return -EINVAL; - } else - loops[nr]->palette=p.palette; - return 0; - } - /* Get the video overlay window */ - case VIDIOCGWIN: - { - struct video_window vw; - vw.x=0; - vw.y=0; - vw.width=loops[nr]->width; - vw.height=loops[nr]->height; - vw.chromakey=0; - vw.flags=0; - vw.clipcount=0; - if(copy_to_user((void*)arg, &vw, sizeof(vw))) - return -EFAULT; - return 0; - } - /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ - case VIDIOCSWIN: - { - struct video_window vw; - - if(copy_from_user(&vw, (void*)arg, sizeof(vw))) - return -EFAULT; - if(vw.flags) - return -EINVAL; - if(vw.clipcount) - return -EINVAL; - if (loops[nr]->height==vw.height && - loops[nr]->width==vw.width) - return 0; - if(!ptr->in) { - return -EINVAL; - } else { - loops[nr]->height=vw.height; - loops[nr]->width=vw.width; - /* Make sure nobody is using the buffer while we - fool around with it. - We are also not allowing changes while - somebody using mmap has the output open. - */ - down(&loops[nr]->lock); - if (loops[nr]->ropen) { - info("Can't change size while opened for read"); - up(&loops[nr]->lock); - return -EINVAL; - } - if (loops[nr]->buffer) - rvfree(loops[nr]->buffer, loops[nr]->buflength*N_BUFFS); - loops[nr]->buflength=vw.width*vw.height*4; - loops[nr]->buffer=rvmalloc(loops[nr]->buflength*N_BUFFS); + if (!ptr->in) { + return -EINVAL; + } else { + loops[nr]->height = vw.height; + loops[nr]->width = vw.width; + /* Make sure nobody is using the buffer while we + fool around with it. + We are also not allowing changes while + somebody using mmap has the output open. + */ + down(&loops[nr]->lock); + if (loops[nr]->ropen) { + info("Can't change size while opened for read"); up(&loops[nr]->lock); - } - return 0; - } - /* Memory map buffer info */ - case VIDIOCGMBUF: - { - struct video_mbuf vm; - - vm.size=loops[nr]->buflength*N_BUFFS; - vm.frames=N_BUFFS; - for (i=0; ibuflength; - if(copy_to_user((void*)arg, &vm, sizeof(vm))) - return -EFAULT; - return 0; - } - /* Grab frames */ - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (ptr->in) - return -EINVAL; - if (!loops[nr]->buffer) return -EINVAL; - if (copy_from_user(&vm, (void*)arg, sizeof(vm))) - return -EFAULT; - if (vm.format!=loops[nr]->palette) - return -EINVAL; - if (vm.frame > N_BUFFS) - return -EINVAL; - return 0; - } - /* Sync with mmap grabbing */ - case VIDIOCSYNC: - { - int frame; - unsigned long fw; + } + + if (loops[nr]->buffer) + rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); - if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) - return -EFAULT; - if (ptr->in) - return -EINVAL; - if (!loops[nr]->buffer) - return -EINVAL; - /* Ok, everything should be alright since the program - should have called VIDIOMCAPTURE and we are ready to - do the 'capturing' */ - if (frame > 1) - return -EINVAL; - loops[nr]->frame=frame; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - fw = loops[nr]->frameswrite; - wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); -#else - interruptible_sleep_on(&loops[nr]->wait); -#endif - if (!loops[nr]->buffer) /* possibly released during sleep */ - return -EINVAL; - loops[nr]->framesread++; - return 0; + loops[nr]->buflength = vw.width * vw.height * 4; + loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); + up(&loops[nr]->lock); } - /* Get attached units */ - case VIDIOCGUNIT: - { - struct video_unit vu; + return 0; + } + /* Memory map buffer info */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; - if (ptr->in) - vu.video=loops[nr]->vloopout->minor; - else - vu.video=loops[nr]->vloopin->minor; - vu.vbi=VIDEO_NO_UNIT; - vu.radio=VIDEO_NO_UNIT; - vu.audio=VIDEO_NO_UNIT; - vu.teletext=VIDEO_NO_UNIT; - if (copy_to_user((void*)arg, &vu, sizeof(vu))) - return -EFAULT; - return 0; - } - /* Get frame buffer */ - case VIDIOCGFBUF: - { - struct video_buffer vb; + vm.size = loops[nr]->buflength * N_BUFFS; + vm.frames = N_BUFFS; + for (i = 0; i < vm.frames; i++) + vm.offsets[i] = i * loops[nr]->buflength; + + if (copy_to_user((void*)arg, &vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + /* Grab frames */ + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (ptr->in) + return -EINVAL; + + if (!loops[nr]->buffer) + return -EINVAL; + + if (copy_from_user(&vm, (void*)arg, sizeof(vm))) + return -EFAULT; + + if (vm.format != loops[nr]->palette) + return -EINVAL; + + if (vm.frame > N_BUFFS) + return -EINVAL; - memset(&vb, 0, sizeof(vb)); - vb.base=NULL; + return 0; + } + /* Sync with mmap grabbing */ + case VIDIOCSYNC: + { + int frame; + unsigned long fw; + + if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) + return -EFAULT; + + if (ptr->in) + return -EINVAL; - if(copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) - return -EFAULT; + if (!loops[nr]->buffer) + return -EINVAL; + + /* Ok, everything should be alright since the program + should have called VIDIOMCAPTURE and we are ready to + do the 'capturing' */ + if (frame > 1) + return -EINVAL; + + loops[nr]->frame = frame; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + fw = loops[nr]->frameswrite; + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); +#else + interruptible_sleep_on(&loops[nr]->wait); +#endif + if (!loops[nr]->buffer) /* possibly released during sleep */ + return -EINVAL; - return 0; - } - /* Start, end capture */ - case VIDIOCCAPTURE: - { - int start; - if (copy_from_user(&start, (void*)arg, sizeof(int))) - return -EFAULT; - if (start) info ("Capture started"); - else info ("Capture stopped"); + loops[nr]->framesread++; + + return 0; + } + /* Get attached units */ + case VIDIOCGUNIT: + { + struct video_unit vu; + + if (ptr->in) + vu.video = loops[nr]->vloopout->minor; + else + vu.video = loops[nr]->vloopin->minor; + + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + + if (copy_to_user((void*)arg, &vu, sizeof(vu))) + return -EFAULT; + + return 0; + } + /* Get frame buffer */ + case VIDIOCGFBUF: + { + struct video_buffer vb; + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; - return 0; - } + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } + /* Start, end capture */ + case VIDIOCCAPTURE: + { + int start; + + if (copy_from_user(&start, (void*)arg, sizeof(int))) + return -EFAULT; - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - case VIDIOCKEY: - return 0; - default: - return -ENOTTY; - //return -ENOIOCTLCMD; + if (start) { + info ("Video loopback %d Capture started", nr); + } else { + info ("Video loopback %d Capture stopped", nr); + } + + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + case VIDIOCKEY: + return 0; + default: + return -ENOTTY; + //return -ENOIOCTLCMD; } return 0; } static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait) { - struct video_device *loopdev=video_devdata(f); - priv_ptr ptr=(priv_ptr)loopdev->priv; - int nr=ptr->pipenr; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; - if (loopdev==NULL) + if (debug > LOG_NODEBUG) + info("Video loopback %d", nr); + + if (loopdev == NULL) return -EFAULT; + if (!ptr->in) return 0; - if (loops[nr]->ioctlnr!=-1) { + if (loops[nr]->ioctlnr != -1) { if (loops[nr]->zerocopy) { return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); } else { @@ -934,7 +1079,7 @@ return 0; } -static struct file_operations fileops_template= +static struct file_operations fileops_template = { owner: THIS_MODULE, open: vloopback_open, @@ -946,11 +1091,14 @@ mmap: vloopback_mmap, }; -static struct video_device vloopback_template= +static struct video_device vloopback_template = { - owner: THIS_MODULE, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + owner: THIS_MODULE, + type: VID_TYPE_CAPTURE, +#endif + minor: -1, name: "Video Loopback", - type: VID_TYPE_CAPTURE, fops: &fileops_template, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) release: video_device_release, @@ -960,39 +1108,46 @@ static int create_pipe(int nr) { int minor_in, minor_out , ret; - - if (dev_offset == -1) + + if (debug > LOG_NODEBUG) + info("Video loopback %d", nr); + + if (dev_offset == -1) { minor_in = minor_out = -1; /* autoassign */ - else { - minor_in = 2*nr + dev_offset; - minor_out = 2*nr+1 + dev_offset; + } else { + minor_in = 2 * nr + dev_offset; + minor_out = 2 * nr + 1 + dev_offset; } /* allocate space for this pipe */ loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); + if (!loops[nr]) return -ENOMEM; /* set up a new video device plus our private area */ - loops[nr]->vloopin= video_device_alloc(); + loops[nr]->vloopin = video_device_alloc(); + if (loops[nr]->vloopin == NULL) return -ENOMEM; *loops[nr]->vloopin = vloopback_template; - loops[nr]->vloopin->priv= kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); + loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private), + GFP_KERNEL); if (loops[nr]->vloopin->priv == NULL) { kfree(loops[nr]->vloopin); return -ENOMEM; } /* repeat for the output device */ - loops[nr]->vloopout= video_device_alloc(); + loops[nr]->vloopout = video_device_alloc(); + if (loops[nr]->vloopout == NULL) { kfree(loops[nr]->vloopin->priv); kfree(loops[nr]->vloopin); return -ENOMEM; } *loops[nr]->vloopout = vloopback_template; - loops[nr]->vloopout->priv= kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); + loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private), + GFP_KERNEL); + if (loops[nr]->vloopout->priv == NULL) { kfree(loops[nr]->vloopin->priv); kfree(loops[nr]->vloopin); @@ -1000,43 +1155,49 @@ return -ENOMEM; } - ((priv_ptr)loops[nr]->vloopin->priv)->pipenr=nr; - ((priv_ptr)loops[nr]->vloopout->priv)->pipenr=nr; + ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr; + ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr; loops[nr]->invalid_ioctl = 0; /* tibit */ - loops[nr]->buffer=NULL; - loops[nr]->width=0; - loops[nr]->height=0; - loops[nr]->palette=0; - loops[nr]->frameswrite=0; - loops[nr]->framesread=0; - loops[nr]->framesdumped=0; - loops[nr]->wopen=0; - loops[nr]->ropen=0; - loops[nr]->frame=0; + loops[nr]->buffer = NULL; + loops[nr]->width = 0; + loops[nr]->height = 0; + loops[nr]->palette = 0; + loops[nr]->frameswrite = 0; + loops[nr]->framesread = 0; + loops[nr]->framesdumped = 0; + loops[nr]->wopen = 0; + loops[nr]->ropen = 0; + loops[nr]->frame = 0; - ((priv_ptr)loops[nr]->vloopin->priv)->in=1; - ((priv_ptr)loops[nr]->vloopout->priv)->in=0; - loops[nr]->vloopin->type=0; - sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); - loops[nr]->vloopout->type=VID_TYPE_CAPTURE; - sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); + ((priv_ptr)loops[nr]->vloopin->priv)->in = 1; + ((priv_ptr)loops[nr]->vloopout->priv)->in = 0; + sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); + sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + loops[nr]->vloopin->type = 0; + loops[nr]->vloopout->type = VID_TYPE_CAPTURE; +#endif + loops[nr]->vloopout->minor = minor_out; + loops[nr]->vloopin->minor = minor_in; + init_waitqueue_head(&loops[nr]->wait); init_MUTEX(&loops[nr]->lock); - ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER,minor_in); + ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER, minor_in); if ((ret == -1 ) || ( ret == -23 )) { - info("error registering device %s",loops[nr]->vloopin->name); + info("error registering device %s", loops[nr]->vloopin->name); kfree(loops[nr]->vloopin->priv); kfree(loops[nr]->vloopin); kfree(loops[nr]->vloopout->priv); kfree(loops[nr]->vloopout); kfree(loops[nr]); - loops[nr]=NULL; + loops[nr] = NULL; return ret; } - ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER,minor_out); + ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER, minor_out); if ((ret ==-1) || (ret == -23)) { info("error registering device %s", loops[nr]->vloopout->name); @@ -1045,12 +1206,12 @@ kfree(loops[nr]->vloopout->priv); kfree(loops[nr]->vloopout); kfree(loops[nr]); - loops[nr]=NULL; + loops[nr] = NULL; return ret; } - loops[nr]->ioctldata=kmalloc(1024, GFP_KERNEL); - loops[nr]->ioctlretdata=kmalloc(1024, GFP_KERNEL); + loops[nr]->ioctldata = kmalloc(1024, GFP_KERNEL); + loops[nr]->ioctlretdata = kmalloc(1024, GFP_KERNEL); return 0; } @@ -1086,6 +1247,16 @@ #endif MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers"); + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +module_param(debug, int, 000); +#else +MODULE_PARM(debug_param, "i"); +#endif + +MODULE_PARM_DESC(debug, "Enable module debug level 0-3 (by default 0)"); + MODULE_LICENSE("GPL"); MODULE_VERSION( VLOOPBACK_VERSION ); @@ -1093,25 +1264,27 @@ { int i,ret; - info("Video4linux loopback driver v"VLOOPBACK_VERSION); + info("video4linux loopback driver v"VLOOPBACK_VERSION); - if (pipes==-1) pipes=1; + if (pipes == -1) + pipes = 1; + if (pipes > MAX_PIPES) { - pipes=MAX_PIPES; + pipes = MAX_PIPES; info("Nr of pipes is limited to: %d", MAX_PIPES); } - for (i=0; ivloopin->minor, loops[i]->vloopout->minor); - nr_o_pipes=i+1; - }else{ + nr_o_pipes = i + 1; + } else { return ret; } } @@ -1123,16 +1296,22 @@ int i; info("Unregistering video4linux loopback devices"); - for (i=0; ivloopin->priv); - video_unregister_device(loops[i]->vloopin); - kfree(loops[i]->vloopout->priv); - video_unregister_device(loops[i]->vloopout); - if (loops[i]->buffer) rvfree(loops[i]->buffer, loops[i]->buflength*N_BUFFS); - kfree(loops[i]->ioctldata); - kfree(loops[i]->ioctlretdata); - kfree(loops[i]); - } + + for (i = 0; i < nr_o_pipes; i++) { + if (loops[i]) { + kfree(loops[i]->vloopin->priv); + video_unregister_device(loops[i]->vloopin); + kfree(loops[i]->vloopout->priv); + video_unregister_device(loops[i]->vloopout); + + if (loops[i]->buffer) + rvfree(loops[i]->buffer, loops[i]->buflength * N_BUFFS); + + kfree(loops[i]->ioctldata); + kfree(loops[i]->ioctlretdata); + kfree(loops[i]); + } + } } module_init(vloopback_init);