0
|
1 /* invert.c
|
|
2 *
|
|
3 * Example program for videoloopback device.
|
|
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 <linux/videodev.h>
|
|
22
|
|
23
|
|
24 int fmt=0;
|
|
25 int noexit = 1;
|
|
26 int read_img=0;
|
|
27
|
|
28 char *start_capture (int dev, int width, int height)
|
|
29 {
|
|
30 struct video_capability vid_caps;
|
|
31 struct video_window vid_win;
|
|
32 struct video_mbuf vid_buf;
|
|
33 char *map;
|
|
34
|
|
35 if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
|
|
36 printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno));
|
|
37 return (NULL);
|
|
38 }
|
|
39 if (vid_caps.type & VID_TYPE_MONOCHROME) fmt=VIDEO_PALETTE_GREY;
|
|
40 if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) {
|
|
41 fprintf(stderr, "no mmap falling back on read\n");
|
|
42 if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) {
|
|
43 printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno));
|
|
44 return (NULL);
|
|
45 }
|
|
46 vid_win.width=width;
|
|
47 vid_win.height=height;
|
|
48 if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) {
|
|
49 printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno));
|
|
50 return (NULL);
|
|
51 }
|
|
52 read_img=1;
|
|
53 map=malloc(width*height*3);
|
|
54 return (map);
|
|
55 }
|
|
56 /* If we are going to capture greyscale we need room to blow the image up */
|
|
57 if (fmt==VIDEO_PALETTE_GREY)
|
|
58 map=mmap(0, vid_buf.size*3, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0);
|
|
59 else
|
|
60 map=mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0);
|
|
61
|
|
62 if ((unsigned char *)-1 == (unsigned char *)map)
|
|
63 return (NULL);
|
|
64 return map;
|
|
65 }
|
|
66
|
|
67 int start_pipe (int dev, int width, int height)
|
|
68 {
|
|
69 struct video_capability vid_caps;
|
|
70 struct video_window vid_win;
|
|
71 struct video_picture vid_pic;
|
|
72
|
|
73 if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) {
|
|
74 printf ("ioctl (VIDIOCGCAP)\nError[%s]\n",strerror(errno));
|
|
75 return (1);
|
|
76 }
|
|
77 if (ioctl (dev, VIDIOCGPICT, &vid_pic)== -1) {
|
|
78 printf ("ioctl VIDIOCGPICT\nError[%s]\n",strerror(errno));
|
|
79 return (1);
|
|
80 }
|
|
81 vid_pic.palette=fmt;
|
|
82 if (ioctl (dev, VIDIOCSPICT, &vid_pic)== -1) {
|
|
83 printf ("ioctl VIDIOCSPICT\nError[%s]\n",strerror(errno));
|
|
84 return (1);
|
|
85 }
|
|
86 if (ioctl (dev, VIDIOCGWIN, &vid_win)== -1) {
|
|
87 printf ("ioctl VIDIOCGWIN\nError[%s]\n",strerror(errno));
|
|
88 return (1);
|
|
89 }
|
|
90 vid_win.width=width;
|
|
91 vid_win.height=height;
|
|
92 if (ioctl (dev, VIDIOCSWIN, &vid_win)== -1) {
|
|
93 printf ("ioctl VIDIOCSWIN\nError[%s]\n",strerror(errno));
|
|
94 return (1);
|
|
95 }
|
|
96 return 0;
|
|
97 }
|
|
98
|
|
99 char *next_capture (int dev, char *map, int width, int height)
|
|
100 {
|
|
101 int i;
|
|
102 char *grey, *rgb;
|
|
103 struct video_mmap vid_mmap;
|
|
104
|
|
105 sigset_t set, old;
|
|
106
|
|
107 if (read_img) {
|
|
108 if (fmt==VIDEO_PALETTE_GREY) {
|
|
109 if (read(dev, map, width*height) != width*height)
|
|
110 return NULL;
|
|
111 } else {
|
|
112 if (read(dev, map, width*height*3) != width*height*3)
|
|
113 return NULL;
|
|
114 }
|
|
115 } else {
|
|
116 vid_mmap.format=fmt;
|
|
117 vid_mmap.frame=0;
|
|
118 vid_mmap.width=width;
|
|
119 vid_mmap.height=height;
|
|
120
|
|
121 sigemptyset (&set); //BTTV hates signals during IOCTL
|
|
122 sigaddset (&set, SIGCHLD); //block SIGCHLD & SIGALRM
|
|
123 sigaddset (&set, SIGALRM); //for the time of ioctls
|
|
124 sigprocmask (SIG_BLOCK, &set, &old);
|
|
125
|
|
126 if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) {
|
|
127 sigprocmask (SIG_UNBLOCK, &old, NULL);
|
|
128 return (NULL);
|
|
129 }
|
|
130 if (ioctl(dev, VIDIOCSYNC, &vid_mmap) == -1) {
|
|
131 sigprocmask (SIG_UNBLOCK, &old, NULL);
|
|
132 return (NULL);
|
|
133 }
|
|
134
|
|
135 sigprocmask (SIG_UNBLOCK, &old, NULL); //undo the signal blocking
|
|
136 }
|
|
137 /* Blow up a grey */
|
|
138 if (fmt==VIDEO_PALETTE_GREY) {
|
|
139 i=width*height;
|
|
140 grey=map+i-1;
|
|
141 rgb=map+i*3;
|
|
142 for (; i>=0; i--, grey--) {
|
|
143 *(rgb--)=*grey;
|
|
144 *(rgb--)=*grey;
|
|
145 *(rgb--)=*grey;
|
|
146 }
|
|
147 }
|
|
148 return map;
|
|
149 }
|
|
150
|
|
151 int put_image(int dev, char *image, int width, int height)
|
|
152 {
|
|
153 if (write(dev, image, width*height*3)!=width*height*3) {
|
|
154 printf("Error writing image to pipe!\nError[%s]\n",strerror(errno));
|
|
155 return 0;
|
|
156 }
|
|
157 return 1;
|
|
158 }
|
|
159
|
|
160
|
|
161 void sig_handler(int signo)
|
|
162 {
|
|
163 noexit = 0;
|
|
164 }
|
|
165
|
|
166 int main (int argc, char **argv)
|
|
167 {
|
|
168 int i, devin, devout;
|
|
169 int width;
|
|
170 int height;
|
|
171 char *image_out, *image_new;
|
|
172 char palette[10]={'\0'};
|
|
173
|
|
174 if (argc != 5) {
|
|
175 printf("Usage:\n\n");
|
|
176 printf("invert input output widthxheight rgb24|yuv420p\n\n");
|
|
177 printf("example: invert /dev/video0 /dev/video1 352x288 yuv420p\n\n");
|
|
178 exit(1);
|
|
179 }
|
|
180 sscanf(argv[3], "%dx%d", &width, &height);
|
|
181 sscanf(argv[4], "%s", palette);
|
|
182
|
|
183 if (!strcmp(palette,"rgb24")) fmt = VIDEO_PALETTE_RGB24;
|
|
184 else if (!strcmp(palette,"yuv420p")) fmt = VIDEO_PALETTE_YUV420P;
|
|
185 else fmt = VIDEO_PALETTE_RGB24;
|
|
186
|
|
187
|
|
188 image_out=malloc(width*height*3);
|
|
189
|
|
190 devin=open (argv[1], O_RDWR);
|
|
191 if (devin < 0) {
|
|
192 printf("Failed to open input video device [%s]\nError:[%s]\n",argv[1],strerror(errno));
|
|
193 exit(1);
|
|
194 }
|
|
195
|
|
196 devout=open (argv[2], O_RDWR);
|
|
197 if (devout < 0) {
|
|
198 printf ("Failed to open output video device [%s]\nError:[%s]\n",argv[2],strerror(errno));
|
|
199 exit(1);
|
|
200 }
|
|
201
|
|
202 image_new=start_capture (devin, width, height);
|
|
203 if (!image_new) {
|
|
204 printf("Capture error \n Error[%s]\n",strerror(errno));
|
|
205 exit(1);
|
|
206 }
|
|
207
|
|
208 start_pipe(devout, width, height);
|
|
209
|
|
210 signal(SIGTERM, sig_handler);
|
|
211
|
|
212 printf("Starting video stream.\n");
|
|
213 while ( (next_capture(devin, image_new, width, height)) && (noexit) ){
|
|
214 for (i=width*height*3; i>=0; i--) image_out[i]=-image_new[i];
|
|
215 if (put_image(devout, image_out, width, height)==0)
|
|
216 exit(1);
|
|
217 }
|
|
218 printf("You bought vaporware!\nError[%s]\n",strerror(errno));
|
|
219 close (devin);
|
|
220 close (devout);
|
|
221 free(image_out);
|
|
222 exit(0);
|
|
223 }
|