grab.c
上传用户:jxp0626
上传日期:2007-01-08
资源大小:102k
文件大小:6k
- /*
- * Linux audio/video grab interface
- * Copyright (c) 2000 Gerard Lantau.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <netinet/in.h>
- #include <linux/videodev.h>
- #include <linux/soundcard.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <getopt.h>
- #include "mpegenc.h"
- long long gettime(void)
- {
- struct timeval tv;
- gettimeofday(&tv,NULL);
- return (long long)tv.tv_sec * 1000000 + tv.tv_usec;
- }
- const char *v4l_device = "/dev/video";
- const char *audio_device = "/dev/dsp";
- /* v4l capture */
- static struct video_capability video_cap;
- int video_fd = -1;
- UINT8 *video_buf, *picture_buf;
- struct video_mbuf gb_buffers;
- struct video_mmap gb_buf;
- struct video_audio audio;
- int gb_frame = 0;
- long long time_frame;
- int frame_rate;
- int use_mmap = 0;
- int v4l_init(int rate, int width, int height)
- {
- frame_rate = rate;
- video_fd = open(v4l_device, O_RDWR);
- if (video_fd < 0) {
- perror(v4l_device);
- return -1;
- }
-
- if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
- perror("VIDIOCGCAP");
- return -1;
- }
-
- /* unmute audio */
- ioctl(video_fd, VIDIOCGAUDIO, &audio);
- audio.flags &= ~VIDEO_AUDIO_MUTE;
- ioctl(video_fd, VIDIOCSAUDIO, &audio);
- if (!(video_cap.type & VID_TYPE_CAPTURE)) {
- /* try to use read based access */
- struct video_window win;
- int val;
- win.x = 0;
- win.y = 0;
- win.width = width;
- win.height = height;
- win.chromakey = -1;
- win.flags = 0;
- ioctl(video_fd, VIDIOCSWIN, &win);
- val = 1;
- ioctl(video_fd, VIDIOCCAPTURE, &val);
- video_buf = malloc( width * height * 2);
- picture_buf = malloc( (width * height * 3) / 2);
- use_mmap = 0;
- return 0;
- }
-
- if (ioctl(video_fd,VIDIOCGMBUF,&gb_buffers) < 0) {
- perror("ioctl VIDIOCGMBUF");
- }
-
- video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
- if ((unsigned char*)-1 == video_buf) {
- perror("mmap");
- return -1;
- }
- gb_frame = 0;
- time_frame = gettime();
-
- /* start to grab the first frame */
- gb_buf.frame = 1 - gb_frame;
- gb_buf.height = height;
- gb_buf.width = width;
- gb_buf.format = VIDEO_PALETTE_YUV420P;
-
- if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
- if (errno == EAGAIN)
- fprintf(stderr,"Cannot Syncn");
- else
- perror("VIDIOCMCAPTURE");
- return -1;
- }
- use_mmap = 1;
- return 0;
- }
- /* test with read call and YUV422 stream */
- static int v4l_basic_read_picture(UINT8 *picture[3],
- int width, int height,
- int picture_number)
- {
- int x, y;
- UINT8 *p, *lum, *cb, *cr;
-
- if (read(video_fd, video_buf, width * height * 2) < 0)
- perror("read");
- picture[0] = picture_buf;
- picture[1] = picture_buf + width * height;
- picture[2] = picture_buf + (width * height) + (width * height) / 4;
-
- /* XXX: optimize */
- lum = picture[0];
- cb = picture[1];
- cr = picture[2];
- p = video_buf;
- for(y=0;y<height;y+=2) {
- for(x=0;x<width;x+=2) {
- lum[0] = p[0];
- cb[0] = p[1];
- lum[1] = p[2];
- cr[0] = p[3];
- p += 4;
- lum += 2;
- cb++;
- cr++;
- }
- for(x=0;x<width;x+=2) {
- lum[0] = p[0];
- lum[1] = p[2];
- p += 4;
- lum += 2;
- }
- }
- return 0;
- }
- static int v4l_mm_read_picture(UINT8 *picture[3],
- int width, int height,
- int picture_number)
- {
- UINT8 *ptr;
- int size;
- long long curtime;
- /* wait based on the frame rate */
- time_frame += 1000000 / frame_rate;
- do {
- curtime = gettime();
- } while (curtime < time_frame);
-
- gb_buf.frame = gb_frame;
- if (ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
- if (errno == EAGAIN)
- fprintf(stderr,"Cannot Syncn");
- else
- perror("VIDIOCMCAPTURE");
- return -1;
- }
- gb_frame = 1 - gb_frame;
- if (ioctl(video_fd, VIDIOCSYNC, &gb_frame) < 0) {
- if (errno != EAGAIN) {
- perror("VIDIOCSYNC");
- }
- }
- size = width * height;
- ptr = video_buf + gb_buffers.offsets[gb_frame];
- picture[0] = ptr;
- picture[1] = ptr + size;
- picture[2] = ptr + size + (size / 4);
-
- return 0;
- }
- int v4l_read_picture(UINT8 *picture[3],
- int width, int height,
- int picture_number)
- {
- if (use_mmap) {
- return v4l_mm_read_picture(picture, width, height, picture_number);
- } else {
- return v4l_basic_read_picture(picture, width, height, picture_number);
- }
- }
- /* open audio device */
- int audio_open(int freq, int channels)
- {
- int audio_fd, tmp, err;
- audio_fd = open(audio_device,O_RDONLY);
- if (audio_fd < 0) {
- perror(audio_device);
- return -1;
- }
- /* non blocking mode */
- fcntl(audio_fd, F_SETFL, O_NONBLOCK);
- #if 0
- tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
- err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
- if (err < 0) {
- perror("SNDCTL_DSP_SETFRAGMENT");
- }
- #endif
- /* always set to this size */
- /* XXX: incorrect if big endian */
- tmp=AFMT_S16_LE;
- err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
- if (err < 0) {
- perror("SNDCTL_DSP_SETFMT");
- }
-
- tmp= (channels == 2);
- err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
- if (err < 0) {
- perror("SNDCTL_DSP_STEREO");
- }
-
- /* should be last */
- tmp = freq;
- err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
- if (err < 0) {
- perror("SNDCTL_DSP_SPEED");
- }
- return audio_fd;
- }