| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Linux video grab interface | 
					
						
							| 
									
										
										
										
											2009-01-19 15:46:40 +00:00
										 |  |  |  * Copyright (c) 2000,2001 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							| 
									
										
										
										
											2002-05-25 22:34:32 +00:00
										 |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2002-05-25 22:34:32 +00:00
										 |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2002-05-25 22:34:32 +00:00
										 |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2006-01-12 22:43:26 +00:00
										 |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-03-20 19:07:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-19 21:20:39 +00:00
										 |  |  | #undef __STRICT_ANSI__ //workaround due to broken kernel headers
 | 
					
						
							| 
									
										
										
										
											2008-03-20 19:07:24 +00:00
										 |  |  | #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  | #include "libavutil/rational.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | #include "libavformat/avformat.h"
 | 
					
						
							|  |  |  | #include "libavcodec/dsputil.h"
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							| 
									
										
										
										
											2003-09-09 19:14:05 +00:00
										 |  |  | #define _LINUX_TIME_H 1
 | 
					
						
							|  |  |  | #include <linux/videodev.h>
 | 
					
						
							| 
									
										
										
										
											2002-02-18 10:20:03 +00:00
										 |  |  | #include <time.h>
 | 
					
						
							| 
									
										
										
										
											2008-08-13 17:22:53 +00:00
										 |  |  | #include <strings.h>
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  |     int frame_format; /* see VIDEO_PALETTE_xxx */ | 
					
						
							|  |  |  |     int use_mmap; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |     AVRational time_base; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t time_frame; | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     int frame_size; | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     struct video_capability video_cap; | 
					
						
							|  |  |  |     struct video_audio audio_saved; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:51:19 +00:00
										 |  |  |     struct video_window video_win; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *video_buf; | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     struct video_mbuf gb_buffers; | 
					
						
							|  |  |  |     struct video_mmap gb_buf; | 
					
						
							|  |  |  |     int gb_frame; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | } VideoData; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-07 12:42:02 +00:00
										 |  |  | static const struct { | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |     int palette; | 
					
						
							|  |  |  |     int depth; | 
					
						
							|  |  |  |     enum PixelFormat pix_fmt; | 
					
						
							|  |  |  | } video_formats [] = { | 
					
						
							|  |  |  |     {.palette = VIDEO_PALETTE_YUV420P, .depth = 12, .pix_fmt = PIX_FMT_YUV420P }, | 
					
						
							|  |  |  |     {.palette = VIDEO_PALETTE_YUV422,  .depth = 16, .pix_fmt = PIX_FMT_YUYV422 }, | 
					
						
							| 
									
										
										
										
											2007-06-04 13:28:02 +00:00
										 |  |  |     {.palette = VIDEO_PALETTE_UYVY,    .depth = 16, .pix_fmt = PIX_FMT_UYVY422 }, | 
					
						
							|  |  |  |     {.palette = VIDEO_PALETTE_YUYV,    .depth = 16, .pix_fmt = PIX_FMT_YUYV422 }, | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |     /* NOTE: v4l uses BGR24, not RGB24 */ | 
					
						
							|  |  |  |     {.palette = VIDEO_PALETTE_RGB24,   .depth = 24, .pix_fmt = PIX_FMT_BGR24   }, | 
					
						
							| 
									
										
										
										
											2007-06-04 13:28:02 +00:00
										 |  |  |     {.palette = VIDEO_PALETTE_RGB565,  .depth = 16, .pix_fmt = PIX_FMT_BGR565  }, | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |     {.palette = VIDEO_PALETTE_GREY,    .depth = 8,  .pix_fmt = PIX_FMT_GRAY8   }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  | static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2002-05-20 16:31:13 +00:00
										 |  |  |     VideoData *s = s1->priv_data; | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     AVStream *st; | 
					
						
							| 
									
										
										
										
											2008-12-26 09:31:21 +00:00
										 |  |  |     int video_fd; | 
					
						
							| 
									
										
										
										
											2006-06-28 12:18:22 +00:00
										 |  |  |     int desired_palette, desired_depth; | 
					
						
							| 
									
										
										
										
											2003-06-25 10:21:45 +00:00
										 |  |  |     struct video_tuner tuner; | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     struct video_audio audio; | 
					
						
							| 
									
										
										
										
											2006-05-04 12:23:12 +00:00
										 |  |  |     struct video_picture pict; | 
					
						
							| 
									
										
										
										
											2004-04-25 13:30:21 +00:00
										 |  |  |     int j; | 
					
						
							| 
									
										
										
										
											2008-10-21 21:40:24 +00:00
										 |  |  |     int vformat_num = FF_ARRAY_ELEMS(video_formats); | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-06 18:20:04 +00:00
										 |  |  |     if (ap->time_base.den <= 0) { | 
					
						
							|  |  |  |         av_log(s1, AV_LOG_ERROR, "Wrong time base (%d)\n", ap->time_base.den); | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2006-03-13 09:47:37 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |     s->time_base = ap->time_base; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 23:51:19 +00:00
										 |  |  |     s->video_win.width = ap->width; | 
					
						
							|  |  |  |     s->video_win.height = ap->height; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-20 16:31:13 +00:00
										 |  |  |     st = av_new_stream(s1, 0); | 
					
						
							|  |  |  |     if (!st) | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |         return AVERROR(ENOMEM); | 
					
						
							| 
									
										
										
										
											2006-02-01 11:31:33 +00:00
										 |  |  |     av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-14 17:01:32 +00:00
										 |  |  |     video_fd = open(s1->filename, O_RDWR); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     if (video_fd < 0) { | 
					
						
							| 
									
										
										
										
											2007-11-19 07:54:04 +00:00
										 |  |  |         av_log(s1, AV_LOG_ERROR, "%s: %s\n", s1->filename, strerror(errno)); | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 09:07:51 +00:00
										 |  |  |     if (ioctl(video_fd, VIDIOCGCAP, &s->video_cap) < 0) { | 
					
						
							| 
									
										
										
										
											2007-11-19 07:54:04 +00:00
										 |  |  |         av_log(s1, AV_LOG_ERROR, "VIDIOCGCAP: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     if (!(s->video_cap.type & VID_TYPE_CAPTURE)) { | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |         av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:12:57 +00:00
										 |  |  |     /* no values set, autodetect them */ | 
					
						
							|  |  |  |     if (s->video_win.width <= 0 || s->video_win.height <= 0) { | 
					
						
							|  |  |  |         if (ioctl(video_fd, VIDIOCGWIN, &s->video_win, sizeof(s->video_win)) < 0) { | 
					
						
							|  |  |  |             av_log(s1, AV_LOG_ERROR, "VIDIOCGWIN: %s\n", strerror(errno)); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-28 14:41:19 +00:00
										 |  |  |     if(avcodec_check_dimensions(s1, s->video_win.width, s->video_win.height) < 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  |     desired_palette = -1; | 
					
						
							| 
									
										
										
										
											2006-06-28 12:18:22 +00:00
										 |  |  |     desired_depth = -1; | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |     for (j = 0; j < vformat_num; j++) { | 
					
						
							|  |  |  |         if (ap->pix_fmt == video_formats[j].pix_fmt) { | 
					
						
							|  |  |  |             desired_palette = video_formats[j].palette; | 
					
						
							|  |  |  |             desired_depth = video_formats[j].depth; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2003-06-25 10:21:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* set tv standard */ | 
					
						
							|  |  |  |     if (ap->standard && !ioctl(video_fd, VIDIOCGTUNER, &tuner)) { | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |         if (!strcasecmp(ap->standard, "pal")) | 
					
						
							|  |  |  |             tuner.mode = VIDEO_MODE_PAL; | 
					
						
							|  |  |  |         else if (!strcasecmp(ap->standard, "secam")) | 
					
						
							|  |  |  |             tuner.mode = VIDEO_MODE_SECAM; | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             tuner.mode = VIDEO_MODE_NTSC; | 
					
						
							|  |  |  |         ioctl(video_fd, VIDIOCSTUNER, &tuner); | 
					
						
							| 
									
										
										
										
											2003-06-25 10:21:45 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     /* unmute audio */ | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     audio.audio = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     ioctl(video_fd, VIDIOCGAUDIO, &audio); | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     memcpy(&s->audio_saved, &audio, sizeof(audio)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     audio.flags &= ~VIDEO_AUDIO_MUTE; | 
					
						
							|  |  |  |     ioctl(video_fd, VIDIOCSAUDIO, &audio); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-04 12:23:12 +00:00
										 |  |  |     ioctl(video_fd, VIDIOCGPICT, &pict); | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  |     printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n", | 
					
						
							|  |  |  |            pict.colour, | 
					
						
							|  |  |  |            pict.hue, | 
					
						
							|  |  |  |            pict.brightness, | 
					
						
							|  |  |  |            pict.contrast, | 
					
						
							|  |  |  |            pict.whiteness); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     /* try to choose a suitable video format */ | 
					
						
							|  |  |  |     pict.palette = desired_palette; | 
					
						
							| 
									
										
										
										
											2006-06-28 12:18:22 +00:00
										 |  |  |     pict.depth= desired_depth; | 
					
						
							| 
									
										
										
										
											2008-12-07 22:52:32 +00:00
										 |  |  |     if (desired_palette == -1 || ioctl(video_fd, VIDIOCSPICT, &pict) < 0) { | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |         for (j = 0; j < vformat_num; j++) { | 
					
						
							|  |  |  |             pict.palette = video_formats[j].palette; | 
					
						
							|  |  |  |             pict.depth = video_formats[j].depth; | 
					
						
							|  |  |  |             if (-1 != ioctl(video_fd, VIDIOCSPICT, &pict)) | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2006-05-04 12:23:12 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |         if (j >= vformat_num) | 
					
						
							|  |  |  |             goto fail1; | 
					
						
							| 
									
										
										
										
											2006-05-04 12:23:12 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 09:07:51 +00:00
										 |  |  |     if (ioctl(video_fd, VIDIOCGMBUF, &s->gb_buffers) < 0) { | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         /* try to use read based access */ | 
					
						
							|  |  |  |         int val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 23:51:19 +00:00
										 |  |  |         s->video_win.x = 0; | 
					
						
							|  |  |  |         s->video_win.y = 0; | 
					
						
							|  |  |  |         s->video_win.chromakey = -1; | 
					
						
							|  |  |  |         s->video_win.flags = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 11:40:07 +00:00
										 |  |  |         if (ioctl(video_fd, VIDIOCSWIN, s->video_win) < 0) { | 
					
						
							|  |  |  |             av_log(s1, AV_LOG_ERROR, "VIDIOCSWIN: %s\n", strerror(errno)); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         s->frame_format = pict.palette; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         val = 1; | 
					
						
							| 
									
										
										
										
											2008-12-26 09:12:12 +00:00
										 |  |  |         if (ioctl(video_fd, VIDIOCCAPTURE, &val) < 0) { | 
					
						
							|  |  |  |             av_log(s1, AV_LOG_ERROR, "VIDIOCCAPTURE: %s\n", strerror(errno)); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |         s->time_frame = av_gettime() * s->time_base.den / s->time_base.num; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         s->use_mmap = 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2008-12-26 09:07:51 +00:00
										 |  |  |         s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, 0); | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |         if ((unsigned char*)-1 == s->video_buf) { | 
					
						
							| 
									
										
										
										
											2008-12-26 09:07:51 +00:00
										 |  |  |             s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_PRIVATE, video_fd, 0); | 
					
						
							| 
									
										
										
										
											2006-12-28 00:32:06 +00:00
										 |  |  |             if ((unsigned char*)-1 == s->video_buf) { | 
					
						
							| 
									
										
										
										
											2007-11-19 07:54:04 +00:00
										 |  |  |                 av_log(s1, AV_LOG_ERROR, "mmap: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2006-12-28 00:32:06 +00:00
										 |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |         s->gb_frame = 0; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |         s->time_frame = av_gettime() * s->time_base.den / s->time_base.num; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         /* start to grab the first frame */ | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |         s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:51:19 +00:00
										 |  |  |         s->gb_buf.height = s->video_win.height; | 
					
						
							|  |  |  |         s->gb_buf.width = s->video_win.width; | 
					
						
							| 
									
										
										
										
											2006-05-04 12:23:12 +00:00
										 |  |  |         s->gb_buf.format = pict.palette; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-07 22:52:32 +00:00
										 |  |  |         if (ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) { | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |             if (errno != EAGAIN) { | 
					
						
							|  |  |  |             fail1: | 
					
						
							| 
									
										
										
										
											2008-12-27 11:44:56 +00:00
										 |  |  |                 av_log(s1, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2008-12-26 09:07:51 +00:00
										 |  |  |                 av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not receive any video signal\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |         for (j = 1; j < s->gb_buffers.frames; j++) { | 
					
						
							|  |  |  |           s->gb_buf.frame = j; | 
					
						
							|  |  |  |           ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |         s->frame_format = s->gb_buf.format; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |         s->use_mmap = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |     for (j = 0; j < vformat_num; j++) { | 
					
						
							|  |  |  |         if (s->frame_format == video_formats[j].palette) { | 
					
						
							| 
									
										
										
										
											2008-12-26 09:31:21 +00:00
										 |  |  |             s->frame_size = s->video_win.width * s->video_win.height * video_formats[j].depth / 8; | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  |             st->codec->pix_fmt = video_formats[j].pix_fmt; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-06-04 13:25:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (j >= vformat_num) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     s->fd = video_fd; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |     st->codec->codec_type = CODEC_TYPE_VIDEO; | 
					
						
							|  |  |  |     st->codec->codec_id = CODEC_ID_RAWVIDEO; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:51:19 +00:00
										 |  |  |     st->codec->width = s->video_win.width; | 
					
						
							|  |  |  |     st->codec->height = s->video_win.height; | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |     st->codec->time_base = s->time_base; | 
					
						
							| 
									
										
										
										
											2008-12-26 09:31:21 +00:00
										 |  |  |     st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8; | 
					
						
							| 
									
										
										
										
											2002-11-19 15:52:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  |  fail: | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     if (video_fd >= 0) | 
					
						
							|  |  |  |         close(video_fd); | 
					
						
							| 
									
										
										
										
											2007-07-19 15:23:32 +00:00
										 |  |  |     return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  | static int v4l_mm_read_picture(VideoData *s, uint8_t *buf) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *ptr; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-04-25 13:30:21 +00:00
										 |  |  |     while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 && | 
					
						
							|  |  |  |            (errno == EAGAIN || errno == EINTR)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame]; | 
					
						
							|  |  |  |     memcpy(buf, ptr, s->frame_size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  |     /* Setup to capture the next frame */ | 
					
						
							| 
									
										
										
										
											2004-04-25 13:30:21 +00:00
										 |  |  |     s->gb_buf.frame = s->gb_frame; | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) { | 
					
						
							| 
									
										
										
										
											2002-05-09 01:18:42 +00:00
										 |  |  |         if (errno == EAGAIN) | 
					
						
							| 
									
										
										
										
											2004-03-03 15:41:21 +00:00
										 |  |  |             av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n"); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:18:42 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2007-11-19 07:54:04 +00:00
										 |  |  |             av_log(NULL, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2007-07-19 15:23:32 +00:00
										 |  |  |         return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* This is now the grabbing frame */ | 
					
						
							| 
									
										
										
										
											2004-04-25 13:30:21 +00:00
										 |  |  |     s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames; | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     return s->frame_size; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  | static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     VideoData *s = s1->priv_data; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t curtime, delay; | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     struct timespec ts; | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Calculate the time of the next frame */ | 
					
						
							| 
									
										
										
										
											2006-12-06 23:46:11 +00:00
										 |  |  |     s->time_frame += INT64_C(1000000); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* wait based on the frame rate */ | 
					
						
							| 
									
										
										
										
											2002-11-19 15:52:29 +00:00
										 |  |  |     for(;;) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:05:25 +00:00
										 |  |  |         curtime = av_gettime(); | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |         delay = s->time_frame * s->time_base.num / s->time_base.den - curtime; | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  |         if (delay <= 0) { | 
					
						
							| 
									
										
										
										
											2008-12-17 23:43:56 +00:00
										 |  |  |             if (delay < INT64_C(-1000000) * s->time_base.num / s->time_base.den) { | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  |                 /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */ | 
					
						
							| 
									
										
										
										
											2006-12-06 23:46:11 +00:00
										 |  |  |                 s->time_frame += INT64_C(1000000); | 
					
						
							| 
									
										
										
										
											2002-04-08 20:58:56 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         ts.tv_sec = delay / 1000000; | 
					
						
							|  |  |  |         ts.tv_nsec = (delay % 1000000) * 1000; | 
					
						
							|  |  |  |         nanosleep(&ts, NULL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (av_new_packet(pkt, s->frame_size) < 0) | 
					
						
							| 
									
										
										
										
											2007-07-19 15:23:32 +00:00
										 |  |  |         return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-01 11:31:33 +00:00
										 |  |  |     pkt->pts = curtime; | 
					
						
							| 
									
										
										
										
											2002-11-19 15:52:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     /* read one frame */ | 
					
						
							| 
									
										
										
										
											2007-12-28 03:30:23 +00:00
										 |  |  |     if (s->use_mmap) { | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         return v4l_mm_read_picture(s, pkt->data); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         if (read(s->fd, pkt->data, pkt->size) != pkt->size) | 
					
						
							| 
									
										
										
										
											2007-07-19 15:23:32 +00:00
										 |  |  |             return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |         return s->frame_size; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  | static int grab_read_close(AVFormatContext *s1) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     VideoData *s = s1->priv_data; | 
					
						
							| 
									
										
										
										
											2002-09-01 08:54:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (s->use_mmap) | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |         munmap(s->video_buf, s->gb_buffers.size); | 
					
						
							| 
									
										
										
										
											2002-09-01 08:54:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 14:57:42 +00:00
										 |  |  |     /* mute audio. we must force it because the BTTV driver does not
 | 
					
						
							|  |  |  |        return its state correctly */ | 
					
						
							|  |  |  |     s->audio_saved.flags |= VIDEO_AUDIO_MUTE; | 
					
						
							|  |  |  |     ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved); | 
					
						
							| 
									
										
										
										
											2001-09-16 21:49:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  |     close(s->fd); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-05 18:29:58 +00:00
										 |  |  | AVInputFormat v4l_demuxer = { | 
					
						
							| 
									
										
										
										
											2003-01-22 22:40:52 +00:00
										 |  |  |     "video4linux", | 
					
						
							| 
									
										
										
										
											2008-12-26 11:23:50 +00:00
										 |  |  |     NULL_IF_CONFIG_SMALL("Video4Linux device grab"), | 
					
						
							| 
									
										
										
										
											2002-05-20 16:31:13 +00:00
										 |  |  |     sizeof(VideoData), | 
					
						
							| 
									
										
										
										
											2001-09-24 23:27:06 +00:00
										 |  |  |     NULL, | 
					
						
							|  |  |  |     grab_read_header, | 
					
						
							|  |  |  |     grab_read_packet, | 
					
						
							|  |  |  |     grab_read_close, | 
					
						
							| 
									
										
										
										
											2002-10-06 23:06:06 +00:00
										 |  |  |     .flags = AVFMT_NOFILE, | 
					
						
							| 
									
										
										
										
											2001-07-22 14:18:56 +00:00
										 |  |  | }; |