Libav
|
00001 /* 00002 * Linux video grab interface 00003 * Copyright (c) 2000,2001 Fabrice Bellard 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #undef __STRICT_ANSI__ //workaround due to broken kernel headers 00023 #include "config.h" 00024 #include "libavutil/rational.h" 00025 #include "libavformat/avformat.h" 00026 #include "libavcodec/dsputil.h" 00027 #include <unistd.h> 00028 #include <fcntl.h> 00029 #include <sys/ioctl.h> 00030 #include <sys/mman.h> 00031 #include <sys/time.h> 00032 #define _LINUX_TIME_H 1 00033 #include <linux/videodev.h> 00034 #include <time.h> 00035 #include <strings.h> 00036 00037 typedef struct { 00038 int fd; 00039 int frame_format; /* see VIDEO_PALETTE_xxx */ 00040 int use_mmap; 00041 AVRational time_base; 00042 int64_t time_frame; 00043 int frame_size; 00044 struct video_capability video_cap; 00045 struct video_audio audio_saved; 00046 struct video_window video_win; 00047 uint8_t *video_buf; 00048 struct video_mbuf gb_buffers; 00049 struct video_mmap gb_buf; 00050 int gb_frame; 00051 } VideoData; 00052 00053 static const struct { 00054 int palette; 00055 int depth; 00056 enum PixelFormat pix_fmt; 00057 } video_formats [] = { 00058 {.palette = VIDEO_PALETTE_YUV420P, .depth = 12, .pix_fmt = PIX_FMT_YUV420P }, 00059 {.palette = VIDEO_PALETTE_YUV422, .depth = 16, .pix_fmt = PIX_FMT_YUYV422 }, 00060 {.palette = VIDEO_PALETTE_UYVY, .depth = 16, .pix_fmt = PIX_FMT_UYVY422 }, 00061 {.palette = VIDEO_PALETTE_YUYV, .depth = 16, .pix_fmt = PIX_FMT_YUYV422 }, 00062 /* NOTE: v4l uses BGR24, not RGB24 */ 00063 {.palette = VIDEO_PALETTE_RGB24, .depth = 24, .pix_fmt = PIX_FMT_BGR24 }, 00064 {.palette = VIDEO_PALETTE_RGB565, .depth = 16, .pix_fmt = PIX_FMT_BGR565 }, 00065 {.palette = VIDEO_PALETTE_GREY, .depth = 8, .pix_fmt = PIX_FMT_GRAY8 }, 00066 }; 00067 00068 00069 static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) 00070 { 00071 VideoData *s = s1->priv_data; 00072 AVStream *st; 00073 int video_fd; 00074 int desired_palette, desired_depth; 00075 struct video_tuner tuner; 00076 struct video_audio audio; 00077 struct video_picture pict; 00078 int j; 00079 int vformat_num = FF_ARRAY_ELEMS(video_formats); 00080 00081 if (ap->time_base.den <= 0) { 00082 av_log(s1, AV_LOG_ERROR, "Wrong time base (%d)\n", ap->time_base.den); 00083 return -1; 00084 } 00085 s->time_base = ap->time_base; 00086 00087 s->video_win.width = ap->width; 00088 s->video_win.height = ap->height; 00089 00090 st = av_new_stream(s1, 0); 00091 if (!st) 00092 return AVERROR(ENOMEM); 00093 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ 00094 00095 video_fd = open(s1->filename, O_RDWR); 00096 if (video_fd < 0) { 00097 av_log(s1, AV_LOG_ERROR, "%s: %s\n", s1->filename, strerror(errno)); 00098 goto fail; 00099 } 00100 00101 if (ioctl(video_fd, VIDIOCGCAP, &s->video_cap) < 0) { 00102 av_log(s1, AV_LOG_ERROR, "VIDIOCGCAP: %s\n", strerror(errno)); 00103 goto fail; 00104 } 00105 00106 if (!(s->video_cap.type & VID_TYPE_CAPTURE)) { 00107 av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n"); 00108 goto fail; 00109 } 00110 00111 /* no values set, autodetect them */ 00112 if (s->video_win.width <= 0 || s->video_win.height <= 0) { 00113 if (ioctl(video_fd, VIDIOCGWIN, &s->video_win, sizeof(s->video_win)) < 0) { 00114 av_log(s1, AV_LOG_ERROR, "VIDIOCGWIN: %s\n", strerror(errno)); 00115 goto fail; 00116 } 00117 } 00118 00119 if(avcodec_check_dimensions(s1, s->video_win.width, s->video_win.height) < 0) 00120 return -1; 00121 00122 desired_palette = -1; 00123 desired_depth = -1; 00124 for (j = 0; j < vformat_num; j++) { 00125 if (ap->pix_fmt == video_formats[j].pix_fmt) { 00126 desired_palette = video_formats[j].palette; 00127 desired_depth = video_formats[j].depth; 00128 break; 00129 } 00130 } 00131 00132 /* set tv standard */ 00133 if (ap->standard && !ioctl(video_fd, VIDIOCGTUNER, &tuner)) { 00134 if (!strcasecmp(ap->standard, "pal")) 00135 tuner.mode = VIDEO_MODE_PAL; 00136 else if (!strcasecmp(ap->standard, "secam")) 00137 tuner.mode = VIDEO_MODE_SECAM; 00138 else 00139 tuner.mode = VIDEO_MODE_NTSC; 00140 ioctl(video_fd, VIDIOCSTUNER, &tuner); 00141 } 00142 00143 /* unmute audio */ 00144 audio.audio = 0; 00145 ioctl(video_fd, VIDIOCGAUDIO, &audio); 00146 memcpy(&s->audio_saved, &audio, sizeof(audio)); 00147 audio.flags &= ~VIDEO_AUDIO_MUTE; 00148 ioctl(video_fd, VIDIOCSAUDIO, &audio); 00149 00150 ioctl(video_fd, VIDIOCGPICT, &pict); 00151 #if 0 00152 printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n", 00153 pict.colour, 00154 pict.hue, 00155 pict.brightness, 00156 pict.contrast, 00157 pict.whiteness); 00158 #endif 00159 /* try to choose a suitable video format */ 00160 pict.palette = desired_palette; 00161 pict.depth= desired_depth; 00162 if (desired_palette == -1 || ioctl(video_fd, VIDIOCSPICT, &pict) < 0) { 00163 for (j = 0; j < vformat_num; j++) { 00164 pict.palette = video_formats[j].palette; 00165 pict.depth = video_formats[j].depth; 00166 if (-1 != ioctl(video_fd, VIDIOCSPICT, &pict)) 00167 break; 00168 } 00169 if (j >= vformat_num) 00170 goto fail1; 00171 } 00172 00173 if (ioctl(video_fd, VIDIOCGMBUF, &s->gb_buffers) < 0) { 00174 /* try to use read based access */ 00175 int val; 00176 00177 s->video_win.x = 0; 00178 s->video_win.y = 0; 00179 s->video_win.chromakey = -1; 00180 s->video_win.flags = 0; 00181 00182 if (ioctl(video_fd, VIDIOCSWIN, s->video_win) < 0) { 00183 av_log(s1, AV_LOG_ERROR, "VIDIOCSWIN: %s\n", strerror(errno)); 00184 goto fail; 00185 } 00186 00187 s->frame_format = pict.palette; 00188 00189 val = 1; 00190 if (ioctl(video_fd, VIDIOCCAPTURE, &val) < 0) { 00191 av_log(s1, AV_LOG_ERROR, "VIDIOCCAPTURE: %s\n", strerror(errno)); 00192 goto fail; 00193 } 00194 00195 s->time_frame = av_gettime() * s->time_base.den / s->time_base.num; 00196 s->use_mmap = 0; 00197 } else { 00198 s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, 0); 00199 if ((unsigned char*)-1 == s->video_buf) { 00200 s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_PRIVATE, video_fd, 0); 00201 if ((unsigned char*)-1 == s->video_buf) { 00202 av_log(s1, AV_LOG_ERROR, "mmap: %s\n", strerror(errno)); 00203 goto fail; 00204 } 00205 } 00206 s->gb_frame = 0; 00207 s->time_frame = av_gettime() * s->time_base.den / s->time_base.num; 00208 00209 /* start to grab the first frame */ 00210 s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames; 00211 s->gb_buf.height = s->video_win.height; 00212 s->gb_buf.width = s->video_win.width; 00213 s->gb_buf.format = pict.palette; 00214 00215 if (ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) { 00216 if (errno != EAGAIN) { 00217 fail1: 00218 av_log(s1, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno)); 00219 } else { 00220 av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not receive any video signal\n"); 00221 } 00222 goto fail; 00223 } 00224 for (j = 1; j < s->gb_buffers.frames; j++) { 00225 s->gb_buf.frame = j; 00226 ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf); 00227 } 00228 s->frame_format = s->gb_buf.format; 00229 s->use_mmap = 1; 00230 } 00231 00232 for (j = 0; j < vformat_num; j++) { 00233 if (s->frame_format == video_formats[j].palette) { 00234 s->frame_size = s->video_win.width * s->video_win.height * video_formats[j].depth / 8; 00235 st->codec->pix_fmt = video_formats[j].pix_fmt; 00236 break; 00237 } 00238 } 00239 00240 if (j >= vformat_num) 00241 goto fail; 00242 00243 s->fd = video_fd; 00244 00245 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00246 st->codec->codec_id = CODEC_ID_RAWVIDEO; 00247 st->codec->width = s->video_win.width; 00248 st->codec->height = s->video_win.height; 00249 st->codec->time_base = s->time_base; 00250 st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8; 00251 00252 return 0; 00253 fail: 00254 if (video_fd >= 0) 00255 close(video_fd); 00256 return AVERROR(EIO); 00257 } 00258 00259 static int v4l_mm_read_picture(VideoData *s, uint8_t *buf) 00260 { 00261 uint8_t *ptr; 00262 00263 while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 && 00264 (errno == EAGAIN || errno == EINTR)); 00265 00266 ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame]; 00267 memcpy(buf, ptr, s->frame_size); 00268 00269 /* Setup to capture the next frame */ 00270 s->gb_buf.frame = s->gb_frame; 00271 if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) { 00272 if (errno == EAGAIN) 00273 av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n"); 00274 else 00275 av_log(NULL, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno)); 00276 return AVERROR(EIO); 00277 } 00278 00279 /* This is now the grabbing frame */ 00280 s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames; 00281 00282 return s->frame_size; 00283 } 00284 00285 static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) 00286 { 00287 VideoData *s = s1->priv_data; 00288 int64_t curtime, delay; 00289 struct timespec ts; 00290 00291 /* Calculate the time of the next frame */ 00292 s->time_frame += INT64_C(1000000); 00293 00294 /* wait based on the frame rate */ 00295 for(;;) { 00296 curtime = av_gettime(); 00297 delay = s->time_frame * s->time_base.num / s->time_base.den - curtime; 00298 if (delay <= 0) { 00299 if (delay < INT64_C(-1000000) * s->time_base.num / s->time_base.den) { 00300 /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */ 00301 s->time_frame += INT64_C(1000000); 00302 } 00303 break; 00304 } 00305 ts.tv_sec = delay / 1000000; 00306 ts.tv_nsec = (delay % 1000000) * 1000; 00307 nanosleep(&ts, NULL); 00308 } 00309 00310 if (av_new_packet(pkt, s->frame_size) < 0) 00311 return AVERROR(EIO); 00312 00313 pkt->pts = curtime; 00314 00315 /* read one frame */ 00316 if (s->use_mmap) { 00317 return v4l_mm_read_picture(s, pkt->data); 00318 } else { 00319 if (read(s->fd, pkt->data, pkt->size) != pkt->size) 00320 return AVERROR(EIO); 00321 return s->frame_size; 00322 } 00323 } 00324 00325 static int grab_read_close(AVFormatContext *s1) 00326 { 00327 VideoData *s = s1->priv_data; 00328 00329 if (s->use_mmap) 00330 munmap(s->video_buf, s->gb_buffers.size); 00331 00332 /* mute audio. we must force it because the BTTV driver does not 00333 return its state correctly */ 00334 s->audio_saved.flags |= VIDEO_AUDIO_MUTE; 00335 ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved); 00336 00337 close(s->fd); 00338 return 0; 00339 } 00340 00341 AVInputFormat v4l_demuxer = { 00342 "video4linux", 00343 NULL_IF_CONFIG_SMALL("Video4Linux device grab"), 00344 sizeof(VideoData), 00345 NULL, 00346 grab_read_header, 00347 grab_read_packet, 00348 grab_read_close, 00349 .flags = AVFMT_NOFILE, 00350 };