Initial revision
[libav.git] / grab.c
CommitLineData
9aeeeb63
FB
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
35long 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
44const char *v4l_device = "/dev/video";
45
46static struct video_capability video_cap;
47int video_fd = -1;
48UINT8 *video_buf, *picture_buf;
49struct video_mbuf gb_buffers;
50struct video_mmap gb_buf;
51struct video_audio audio;
52int gb_frame = 0;
53long long time_frame;
54int frame_rate;
55int use_mmap = 0;
56
57int 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 */
125static 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
165static 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
204int 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 */
216int 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