1 /* fswebcam - FireStorm.cx's webcam generator */
2 /*===========================================================*/
3 /* Copyright (C)2005-2009 Philip Heron <phil@firestorm.cx> */
5 /* This program is distributed under the terms of the GNU */
6 /* General Public License, version 2. You may use, modify, */
7 /* and redistribute it under the terms of this license. A */
8 /* copy should be included with this source. */
20 #include <sys/ioctl.h>
22 #include "videodev2.h"
38 struct v4l2_capability cap
;
39 struct v4l2_format fmt
;
40 struct v4l2_requestbuffers req
;
41 struct v4l2_buffer buf
;
43 v4l2_buffer_t
*buffer
;
54 v4l2_palette_t v4l2_palette
[] = {
55 { SRC_PAL_JPEG
, V4L2_PIX_FMT_JPEG
},
56 { SRC_PAL_MJPEG
, V4L2_PIX_FMT_MJPEG
},
57 { SRC_PAL_RGB24
, V4L2_PIX_FMT_RGB24
},
58 { SRC_PAL_BGR24
, V4L2_PIX_FMT_BGR24
},
59 { SRC_PAL_RGB32
, V4L2_PIX_FMT_RGB32
},
60 { SRC_PAL_BGR32
, V4L2_PIX_FMT_BGR32
},
61 { SRC_PAL_YUYV
, V4L2_PIX_FMT_YUYV
},
62 { SRC_PAL_UYVY
, V4L2_PIX_FMT_UYVY
},
63 { SRC_PAL_YUV420P
, V4L2_PIX_FMT_YUV420
},
64 { SRC_PAL_BAYER
, V4L2_PIX_FMT_SBGGR8
},
65 { SRC_PAL_SGBRG8
, V4L2_PIX_FMT_SGBRG8
},
66 { SRC_PAL_RGB565
, V4L2_PIX_FMT_RGB565
},
67 { SRC_PAL_RGB555
, V4L2_PIX_FMT_RGB555
},
68 { SRC_PAL_GREY
, V4L2_PIX_FMT_GREY
},
72 int src_v4l2_get_capability(src_t
*src
)
74 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
76 if(ioctl(s
->fd
, VIDIOC_QUERYCAP
, &s
->cap
) < 0)
78 ERROR("%s: Not a V4L2 device?", src
->source
);
82 DEBUG("%s information:", src
->source
);
83 DEBUG("cap.driver: \"%s\"", s
->cap
.driver
);
84 DEBUG("cap.card: \"%s\"", s
->cap
.card
);
85 DEBUG("cap.bus_info: \"%s\"", s
->cap
.bus_info
);
86 DEBUG("cap.capabilities=0x%08X", s
->cap
.capabilities
);
87 if(s
->cap
.capabilities
& V4L2_CAP_VIDEO_CAPTURE
) DEBUG("- VIDEO_CAPTURE");
88 if(s
->cap
.capabilities
& V4L2_CAP_VIDEO_OUTPUT
) DEBUG("- VIDEO_OUTPUT");
89 if(s
->cap
.capabilities
& V4L2_CAP_VIDEO_OVERLAY
) DEBUG("- VIDEO_OVERLAY");
90 if(s
->cap
.capabilities
& V4L2_CAP_VBI_CAPTURE
) DEBUG("- VBI_CAPTURE");
91 if(s
->cap
.capabilities
& V4L2_CAP_VBI_OUTPUT
) DEBUG("- VBI_OUTPUT");
92 if(s
->cap
.capabilities
& V4L2_CAP_RDS_CAPTURE
) DEBUG("- RDS_CAPTURE");
93 if(s
->cap
.capabilities
& V4L2_CAP_TUNER
) DEBUG("- TUNER");
94 if(s
->cap
.capabilities
& V4L2_CAP_AUDIO
) DEBUG("- AUDIO");
95 if(s
->cap
.capabilities
& V4L2_CAP_RADIO
) DEBUG("- RADIO");
96 if(s
->cap
.capabilities
& V4L2_CAP_READWRITE
) DEBUG("- READWRITE");
97 if(s
->cap
.capabilities
& V4L2_CAP_ASYNCIO
) DEBUG("- ASYNCIO");
98 if(s
->cap
.capabilities
& V4L2_CAP_STREAMING
) DEBUG("- STREAMING");
99 if(s
->cap
.capabilities
& V4L2_CAP_TIMEPERFRAME
) DEBUG("- TIMEPERFRAME");
101 if(!s
->cap
.capabilities
& V4L2_CAP_VIDEO_CAPTURE
)
103 ERROR("Device does not support capturing.");
110 int src_v4l2_set_input(src_t
*src
)
112 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
113 struct v4l2_input input
;
114 int count
= 0, i
= -1;
116 memset(&input
, 0, sizeof(input
));
118 if(src
->list
& SRC_LIST_INPUTS
)
120 HEAD("--- Avaliable inputs:");
123 while(!ioctl(s
->fd
, VIDIOC_ENUMINPUT
, &input
))
125 MSG("%i: %s", count
, input
.name
);
126 input
.index
= ++count
;
130 /* If no input was specified, use input 0. */
133 MSG("No input was specified, using the first.");
138 /* Check if the input is specified by name. */
142 while(!ioctl(s
->fd
, VIDIOC_ENUMINPUT
, &input
))
144 if(!strncasecmp((char *) input
.name
, src
->input
, 32))
146 input
.index
= ++count
;
154 /* Is the input specified by number? */
155 i
= strtol(src
->input
, &endptr
, 10);
157 if(endptr
== src
->input
) i
= -1;
160 if(i
== -1 || i
>= count
)
162 /* The specified input wasn't found! */
163 ERROR("Unrecognised input \"%s\"", src
->input
);
169 if(ioctl(s
->fd
, VIDIOC_ENUMINPUT
, &input
) == -1)
171 ERROR("Unable to query input %i.", i
);
172 ERROR("VIDIOC_ENUMINPUT: %s", strerror(errno
));
176 DEBUG("%s: Input %i information:", src
->source
, i
);
177 DEBUG("name = \"%s\"", input
.name
);
178 DEBUG("type = %08X", input
.type
);
179 if(input
.type
& V4L2_INPUT_TYPE_TUNER
) DEBUG("- TUNER");
180 if(input
.type
& V4L2_INPUT_TYPE_CAMERA
) DEBUG("- CAMERA");
181 DEBUG("audioset = %08X", input
.audioset
);
182 DEBUG("tuner = %08X", input
.tuner
);
183 DEBUG("status = %08X", input
.status
);
184 if(input
.status
& V4L2_IN_ST_NO_POWER
) DEBUG("- NO_POWER");
185 if(input
.status
& V4L2_IN_ST_NO_SIGNAL
) DEBUG("- NO_SIGNAL");
186 if(input
.status
& V4L2_IN_ST_NO_COLOR
) DEBUG("- NO_COLOR");
187 if(input
.status
& V4L2_IN_ST_NO_H_LOCK
) DEBUG("- NO_H_LOCK");
188 if(input
.status
& V4L2_IN_ST_COLOR_KILL
) DEBUG("- COLOR_KILL");
189 if(input
.status
& V4L2_IN_ST_NO_SYNC
) DEBUG("- NO_SYNC");
190 if(input
.status
& V4L2_IN_ST_NO_EQU
) DEBUG("- NO_EQU");
191 if(input
.status
& V4L2_IN_ST_NO_CARRIER
) DEBUG("- NO_CARRIER");
192 if(input
.status
& V4L2_IN_ST_MACROVISION
) DEBUG("- MACROVISION");
193 if(input
.status
& V4L2_IN_ST_NO_ACCESS
) DEBUG("- NO_ACCESS");
194 if(input
.status
& V4L2_IN_ST_VTR
) DEBUG("- VTR");
196 if(ioctl(s
->fd
, VIDIOC_S_INPUT
, &i
) == -1)
198 ERROR("Error selecting input %i", i
);
199 ERROR("VIDIOC_S_INPUT: %s", strerror(errno
));
203 /* If this input is attached to a tuner, set the frequency. */
204 if(input
.type
& V4L2_INPUT_TYPE_TUNER
)
207 struct v4l2_tuner tuner
;
208 struct v4l2_frequency freq
;
210 /* Query the tuners capabilities. */
212 memset(&tuner
, 0, sizeof(tuner
));
213 tuner
.index
= input
.tuner
;
215 if(ioctl(s
->fd
, VIDIOC_G_TUNER
, &tuner
) == -1)
217 WARN("Error querying tuner %i.", input
.tuner
);
218 WARN("VIDIOC_G_TUNER: %s", strerror(errno
));
222 if(tuner
.capability
& V4L2_TUNER_CAP_LOW
) range
= "kHz";
225 DEBUG("%s: Tuner %i information:", src
->source
, input
.tuner
);
226 DEBUG("name = \"%s\"", tuner
.name
);
227 DEBUG("type = %08X", tuner
.type
);
228 if(tuner
.type
== V4L2_TUNER_RADIO
) DEBUG("- RADIO");
229 if(tuner
.type
== V4L2_TUNER_ANALOG_TV
) DEBUG("- ANALOG_TV");
230 DEBUG("capability = %08X", tuner
.capability
);
231 if(tuner
.capability
& V4L2_TUNER_CAP_LOW
) DEBUG("- LOW");
232 if(tuner
.capability
& V4L2_TUNER_CAP_NORM
) DEBUG("- NORM");
233 if(tuner
.capability
& V4L2_TUNER_CAP_STEREO
) DEBUG("- STEREO");
234 if(tuner
.capability
& V4L2_TUNER_CAP_LANG1
) DEBUG("- LANG1");
235 if(tuner
.capability
& V4L2_TUNER_CAP_LANG2
) DEBUG("- LANG2");
236 if(tuner
.capability
& V4L2_TUNER_CAP_SAP
) DEBUG("- SAP");
237 DEBUG("rangelow = %08X, (%.3f%s)", tuner
.rangelow
, (double) tuner
.rangelow
* 16 / 1000, range
);
238 DEBUG("rangehigh = %08X, (%.3f%s)", tuner
.rangehigh
, (double) tuner
.rangehigh
* 16 / 1000, range
);
239 DEBUG("signal = %08X", tuner
.signal
);
240 DEBUG("afc = %08X", tuner
.afc
);
242 /* Set the frequency. */
243 memset(&freq
, 0, sizeof(freq
));
244 freq
.tuner
= input
.tuner
;
245 freq
.type
= V4L2_TUNER_ANALOG_TV
;
246 freq
.frequency
= (src
->frequency
/ 1000) * 16;
248 if(ioctl(s
->fd
, VIDIOC_S_FREQUENCY
, &freq
) == -1)
250 WARN("Error setting frequency %.3f%s", src
->frequency
/ 16.0, range
);
251 WARN("VIDIOC_S_FREQUENCY: %s", strerror(errno
));
255 MSG("Set frequency to %.3f%s",
256 (double) src
->frequency
/ 1000, range
);
262 int src_v4l2_show_control(src_t
*src
, struct v4l2_queryctrl
*queryctrl
)
264 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
265 struct v4l2_querymenu querymenu
;
266 struct v4l2_control control
;
270 if(queryctrl
->flags
& V4L2_CTRL_FLAG_DISABLED
) return(0);
272 memset(&querymenu
, 0, sizeof(querymenu
));
273 memset(&control
, 0, sizeof(control
));
275 if(queryctrl
->type
!= V4L2_CTRL_TYPE_BUTTON
)
277 control
.id
= queryctrl
->id
;
278 if(ioctl(s
->fd
, VIDIOC_G_CTRL
, &control
))
280 ERROR("Error reading value of control '%s'.", queryctrl
->name
);
281 ERROR("VIDIOC_G_CTRL: %s", strerror(errno
));
285 switch(queryctrl
->type
)
287 case V4L2_CTRL_TYPE_INTEGER
:
289 t
= malloc(64); /* Ick ... TODO: re-write this. */
292 ERROR("Out of memory.");
296 if(queryctrl
->maximum
- queryctrl
->minimum
<= 10)
298 snprintf(t
, 63, "%i", control
.value
);
302 snprintf(t
, 63, "%i (%i%%)",
310 MSG("%-25s %-15s %i - %i", queryctrl
->name
, t
,
311 queryctrl
->minimum
, queryctrl
->maximum
);
317 case V4L2_CTRL_TYPE_BOOLEAN
:
318 MSG("%-25s %-15s True | False", queryctrl
->name
,
319 (control
.value
? "True" : "False"));
322 case V4L2_CTRL_TYPE_MENU
:
324 querymenu
.id
= queryctrl
->id
;
326 t
= calloc((queryctrl
->maximum
- queryctrl
->minimum
) + 1, 34);
327 m
= queryctrl
->minimum
;
328 for(m
= queryctrl
->minimum
; m
<= queryctrl
->maximum
; m
++)
331 if(!ioctl(s
->fd
, VIDIOC_QUERYMENU
, &querymenu
))
333 strncat(t
, (char *) querymenu
.name
, 32);
334 if(m
< queryctrl
->maximum
) strncat(t
, " | ", 3);
338 querymenu
.index
= control
.value
;
339 if(ioctl(s
->fd
, VIDIOC_QUERYMENU
, &querymenu
))
342 ERROR("Error reading value of menu item %i for control '%s'",
343 control
.value
, queryctrl
->name
);
344 ERROR("VIDIOC_QUERYMENU: %s", strerror(errno
));
348 MSG("%-25s %-15s %s", queryctrl
->name
, querymenu
.name
, t
);
353 case V4L2_CTRL_TYPE_BUTTON
:
354 MSG("%-25s %-15s %s", queryctrl
->name
, "-", "[Button]");
358 MSG("%-25s %-15s %s", queryctrl
->name
, "N/A", "[Unknown Control Type]");
365 int src_v4l2_set_control(src_t
*src
, struct v4l2_queryctrl
*queryctrl
)
367 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
368 struct v4l2_control control
;
369 struct v4l2_querymenu querymenu
;
373 if(queryctrl
->flags
& V4L2_CTRL_FLAG_DISABLED
) return(0);
374 if(src_get_option_by_name(src
->option
, (char *) queryctrl
->name
, &sv
))
377 memset(&querymenu
, 0, sizeof(querymenu
));
378 memset(&control
, 0, sizeof(control
));
380 control
.id
= queryctrl
->id
;
382 switch(queryctrl
->type
)
384 case V4L2_CTRL_TYPE_INTEGER
:
386 /* Convert the value to an integer. */
389 /* Is the value a precentage? */
392 /* Adjust the precentage to fit the controls range. */
393 iv
= SCALE(queryctrl
->minimum
, queryctrl
->maximum
,
397 MSG("Setting %s to %i (%i%%).", queryctrl
->name
, iv
,
398 SCALE(0, 100, queryctrl
->minimum
, queryctrl
->maximum
, iv
));
400 if(iv
< queryctrl
->minimum
|| iv
> queryctrl
->maximum
)
401 WARN("Value is out of range. Setting anyway.");
404 ioctl(s
->fd
, VIDIOC_S_CTRL
, &control
);
407 case V4L2_CTRL_TYPE_BOOLEAN
:
410 if(!strcasecmp(sv
, "1") || !strcasecmp(sv
, "true")) iv
= 1;
411 if(!strcasecmp(sv
, "0") || !strcasecmp(sv
, "false")) iv
= 0;
415 WARN("Unknown boolean value '%s' for %s.",
416 sv
, queryctrl
->name
);
420 MSG("Setting %s to %s (%i).", queryctrl
->name
, sv
, iv
);
423 ioctl(s
->fd
, VIDIOC_S_CTRL
, &control
);
427 case V4L2_CTRL_TYPE_MENU
:
429 /* Scan for a matching value. */
430 querymenu
.id
= queryctrl
->id
;
432 for(iv
= queryctrl
->minimum
; iv
<= queryctrl
->maximum
; iv
++)
434 querymenu
.index
= iv
;
436 if(ioctl(s
->fd
, VIDIOC_QUERYMENU
, &querymenu
))
438 ERROR("Error querying menu.");
442 if(!strncasecmp((char *) querymenu
.name
, sv
, 32))
446 if(iv
> queryctrl
->maximum
)
448 MSG("Unknown value '%s' for %s.", sv
, queryctrl
->name
);
452 MSG("Setting %s to %s (%i).",
453 queryctrl
->name
, querymenu
.name
, iv
);
456 ioctl(s
->fd
, VIDIOC_S_CTRL
, &control
);
460 case V4L2_CTRL_TYPE_BUTTON
:
462 MSG("Triggering %s control.", queryctrl
->name
);
463 ioctl(s
->fd
, VIDIOC_S_CTRL
, &control
);
468 WARN("Not setting unknown control type %i (%s).",
476 int src_v4l2_set_controls(src_t
*src
)
478 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
479 struct v4l2_queryctrl queryctrl
;
482 memset(&queryctrl
, 0, sizeof(queryctrl
));
484 if(src
->list
& SRC_LIST_CONTROLS
)
486 HEAD("%-25s %-15s %s", "Available Controls", "Current Value", "Range");
487 MSG("%-25s %-15s %s", "------------------", "-------------", "-----");
489 /* Display normal controls. */
490 for(c
= V4L2_CID_BASE
; c
< V4L2_CID_LASTP1
; c
++)
494 if(ioctl(s
->fd
, VIDIOC_QUERYCTRL
, &queryctrl
)) continue;
495 src_v4l2_show_control(src
, &queryctrl
);
498 /* Display device-specific controls. */
499 for(c
= V4L2_CID_PRIVATE_BASE
; ; c
++)
503 if(ioctl(s
->fd
, VIDIOC_QUERYCTRL
, &queryctrl
)) break;
504 src_v4l2_show_control(src
, &queryctrl
);
508 /* Scan normal controls. */
509 for(c
= V4L2_CID_BASE
; c
< V4L2_CID_LASTP1
; c
++)
513 if(ioctl(s
->fd
, VIDIOC_QUERYCTRL
, &queryctrl
)) continue;
514 src_v4l2_set_control(src
, &queryctrl
);
517 /* Scan device-specific controls. */
518 for(c
= V4L2_CID_PRIVATE_BASE
; ; c
++)
522 if(ioctl(s
->fd
, VIDIOC_QUERYCTRL
, &queryctrl
)) break;
523 src_v4l2_set_control(src
, &queryctrl
);
529 int src_v4l2_set_pix_format(src_t
*src
)
531 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
532 struct v4l2_fmtdesc fmt
;
535 /* Dump a list of formats the device supports. */
536 DEBUG("Device offers the following V4L2 pixel formats:");
539 memset(&fmt
, 0, sizeof(fmt
));
540 fmt
.index
= v4l2_pal
;
541 fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
543 while(ioctl(s
->fd
, VIDIOC_ENUM_FMT
, &fmt
) != -1)
545 DEBUG("%i: %c%c%c%c (%s)", v4l2_pal
,
546 fmt
.pixelformat
>> 0, fmt
.pixelformat
>> 8,
547 fmt
.pixelformat
>> 16, fmt
.pixelformat
>> 24,
550 memset(&fmt
, 0, sizeof(fmt
));
551 fmt
.index
= ++v4l2_pal
;
552 fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
555 /* Step through each palette type. */
558 if(src
->palette
!= -1)
560 while(v4l2_palette
[v4l2_pal
].v4l2
)
562 if(v4l2_palette
[v4l2_pal
].src
== src
->palette
) break;
566 if(!v4l2_palette
[v4l2_pal
].v4l2
)
568 ERROR("Unable to handle palette format %s.",
569 src_palette
[src
->palette
]);
575 while(v4l2_palette
[v4l2_pal
].v4l2
)
577 /* Try the palette... */
578 memset(&s
->fmt
, 0, sizeof(s
->fmt
));
579 s
->fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
580 s
->fmt
.fmt
.pix
.width
= src
->width
;
581 s
->fmt
.fmt
.pix
.height
= src
->height
;
582 s
->fmt
.fmt
.pix
.pixelformat
= v4l2_palette
[v4l2_pal
].v4l2
;
583 s
->fmt
.fmt
.pix
.field
= V4L2_FIELD_ANY
;
585 if(ioctl(s
->fd
, VIDIOC_TRY_FMT
, &s
->fmt
) != -1 &&
586 s
->fmt
.fmt
.pix
.pixelformat
== v4l2_palette
[v4l2_pal
].v4l2
)
588 src
->palette
= v4l2_palette
[v4l2_pal
].src
;
590 INFO("Using palette %s", src_palette
[src
->palette
].name
);
592 if(s
->fmt
.fmt
.pix
.width
!= src
->width
||
593 s
->fmt
.fmt
.pix
.height
!= src
->height
)
595 MSG("Adjusting resolution from %ix%i to %ix%i.",
596 src
->width
, src
->height
,
597 s
->fmt
.fmt
.pix
.width
,
598 s
->fmt
.fmt
.pix
.height
);
599 src
->width
= s
->fmt
.fmt
.pix
.width
;
600 src
->height
= s
->fmt
.fmt
.pix
.height
;
603 if(ioctl(s
->fd
, VIDIOC_S_FMT
, &s
->fmt
) == -1)
605 ERROR("Error setting pixel format.");
606 ERROR("VIDIOC_S_FMT: %s", strerror(errno
));
610 if(v4l2_palette
[v4l2_pal
].v4l2
== V4L2_PIX_FMT_MJPEG
)
612 struct v4l2_jpegcompression jpegcomp
;
614 memset(&jpegcomp
, 0, sizeof(jpegcomp
));
615 ioctl(s
->fd
, VIDIOC_G_JPEGCOMP
, &jpegcomp
);
616 jpegcomp
.jpeg_markers
|= V4L2_JPEG_MARKER_DHT
;
617 ioctl(s
->fd
, VIDIOC_S_JPEGCOMP
, &jpegcomp
);
623 if(src
->palette
!= -1) break;
628 ERROR("Unable to find a compatible palette format.");
633 int src_v4l2_set_fps(src_t
*src
)
635 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
636 struct v4l2_streamparm setfps
;
638 memset(&setfps
, 0, sizeof(setfps
));
640 setfps
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
641 setfps
.parm
.capture
.timeperframe
.numerator
= 1;
642 setfps
.parm
.capture
.timeperframe
.denominator
= src
->fps
;
643 if(ioctl(s
->fd
, VIDIOC_S_PARM
, setfps
) == -1)
645 /* Not fatal - just warn about it */
646 WARN("Error setting frame rate:");
647 WARN("VIDIOC_S_PARM: %s", strerror(errno
));
654 int src_v4l2_free_mmap(src_t
*src
)
656 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
659 for(i
= 0; i
< s
->req
.count
; i
++)
660 munmap(s
->buffer
[i
].start
, s
->buffer
[i
].length
);
665 int src_v4l2_set_mmap(src_t
*src
)
667 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
668 enum v4l2_buf_type type
;
671 /* Does the device support streaming? */
672 if(~s
->cap
.capabilities
& V4L2_CAP_STREAMING
) return(-1);
674 memset(&s
->req
, 0, sizeof(s
->req
));
677 s
->req
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
678 s
->req
.memory
= V4L2_MEMORY_MMAP
;
680 if(ioctl(s
->fd
, VIDIOC_REQBUFS
, &s
->req
) == -1)
682 ERROR("Error requesting buffers for memory map.");
683 ERROR("VIDIOC_REQBUFS: %s", strerror(errno
));
687 DEBUG("mmap information:");
688 DEBUG("frames=%d", s
->req
.count
);
692 ERROR("Insufficient buffer memory.");
696 s
->buffer
= calloc(s
->req
.count
, sizeof(v4l2_buffer_t
));
699 ERROR("Out of memory.");
703 for(b
= 0; b
< s
->req
.count
; b
++)
705 struct v4l2_buffer buf
;
707 memset(&buf
, 0, sizeof(buf
));
709 buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
710 buf
.memory
= V4L2_MEMORY_MMAP
;
713 if(ioctl(s
->fd
, VIDIOC_QUERYBUF
, &buf
) == -1)
715 ERROR("Error querying buffer %i", b
);
716 ERROR("VIDIOC_QUERYBUF: %s", strerror(errno
));
721 s
->buffer
[b
].length
= buf
.length
;
722 s
->buffer
[b
].start
= mmap(NULL
, buf
.length
,
723 PROT_READ
| PROT_WRITE
, MAP_SHARED
, s
->fd
, buf
.m
.offset
);
725 if(s
->buffer
[b
].start
== MAP_FAILED
)
727 ERROR("Error mapping buffer %i", b
);
728 ERROR("mmap: %s", strerror(errno
));
730 src_v4l2_free_mmap(src
);
735 DEBUG("%i length=%d", b
, buf
.length
);
740 for(b
= 0; b
< s
->req
.count
; b
++)
742 memset(&s
->buf
, 0, sizeof(s
->buf
));
744 s
->buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
745 s
->buf
.memory
= V4L2_MEMORY_MMAP
;
748 if(ioctl(s
->fd
, VIDIOC_QBUF
, &s
->buf
) == -1)
750 ERROR("VIDIOC_QBUF: %s", strerror(errno
));
751 src_v4l2_free_mmap(src
);
757 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
759 if(ioctl(s
->fd
, VIDIOC_STREAMON
, &type
) == -1)
761 ERROR("Error starting stream.");
762 ERROR("VIDIOC_STREAMON: %s", strerror(errno
));
763 src_v4l2_free_mmap(src
);
771 int src_v4l2_set_read(src_t
*src
)
773 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
775 if(~s
->cap
.capabilities
& V4L2_CAP_READWRITE
) return(-1);
777 s
->buffer
= calloc(1, sizeof(v4l2_buffer_t
));
780 ERROR("Out of memory.");
784 s
->buffer
[0].length
= s
->fmt
.fmt
.pix
.sizeimage
;
785 s
->buffer
[0].start
= malloc(s
->buffer
[0].length
);
787 if(!s
->buffer
[0].start
)
789 ERROR("Out of memory.");
800 int src_v4l2_open(src_t
*src
)
806 ERROR("No device name specified.");
810 /* Allocate memory for the state structure. */
811 s
= calloc(sizeof(src_v4l2_t
), 1);
814 ERROR("Out of memory.");
818 src
->state
= (void *) s
;
820 /* Open the device. */
821 s
->fd
= open(src
->source
, O_RDWR
| O_NONBLOCK
);
824 ERROR("Error opening device: %s", src
->source
);
825 ERROR("open: %s", strerror(errno
));
830 MSG("%s opened.", src
->source
);
832 /* Get the device capabilities. */
833 if(src_v4l2_get_capability(src
))
840 if(src_v4l2_set_input(src
))
846 /* Set picture options. */
847 src_v4l2_set_controls(src
);
849 /* Set the pixel format. */
850 if(src_v4l2_set_pix_format(src
))
856 /* Set the frame-rate if > 0 */
857 if(src
->fps
) src_v4l2_set_fps(src
);
859 /* Delay to let the image settle down. */
862 MSG("Delaying %i seconds.", src
->delay
);
863 usleep(src
->delay
* 1000 * 1000);
866 /* Try to setup mmap. */
867 if(!src
->use_read
&& src_v4l2_set_mmap(src
))
869 WARN("Unable to use mmap. Using read instead.");
873 /* If unable to use mmap or user requested read(). */
876 if(src_v4l2_set_read(src
))
878 ERROR("Unable to use read.");
889 int src_v4l2_close(src_t
*src
)
891 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
895 if(!s
->map
) free(s
->buffer
[0].start
);
896 else src_v4l2_free_mmap(src
);
899 if(s
->fd
>= 0) close(s
->fd
);
905 int src_v4l2_grab(src_t
*src
)
907 src_v4l2_t
*s
= (src_v4l2_t
*) src
->state
;
915 /* Is a frame ready? */
919 tv
.tv_sec
= src
->timeout
;
922 r
= select(s
->fd
+ 1, &fds
, NULL
, NULL
, &tv
);
926 ERROR("select: %s", strerror(errno
));
932 ERROR("Timed out waiting for frame!");
941 if(ioctl(s
->fd
, VIDIOC_QBUF
, &s
->buf
) == -1)
943 ERROR("VIDIOC_QBUF: %s", strerror(errno
));
948 memset(&s
->buf
, 0, sizeof(s
->buf
));
950 s
->buf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
951 s
->buf
.memory
= V4L2_MEMORY_MMAP
;
953 if(ioctl(s
->fd
, VIDIOC_DQBUF
, &s
->buf
) == -1)
955 ERROR("VIDIOC_DQBUF: %s", strerror(errno
));
959 src
->img
= s
->buffer
[s
->buf
.index
].start
;
960 src
->length
= s
->buffer
[s
->buf
.index
].length
;
962 s
->pframe
= s
->buf
.index
;
968 r
= read(s
->fd
, s
->buffer
[0].start
, s
->buffer
[0].length
);
971 ERROR("Unable to read a frame.");
972 ERROR("read: %s", strerror(errno
));
976 src
->img
= s
->buffer
[0].start
;
983 src_mod_t src_v4l2
= {
984 "v4l2", SRC_TYPE_DEVICE
,
990 #else /* #ifdef HAVE_V4L2 */
992 src_mod_t src_v4l2
= {
999 #endif /* #ifdef HAVE_V4L2 */