Mercurial > libavformat.hg
annotate v4l2.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | 62792a60f740 |
children | 0bb1bfbaa031 |
rev | line source |
---|---|
921 | 1 /* |
2 * Video4Linux2 grab interface | |
3 * Copyright (c) 2000,2001 Fabrice Bellard. | |
4 * Copyright (c) 2006 Luca Abeni. | |
5 * | |
6 * Part of this file is based on the V4L2 video capture example | |
7 * (http://v4l2spec.bytesex.org/v4l2spec/capture.c) | |
8 * | |
9 * Thanks to Michael Niedermayer for providing the mapping between | |
10 * V4L2_PIX_FMT_* and PIX_FMT_* | |
11 * | |
12 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
13 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
14 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
15 * FFmpeg is free software; you can redistribute it and/or |
921 | 16 * modify it under the terms of the GNU Lesser General Public |
17 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
18 * version 2.1 of the License, or (at your option) any later version. |
921 | 19 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
20 * FFmpeg is distributed in the hope that it will be useful, |
921 | 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
23 * Lesser General Public License for more details. | |
24 * | |
25 * You should have received a copy of the GNU Lesser General Public | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
26 * License along with FFmpeg; if not, write to the Free Software |
921 | 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
28 */ | |
29 #include "avformat.h" | |
30 #include <unistd.h> | |
31 #include <fcntl.h> | |
32 #include <sys/ioctl.h> | |
33 #include <sys/mman.h> | |
34 #include <sys/time.h> | |
1100 | 35 #include <asm/types.h> |
36 #include <linux/videodev2.h> | |
921 | 37 #include <time.h> |
38 | |
39 static const int desired_video_buffers = 256; | |
40 | |
41 enum io_method { | |
42 io_read, | |
43 io_mmap, | |
44 io_userptr | |
45 }; | |
46 | |
47 struct video_data { | |
48 int fd; | |
49 int frame_format; /* V4L2_PIX_FMT_* */ | |
50 enum io_method io_method; | |
51 int width, height; | |
52 int frame_rate; | |
53 int frame_rate_base; | |
54 int frame_size; | |
55 int top_field_first; | |
56 | |
57 int buffers; | |
58 void **buf_start; | |
59 unsigned int *buf_len; | |
60 }; | |
61 | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
62 struct buff_data { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
63 int index; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
64 int fd; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
65 }; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
66 |
921 | 67 struct fmt_map { |
68 enum PixelFormat ff_fmt; | |
69 int32_t v4l2_fmt; | |
70 }; | |
71 | |
72 static struct fmt_map fmt_conversion_table[] = { | |
73 { | |
74 .ff_fmt = PIX_FMT_YUV420P, | |
75 .v4l2_fmt = V4L2_PIX_FMT_YUV420, | |
76 }, | |
77 { | |
78 .ff_fmt = PIX_FMT_YUV422P, | |
79 .v4l2_fmt = V4L2_PIX_FMT_YUV422P, | |
80 }, | |
81 { | |
1760
8cba5672faa4
Replace deprecated PIX_FMT names by the newer variants.
diego
parents:
1556
diff
changeset
|
82 .ff_fmt = PIX_FMT_YUYV422, |
921 | 83 .v4l2_fmt = V4L2_PIX_FMT_YUYV, |
84 }, | |
85 { | |
86 .ff_fmt = PIX_FMT_UYVY422, | |
87 .v4l2_fmt = V4L2_PIX_FMT_UYVY, | |
88 }, | |
89 { | |
90 .ff_fmt = PIX_FMT_YUV411P, | |
91 .v4l2_fmt = V4L2_PIX_FMT_YUV411P, | |
92 }, | |
93 { | |
94 .ff_fmt = PIX_FMT_YUV410P, | |
95 .v4l2_fmt = V4L2_PIX_FMT_YUV410, | |
96 }, | |
97 { | |
98 .ff_fmt = PIX_FMT_BGR24, | |
99 .v4l2_fmt = V4L2_PIX_FMT_BGR24, | |
100 }, | |
101 { | |
102 .ff_fmt = PIX_FMT_RGB24, | |
103 .v4l2_fmt = V4L2_PIX_FMT_RGB24, | |
104 }, | |
105 /* | |
106 { | |
1760
8cba5672faa4
Replace deprecated PIX_FMT names by the newer variants.
diego
parents:
1556
diff
changeset
|
107 .ff_fmt = PIX_FMT_RGB32, |
921 | 108 .v4l2_fmt = V4L2_PIX_FMT_BGR32, |
109 }, | |
110 */ | |
111 { | |
112 .ff_fmt = PIX_FMT_GRAY8, | |
113 .v4l2_fmt = V4L2_PIX_FMT_GREY, | |
114 }, | |
115 }; | |
116 | |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1793
diff
changeset
|
117 static int device_open(AVFormatContext *ctx, uint32_t *capabilities) |
921 | 118 { |
119 struct v4l2_capability cap; | |
120 int fd; | |
121 int res; | |
122 | |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1793
diff
changeset
|
123 fd = open(ctx->filename, O_RDWR /*| O_NONBLOCK*/, 0); |
921 | 124 if (fd < 0) { |
1780 | 125 av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s : %s\n", |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1793
diff
changeset
|
126 ctx->filename, strerror(errno)); |
921 | 127 |
128 return -1; | |
129 } | |
130 | |
131 res = ioctl(fd, VIDIOC_QUERYCAP, &cap); | |
973 | 132 // ENOIOCTLCMD definition only availble on __KERNEL__ |
133 if (res < 0 && errno == 515) | |
134 { | |
1780 | 135 av_log(ctx, AV_LOG_ERROR, "QUERYCAP not implemented, probably V4L device but not supporting V4L2\n"); |
974 | 136 close(fd); |
973 | 137 |
138 return -1; | |
139 } | |
921 | 140 if (res < 0) { |
1780 | 141 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n", |
921 | 142 strerror(errno)); |
974 | 143 close(fd); |
921 | 144 |
145 return -1; | |
146 } | |
147 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { | |
1780 | 148 av_log(ctx, AV_LOG_ERROR, "Not a video capture device\n"); |
974 | 149 close(fd); |
921 | 150 |
151 return -1; | |
152 } | |
153 *capabilities = cap.capabilities; | |
154 | |
155 return fd; | |
156 } | |
157 | |
1780 | 158 static int device_init(AVFormatContext *ctx, int *width, int *height, int pix_fmt) |
921 | 159 { |
1780 | 160 struct video_data *s = ctx->priv_data; |
161 int fd = s->fd; | |
921 | 162 struct v4l2_format fmt; |
975
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
163 int res; |
921 | 164 |
165 memset(&fmt, 0, sizeof(struct v4l2_format)); | |
166 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
975
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
167 fmt.fmt.pix.width = *width; |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
168 fmt.fmt.pix.height = *height; |
921 | 169 fmt.fmt.pix.pixelformat = pix_fmt; |
170 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; | |
975
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
171 res = ioctl(fd, VIDIOC_S_FMT, &fmt); |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
172 if ((*width != fmt.fmt.pix.width) || (*height != fmt.fmt.pix.height)) { |
1780 | 173 av_log(ctx, AV_LOG_INFO, "The V4L2 driver changed the video from %dx%d to %dx%d\n", *width, *height, fmt.fmt.pix.width, fmt.fmt.pix.height); |
975
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
174 *width = fmt.fmt.pix.width; |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
175 *height = fmt.fmt.pix.height; |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
176 } |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
177 |
36a69fbabcfb
Add support for drivers that can change the capture size on VIDIOC_S_FMT
lucabe
parents:
974
diff
changeset
|
178 return res; |
921 | 179 } |
180 | |
181 static int first_field(int fd) | |
182 { | |
183 int res; | |
184 v4l2_std_id std; | |
185 | |
186 res = ioctl(fd, VIDIOC_G_STD, &std); | |
187 if (res < 0) { | |
188 return 0; | |
189 } | |
190 if (std & V4L2_STD_NTSC) { | |
191 return 0; | |
192 } | |
193 | |
194 return 1; | |
195 } | |
196 | |
197 static uint32_t fmt_ff2v4l(enum PixelFormat pix_fmt) | |
198 { | |
199 int i; | |
200 | |
201 for (i = 0; i < sizeof(fmt_conversion_table) / sizeof(struct fmt_map); i++) { | |
202 if (fmt_conversion_table[i].ff_fmt == pix_fmt) { | |
203 return fmt_conversion_table[i].v4l2_fmt; | |
204 } | |
205 } | |
206 | |
207 return 0; | |
208 } | |
209 | |
210 static enum PixelFormat fmt_v4l2ff(uint32_t pix_fmt) | |
211 { | |
212 int i; | |
213 | |
214 for (i = 0; i < sizeof(fmt_conversion_table) / sizeof(struct fmt_map); i++) { | |
215 if (fmt_conversion_table[i].v4l2_fmt == pix_fmt) { | |
216 return fmt_conversion_table[i].ff_fmt; | |
217 } | |
218 } | |
219 | |
220 return -1; | |
221 } | |
222 | |
1780 | 223 static int mmap_init(AVFormatContext *ctx) |
921 | 224 { |
1780 | 225 struct video_data *s = ctx->priv_data; |
921 | 226 struct v4l2_requestbuffers req; |
227 int i, res; | |
228 | |
229 memset(&req, 0, sizeof(struct v4l2_requestbuffers)); | |
230 req.count = desired_video_buffers; | |
231 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
232 req.memory = V4L2_MEMORY_MMAP; | |
233 res = ioctl (s->fd, VIDIOC_REQBUFS, &req); | |
234 if (res < 0) { | |
235 if (errno == EINVAL) { | |
1780 | 236 av_log(ctx, AV_LOG_ERROR, "Device does not support mmap\n"); |
921 | 237 } else { |
1780 | 238 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS)\n"); |
921 | 239 } |
240 | |
241 return -1; | |
242 } | |
243 | |
244 if (req.count < 2) { | |
1780 | 245 av_log(ctx, AV_LOG_ERROR, "Insufficient buffer memory\n"); |
921 | 246 |
247 return -1; | |
248 } | |
249 s->buffers = req.count; | |
250 s->buf_start = av_malloc(sizeof(void *) * s->buffers); | |
251 if (s->buf_start == NULL) { | |
1780 | 252 av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n"); |
921 | 253 |
254 return -1; | |
255 } | |
256 s->buf_len = av_malloc(sizeof(unsigned int) * s->buffers); | |
257 if (s->buf_len == NULL) { | |
1780 | 258 av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n"); |
921 | 259 av_free(s->buf_start); |
260 | |
261 return -1; | |
262 } | |
263 | |
264 for (i = 0; i < req.count; i++) { | |
265 struct v4l2_buffer buf; | |
266 | |
267 memset(&buf, 0, sizeof(struct v4l2_buffer)); | |
268 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
269 buf.memory = V4L2_MEMORY_MMAP; | |
270 buf.index = i; | |
271 res = ioctl (s->fd, VIDIOC_QUERYBUF, &buf); | |
272 if (res < 0) { | |
1780 | 273 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF)\n"); |
921 | 274 |
275 return -1; | |
276 } | |
277 | |
278 s->buf_len[i] = buf.length; | |
279 if (s->buf_len[i] < s->frame_size) { | |
1780 | 280 av_log(ctx, AV_LOG_ERROR, "Buffer len [%d] = %d != %d\n", i, s->buf_len[i], s->frame_size); |
921 | 281 |
282 return -1; | |
283 } | |
284 s->buf_start[i] = mmap (NULL, buf.length, | |
285 PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset); | |
286 if (s->buf_start[i] == MAP_FAILED) { | |
1780 | 287 av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", strerror(errno)); |
921 | 288 |
289 return -1; | |
290 } | |
291 } | |
292 | |
293 return 0; | |
294 } | |
295 | |
1780 | 296 static int read_init(AVFormatContext *ctx) |
921 | 297 { |
298 return -1; | |
299 } | |
300 | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
301 static void mmap_release_buffer(AVPacket *pkt) |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
302 { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
303 struct v4l2_buffer buf; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
304 int res, fd; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
305 struct buff_data *buf_descriptor = pkt->priv; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
306 |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
307 memset(&buf, 0, sizeof(struct v4l2_buffer)); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
308 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
309 buf.memory = V4L2_MEMORY_MMAP; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
310 buf.index = buf_descriptor->index; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
311 fd = buf_descriptor->fd; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
312 av_free(buf_descriptor); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
313 |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
314 res = ioctl (fd, VIDIOC_QBUF, &buf); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
315 if (res < 0) { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
316 av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n"); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
317 } |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
318 pkt->data = NULL; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
319 pkt->size = 0; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
320 } |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
321 |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
322 static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) |
921 | 323 { |
1780 | 324 struct video_data *s = ctx->priv_data; |
921 | 325 struct v4l2_buffer buf; |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
326 struct buff_data *buf_descriptor; |
921 | 327 int res; |
328 | |
329 memset(&buf, 0, sizeof(struct v4l2_buffer)); | |
330 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
331 buf.memory = V4L2_MEMORY_MMAP; | |
332 | |
333 /* FIXME: Some special treatment might be needed in case of loss of signal... */ | |
334 while ((res = ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && | |
335 ((errno == EAGAIN) || (errno == EINTR))); | |
336 if (res < 0) { | |
1780 | 337 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", strerror(errno)); |
921 | 338 |
339 return -1; | |
340 } | |
341 assert (buf.index < s->buffers); | |
1407
fb4bf3858f77
Make read_packet fail is the v4l2 driver returns an unexpected frame size
lucabe
parents:
1358
diff
changeset
|
342 if (buf.bytesused != s->frame_size) { |
1780 | 343 av_log(ctx, AV_LOG_ERROR, "The v4l2 frame is %d bytes, but %d bytes are expected\n", buf.bytesused, s->frame_size); |
1407
fb4bf3858f77
Make read_packet fail is the v4l2 driver returns an unexpected frame size
lucabe
parents:
1358
diff
changeset
|
344 |
fb4bf3858f77
Make read_packet fail is the v4l2 driver returns an unexpected frame size
lucabe
parents:
1358
diff
changeset
|
345 return -1; |
fb4bf3858f77
Make read_packet fail is the v4l2 driver returns an unexpected frame size
lucabe
parents:
1358
diff
changeset
|
346 } |
fb4bf3858f77
Make read_packet fail is the v4l2 driver returns an unexpected frame size
lucabe
parents:
1358
diff
changeset
|
347 |
921 | 348 /* Image is at s->buff_start[buf.index] */ |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
349 pkt->data= s->buf_start[buf.index]; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
350 pkt->size = buf.bytesused; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
351 pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
352 pkt->destruct = mmap_release_buffer; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
353 buf_descriptor = av_malloc(sizeof(struct buff_data)); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
354 if (buf_descriptor == NULL) { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
355 /* Something went wrong... Since av_malloc() failed, we cannot even |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
356 * allocate a buffer for memcopying into it |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
357 */ |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
358 av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
359 res = ioctl (s->fd, VIDIOC_QBUF, &buf); |
921 | 360 |
361 return -1; | |
362 } | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
363 buf_descriptor->fd = s->fd; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
364 buf_descriptor->index = buf.index; |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
365 pkt->priv = buf_descriptor; |
921 | 366 |
367 return s->buf_len[buf.index]; | |
368 } | |
369 | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
370 static int read_frame(AVFormatContext *ctx, AVPacket *pkt) |
921 | 371 { |
372 return -1; | |
373 } | |
374 | |
1780 | 375 static int mmap_start(AVFormatContext *ctx) |
921 | 376 { |
1780 | 377 struct video_data *s = ctx->priv_data; |
921 | 378 enum v4l2_buf_type type; |
379 int i, res; | |
380 | |
381 for (i = 0; i < s->buffers; i++) { | |
382 struct v4l2_buffer buf; | |
383 | |
384 memset(&buf, 0, sizeof(struct v4l2_buffer)); | |
385 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
386 buf.memory = V4L2_MEMORY_MMAP; | |
387 buf.index = i; | |
388 | |
389 res = ioctl (s->fd, VIDIOC_QBUF, &buf); | |
390 if (res < 0) { | |
1780 | 391 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", strerror(errno)); |
921 | 392 |
393 return -1; | |
394 } | |
395 } | |
396 | |
397 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
398 res = ioctl (s->fd, VIDIOC_STREAMON, &type); | |
399 if (res < 0) { | |
1780 | 400 av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", strerror(errno)); |
921 | 401 |
402 return -1; | |
403 } | |
404 | |
405 return 0; | |
406 } | |
407 | |
408 static void mmap_close(struct video_data *s) | |
409 { | |
410 enum v4l2_buf_type type; | |
411 int i; | |
412 | |
413 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
414 /* We do not check for the result, because we could | |
415 * not do anything about it anyway... | |
416 */ | |
417 ioctl(s->fd, VIDIOC_STREAMOFF, &type); | |
418 for (i = 0; i < s->buffers; i++) { | |
419 munmap(s->buf_start[i], s->buf_len[i]); | |
420 } | |
421 av_free(s->buf_start); | |
422 av_free(s->buf_len); | |
423 } | |
424 | |
425 static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |
426 { | |
427 struct video_data *s = s1->priv_data; | |
428 AVStream *st; | |
429 int width, height; | |
430 int res, frame_rate, frame_rate_base; | |
431 uint32_t desired_format, capabilities; | |
432 | |
1003 | 433 if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) { |
921 | 434 av_log(s1, AV_LOG_ERROR, "Missing/Wrong parameters\n"); |
435 | |
436 return -1; | |
437 } | |
438 | |
439 width = ap->width; | |
440 height = ap->height; | |
441 frame_rate = ap->time_base.den; | |
442 frame_rate_base = ap->time_base.num; | |
443 | |
444 if((unsigned)width > 32767 || (unsigned)height > 32767) { | |
445 av_log(s1, AV_LOG_ERROR, "Wrong size %dx%d\n", width, height); | |
446 | |
447 return -1; | |
448 } | |
449 | |
450 st = av_new_stream(s1, 0); | |
451 if (!st) { | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1780
diff
changeset
|
452 return AVERROR(ENOMEM); |
921 | 453 } |
454 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ | |
455 | |
456 s->width = width; | |
457 s->height = height; | |
458 s->frame_rate = frame_rate; | |
459 s->frame_rate_base = frame_rate_base; | |
460 | |
461 capabilities = 0; | |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1793
diff
changeset
|
462 s->fd = device_open(s1, &capabilities); |
921 | 463 if (s->fd < 0) { |
464 av_free(st); | |
465 | |
466 return AVERROR_IO; | |
467 } | |
1013 | 468 av_log(s1, AV_LOG_INFO, "[%d]Capabilities: %x\n", s->fd, capabilities); |
921 | 469 |
470 desired_format = fmt_ff2v4l(ap->pix_fmt); | |
1780 | 471 if (desired_format == 0 || (device_init(s1, &width, &height, desired_format) < 0)) { |
921 | 472 int i, done; |
473 | |
474 done = 0; i = 0; | |
475 while (!done) { | |
476 desired_format = fmt_conversion_table[i].v4l2_fmt; | |
1780 | 477 if (device_init(s1, &width, &height, desired_format) < 0) { |
921 | 478 desired_format = 0; |
479 i++; | |
480 } else { | |
481 done = 1; | |
482 } | |
483 if (i == sizeof(fmt_conversion_table) / sizeof(struct fmt_map)) { | |
484 done = 1; | |
485 } | |
486 } | |
487 } | |
488 if (desired_format == 0) { | |
489 av_log(s1, AV_LOG_ERROR, "Cannot find a proper format.\n"); | |
490 close(s->fd); | |
491 av_free(st); | |
492 | |
493 return AVERROR_IO; | |
494 } | |
495 s->frame_format = desired_format; | |
496 | |
497 st->codec->pix_fmt = fmt_v4l2ff(desired_format); | |
498 s->frame_size = avpicture_get_size(st->codec->pix_fmt, width, height); | |
499 if (capabilities & V4L2_CAP_STREAMING) { | |
500 s->io_method = io_mmap; | |
1780 | 501 res = mmap_init(s1); |
1117 | 502 if (res == 0) { |
1780 | 503 res = mmap_start(s1); |
1117 | 504 } |
921 | 505 } else { |
506 s->io_method = io_read; | |
1780 | 507 res = read_init(s1); |
921 | 508 } |
509 if (res < 0) { | |
510 close(s->fd); | |
511 av_free(st); | |
512 | |
513 return AVERROR_IO; | |
514 } | |
515 s->top_field_first = first_field(s->fd); | |
516 | |
517 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
518 st->codec->codec_id = CODEC_ID_RAWVIDEO; | |
519 st->codec->width = width; | |
520 st->codec->height = height; | |
521 st->codec->time_base.den = frame_rate; | |
522 st->codec->time_base.num = frame_rate_base; | |
523 st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8; | |
524 | |
525 return 0; | |
526 } | |
527 | |
528 static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt) | |
529 { | |
530 struct video_data *s = s1->priv_data; | |
531 int res; | |
532 | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
533 if (s->io_method == io_mmap) { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
534 av_init_packet(pkt); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
535 res = mmap_read_frame(s1, pkt); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
536 } else if (s->io_method == io_read) { |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
537 if (av_new_packet(pkt, s->frame_size) < 0) |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
538 return AVERROR_IO; |
921 | 539 |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
540 res = read_frame(s1, pkt); |
921 | 541 } else { |
542 return AVERROR_IO; | |
543 } | |
544 if (res < 0) { | |
545 return AVERROR_IO; | |
546 } | |
547 | |
548 if (s1->streams[0]->codec->coded_frame) { | |
549 s1->streams[0]->codec->coded_frame->interlaced_frame = 1; | |
550 s1->streams[0]->codec->coded_frame->top_field_first = s->top_field_first; | |
551 } | |
552 | |
553 return s->frame_size; | |
554 } | |
555 | |
556 static int v4l2_read_close(AVFormatContext *s1) | |
557 { | |
558 struct video_data *s = s1->priv_data; | |
559 | |
560 if (s->io_method == io_mmap) { | |
561 mmap_close(s); | |
562 } | |
563 | |
564 close(s->fd); | |
565 return 0; | |
566 } | |
567 | |
1169 | 568 AVInputFormat v4l2_demuxer = { |
921 | 569 "video4linux2", |
570 "video grab", | |
571 sizeof(struct video_data), | |
572 NULL, | |
573 v4l2_read_header, | |
574 v4l2_read_packet, | |
575 v4l2_read_close, | |
576 .flags = AVFMT_NOFILE, | |
577 }; |