2 * Linux video grab interface
3 * Copyright (c) 2000,2001 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #undef __STRICT_ANSI__ //workaround due to broken kernel headers
26 #include "libavutil/rational.h"
27 #include "libavutil/imgutils.h"
28 #include "libavutil/log.h"
29 #include "libavutil/opt.h"
30 #include "libavformat/internal.h"
31 #include "libavcodec/dsputil.h"
34 #include <sys/ioctl.h>
37 #define _LINUX_TIME_H 1
38 #include <linux/videodev.h>
44 int frame_format
; /* see VIDEO_PALETTE_xxx */
49 struct video_capability video_cap
;
50 struct video_audio audio_saved
;
51 struct video_window video_win
;
53 struct video_mbuf gb_buffers
;
54 struct video_mmap gb_buf
;
62 enum AVPixelFormat pix_fmt
;
63 } video_formats
[] = {
64 {.palette
= VIDEO_PALETTE_YUV420P
, .depth
= 12, .pix_fmt
= AV_PIX_FMT_YUV420P
},
65 {.palette
= VIDEO_PALETTE_YUV422
, .depth
= 16, .pix_fmt
= AV_PIX_FMT_YUYV422
},
66 {.palette
= VIDEO_PALETTE_UYVY
, .depth
= 16, .pix_fmt
= AV_PIX_FMT_UYVY422
},
67 {.palette
= VIDEO_PALETTE_YUYV
, .depth
= 16, .pix_fmt
= AV_PIX_FMT_YUYV422
},
68 /* NOTE: v4l uses BGR24, not RGB24 */
69 {.palette
= VIDEO_PALETTE_RGB24
, .depth
= 24, .pix_fmt
= AV_PIX_FMT_BGR24
},
70 {.palette
= VIDEO_PALETTE_RGB565
, .depth
= 16, .pix_fmt
= AV_PIX_FMT_BGR565
},
71 {.palette
= VIDEO_PALETTE_GREY
, .depth
= 8, .pix_fmt
= AV_PIX_FMT_GRAY8
},
75 static int grab_read_header(AVFormatContext
*s1
, AVFormatParameters
*ap
)
77 VideoData
*s
= s1
->priv_data
;
80 int desired_palette
, desired_depth
;
81 struct video_tuner tuner
;
82 struct video_audio audio
;
83 struct video_picture pict
;
85 int vformat_num
= FF_ARRAY_ELEMS(video_formats
);
87 av_log(s1
, AV_LOG_WARNING
, "V4L input device is deprecated and will be removed in the next release.");
89 if (ap
->time_base
.den
<= 0) {
90 av_log(s1
, AV_LOG_ERROR
, "Wrong time base (%d)\n", ap
->time_base
.den
);
93 s
->time_base
= ap
->time_base
;
95 s
->video_win
.width
= ap
->width
;
96 s
->video_win
.height
= ap
->height
;
98 st
= avformat_new_stream(s1
, NULL
);
100 return AVERROR(ENOMEM
);
101 avpriv_set_pts_info(st
, 64, 1, 1000000); /* 64 bits pts in us */
103 video_fd
= open(s1
->filename
, O_RDWR
);
105 av_log(s1
, AV_LOG_ERROR
, "%s: %s\n", s1
->filename
, strerror(errno
));
109 if (ioctl(video_fd
, VIDIOCGCAP
, &s
->video_cap
) < 0) {
110 av_log(s1
, AV_LOG_ERROR
, "VIDIOCGCAP: %s\n", strerror(errno
));
114 if (!(s
->video_cap
.type
& VID_TYPE_CAPTURE
)) {
115 av_log(s1
, AV_LOG_ERROR
, "Fatal: grab device does not handle capture\n");
119 /* no values set, autodetect them */
120 if (s
->video_win
.width
<= 0 || s
->video_win
.height
<= 0) {
121 if (ioctl(video_fd
, VIDIOCGWIN
, &s
->video_win
, sizeof(s
->video_win
)) < 0) {
122 av_log(s1
, AV_LOG_ERROR
, "VIDIOCGWIN: %s\n", strerror(errno
));
127 if(av_image_check_size(s
->video_win
.width
, s
->video_win
.height
, 0, s1
) < 0)
130 desired_palette
= -1;
132 for (j
= 0; j
< vformat_num
; j
++) {
133 if (ap
->pix_fmt
== video_formats
[j
].pix_fmt
) {
134 desired_palette
= video_formats
[j
].palette
;
135 desired_depth
= video_formats
[j
].depth
;
140 /* set tv standard */
141 if (!ioctl(video_fd
, VIDIOCGTUNER
, &tuner
)) {
142 tuner
.mode
= s
->standard
;
143 ioctl(video_fd
, VIDIOCSTUNER
, &tuner
);
148 ioctl(video_fd
, VIDIOCGAUDIO
, &audio
);
149 memcpy(&s
->audio_saved
, &audio
, sizeof(audio
));
150 audio
.flags
&= ~VIDEO_AUDIO_MUTE
;
151 ioctl(video_fd
, VIDIOCSAUDIO
, &audio
);
153 ioctl(video_fd
, VIDIOCGPICT
, &pict
);
154 av_dlog(s1
, "v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
155 pict
.colour
, pict
.hue
, pict
.brightness
, pict
.contrast
, pict
.whiteness
);
156 /* try to choose a suitable video format */
157 pict
.palette
= desired_palette
;
158 pict
.depth
= desired_depth
;
159 if (desired_palette
== -1 || ioctl(video_fd
, VIDIOCSPICT
, &pict
) < 0) {
160 for (j
= 0; j
< vformat_num
; j
++) {
161 pict
.palette
= video_formats
[j
].palette
;
162 pict
.depth
= video_formats
[j
].depth
;
163 if (-1 != ioctl(video_fd
, VIDIOCSPICT
, &pict
))
166 if (j
>= vformat_num
)
170 if (ioctl(video_fd
, VIDIOCGMBUF
, &s
->gb_buffers
) < 0) {
171 /* try to use read based access */
176 s
->video_win
.chromakey
= -1;
177 s
->video_win
.flags
= 0;
179 if (ioctl(video_fd
, VIDIOCSWIN
, s
->video_win
) < 0) {
180 av_log(s1
, AV_LOG_ERROR
, "VIDIOCSWIN: %s\n", strerror(errno
));
184 s
->frame_format
= pict
.palette
;
187 if (ioctl(video_fd
, VIDIOCCAPTURE
, &val
) < 0) {
188 av_log(s1
, AV_LOG_ERROR
, "VIDIOCCAPTURE: %s\n", strerror(errno
));
192 s
->time_frame
= av_gettime() * s
->time_base
.den
/ s
->time_base
.num
;
195 s
->video_buf
= mmap(0, s
->gb_buffers
.size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, video_fd
, 0);
196 if ((unsigned char*)-1 == s
->video_buf
) {
197 s
->video_buf
= mmap(0, s
->gb_buffers
.size
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, video_fd
, 0);
198 if ((unsigned char*)-1 == s
->video_buf
) {
199 av_log(s1
, AV_LOG_ERROR
, "mmap: %s\n", strerror(errno
));
204 s
->time_frame
= av_gettime() * s
->time_base
.den
/ s
->time_base
.num
;
206 /* start to grab the first frame */
207 s
->gb_buf
.frame
= s
->gb_frame
% s
->gb_buffers
.frames
;
208 s
->gb_buf
.height
= s
->video_win
.height
;
209 s
->gb_buf
.width
= s
->video_win
.width
;
210 s
->gb_buf
.format
= pict
.palette
;
212 if (ioctl(video_fd
, VIDIOCMCAPTURE
, &s
->gb_buf
) < 0) {
213 if (errno
!= EAGAIN
) {
215 av_log(s1
, AV_LOG_ERROR
, "VIDIOCMCAPTURE: %s\n", strerror(errno
));
217 av_log(s1
, AV_LOG_ERROR
, "Fatal: grab device does not receive any video signal\n");
221 for (j
= 1; j
< s
->gb_buffers
.frames
; j
++) {
223 ioctl(video_fd
, VIDIOCMCAPTURE
, &s
->gb_buf
);
225 s
->frame_format
= s
->gb_buf
.format
;
229 for (j
= 0; j
< vformat_num
; j
++) {
230 if (s
->frame_format
== video_formats
[j
].palette
) {
231 s
->frame_size
= s
->video_win
.width
* s
->video_win
.height
* video_formats
[j
].depth
/ 8;
232 st
->codec
->pix_fmt
= video_formats
[j
].pix_fmt
;
237 if (j
>= vformat_num
)
242 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
243 st
->codec
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
244 st
->codec
->width
= s
->video_win
.width
;
245 st
->codec
->height
= s
->video_win
.height
;
246 st
->codec
->time_base
= s
->time_base
;
247 st
->codec
->bit_rate
= s
->frame_size
* 1/av_q2d(st
->codec
->time_base
) * 8;
256 static int v4l_mm_read_picture(VideoData
*s
, uint8_t *buf
)
260 while (ioctl(s
->fd
, VIDIOCSYNC
, &s
->gb_frame
) < 0 &&
261 (errno
== EAGAIN
|| errno
== EINTR
));
263 ptr
= s
->video_buf
+ s
->gb_buffers
.offsets
[s
->gb_frame
];
264 memcpy(buf
, ptr
, s
->frame_size
);
266 /* Setup to capture the next frame */
267 s
->gb_buf
.frame
= s
->gb_frame
;
268 if (ioctl(s
->fd
, VIDIOCMCAPTURE
, &s
->gb_buf
) < 0) {
270 av_log(NULL
, AV_LOG_ERROR
, "Cannot Sync\n");
272 av_log(NULL
, AV_LOG_ERROR
, "VIDIOCMCAPTURE: %s\n", strerror(errno
));
276 /* This is now the grabbing frame */
277 s
->gb_frame
= (s
->gb_frame
+ 1) % s
->gb_buffers
.frames
;
279 return s
->frame_size
;
282 static int grab_read_packet(AVFormatContext
*s1
, AVPacket
*pkt
)
284 VideoData
*s
= s1
->priv_data
;
285 int64_t curtime
, delay
;
288 /* Calculate the time of the next frame */
289 s
->time_frame
+= INT64_C(1000000);
291 /* wait based on the frame rate */
293 curtime
= av_gettime();
294 delay
= s
->time_frame
* s
->time_base
.num
/ s
->time_base
.den
- curtime
;
296 if (delay
< INT64_C(-1000000) * s
->time_base
.num
/ s
->time_base
.den
) {
297 /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */
298 s
->time_frame
+= INT64_C(1000000);
302 ts
.tv_sec
= delay
/ 1000000;
303 ts
.tv_nsec
= (delay
% 1000000) * 1000;
304 nanosleep(&ts
, NULL
);
307 if (av_new_packet(pkt
, s
->frame_size
) < 0)
314 return v4l_mm_read_picture(s
, pkt
->data
);
316 if (read(s
->fd
, pkt
->data
, pkt
->size
) != pkt
->size
)
318 return s
->frame_size
;
322 static int grab_read_close(AVFormatContext
*s1
)
324 VideoData
*s
= s1
->priv_data
;
327 munmap(s
->video_buf
, s
->gb_buffers
.size
);
329 /* mute audio. we must force it because the BTTV driver does not
330 return its state correctly */
331 s
->audio_saved
.flags
|= VIDEO_AUDIO_MUTE
;
332 ioctl(s
->fd
, VIDIOCSAUDIO
, &s
->audio_saved
);
338 static const AVOption options
[] = {
339 { "standard", "", offsetof(VideoData
, standard
), AV_OPT_TYPE_INT
, {.i64
= VIDEO_MODE_NTSC
}, VIDEO_MODE_PAL
, VIDEO_MODE_NTSC
, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
340 { "PAL", "", 0, AV_OPT_TYPE_CONST
, {.i64
= VIDEO_MODE_PAL
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
341 { "SECAM", "", 0, AV_OPT_TYPE_CONST
, {.i64
= VIDEO_MODE_SECAM
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
342 { "NTSC", "", 0, AV_OPT_TYPE_CONST
, {.i64
= VIDEO_MODE_NTSC
}, 0, 0, AV_OPT_FLAG_DECODING_PARAM
, "standard" },
346 static const AVClass v4l_class
= {
347 .class_name
= "V4L indev",
348 .item_name
= av_default_item_name
,
350 .version
= LIBAVUTIL_VERSION_INT
,
351 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
,
354 AVInputFormat ff_v4l_demuxer
= {
355 .name
= "video4linux,v4l",
356 .long_name
= NULL_IF_CONFIG_SMALL("Video4Linux device grab"),
357 .priv_data_size
= sizeof(VideoData
),
358 .read_header
= grab_read_header
,
359 .read_packet
= grab_read_packet
,
360 .read_close
= grab_read_close
,
361 .flags
= AVFMT_NOFILE
,
362 .priv_class
= &v4l_class
,