2 * Video4Linux2 grab interface
3 * Copyright (c) 2000,2001 Fabrice Bellard.
4 * Copyright (c) 2006 Luca Abeni.
6 * Part of this file is based on the V4L2 video capture example
7 * (http://v4l2spec.bytesex.org/v4l2spec/capture.c)
9 * Thanks to Michael Niedermayer for providing the mapping between
10 * V4L2_PIX_FMT_* and PIX_FMT_*
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <sys/ioctl.h>
33 #define _LINUX_TIME_H 1
34 #include <linux/videodev.h>
37 static const int desired_video_buffers
= 256;
47 int frame_format
; /* V4L2_PIX_FMT_* */
48 enum io_method io_method
;
57 unsigned int *buf_len
;
61 enum PixelFormat ff_fmt
;
65 static struct fmt_map fmt_conversion_table
[] = {
67 .ff_fmt
= PIX_FMT_YUV420P
,
68 .v4l2_fmt
= V4L2_PIX_FMT_YUV420
,
71 .ff_fmt
= PIX_FMT_YUV422P
,
72 .v4l2_fmt
= V4L2_PIX_FMT_YUV422P
,
75 .ff_fmt
= PIX_FMT_YUV422
,
76 .v4l2_fmt
= V4L2_PIX_FMT_YUYV
,
79 .ff_fmt
= PIX_FMT_UYVY422
,
80 .v4l2_fmt
= V4L2_PIX_FMT_UYVY
,
83 .ff_fmt
= PIX_FMT_YUV411P
,
84 .v4l2_fmt
= V4L2_PIX_FMT_YUV411P
,
87 .ff_fmt
= PIX_FMT_YUV410P
,
88 .v4l2_fmt
= V4L2_PIX_FMT_YUV410
,
91 .ff_fmt
= PIX_FMT_BGR24
,
92 .v4l2_fmt
= V4L2_PIX_FMT_BGR24
,
95 .ff_fmt
= PIX_FMT_RGB24
,
96 .v4l2_fmt
= V4L2_PIX_FMT_RGB24
,
100 .ff_fmt = PIX_FMT_RGBA32,
101 .v4l2_fmt = V4L2_PIX_FMT_BGR32,
105 .ff_fmt
= PIX_FMT_GRAY8
,
106 .v4l2_fmt
= V4L2_PIX_FMT_GREY
,
110 static int device_open(const char *devname
, uint32_t *capabilities
)
112 struct v4l2_capability cap
;
116 fd
= open(devname
, O_RDWR
/*| O_NONBLOCK*/, 0);
118 av_log(NULL
, AV_LOG_ERROR
, "Cannot open video device %s : %s\n",
119 devname
, strerror(errno
));
124 res
= ioctl(fd
, VIDIOC_QUERYCAP
, &cap
);
126 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_QUERYCAP): %s\n",
131 if ((cap
.capabilities
& V4L2_CAP_VIDEO_CAPTURE
) == 0) {
132 av_log(NULL
, AV_LOG_ERROR
, "Not a video capture device\n");
136 *capabilities
= cap
.capabilities
;
141 static int device_init(int fd
, int width
, int height
, int pix_fmt
)
143 struct v4l2_format fmt
;
145 memset(&fmt
, 0, sizeof(struct v4l2_format
));
146 fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
147 fmt
.fmt
.pix
.width
= width
;
148 fmt
.fmt
.pix
.height
= height
;
149 fmt
.fmt
.pix
.pixelformat
= pix_fmt
;
150 fmt
.fmt
.pix
.field
= V4L2_FIELD_INTERLACED
;
151 return ioctl (fd
, VIDIOC_S_FMT
, &fmt
);
154 static int first_field(int fd
)
159 res
= ioctl(fd
, VIDIOC_G_STD
, &std
);
163 if (std
& V4L2_STD_NTSC
) {
170 static uint32_t fmt_ff2v4l(enum PixelFormat pix_fmt
)
174 for (i
= 0; i
< sizeof(fmt_conversion_table
) / sizeof(struct fmt_map
); i
++) {
175 if (fmt_conversion_table
[i
].ff_fmt
== pix_fmt
) {
176 return fmt_conversion_table
[i
].v4l2_fmt
;
183 static enum PixelFormat
fmt_v4l2ff(uint32_t pix_fmt
)
187 for (i
= 0; i
< sizeof(fmt_conversion_table
) / sizeof(struct fmt_map
); i
++) {
188 if (fmt_conversion_table
[i
].v4l2_fmt
== pix_fmt
) {
189 return fmt_conversion_table
[i
].ff_fmt
;
196 static int mmap_init(struct video_data
*s
)
198 struct v4l2_requestbuffers req
;
201 memset(&req
, 0, sizeof(struct v4l2_requestbuffers
));
202 req
.count
= desired_video_buffers
;
203 req
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
204 req
.memory
= V4L2_MEMORY_MMAP
;
205 res
= ioctl (s
->fd
, VIDIOC_REQBUFS
, &req
);
207 if (errno
== EINVAL
) {
208 av_log(NULL
, AV_LOG_ERROR
, "Device does not support mmap\n");
210 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_REQBUFS)\n");
217 av_log(NULL
, AV_LOG_ERROR
, "Insufficient buffer memory\n");
221 s
->buffers
= req
.count
;
222 s
->buf_start
= av_malloc(sizeof(void *) * s
->buffers
);
223 if (s
->buf_start
== NULL
) {
224 av_log(NULL
, AV_LOG_ERROR
, "Cannot allocate buffer pointers\n");
228 s
->buf_len
= av_malloc(sizeof(unsigned int) * s
->buffers
);
229 if (s
->buf_len
== NULL
) {
230 av_log(NULL
, AV_LOG_ERROR
, "Cannot allocate buffer sizes\n");
231 av_free(s
->buf_start
);
236 for (i
= 0; i
< req
.count
; i
++) {
237 struct v4l2_buffer buf
;
239 memset(&buf
, 0, sizeof(struct v4l2_buffer
));
240 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
241 buf
.memory
= V4L2_MEMORY_MMAP
;
243 res
= ioctl (s
->fd
, VIDIOC_QUERYBUF
, &buf
);
245 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_QUERYBUF)\n");
250 s
->buf_len
[i
] = buf
.length
;
251 if (s
->buf_len
[i
] < s
->frame_size
) {
252 av_log(NULL
, AV_LOG_ERROR
, "Buffer len [%d] = %d != %d\n", i
, s
->buf_len
[i
], s
->frame_size
);
256 s
->buf_start
[i
] = mmap (NULL
, buf
.length
,
257 PROT_READ
| PROT_WRITE
, MAP_SHARED
, s
->fd
, buf
.m
.offset
);
258 if (s
->buf_start
[i
] == MAP_FAILED
) {
259 av_log(NULL
, AV_LOG_ERROR
, "mmap: %s\n", strerror(errno
));
268 static int read_init(struct video_data
*s
)
273 static int mmap_read_frame(struct video_data
*s
, void *frame
, int64_t *ts
)
275 struct v4l2_buffer buf
;
278 memset(&buf
, 0, sizeof(struct v4l2_buffer
));
279 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
280 buf
.memory
= V4L2_MEMORY_MMAP
;
282 /* FIXME: Some special treatment might be needed in case of loss of signal... */
283 while ((res
= ioctl(s
->fd
, VIDIOC_DQBUF
, &buf
)) < 0 &&
284 ((errno
== EAGAIN
) || (errno
== EINTR
)));
286 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_DQBUF): %s\n", strerror(errno
));
290 assert (buf
.index
< s
->buffers
);
291 assert(buf
.bytesused
== s
->frame_size
);
292 /* Image is at s->buff_start[buf.index] */
293 memcpy(frame
, s
->buf_start
[buf
.index
], buf
.bytesused
);
294 *ts
= buf
.timestamp
.tv_sec
* int64_t_C(1000000) + buf
.timestamp
.tv_usec
;
296 res
= ioctl (s
->fd
, VIDIOC_QBUF
, &buf
);
298 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_QBUF)\n");
303 return s
->buf_len
[buf
.index
];
306 static int read_frame(struct video_data
*s
, void *frame
, int64_t *ts
)
311 static int mmap_start(struct video_data
*s
)
313 enum v4l2_buf_type type
;
316 for (i
= 0; i
< s
->buffers
; i
++) {
317 struct v4l2_buffer buf
;
319 memset(&buf
, 0, sizeof(struct v4l2_buffer
));
320 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
321 buf
.memory
= V4L2_MEMORY_MMAP
;
324 res
= ioctl (s
->fd
, VIDIOC_QBUF
, &buf
);
326 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_QBUF): %s\n", strerror(errno
));
332 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
333 res
= ioctl (s
->fd
, VIDIOC_STREAMON
, &type
);
335 av_log(NULL
, AV_LOG_ERROR
, "ioctl(VIDIOC_STREAMON): %s\n", strerror(errno
));
343 static void mmap_close(struct video_data
*s
)
345 enum v4l2_buf_type type
;
348 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
349 /* We do not check for the result, because we could
350 * not do anything about it anyway...
352 ioctl(s
->fd
, VIDIOC_STREAMOFF
, &type
);
353 for (i
= 0; i
< s
->buffers
; i
++) {
354 munmap(s
->buf_start
[i
], s
->buf_len
[i
]);
356 av_free(s
->buf_start
);
360 static int v4l2_read_header(AVFormatContext
*s1
, AVFormatParameters
*ap
)
362 struct video_data
*s
= s1
->priv_data
;
365 int res
, frame_rate
, frame_rate_base
;
366 uint32_t desired_format
, capabilities
;
367 const char *video_device
;
369 if (!ap
|| ap
->width
<= 0 || ap
->height
<= 0 || ap
->time_base
.den
<= 0) {
370 av_log(s1
, AV_LOG_ERROR
, "Missing/Wrong parameters\n");
377 frame_rate
= ap
->time_base
.den
;
378 frame_rate_base
= ap
->time_base
.num
;
380 if((unsigned)width
> 32767 || (unsigned)height
> 32767) {
381 av_log(s1
, AV_LOG_ERROR
, "Wrong size %dx%d\n", width
, height
);
386 st
= av_new_stream(s1
, 0);
390 av_set_pts_info(st
, 64, 1, 1000000); /* 64 bits pts in us */
394 s
->frame_rate
= frame_rate
;
395 s
->frame_rate_base
= frame_rate_base
;
397 video_device
= ap
->device
;
399 video_device
= "/dev/video";
402 s
->fd
= device_open(video_device
, &capabilities
);
408 av_log(s1
, AV_LOG_ERROR
, "[%d]Capabilities: %x\n", s
->fd
, capabilities
);
410 desired_format
= fmt_ff2v4l(ap
->pix_fmt
);
411 if (desired_format
== 0 || (device_init(s
->fd
, width
, height
, desired_format
) < 0)) {
416 desired_format
= fmt_conversion_table
[i
].v4l2_fmt
;
417 if (device_init(s
->fd
, width
, height
, desired_format
) < 0) {
423 if (i
== sizeof(fmt_conversion_table
) / sizeof(struct fmt_map
)) {
428 if (desired_format
== 0) {
429 av_log(s1
, AV_LOG_ERROR
, "Cannot find a proper format.\n");
435 s
->frame_format
= desired_format
;
437 st
->codec
->pix_fmt
= fmt_v4l2ff(desired_format
);
438 s
->frame_size
= avpicture_get_size(st
->codec
->pix_fmt
, width
, height
);
439 if (capabilities
& V4L2_CAP_STREAMING
) {
440 s
->io_method
= io_mmap
;
444 s
->io_method
= io_read
;
453 s
->top_field_first
= first_field(s
->fd
);
455 st
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
456 st
->codec
->codec_id
= CODEC_ID_RAWVIDEO
;
457 st
->codec
->width
= width
;
458 st
->codec
->height
= height
;
459 st
->codec
->time_base
.den
= frame_rate
;
460 st
->codec
->time_base
.num
= frame_rate_base
;
461 st
->codec
->bit_rate
= s
->frame_size
* 1/av_q2d(st
->codec
->time_base
) * 8;
466 static int v4l2_read_packet(AVFormatContext
*s1
, AVPacket
*pkt
)
468 struct video_data
*s
= s1
->priv_data
;
471 if (av_new_packet(pkt
, s
->frame_size
) < 0)
474 if (s
->io_method
== io_mmap
) {
475 res
= mmap_read_frame(s
, pkt
->data
, &pkt
->pts
);
476 } else if (s
->io_method
== io_read
) {
477 res
= read_frame(s
, pkt
->data
, &pkt
->pts
);
485 if (s1
->streams
[0]->codec
->coded_frame
) {
486 s1
->streams
[0]->codec
->coded_frame
->interlaced_frame
= 1;
487 s1
->streams
[0]->codec
->coded_frame
->top_field_first
= s
->top_field_first
;
490 return s
->frame_size
;
493 static int v4l2_read_close(AVFormatContext
*s1
)
495 struct video_data
*s
= s1
->priv_data
;
497 if (s
->io_method
== io_mmap
) {
505 static AVInputFormat v4l2_format
= {
508 sizeof(struct video_data
),
513 .flags
= AVFMT_NOFILE
,
518 av_register_input_format(&v4l2_format
);