]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - grab.c
test
[frescor/ffmpeg.git] / grab.c
1 /*
2  * Linux audio/video grab interface
3  * Copyright (c) 2000 Gerard Lantau.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <netinet/in.h>
22 #include <linux/videodev.h>
23 #include <linux/soundcard.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27 #include <sys/mman.h>
28 #include <errno.h>
29 #include <sys/time.h>
30 #include <getopt.h>
31
32 #include "mpegenc.h"
33 #include "mpegvideo.h"
34
35 long long gettime(void)
36 {
37     struct timeval tv;
38     gettimeofday(&tv,NULL);
39     return (long long)tv.tv_sec * 1000000 + tv.tv_usec;
40 }
41
42 /* v4l capture */
43
44 const char *v4l_device = "/dev/video";
45
46 static struct video_capability  video_cap;
47 int video_fd = -1;
48 UINT8 *video_buf, *picture_buf;
49 struct video_mbuf gb_buffers;
50 struct video_mmap gb_buf;
51 struct video_audio audio;
52 int gb_frame = 0;
53 long long time_frame;
54 int frame_rate;
55 int use_mmap = 0;
56
57 int v4l_init(int rate, int width, int height)
58 {
59     frame_rate = rate;
60
61     video_fd = open(v4l_device, O_RDWR);
62     
63     if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
64         perror("VIDIOCGCAP");
65         return -1;
66     }
67     
68     /* unmute audio */
69     ioctl(video_fd, VIDIOCGAUDIO, &audio);
70     audio.flags &= ~VIDEO_AUDIO_MUTE;
71     ioctl(video_fd, VIDIOCSAUDIO, &audio);
72
73     if (!(video_cap.type & VID_TYPE_CAPTURE)) {
74         /* try to use read based access */
75         struct video_window win;
76         int val;
77
78         win.x = 0;
79         win.y = 0;
80         win.width = width;
81         win.height = height;
82         win.chromakey = -1;
83         win.flags = 0;
84
85         ioctl(video_fd, VIDIOCSWIN, &win);
86
87         val = 1;
88         ioctl(video_fd, VIDIOCCAPTURE, &val);
89         video_buf = malloc( width * height * 2);
90         picture_buf = malloc( (width * height * 3) / 2);
91         use_mmap = 0;
92         return 0;
93     }
94     
95     if (ioctl(video_fd,VIDIOCGMBUF,&gb_buffers) < 0) {
96         perror("ioctl VIDIOCGMBUF");
97     }
98     
99     video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
100     if ((unsigned char*)-1 == video_buf) {
101         perror("mmap");
102         return -1;
103     }
104     gb_frame = 0;
105     time_frame = gettime();
106     
107     /* start to grab the first frame */
108     gb_buf.frame = 1 - gb_frame;
109     gb_buf.height = height;
110     gb_buf.width = width;
111     gb_buf.format = VIDEO_PALETTE_YUV420P;
112     
113     if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
114         if (errno == EAGAIN)
115             fprintf(stderr,"Cannot Sync\n");
116         else
117             perror("VIDIOCMCAPTURE");
118         return -1;
119     }
120     use_mmap = 1;
121     return 0;
122 }
123
124 /* test with read call and YUV422 stream */
125 static int v4l_basic_read_picture(UINT8 *picture[3],
126                                   int width, int height,
127                                   int picture_number)
128 {
129     int x, y;
130     UINT8 *p, *lum, *cb, *cr;
131     
132     if (read(video_fd, video_buf, width * height * 2) < 0)
133         perror("read");
134
135     picture[0] = picture_buf;
136     picture[1] = picture_buf + width * height;
137     picture[2] = picture_buf + (width * height) + (width * height) / 4;
138     
139     /* XXX: optimize */
140     lum = picture[0];
141     cb = picture[1];
142     cr = picture[2];
143     p = video_buf;
144     for(y=0;y<height;y+=2) {
145         for(x=0;x<width;x+=2) {
146             lum[0] = p[0];
147             cb[0] = p[1];
148             lum[1] = p[2];
149             cr[0] = p[3];
150             p += 4;
151             lum += 2;
152             cb++;
153             cr++;
154         }
155         for(x=0;x<width;x+=2) {
156             lum[0] = p[0];
157             lum[1] = p[2];
158             p += 4;
159             lum += 2;
160         }
161     }
162     return 0;
163 }
164
165 static int v4l_mm_read_picture(UINT8 *picture[3],
166                                int width, int height,
167                                int picture_number)
168 {
169     UINT8 *ptr;
170     int size;
171     long long curtime;
172
173     /* wait based on the frame rate */
174     time_frame += 1000000 / frame_rate;
175     do {
176         curtime = gettime();
177     } while (curtime < time_frame);
178     
179     gb_buf.frame = gb_frame;
180     if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
181         if (errno == EAGAIN)
182             fprintf(stderr,"Cannot Sync\n");
183         else
184             perror("VIDIOCMCAPTURE");
185         return -1;
186     }
187     gb_frame = 1 - gb_frame;
188
189     if (ioctl(video_fd, VIDIOCSYNC, &gb_frame) < 0) {
190         if (errno != EAGAIN) {
191             perror("VIDIOCSYNC");
192         }
193     }
194
195     size = width * height;
196     ptr = video_buf + gb_buffers.offsets[gb_frame];
197     picture[0] = ptr;
198     picture[1] = ptr + size;
199     picture[2] = ptr + size + (size / 4);
200     
201     return 0;
202 }
203
204 int v4l_read_picture(UINT8 *picture[3],
205                      int width, int height,
206                      int picture_number)
207 {
208     if (use_mmap) {
209         return v4l_mm_read_picture(picture, width, height, picture_number);
210     } else {
211         return v4l_basic_read_picture(picture, width, height, picture_number);
212     }
213 }
214
215 /* open audio device */
216 int audio_open(int freq, int channels)
217 {
218     int audio_fd, tmp, err;
219
220     audio_fd = open("/dev/dsp",O_RDONLY);
221     if (audio_fd == -1) {
222         perror("/dev/dsp");
223         return -1;
224     }
225     /* non blocking mode */
226     fcntl(audio_fd, F_SETFL, O_NONBLOCK);
227
228 #if 0
229     tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
230     err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
231     if (err < 0) {
232         perror("SNDCTL_DSP_SETFRAGMENT");
233     }
234 #endif
235
236     /* always set to this size */
237     /* XXX: incorrect if big endian */
238     tmp=AFMT_S16_LE;
239     err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
240     if (err < 0) {
241         perror("SNDCTL_DSP_SETFMT");
242     }
243     
244     tmp= (channels == 2);
245     err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
246     if (err < 0) {
247         perror("SNDCTL_DSP_STEREO");
248     }
249     
250     /* should be last */
251     tmp = freq;
252     err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
253     if (err < 0) {
254         perror("SNDCTL_DSP_SPEED");
255     }
256     return audio_fd;
257 }
258