Mercurial > libavformat.hg
annotate v4l2.c @ 2136:b53a19eed95d libavformat
remove duplicate PAT scaning code and actual PAT scan
also disabling the nonsense 3yr old rawts change (it would after the
above chage totally break the demuxer if its left enabled)
author | michael |
---|---|
date | Mon, 04 Jun 2007 14:44:52 +0000 |
parents | 17b7ebc3e1f9 |
children | efb7b615d57c |
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 | |
1961 | 425 static int v4l2_set_parameters( AVFormatContext *s1, AVFormatParameters *ap ) |
426 { | |
427 struct video_data *s = s1->priv_data; | |
428 struct v4l2_input input; | |
429 struct v4l2_standard standard; | |
430 int i; | |
431 | |
2077
4b07eb8709f2
Allow avoid setting the video standard and input when capturing v4l2 video.
lucabe
parents:
1961
diff
changeset
|
432 if(ap->channel>=0) { |
2078 | 433 /* set tv video input */ |
434 memset (&input, 0, sizeof (input)); | |
435 input.index = ap->channel; | |
436 if(ioctl (s->fd, VIDIOC_ENUMINPUT, &input) < 0) { | |
437 av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl enum input failed:\n"); | |
438 return AVERROR_IO; | |
439 } | |
1961 | 440 |
2078 | 441 av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set input_id: %d, input: %s\n", |
442 ap->channel, input.name); | |
443 if(ioctl (s->fd, VIDIOC_S_INPUT, &input.index) < 0 ) { | |
444 av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set input(%d) failed\n", | |
445 ap->channel); | |
446 return AVERROR_IO; | |
447 } | |
2077
4b07eb8709f2
Allow avoid setting the video standard and input when capturing v4l2 video.
lucabe
parents:
1961
diff
changeset
|
448 } |
1961 | 449 |
2077
4b07eb8709f2
Allow avoid setting the video standard and input when capturing v4l2 video.
lucabe
parents:
1961
diff
changeset
|
450 if(ap->standard) { |
2078 | 451 av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s\n", |
452 ap->standard ); | |
453 /* set tv standard */ | |
454 memset (&standard, 0, sizeof (standard)); | |
455 for(i=0;;i++) { | |
456 standard.index = i; | |
457 if (ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) { | |
458 av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set standard(%s) failed\n", | |
459 ap->standard); | |
460 return AVERROR_IO; | |
461 } | |
462 | |
463 if(!strcasecmp(standard.name, ap->standard)) { | |
464 break; | |
465 } | |
466 } | |
467 | |
468 av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s, id: %"PRIu64"\n", | |
469 ap->standard, standard.id); | |
470 if (ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) { | |
1961 | 471 av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set standard(%s) failed\n", |
472 ap->standard); | |
473 return AVERROR_IO; | |
474 } | |
2077
4b07eb8709f2
Allow avoid setting the video standard and input when capturing v4l2 video.
lucabe
parents:
1961
diff
changeset
|
475 } |
1961 | 476 |
477 return 0; | |
478 } | |
479 | |
921 | 480 static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) |
481 { | |
482 struct video_data *s = s1->priv_data; | |
483 AVStream *st; | |
484 int width, height; | |
485 int res, frame_rate, frame_rate_base; | |
486 uint32_t desired_format, capabilities; | |
487 | |
1003 | 488 if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) { |
921 | 489 av_log(s1, AV_LOG_ERROR, "Missing/Wrong parameters\n"); |
490 | |
491 return -1; | |
492 } | |
493 | |
494 width = ap->width; | |
495 height = ap->height; | |
496 frame_rate = ap->time_base.den; | |
497 frame_rate_base = ap->time_base.num; | |
498 | |
499 if((unsigned)width > 32767 || (unsigned)height > 32767) { | |
500 av_log(s1, AV_LOG_ERROR, "Wrong size %dx%d\n", width, height); | |
501 | |
502 return -1; | |
503 } | |
504 | |
505 st = av_new_stream(s1, 0); | |
506 if (!st) { | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1780
diff
changeset
|
507 return AVERROR(ENOMEM); |
921 | 508 } |
509 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ | |
510 | |
511 s->width = width; | |
512 s->height = height; | |
513 s->frame_rate = frame_rate; | |
514 s->frame_rate_base = frame_rate_base; | |
515 | |
516 capabilities = 0; | |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1793
diff
changeset
|
517 s->fd = device_open(s1, &capabilities); |
921 | 518 if (s->fd < 0) { |
519 av_free(st); | |
520 | |
521 return AVERROR_IO; | |
522 } | |
1013 | 523 av_log(s1, AV_LOG_INFO, "[%d]Capabilities: %x\n", s->fd, capabilities); |
921 | 524 |
525 desired_format = fmt_ff2v4l(ap->pix_fmt); | |
1780 | 526 if (desired_format == 0 || (device_init(s1, &width, &height, desired_format) < 0)) { |
921 | 527 int i, done; |
528 | |
529 done = 0; i = 0; | |
530 while (!done) { | |
531 desired_format = fmt_conversion_table[i].v4l2_fmt; | |
1780 | 532 if (device_init(s1, &width, &height, desired_format) < 0) { |
921 | 533 desired_format = 0; |
534 i++; | |
535 } else { | |
536 done = 1; | |
537 } | |
538 if (i == sizeof(fmt_conversion_table) / sizeof(struct fmt_map)) { | |
539 done = 1; | |
540 } | |
541 } | |
542 } | |
543 if (desired_format == 0) { | |
544 av_log(s1, AV_LOG_ERROR, "Cannot find a proper format.\n"); | |
545 close(s->fd); | |
546 av_free(st); | |
547 | |
548 return AVERROR_IO; | |
549 } | |
550 s->frame_format = desired_format; | |
551 | |
1961 | 552 if( v4l2_set_parameters( s1, ap ) < 0 ) |
553 return AVERROR_IO; | |
554 | |
921 | 555 st->codec->pix_fmt = fmt_v4l2ff(desired_format); |
556 s->frame_size = avpicture_get_size(st->codec->pix_fmt, width, height); | |
557 if (capabilities & V4L2_CAP_STREAMING) { | |
558 s->io_method = io_mmap; | |
1780 | 559 res = mmap_init(s1); |
1117 | 560 if (res == 0) { |
1780 | 561 res = mmap_start(s1); |
1117 | 562 } |
921 | 563 } else { |
564 s->io_method = io_read; | |
1780 | 565 res = read_init(s1); |
921 | 566 } |
567 if (res < 0) { | |
568 close(s->fd); | |
569 av_free(st); | |
570 | |
571 return AVERROR_IO; | |
572 } | |
573 s->top_field_first = first_field(s->fd); | |
574 | |
575 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
576 st->codec->codec_id = CODEC_ID_RAWVIDEO; | |
577 st->codec->width = width; | |
578 st->codec->height = height; | |
579 st->codec->time_base.den = frame_rate; | |
580 st->codec->time_base.num = frame_rate_base; | |
581 st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8; | |
582 | |
583 return 0; | |
584 } | |
585 | |
586 static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt) | |
587 { | |
588 struct video_data *s = s1->priv_data; | |
589 int res; | |
590 | |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
591 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
|
592 av_init_packet(pkt); |
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
593 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
|
594 } 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
|
595 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
|
596 return AVERROR_IO; |
921 | 597 |
1793
951d219ab67b
Pass the v4l2 buffer into the AVPacket, instead of allocating a new buffer
lucabe
parents:
1787
diff
changeset
|
598 res = read_frame(s1, pkt); |
921 | 599 } else { |
600 return AVERROR_IO; | |
601 } | |
602 if (res < 0) { | |
603 return AVERROR_IO; | |
604 } | |
605 | |
606 if (s1->streams[0]->codec->coded_frame) { | |
607 s1->streams[0]->codec->coded_frame->interlaced_frame = 1; | |
608 s1->streams[0]->codec->coded_frame->top_field_first = s->top_field_first; | |
609 } | |
610 | |
611 return s->frame_size; | |
612 } | |
613 | |
614 static int v4l2_read_close(AVFormatContext *s1) | |
615 { | |
616 struct video_data *s = s1->priv_data; | |
617 | |
618 if (s->io_method == io_mmap) { | |
619 mmap_close(s); | |
620 } | |
621 | |
622 close(s->fd); | |
623 return 0; | |
624 } | |
625 | |
1169 | 626 AVInputFormat v4l2_demuxer = { |
921 | 627 "video4linux2", |
628 "video grab", | |
629 sizeof(struct video_data), | |
630 NULL, | |
631 v4l2_read_header, | |
632 v4l2_read_packet, | |
633 v4l2_read_close, | |
634 .flags = AVFMT_NOFILE, | |
635 }; |