Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Copyright (c) 2000,2001 Fabrice Bellard |
||
3 | * Copyright (c) 2006 Luca Abeni |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
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. |
||
11 | * |
||
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. |
||
16 | * |
||
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 |
||
20 | */ |
||
21 | |||
22 | /** |
||
23 | * @file |
||
24 | * Video4Linux2 grab interface |
||
25 | * |
||
26 | * Part of this file is based on the V4L2 video capture example |
||
27 | * (http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html) |
||
28 | * |
||
29 | * Thanks to Michael Niedermayer for providing the mapping between |
||
30 | * V4L2_PIX_FMT_* and AV_PIX_FMT_* |
||
31 | */ |
||
32 | |||
33 | #include "v4l2-common.h" |
||
34 | |||
35 | #if CONFIG_LIBV4L2 |
||
36 | #include |
||
37 | #endif |
||
38 | |||
39 | static const int desired_video_buffers = 256; |
||
40 | |||
41 | #define V4L_ALLFORMATS 3 |
||
42 | #define V4L_RAWFORMATS 1 |
||
43 | #define V4L_COMPFORMATS 2 |
||
44 | |||
45 | /** |
||
46 | * Return timestamps to the user exactly as returned by the kernel |
||
47 | */ |
||
48 | #define V4L_TS_DEFAULT 0 |
||
49 | /** |
||
50 | * Autodetect the kind of timestamps returned by the kernel and convert to |
||
51 | * absolute (wall clock) timestamps. |
||
52 | */ |
||
53 | #define V4L_TS_ABS 1 |
||
54 | /** |
||
55 | * Assume kernel timestamps are from the monotonic clock and convert to |
||
56 | * absolute timestamps. |
||
57 | */ |
||
58 | #define V4L_TS_MONO2ABS 2 |
||
59 | |||
60 | /** |
||
61 | * Once the kind of timestamps returned by the kernel have been detected, |
||
62 | * the value of the timefilter (NULL or not) determines whether a conversion |
||
63 | * takes place. |
||
64 | */ |
||
65 | #define V4L_TS_CONVERT_READY V4L_TS_DEFAULT |
||
66 | |||
67 | struct video_data { |
||
68 | AVClass *class; |
||
69 | int fd; |
||
70 | int frame_format; /* V4L2_PIX_FMT_* */ |
||
71 | int width, height; |
||
72 | int frame_size; |
||
73 | int interlaced; |
||
74 | int top_field_first; |
||
75 | int ts_mode; |
||
76 | TimeFilter *timefilter; |
||
77 | int64_t last_time_m; |
||
78 | |||
79 | int buffers; |
||
80 | volatile int buffers_queued; |
||
81 | void **buf_start; |
||
82 | unsigned int *buf_len; |
||
83 | char *standard; |
||
84 | v4l2_std_id std_id; |
||
85 | int channel; |
||
86 | char *pixel_format; /**< Set by a private option. */ |
||
87 | int list_format; /**< Set by a private option. */ |
||
88 | int list_standard; /**< Set by a private option. */ |
||
89 | char *framerate; /**< Set by a private option. */ |
||
90 | |||
91 | int use_libv4l2; |
||
92 | int (*open_f)(const char *file, int oflag, ...); |
||
93 | int (*close_f)(int fd); |
||
94 | int (*dup_f)(int fd); |
||
95 | int (*ioctl_f)(int fd, unsigned long int request, ...); |
||
96 | ssize_t (*read_f)(int fd, void *buffer, size_t n); |
||
97 | void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, int64_t offset); |
||
98 | int (*munmap_f)(void *_start, size_t length); |
||
99 | }; |
||
100 | |||
101 | struct buff_data { |
||
102 | struct video_data *s; |
||
103 | int index; |
||
104 | }; |
||
105 | |||
106 | static int device_open(AVFormatContext *ctx) |
||
107 | { |
||
108 | struct video_data *s = ctx->priv_data; |
||
109 | struct v4l2_capability cap; |
||
110 | int fd; |
||
111 | int ret; |
||
112 | int flags = O_RDWR; |
||
113 | |||
114 | #define SET_WRAPPERS(prefix) do { \ |
||
115 | s->open_f = prefix ## open; \ |
||
116 | s->close_f = prefix ## close; \ |
||
117 | s->dup_f = prefix ## dup; \ |
||
118 | s->ioctl_f = prefix ## ioctl; \ |
||
119 | s->read_f = prefix ## read; \ |
||
120 | s->mmap_f = prefix ## mmap; \ |
||
121 | s->munmap_f = prefix ## munmap; \ |
||
122 | } while (0) |
||
123 | |||
124 | if (s->use_libv4l2) { |
||
125 | #if CONFIG_LIBV4L2 |
||
126 | SET_WRAPPERS(v4l2_); |
||
127 | #else |
||
128 | av_log(ctx, AV_LOG_ERROR, "libavdevice is not build with libv4l2 support.\n"); |
||
129 | return AVERROR(EINVAL); |
||
130 | #endif |
||
131 | } else { |
||
132 | SET_WRAPPERS(); |
||
133 | } |
||
134 | |||
135 | #define v4l2_open s->open_f |
||
136 | #define v4l2_close s->close_f |
||
137 | #define v4l2_dup s->dup_f |
||
138 | #define v4l2_ioctl s->ioctl_f |
||
139 | #define v4l2_read s->read_f |
||
140 | #define v4l2_mmap s->mmap_f |
||
141 | #define v4l2_munmap s->munmap_f |
||
142 | |||
143 | if (ctx->flags & AVFMT_FLAG_NONBLOCK) { |
||
144 | flags |= O_NONBLOCK; |
||
145 | } |
||
146 | |||
147 | fd = v4l2_open(ctx->filename, flags, 0); |
||
148 | if (fd < 0) { |
||
149 | ret = AVERROR(errno); |
||
150 | av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s: %s\n", |
||
151 | ctx->filename, av_err2str(ret)); |
||
152 | return ret; |
||
153 | } |
||
154 | |||
155 | if (v4l2_ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { |
||
156 | ret = AVERROR(errno); |
||
157 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n", |
||
158 | av_err2str(ret)); |
||
159 | goto fail; |
||
160 | } |
||
161 | |||
162 | av_log(ctx, AV_LOG_VERBOSE, "fd:%d capabilities:%x\n", |
||
163 | fd, cap.capabilities); |
||
164 | |||
165 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { |
||
166 | av_log(ctx, AV_LOG_ERROR, "Not a video capture device.\n"); |
||
167 | ret = AVERROR(ENODEV); |
||
168 | goto fail; |
||
169 | } |
||
170 | |||
171 | if (!(cap.capabilities & V4L2_CAP_STREAMING)) { |
||
172 | av_log(ctx, AV_LOG_ERROR, |
||
173 | "The device does not support the streaming I/O method.\n"); |
||
174 | ret = AVERROR(ENOSYS); |
||
175 | goto fail; |
||
176 | } |
||
177 | |||
178 | return fd; |
||
179 | |||
180 | fail: |
||
181 | v4l2_close(fd); |
||
182 | return ret; |
||
183 | } |
||
184 | |||
185 | static int device_init(AVFormatContext *ctx, int *width, int *height, |
||
186 | uint32_t pix_fmt) |
||
187 | { |
||
188 | struct video_data *s = ctx->priv_data; |
||
189 | int fd = s->fd; |
||
190 | struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; |
||
191 | struct v4l2_pix_format *pix = &fmt.fmt.pix; |
||
192 | |||
193 | int res = 0; |
||
194 | |||
195 | pix->width = *width; |
||
196 | pix->height = *height; |
||
197 | pix->pixelformat = pix_fmt; |
||
198 | pix->field = V4L2_FIELD_ANY; |
||
199 | |||
200 | if (v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) |
||
201 | res = AVERROR(errno); |
||
202 | |||
203 | if ((*width != fmt.fmt.pix.width) || (*height != fmt.fmt.pix.height)) { |
||
204 | av_log(ctx, AV_LOG_INFO, |
||
205 | "The V4L2 driver changed the video from %dx%d to %dx%d\n", |
||
206 | *width, *height, fmt.fmt.pix.width, fmt.fmt.pix.height); |
||
207 | *width = fmt.fmt.pix.width; |
||
208 | *height = fmt.fmt.pix.height; |
||
209 | } |
||
210 | |||
211 | if (pix_fmt != fmt.fmt.pix.pixelformat) { |
||
212 | av_log(ctx, AV_LOG_DEBUG, |
||
213 | "The V4L2 driver changed the pixel format " |
||
214 | "from 0x%08X to 0x%08X\n", |
||
215 | pix_fmt, fmt.fmt.pix.pixelformat); |
||
216 | res = AVERROR(EINVAL); |
||
217 | } |
||
218 | |||
219 | if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED) { |
||
220 | av_log(ctx, AV_LOG_DEBUG, |
||
221 | "The V4L2 driver is using the interlaced mode\n"); |
||
222 | s->interlaced = 1; |
||
223 | } |
||
224 | |||
225 | return res; |
||
226 | } |
||
227 | |||
228 | static int first_field(const struct video_data *s, int fd) |
||
229 | { |
||
230 | int res; |
||
231 | v4l2_std_id std; |
||
232 | |||
233 | res = v4l2_ioctl(fd, VIDIOC_G_STD, &std); |
||
234 | if (res < 0) { |
||
235 | return 0; |
||
236 | } |
||
237 | if (std & V4L2_STD_NTSC) { |
||
238 | return 0; |
||
239 | } |
||
240 | |||
241 | return 1; |
||
242 | } |
||
243 | |||
244 | #if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE |
||
245 | static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat) |
||
246 | { |
||
247 | const struct video_data *s = ctx->priv_data; |
||
248 | struct v4l2_frmsizeenum vfse = { .pixel_format = pixelformat }; |
||
249 | |||
250 | while(!v4l2_ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) { |
||
251 | switch (vfse.type) { |
||
252 | case V4L2_FRMSIZE_TYPE_DISCRETE: |
||
253 | av_log(ctx, AV_LOG_INFO, " %ux%u", |
||
254 | vfse.discrete.width, vfse.discrete.height); |
||
255 | break; |
||
256 | case V4L2_FRMSIZE_TYPE_CONTINUOUS: |
||
257 | case V4L2_FRMSIZE_TYPE_STEPWISE: |
||
258 | av_log(ctx, AV_LOG_INFO, " {%u-%u, %u}x{%u-%u, %u}", |
||
259 | vfse.stepwise.min_width, |
||
260 | vfse.stepwise.max_width, |
||
261 | vfse.stepwise.step_width, |
||
262 | vfse.stepwise.min_height, |
||
263 | vfse.stepwise.max_height, |
||
264 | vfse.stepwise.step_height); |
||
265 | } |
||
266 | vfse.index++; |
||
267 | } |
||
268 | } |
||
269 | #endif |
||
270 | |||
271 | static void list_formats(AVFormatContext *ctx, int fd, int type) |
||
272 | { |
||
273 | const struct video_data *s = ctx->priv_data; |
||
274 | struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; |
||
275 | |||
276 | while(!v4l2_ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) { |
||
277 | enum AVCodecID codec_id = avpriv_fmt_v4l2codec(vfd.pixelformat); |
||
278 | enum AVPixelFormat pix_fmt = avpriv_fmt_v4l2ff(vfd.pixelformat, codec_id); |
||
279 | |||
280 | vfd.index++; |
||
281 | |||
282 | if (!(vfd.flags & V4L2_FMT_FLAG_COMPRESSED) && |
||
283 | type & V4L_RAWFORMATS) { |
||
284 | const char *fmt_name = av_get_pix_fmt_name(pix_fmt); |
||
285 | av_log(ctx, AV_LOG_INFO, "Raw : %9s : %20s :", |
||
286 | fmt_name ? fmt_name : "Unsupported", |
||
287 | vfd.description); |
||
288 | } else if (vfd.flags & V4L2_FMT_FLAG_COMPRESSED && |
||
289 | type & V4L_COMPFORMATS) { |
||
290 | AVCodec *codec = avcodec_find_decoder(codec_id); |
||
291 | av_log(ctx, AV_LOG_INFO, "Compressed: %9s : %20s :", |
||
292 | codec ? codec->name : "Unsupported", |
||
293 | vfd.description); |
||
294 | } else { |
||
295 | continue; |
||
296 | } |
||
297 | |||
298 | #ifdef V4L2_FMT_FLAG_EMULATED |
||
299 | if (vfd.flags & V4L2_FMT_FLAG_EMULATED) |
||
300 | av_log(ctx, AV_LOG_INFO, " Emulated :"); |
||
301 | #endif |
||
302 | #if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE |
||
303 | list_framesizes(ctx, fd, vfd.pixelformat); |
||
304 | #endif |
||
305 | av_log(ctx, AV_LOG_INFO, "\n"); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | static void list_standards(AVFormatContext *ctx) |
||
310 | { |
||
311 | int ret; |
||
312 | struct video_data *s = ctx->priv_data; |
||
313 | struct v4l2_standard standard; |
||
314 | |||
315 | if (s->std_id == 0) |
||
316 | return; |
||
317 | |||
318 | for (standard.index = 0; ; standard.index++) { |
||
319 | if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) { |
||
320 | ret = AVERROR(errno); |
||
321 | if (ret == AVERROR(EINVAL)) { |
||
322 | break; |
||
323 | } else { |
||
324 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", av_err2str(ret)); |
||
325 | return; |
||
326 | } |
||
327 | } |
||
328 | av_log(ctx, AV_LOG_INFO, "%2d, %16"PRIx64", %s\n", |
||
329 | standard.index, (uint64_t)standard.id, standard.name); |
||
330 | } |
||
331 | } |
||
332 | |||
333 | static int mmap_init(AVFormatContext *ctx) |
||
334 | { |
||
335 | int i, res; |
||
336 | struct video_data *s = ctx->priv_data; |
||
337 | struct v4l2_requestbuffers req = { |
||
338 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
||
339 | .count = desired_video_buffers, |
||
340 | .memory = V4L2_MEMORY_MMAP |
||
341 | }; |
||
342 | |||
343 | if (v4l2_ioctl(s->fd, VIDIOC_REQBUFS, &req) < 0) { |
||
344 | res = AVERROR(errno); |
||
345 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS): %s\n", av_err2str(res)); |
||
346 | return res; |
||
347 | } |
||
348 | |||
349 | if (req.count < 2) { |
||
350 | av_log(ctx, AV_LOG_ERROR, "Insufficient buffer memory\n"); |
||
351 | return AVERROR(ENOMEM); |
||
352 | } |
||
353 | s->buffers = req.count; |
||
354 | s->buf_start = av_malloc(sizeof(void *) * s->buffers); |
||
355 | if (s->buf_start == NULL) { |
||
356 | av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n"); |
||
357 | return AVERROR(ENOMEM); |
||
358 | } |
||
359 | s->buf_len = av_malloc(sizeof(unsigned int) * s->buffers); |
||
360 | if (s->buf_len == NULL) { |
||
361 | av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n"); |
||
362 | av_free(s->buf_start); |
||
363 | return AVERROR(ENOMEM); |
||
364 | } |
||
365 | |||
366 | for (i = 0; i < req.count; i++) { |
||
367 | struct v4l2_buffer buf = { |
||
368 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
||
369 | .index = i, |
||
370 | .memory = V4L2_MEMORY_MMAP |
||
371 | }; |
||
372 | if (v4l2_ioctl(s->fd, VIDIOC_QUERYBUF, &buf) < 0) { |
||
373 | res = AVERROR(errno); |
||
374 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF): %s\n", av_err2str(res)); |
||
375 | return res; |
||
376 | } |
||
377 | |||
378 | s->buf_len[i] = buf.length; |
||
379 | if (s->frame_size > 0 && s->buf_len[i] < s->frame_size) { |
||
380 | av_log(ctx, AV_LOG_ERROR, |
||
381 | "buf_len[%d] = %d < expected frame size %d\n", |
||
382 | i, s->buf_len[i], s->frame_size); |
||
383 | return AVERROR(ENOMEM); |
||
384 | } |
||
385 | s->buf_start[i] = v4l2_mmap(NULL, buf.length, |
||
386 | PROT_READ | PROT_WRITE, MAP_SHARED, |
||
387 | s->fd, buf.m.offset); |
||
388 | |||
389 | if (s->buf_start[i] == MAP_FAILED) { |
||
390 | res = AVERROR(errno); |
||
391 | av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", av_err2str(res)); |
||
392 | return res; |
||
393 | } |
||
394 | } |
||
395 | |||
396 | return 0; |
||
397 | } |
||
398 | |||
399 | #if FF_API_DESTRUCT_PACKET |
||
400 | static void dummy_release_buffer(AVPacket *pkt) |
||
401 | { |
||
402 | av_assert0(0); |
||
403 | } |
||
404 | #endif |
||
405 | |||
406 | static void mmap_release_buffer(void *opaque, uint8_t *data) |
||
407 | { |
||
408 | struct v4l2_buffer buf = { 0 }; |
||
409 | int res; |
||
410 | struct buff_data *buf_descriptor = opaque; |
||
411 | struct video_data *s = buf_descriptor->s; |
||
412 | |||
413 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
||
414 | buf.memory = V4L2_MEMORY_MMAP; |
||
415 | buf.index = buf_descriptor->index; |
||
416 | av_free(buf_descriptor); |
||
417 | |||
418 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { |
||
419 | res = AVERROR(errno); |
||
420 | av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", |
||
421 | av_err2str(res)); |
||
422 | } |
||
423 | |||
424 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); |
||
425 | } |
||
426 | |||
427 | #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) |
||
428 | static int64_t av_gettime_monotonic(void) |
||
429 | { |
||
430 | struct timespec tv; |
||
431 | |||
432 | clock_gettime(CLOCK_MONOTONIC, &tv); |
||
433 | return (int64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; |
||
434 | } |
||
435 | #endif |
||
436 | |||
437 | static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts) |
||
438 | { |
||
439 | struct video_data *s = ctx->priv_data; |
||
440 | int64_t now; |
||
441 | |||
442 | now = av_gettime(); |
||
443 | if (s->ts_mode == V4L_TS_ABS && |
||
444 | ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE) { |
||
445 | av_log(ctx, AV_LOG_INFO, "Detected absolute timestamps\n"); |
||
446 | s->ts_mode = V4L_TS_CONVERT_READY; |
||
447 | return 0; |
||
448 | } |
||
449 | #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) |
||
450 | now = av_gettime_monotonic(); |
||
451 | if (s->ts_mode == V4L_TS_MONO2ABS || |
||
452 | (ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE)) { |
||
453 | AVRational tb = {AV_TIME_BASE, 1}; |
||
454 | int64_t period = av_rescale_q(1, tb, ctx->streams[0]->avg_frame_rate); |
||
455 | av_log(ctx, AV_LOG_INFO, "Detected monotonic timestamps, converting\n"); |
||
456 | /* microseconds instead of seconds, MHz instead of Hz */ |
||
457 | s->timefilter = ff_timefilter_new(1, period, 1.0E-6); |
||
458 | if (!s->timefilter) |
||
459 | return AVERROR(ENOMEM); |
||
460 | s->ts_mode = V4L_TS_CONVERT_READY; |
||
461 | return 0; |
||
462 | } |
||
463 | #endif |
||
464 | av_log(ctx, AV_LOG_ERROR, "Unknown timestamps\n"); |
||
465 | return AVERROR(EIO); |
||
466 | } |
||
467 | |||
468 | static int convert_timestamp(AVFormatContext *ctx, int64_t *ts) |
||
469 | { |
||
470 | struct video_data *s = ctx->priv_data; |
||
471 | |||
472 | if (s->ts_mode) { |
||
473 | int r = init_convert_timestamp(ctx, *ts); |
||
474 | if (r < 0) |
||
475 | return r; |
||
476 | } |
||
477 | #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) |
||
478 | if (s->timefilter) { |
||
479 | int64_t nowa = av_gettime(); |
||
480 | int64_t nowm = av_gettime_monotonic(); |
||
481 | ff_timefilter_update(s->timefilter, nowa, nowm - s->last_time_m); |
||
482 | s->last_time_m = nowm; |
||
483 | *ts = ff_timefilter_eval(s->timefilter, *ts - nowm); |
||
484 | } |
||
485 | #endif |
||
486 | return 0; |
||
487 | } |
||
488 | |||
489 | static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) |
||
490 | { |
||
491 | struct video_data *s = ctx->priv_data; |
||
492 | struct v4l2_buffer buf = { |
||
493 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
||
494 | .memory = V4L2_MEMORY_MMAP |
||
495 | }; |
||
496 | int res; |
||
497 | |||
498 | /* FIXME: Some special treatment might be needed in case of loss of signal... */ |
||
499 | while ((res = v4l2_ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR)); |
||
500 | if (res < 0) { |
||
501 | if (errno == EAGAIN) { |
||
502 | pkt->size = 0; |
||
503 | return AVERROR(EAGAIN); |
||
504 | } |
||
505 | res = AVERROR(errno); |
||
506 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", av_err2str(res)); |
||
507 | return res; |
||
508 | } |
||
509 | |||
510 | if (buf.index >= s->buffers) { |
||
511 | av_log(ctx, AV_LOG_ERROR, "Invalid buffer index received.\n"); |
||
512 | return AVERROR(EINVAL); |
||
513 | } |
||
514 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, -1); |
||
515 | // always keep at least one buffer queued |
||
516 | av_assert0(avpriv_atomic_int_get(&s->buffers_queued) >= 1); |
||
517 | |||
518 | /* CPIA is a compressed format and we don't know the exact number of bytes |
||
519 | * used by a frame, so set it here as the driver announces it. |
||
520 | */ |
||
521 | if (ctx->video_codec_id == AV_CODEC_ID_CPIA) |
||
522 | s->frame_size = buf.bytesused; |
||
523 | |||
524 | if (s->frame_size > 0 && buf.bytesused != s->frame_size) { |
||
525 | av_log(ctx, AV_LOG_ERROR, |
||
526 | "The v4l2 frame is %d bytes, but %d bytes are expected\n", |
||
527 | buf.bytesused, s->frame_size); |
||
528 | return AVERROR_INVALIDDATA; |
||
529 | } |
||
530 | |||
531 | /* Image is at s->buff_start[buf.index] */ |
||
532 | if (avpriv_atomic_int_get(&s->buffers_queued) == FFMAX(s->buffers / 8, 1)) { |
||
533 | /* when we start getting low on queued buffers, fall back on copying data */ |
||
534 | res = av_new_packet(pkt, buf.bytesused); |
||
535 | if (res < 0) { |
||
536 | av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); |
||
537 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) |
||
538 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); |
||
539 | return res; |
||
540 | } |
||
541 | memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused); |
||
542 | |||
543 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { |
||
544 | res = AVERROR(errno); |
||
545 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res)); |
||
546 | av_free_packet(pkt); |
||
547 | return res; |
||
548 | } |
||
549 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); |
||
550 | } else { |
||
551 | struct buff_data *buf_descriptor; |
||
552 | |||
553 | pkt->data = s->buf_start[buf.index]; |
||
554 | pkt->size = buf.bytesused; |
||
555 | #if FF_API_DESTRUCT_PACKET |
||
556 | FF_DISABLE_DEPRECATION_WARNINGS |
||
557 | pkt->destruct = dummy_release_buffer; |
||
558 | FF_ENABLE_DEPRECATION_WARNINGS |
||
559 | #endif |
||
560 | |||
561 | buf_descriptor = av_malloc(sizeof(struct buff_data)); |
||
562 | if (buf_descriptor == NULL) { |
||
563 | /* Something went wrong... Since av_malloc() failed, we cannot even |
||
564 | * allocate a buffer for memcpying into it |
||
565 | */ |
||
566 | av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); |
||
567 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) |
||
568 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); |
||
569 | |||
570 | return AVERROR(ENOMEM); |
||
571 | } |
||
572 | buf_descriptor->index = buf.index; |
||
573 | buf_descriptor->s = s; |
||
574 | |||
575 | pkt->buf = av_buffer_create(pkt->data, pkt->size, mmap_release_buffer, |
||
576 | buf_descriptor, 0); |
||
577 | if (!pkt->buf) { |
||
578 | av_log(ctx, AV_LOG_ERROR, "Failed to create a buffer\n"); |
||
579 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) |
||
580 | avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); |
||
581 | av_freep(&buf_descriptor); |
||
582 | return AVERROR(ENOMEM); |
||
583 | } |
||
584 | } |
||
585 | pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec; |
||
586 | convert_timestamp(ctx, &pkt->pts); |
||
587 | |||
588 | return s->buf_len[buf.index]; |
||
589 | } |
||
590 | |||
591 | static int mmap_start(AVFormatContext *ctx) |
||
592 | { |
||
593 | struct video_data *s = ctx->priv_data; |
||
594 | enum v4l2_buf_type type; |
||
595 | int i, res; |
||
596 | |||
597 | for (i = 0; i < s->buffers; i++) { |
||
598 | struct v4l2_buffer buf = { |
||
599 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
||
600 | .index = i, |
||
601 | .memory = V4L2_MEMORY_MMAP |
||
602 | }; |
||
603 | |||
604 | if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { |
||
605 | res = AVERROR(errno); |
||
606 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res)); |
||
607 | return res; |
||
608 | } |
||
609 | } |
||
610 | s->buffers_queued = s->buffers; |
||
611 | |||
612 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
||
613 | if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) { |
||
614 | res = AVERROR(errno); |
||
615 | av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", av_err2str(res)); |
||
616 | return res; |
||
617 | } |
||
618 | |||
619 | return 0; |
||
620 | } |
||
621 | |||
622 | static void mmap_close(struct video_data *s) |
||
623 | { |
||
624 | enum v4l2_buf_type type; |
||
625 | int i; |
||
626 | |||
627 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
||
628 | /* We do not check for the result, because we could |
||
629 | * not do anything about it anyway... |
||
630 | */ |
||
631 | v4l2_ioctl(s->fd, VIDIOC_STREAMOFF, &type); |
||
632 | for (i = 0; i < s->buffers; i++) { |
||
633 | v4l2_munmap(s->buf_start[i], s->buf_len[i]); |
||
634 | } |
||
635 | av_free(s->buf_start); |
||
636 | av_free(s->buf_len); |
||
637 | } |
||
638 | |||
639 | static int v4l2_set_parameters(AVFormatContext *s1) |
||
640 | { |
||
641 | struct video_data *s = s1->priv_data; |
||
642 | struct v4l2_standard standard = { 0 }; |
||
643 | struct v4l2_streamparm streamparm = { 0 }; |
||
644 | struct v4l2_fract *tpf; |
||
645 | AVRational framerate_q = { 0 }; |
||
646 | int i, ret; |
||
647 | |||
648 | if (s->framerate && |
||
649 | (ret = av_parse_video_rate(&framerate_q, s->framerate)) < 0) { |
||
650 | av_log(s1, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", |
||
651 | s->framerate); |
||
652 | return ret; |
||
653 | } |
||
654 | |||
655 | if (s->standard) { |
||
656 | if (s->std_id) { |
||
657 | ret = 0; |
||
658 | av_log(s1, AV_LOG_DEBUG, "Setting standard: %s\n", s->standard); |
||
659 | /* set tv standard */ |
||
660 | for (i = 0; ; i++) { |
||
661 | standard.index = i; |
||
662 | if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) { |
||
663 | ret = AVERROR(errno); |
||
664 | break; |
||
665 | } |
||
666 | if (!av_strcasecmp(standard.name, s->standard)) |
||
667 | break; |
||
668 | } |
||
669 | if (ret < 0) { |
||
670 | av_log(s1, AV_LOG_ERROR, "Unknown or unsupported standard '%s'\n", s->standard); |
||
671 | return ret; |
||
672 | } |
||
673 | |||
674 | if (v4l2_ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) { |
||
675 | ret = AVERROR(errno); |
||
676 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_STD): %s\n", av_err2str(ret)); |
||
677 | return ret; |
||
678 | } |
||
679 | } else { |
||
680 | av_log(s1, AV_LOG_WARNING, |
||
681 | "This device does not support any standard\n"); |
||
682 | } |
||
683 | } |
||
684 | |||
685 | /* get standard */ |
||
686 | if (v4l2_ioctl(s->fd, VIDIOC_G_STD, &s->std_id) == 0) { |
||
687 | tpf = &standard.frameperiod; |
||
688 | for (i = 0; ; i++) { |
||
689 | standard.index = i; |
||
690 | if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) { |
||
691 | ret = AVERROR(errno); |
||
692 | if (ret == AVERROR(EINVAL)) { |
||
693 | tpf = &streamparm.parm.capture.timeperframe; |
||
694 | break; |
||
695 | } |
||
696 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", av_err2str(ret)); |
||
697 | return ret; |
||
698 | } |
||
699 | if (standard.id == s->std_id) { |
||
700 | av_log(s1, AV_LOG_DEBUG, |
||
701 | "Current standard: %s, id: %"PRIx64", frameperiod: %d/%d\n", |
||
702 | standard.name, (uint64_t)standard.id, tpf->numerator, tpf->denominator); |
||
703 | break; |
||
704 | } |
||
705 | } |
||
706 | } else { |
||
707 | tpf = &streamparm.parm.capture.timeperframe; |
||
708 | } |
||
709 | |||
710 | streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
||
711 | if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) { |
||
712 | ret = AVERROR(errno); |
||
713 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); |
||
714 | return ret; |
||
715 | } |
||
716 | |||
717 | if (framerate_q.num && framerate_q.den) { |
||
718 | if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { |
||
719 | tpf = &streamparm.parm.capture.timeperframe; |
||
720 | |||
721 | av_log(s1, AV_LOG_DEBUG, "Setting time per frame to %d/%d\n", |
||
722 | framerate_q.den, framerate_q.num); |
||
723 | tpf->numerator = framerate_q.den; |
||
724 | tpf->denominator = framerate_q.num; |
||
725 | |||
726 | if (v4l2_ioctl(s->fd, VIDIOC_S_PARM, &streamparm) < 0) { |
||
727 | ret = AVERROR(errno); |
||
728 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_PARM): %s\n", av_err2str(ret)); |
||
729 | return ret; |
||
730 | } |
||
731 | |||
732 | if (framerate_q.num != tpf->denominator || |
||
733 | framerate_q.den != tpf->numerator) { |
||
734 | av_log(s1, AV_LOG_INFO, |
||
735 | "The driver changed the time per frame from " |
||
736 | "%d/%d to %d/%d\n", |
||
737 | framerate_q.den, framerate_q.num, |
||
738 | tpf->numerator, tpf->denominator); |
||
739 | } |
||
740 | } else { |
||
741 | av_log(s1, AV_LOG_WARNING, |
||
742 | "The driver does not allow to change time per frame\n"); |
||
743 | } |
||
744 | } |
||
745 | s1->streams[0]->avg_frame_rate.num = tpf->denominator; |
||
746 | s1->streams[0]->avg_frame_rate.den = tpf->numerator; |
||
747 | s1->streams[0]->r_frame_rate = s1->streams[0]->avg_frame_rate; |
||
748 | |||
749 | return 0; |
||
750 | } |
||
751 | |||
752 | static int device_try_init(AVFormatContext *s1, |
||
753 | enum AVPixelFormat pix_fmt, |
||
754 | int *width, |
||
755 | int *height, |
||
756 | uint32_t *desired_format, |
||
757 | enum AVCodecID *codec_id) |
||
758 | { |
||
759 | int ret, i; |
||
760 | |||
761 | *desired_format = avpriv_fmt_ff2v4l(pix_fmt, s1->video_codec_id); |
||
762 | |||
763 | if (*desired_format) { |
||
764 | ret = device_init(s1, width, height, *desired_format); |
||
765 | if (ret < 0) { |
||
766 | *desired_format = 0; |
||
767 | if (ret != AVERROR(EINVAL)) |
||
768 | return ret; |
||
769 | } |
||
770 | } |
||
771 | |||
772 | if (!*desired_format) { |
||
773 | for (i = 0; avpriv_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) { |
||
774 | if (s1->video_codec_id == AV_CODEC_ID_NONE || |
||
775 | avpriv_fmt_conversion_table[i].codec_id == s1->video_codec_id) { |
||
776 | av_log(s1, AV_LOG_DEBUG, "Trying to set codec:%s pix_fmt:%s\n", |
||
777 | avcodec_get_name(avpriv_fmt_conversion_table[i].codec_id), |
||
778 | (char *)av_x_if_null(av_get_pix_fmt_name(avpriv_fmt_conversion_table[i].ff_fmt), "none")); |
||
779 | |||
780 | *desired_format = avpriv_fmt_conversion_table[i].v4l2_fmt; |
||
781 | ret = device_init(s1, width, height, *desired_format); |
||
782 | if (ret >= 0) |
||
783 | break; |
||
784 | else if (ret != AVERROR(EINVAL)) |
||
785 | return ret; |
||
786 | *desired_format = 0; |
||
787 | } |
||
788 | } |
||
789 | |||
790 | if (*desired_format == 0) { |
||
791 | av_log(s1, AV_LOG_ERROR, "Cannot find a proper format for " |
||
792 | "codec '%s' (id %d), pixel format '%s' (id %d)\n", |
||
793 | avcodec_get_name(s1->video_codec_id), s1->video_codec_id, |
||
794 | (char *)av_x_if_null(av_get_pix_fmt_name(pix_fmt), "none"), pix_fmt); |
||
795 | ret = AVERROR(EINVAL); |
||
796 | } |
||
797 | } |
||
798 | |||
799 | *codec_id = avpriv_fmt_v4l2codec(*desired_format); |
||
800 | av_assert0(*codec_id != AV_CODEC_ID_NONE); |
||
801 | return ret; |
||
802 | } |
||
803 | |||
804 | static int v4l2_read_header(AVFormatContext *s1) |
||
805 | { |
||
806 | struct video_data *s = s1->priv_data; |
||
807 | AVStream *st; |
||
808 | int res = 0; |
||
809 | uint32_t desired_format; |
||
810 | enum AVCodecID codec_id = AV_CODEC_ID_NONE; |
||
811 | enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE; |
||
812 | struct v4l2_input input = { 0 }; |
||
813 | |||
814 | st = avformat_new_stream(s1, NULL); |
||
815 | if (!st) |
||
816 | return AVERROR(ENOMEM); |
||
817 | |||
818 | #if CONFIG_LIBV4L2 |
||
819 | /* silence libv4l2 logging. if fopen() fails v4l2_log_file will be NULL |
||
820 | and errors will get sent to stderr */ |
||
821 | if (s->use_libv4l2) |
||
822 | v4l2_log_file = fopen("/dev/null", "w"); |
||
823 | #endif |
||
824 | |||
825 | s->fd = device_open(s1); |
||
826 | if (s->fd < 0) |
||
827 | return s->fd; |
||
828 | |||
829 | if (s->channel != -1) { |
||
830 | /* set video input */ |
||
831 | av_log(s1, AV_LOG_DEBUG, "Selecting input_channel: %d\n", s->channel); |
||
832 | if (v4l2_ioctl(s->fd, VIDIOC_S_INPUT, &s->channel) < 0) { |
||
833 | res = AVERROR(errno); |
||
834 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res)); |
||
835 | return res; |
||
836 | } |
||
837 | } else { |
||
838 | /* get current video input */ |
||
839 | if (v4l2_ioctl(s->fd, VIDIOC_G_INPUT, &s->channel) < 0) { |
||
840 | res = AVERROR(errno); |
||
841 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res)); |
||
842 | return res; |
||
843 | } |
||
844 | } |
||
845 | |||
846 | /* enum input */ |
||
847 | input.index = s->channel; |
||
848 | if (v4l2_ioctl(s->fd, VIDIOC_ENUMINPUT, &input) < 0) { |
||
849 | res = AVERROR(errno); |
||
850 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMINPUT): %s\n", av_err2str(res)); |
||
851 | return res; |
||
852 | } |
||
853 | s->std_id = input.std; |
||
854 | av_log(s1, AV_LOG_DEBUG, "Current input_channel: %d, input_name: %s, input_std: %"PRIx64"\n", |
||
855 | s->channel, input.name, (uint64_t)input.std); |
||
856 | |||
857 | if (s->list_format) { |
||
858 | list_formats(s1, s->fd, s->list_format); |
||
859 | return AVERROR_EXIT; |
||
860 | } |
||
861 | |||
862 | if (s->list_standard) { |
||
863 | list_standards(s1); |
||
864 | return AVERROR_EXIT; |
||
865 | } |
||
866 | |||
867 | avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ |
||
868 | |||
869 | if (s->pixel_format) { |
||
870 | AVCodec *codec = avcodec_find_decoder_by_name(s->pixel_format); |
||
871 | |||
872 | if (codec) |
||
873 | s1->video_codec_id = codec->id; |
||
874 | |||
875 | pix_fmt = av_get_pix_fmt(s->pixel_format); |
||
876 | |||
877 | if (pix_fmt == AV_PIX_FMT_NONE && !codec) { |
||
878 | av_log(s1, AV_LOG_ERROR, "No such input format: %s.\n", |
||
879 | s->pixel_format); |
||
880 | |||
881 | return AVERROR(EINVAL); |
||
882 | } |
||
883 | } |
||
884 | |||
885 | if (!s->width && !s->height) { |
||
886 | struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; |
||
887 | |||
888 | av_log(s1, AV_LOG_VERBOSE, |
||
889 | "Querying the device for the current frame size\n"); |
||
890 | if (v4l2_ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) { |
||
891 | res = AVERROR(errno); |
||
892 | av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n", av_err2str(res)); |
||
893 | return res; |
||
894 | } |
||
895 | |||
896 | s->width = fmt.fmt.pix.width; |
||
897 | s->height = fmt.fmt.pix.height; |
||
898 | av_log(s1, AV_LOG_VERBOSE, |
||
899 | "Setting frame size to %dx%d\n", s->width, s->height); |
||
900 | } |
||
901 | |||
902 | res = device_try_init(s1, pix_fmt, &s->width, &s->height, &desired_format, &codec_id); |
||
903 | if (res < 0) { |
||
904 | v4l2_close(s->fd); |
||
905 | return res; |
||
906 | } |
||
907 | |||
908 | /* If no pixel_format was specified, the codec_id was not known up |
||
909 | * until now. Set video_codec_id in the context, as codec_id will |
||
910 | * not be available outside this function |
||
911 | */ |
||
912 | if (codec_id != AV_CODEC_ID_NONE && s1->video_codec_id == AV_CODEC_ID_NONE) |
||
913 | s1->video_codec_id = codec_id; |
||
914 | |||
915 | if ((res = av_image_check_size(s->width, s->height, 0, s1)) < 0) |
||
916 | return res; |
||
917 | |||
918 | s->frame_format = desired_format; |
||
919 | |||
920 | if ((res = v4l2_set_parameters(s1)) < 0) |
||
921 | return res; |
||
922 | |||
923 | st->codec->pix_fmt = avpriv_fmt_v4l2ff(desired_format, codec_id); |
||
924 | s->frame_size = |
||
925 | avpicture_get_size(st->codec->pix_fmt, s->width, s->height); |
||
926 | |||
927 | if ((res = mmap_init(s1)) || |
||
928 | (res = mmap_start(s1)) < 0) { |
||
929 | v4l2_close(s->fd); |
||
930 | return res; |
||
931 | } |
||
932 | |||
933 | s->top_field_first = first_field(s, s->fd); |
||
934 | |||
935 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
||
936 | st->codec->codec_id = codec_id; |
||
937 | if (codec_id == AV_CODEC_ID_RAWVIDEO) |
||
938 | st->codec->codec_tag = |
||
939 | avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); |
||
940 | else if (codec_id == AV_CODEC_ID_H264) { |
||
941 | st->need_parsing = AVSTREAM_PARSE_HEADERS; |
||
942 | } |
||
943 | if (desired_format == V4L2_PIX_FMT_YVU420) |
||
944 | st->codec->codec_tag = MKTAG('Y', 'V', '1', '2'); |
||
945 | else if (desired_format == V4L2_PIX_FMT_YVU410) |
||
946 | st->codec->codec_tag = MKTAG('Y', 'V', 'U', '9'); |
||
947 | st->codec->width = s->width; |
||
948 | st->codec->height = s->height; |
||
949 | st->codec->bit_rate = s->frame_size * av_q2d(st->avg_frame_rate) * 8; |
||
950 | |||
951 | return 0; |
||
952 | } |
||
953 | |||
954 | static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt) |
||
955 | { |
||
956 | struct video_data *s = s1->priv_data; |
||
957 | AVFrame *frame = s1->streams[0]->codec->coded_frame; |
||
958 | int res; |
||
959 | |||
960 | av_init_packet(pkt); |
||
961 | if ((res = mmap_read_frame(s1, pkt)) < 0) { |
||
962 | return res; |
||
963 | } |
||
964 | |||
965 | if (frame && s->interlaced) { |
||
966 | frame->interlaced_frame = 1; |
||
967 | frame->top_field_first = s->top_field_first; |
||
968 | } |
||
969 | |||
970 | return pkt->size; |
||
971 | } |
||
972 | |||
973 | static int v4l2_read_close(AVFormatContext *s1) |
||
974 | { |
||
975 | struct video_data *s = s1->priv_data; |
||
976 | |||
977 | if (avpriv_atomic_int_get(&s->buffers_queued) != s->buffers) |
||
978 | av_log(s1, AV_LOG_WARNING, "Some buffers are still owned by the caller on " |
||
979 | "close.\n"); |
||
980 | |||
981 | mmap_close(s); |
||
982 | |||
983 | v4l2_close(s->fd); |
||
984 | return 0; |
||
985 | } |
||
986 | |||
987 | #define OFFSET(x) offsetof(struct video_data, x) |
||
988 | #define DEC AV_OPT_FLAG_DECODING_PARAM |
||
989 | |||
990 | static const AVOption options[] = { |
||
991 | { "standard", "set TV standard, used only by analog frame grabber", OFFSET(standard), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC }, |
||
992 | { "channel", "set TV channel, used only by frame grabber", OFFSET(channel), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, DEC }, |
||
993 | { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, |
||
994 | { "pixel_format", "set preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, |
||
995 | { "input_format", "set preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, |
||
996 | { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, |
||
997 | |||
998 | { "list_formats", "list available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC, "list_formats" }, |
||
999 | { "all", "show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" }, |
||
1000 | { "raw", "show only non-compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_RAWFORMATS }, 0, INT_MAX, DEC, "list_formats" }, |
||
1001 | { "compressed", "show only compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_COMPFORMATS }, 0, INT_MAX, DEC, "list_formats" }, |
||
1002 | |||
1003 | { "list_standards", "list supported standards and exit", OFFSET(list_standard), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC, "list_standards" }, |
||
1004 | { "all", "show all supported standards", OFFSET(list_standard), AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, DEC, "list_standards" }, |
||
1005 | |||
1006 | { "timestamps", "set type of timestamps for grabbed frames", OFFSET(ts_mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "timestamps" }, |
||
1007 | { "ts", "set type of timestamps for grabbed frames", OFFSET(ts_mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "timestamps" }, |
||
1008 | { "default", "use timestamps from the kernel", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_DEFAULT }, 0, 2, DEC, "timestamps" }, |
||
1009 | { "abs", "use absolute timestamps (wall clock)", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_ABS }, 0, 2, DEC, "timestamps" }, |
||
1010 | { "mono2abs", "force conversion from monotonic to absolute timestamps", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_MONO2ABS }, 0, 2, DEC, "timestamps" }, |
||
1011 | { "use_libv4l2", "use libv4l2 (v4l-utils) convertion functions", OFFSET(use_libv4l2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, |
||
1012 | { NULL }, |
||
1013 | }; |
||
1014 | |||
1015 | static const AVClass v4l2_class = { |
||
1016 | .class_name = "V4L2 indev", |
||
1017 | .item_name = av_default_item_name, |
||
1018 | .option = options, |
||
1019 | .version = LIBAVUTIL_VERSION_INT, |
||
1020 | }; |
||
1021 | |||
1022 | AVInputFormat ff_v4l2_demuxer = { |
||
1023 | .name = "video4linux2,v4l2", |
||
1024 | .long_name = NULL_IF_CONFIG_SMALL("Video4Linux2 device grab"), |
||
1025 | .priv_data_size = sizeof(struct video_data), |
||
1026 | .read_header = v4l2_read_header, |
||
1027 | .read_packet = v4l2_read_packet, |
||
1028 | .read_close = v4l2_read_close, |
||
1029 | .flags = AVFMT_NOFILE, |
||
1030 | .priv_class = &v4l2_class, |
||
1031 | };>>>>>>>>>>>>>>>>>>>>>>>>>>>=>=>>>>>>>>>>>>>>>>> |