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
22 #undef __STRICT_ANSI__ //workaround due to broken kernel headers
24 #include "libavutil/rational.h"
25 #include "libavformat/avformat.h"
26 #include "libavcodec/dsputil.h"
29 #include <sys/ioctl.h>
32 #define _LINUX_TIME_H 1
33 #include <linux/videodev.h>
39 int frame_format
; /* see VIDEO_PALETTE_xxx */
44 struct video_capability video_cap
;
45 struct video_audio audio_saved
;
46 struct video_window video_win
;
48 struct video_mbuf gb_buffers
;
49 struct video_mmap gb_buf
;
56 enum PixelFormat pix_fmt
;
57 } video_formats
[] = {
58 {.palette
= VIDEO_PALETTE_YUV420P
, .depth
= 12, .pix_fmt
= PIX_FMT_YUV420P
},
59 {.palette
= VIDEO_PALETTE_YUV422
, .depth
= 16, .pix_fmt
= PIX_FMT_YUYV422
},
60 {.palette
= VIDEO_PALETTE_UYVY
, .depth
= 16, .pix_fmt
= PIX_FMT_UYVY422
},
61 {.palette
= VIDEO_PALETTE_YUYV
, .depth
= 16, .pix_fmt
= PIX_FMT_YUYV422
},
62 /* NOTE: v4l uses BGR24, not RGB24 */
63 {.palette
= VIDEO_PALETTE_RGB24
, .depth
= 24, .pix_fmt
= PIX_FMT_BGR24
},
64 {.palette
= VIDEO_PALETTE_RGB565
, .depth
= 16, .pix_fmt
= PIX_FMT_BGR565
},
65 {.palette
= VIDEO_PALETTE_GREY
, .depth
= 8, .pix_fmt
= PIX_FMT_GRAY8
},
69 static int grab_read_header(AVFormatContext
*s1
, AVFormatParameters
*ap
)
71 VideoData
*s
= s1
->priv_data
;
74 int desired_palette
, desired_depth
;
75 struct video_tuner tuner
;
76 struct video_audio audio
;
77 struct video_picture pict
;
79 int vformat_num
= FF_ARRAY_ELEMS(video_formats
);
81 if (ap
->time_base
.den
<= 0) {
82 av_log(s1
, AV_LOG_ERROR
, "Wrong time base (%d)\n", ap
->time_base
.den
);
85 s
->time_base
= ap
->time_base
;
87 s
->video_win
.width
= ap
->width
;
88 s
->video_win
.height
= ap
->height
;
90 st
= av_new_stream(s1
, 0);
92 return AVERROR(ENOMEM
);
93 av_set_pts_info(st
, 64, 1, 1000000); /* 64 bits pts in us */
95 video_fd
= open(s1
->filename
, O_RDWR
);
97 av_log(s1
, AV_LOG_ERROR
, "%s: %s\n", s1
->filename
, strerror(errno
));
101 if (ioctl(video_fd
, VIDIOCGCAP
, &s
->video_cap
) < 0) {
102 av_log(s1
, AV_LOG_ERROR
, "VIDIOCGCAP: %s\n", strerror(errno
));
106 if (!(s
->video_cap
.type
& VID_TYPE_CAPTURE
)) {
107 av_log(s1
, AV_LOG_ERROR
, "Fatal: grab device does not handle capture\n");
111 /* no values set, autodetect them */
112 if (s
->video_win
.width
<= 0 || s
->video_win
.height
<= 0) {
113 if (ioctl(video_fd
, VIDIOCGWIN
, &s
->video_win
, sizeof(s
->video_win
)) < 0) {
114 av_log(s1
, AV_LOG_ERROR
, "VIDIOCGWIN: %s\n", strerror(errno
));
119 if(avcodec_check_dimensions(s1
, s
->video_win
.width
, s
->video_win
.height
) < 0)
122 desired_palette
= -1;
124 for (j
= 0; j
< vformat_num
; j
++) {
125 if (ap
->pix_fmt
== video_formats
[j
].pix_fmt
) {
126 desired_palette
= video_formats
[j
].palette
;
127 desired_depth
= video_formats
[j
].depth
;
132 /* set tv standard */
133 if (ap
->standard
&& !ioctl(video_fd
, VIDIOCGTUNER
, &tuner
)) {
134 if (!strcasecmp(ap
->standard
, "pal"))
135 tuner
.mode
= VIDEO_MODE_PAL
;
136 else if (!strcasecmp(ap
->standard
, "secam"))
137 tuner
.mode
= VIDEO_MODE_SECAM
;
139 tuner
.mode
= VIDEO_MODE_NTSC
;
140 ioctl(video_fd
, VIDIOCSTUNER
, &tuner
);
145 ioctl(video_fd
, VIDIOCGAUDIO
, &audio
);
146 memcpy(&s
->audio_saved
, &audio
, sizeof(audio
));
147 audio
.flags
&= ~VIDEO_AUDIO_MUTE
;
148 ioctl(video_fd
, VIDIOCSAUDIO
, &audio
);
150 ioctl(video_fd
, VIDIOCGPICT
, &pict
);
152 printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
159 /* try to choose a suitable video format */
160 pict
.palette
= desired_palette
;
161 pict
.depth
= desired_depth
;
162 if (desired_palette
== -1 || ioctl(video_fd
, VIDIOCSPICT
, &pict
) < 0) {
163 for (j
= 0; j
< vformat_num
; j
++) {
164 pict
.palette
= video_formats
[j
].palette
;
165 pict
.depth
= video_formats
[j
].depth
;
166 if (-1 != ioctl(video_fd
, VIDIOCSPICT
, &pict
))
169 if (j
>= vformat_num
)
173 if (ioctl(video_fd
, VIDIOCGMBUF
, &s
->gb_buffers
) < 0) {
174 /* try to use read based access */
179 s
->video_win
.chromakey
= -1;
180 s
->video_win
.flags
= 0;
182 if (ioctl(video_fd
, VIDIOCSWIN
, s
->video_win
) < 0) {
183 av_log(s1
, AV_LOG_ERROR
, "VIDIOCSWIN: %s\n", strerror(errno
));
187 s
->frame_format
= pict
.palette
;
190 if (ioctl(video_fd
, VIDIOCCAPTURE
, &val
) < 0) {
191 av_log(s1
, AV_LOG_ERROR
, "VIDIOCCAPTURE: %s\n", strerror(errno
));
195 s
->time_frame
= av_gettime() * s
->time_base
.den
/ s
->time_base
.num
;
198 s
->video_buf
= mmap(0, s
->gb_buffers
.size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, video_fd
, 0);
199 if ((unsigned char*)-1 == s
->video_buf
) {
200 s
->video_buf
= mmap(0, s
->gb_buffers
.size
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, video_fd
, 0);
201 if ((unsigned char*)-1 == s
->video_buf
) {
202 av_log(s1
, AV_LOG_ERROR
, "mmap: %s\n", strerror(errno
));
207 s
->time_frame
= av_gettime() * s
->time_base
.den
/ s
->time_base
.num
;
209 /* start to grab the first frame */
210 s
->gb_buf
.frame
= s
->gb_frame
% s
->gb_buffers
.frames
;
211 s
->gb_buf
.height
= s
->video_win
.height
;
212 s
->gb_buf
.width
= s
->video_win
.width
;
213 s
->gb_buf
.format
= pict
.palette
;
215 if (ioctl(video_fd
, VIDIOCMCAPTURE
, &s
->gb_buf
) < 0) {
216 if (errno
!= EAGAIN
) {
218 av_log(s1
, AV_LOG_ERROR
, "VIDIOCMCAPTURE: %s\n", strerror(errno
));
220 av_log(s1
, AV_LOG_ERROR
, "Fatal: grab device does not receive any video signal\n");
224 for (j
= 1; j
< s
->gb_buffers
.frames
; j
++) {
226 ioctl(video_fd
, VIDIOCMCAPTURE
, &s
->gb_buf
);
228 s
->frame_format
= s
->gb_buf
.format
;
232 for (j
= 0; j
< vformat_num
; j
++) {
233 if (s
->frame_format
== video_formats
[j
].palette
) {
234 s
->frame_size
= s
->video_win
.width
* s
->video_win
.height
* video_formats
[j
].depth
/ 8;
235 st
->codec
->pix_fmt
= video_formats
[j
].pix_fmt
;
240 if (j
>= vformat_num
)
245 st
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
246 st
->codec
->codec_id
= CODEC_ID_RAWVIDEO
;
247 st
->codec
->width
= s
->video_win
.width
;
248 st
->codec
->height
= s
->video_win
.height
;
249 st
->codec
->time_base
= s
->time_base
;
250 st
->codec
->bit_rate
= s
->frame_size
* 1/av_q2d(st
->codec
->time_base
) * 8;
259 static int v4l_mm_read_picture(VideoData
*s
, uint8_t *buf
)
263 while (ioctl(s
->fd
, VIDIOCSYNC
, &s
->gb_frame
) < 0 &&
264 (errno
== EAGAIN
|| errno
== EINTR
));
266 ptr
= s
->video_buf
+ s
->gb_buffers
.offsets
[s
->gb_frame
];
267 memcpy(buf
, ptr
, s
->frame_size
);
269 /* Setup to capture the next frame */
270 s
->gb_buf
.frame
= s
->gb_frame
;
271 if (ioctl(s
->fd
, VIDIOCMCAPTURE
, &s
->gb_buf
) < 0) {
273 av_log(NULL
, AV_LOG_ERROR
, "Cannot Sync\n");
275 av_log(NULL
, AV_LOG_ERROR
, "VIDIOCMCAPTURE: %s\n", strerror(errno
));
279 /* This is now the grabbing frame */
280 s
->gb_frame
= (s
->gb_frame
+ 1) % s
->gb_buffers
.frames
;
282 return s
->frame_size
;
285 static int grab_read_packet(AVFormatContext
*s1
, AVPacket
*pkt
)
287 VideoData
*s
= s1
->priv_data
;
288 int64_t curtime
, delay
;
291 /* Calculate the time of the next frame */
292 s
->time_frame
+= INT64_C(1000000);
294 /* wait based on the frame rate */
296 curtime
= av_gettime();
297 delay
= s
->time_frame
* s
->time_base
.num
/ s
->time_base
.den
- curtime
;
299 if (delay
< INT64_C(-1000000) * s
->time_base
.num
/ s
->time_base
.den
) {
300 /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */
301 s
->time_frame
+= INT64_C(1000000);
305 ts
.tv_sec
= delay
/ 1000000;
306 ts
.tv_nsec
= (delay
% 1000000) * 1000;
307 nanosleep(&ts
, NULL
);
310 if (av_new_packet(pkt
, s
->frame_size
) < 0)
317 return v4l_mm_read_picture(s
, pkt
->data
);
319 if (read(s
->fd
, pkt
->data
, pkt
->size
) != pkt
->size
)
321 return s
->frame_size
;
325 static int grab_read_close(AVFormatContext
*s1
)
327 VideoData
*s
= s1
->priv_data
;
330 munmap(s
->video_buf
, s
->gb_buffers
.size
);
332 /* mute audio. we must force it because the BTTV driver does not
333 return its state correctly */
334 s
->audio_saved
.flags
|= VIDEO_AUDIO_MUTE
;
335 ioctl(s
->fd
, VIDIOCSAUDIO
, &s
->audio_saved
);
341 AVInputFormat v4l_demuxer
= {
343 NULL_IF_CONFIG_SMALL("Video4Linux device grab"),
349 .flags
= AVFMT_NOFILE
,