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