2 // Python extension to capture video with video4linux2
4 // 2009, 2010, 2011 Fredrik Portstrom
6 // I, the copyright holder of this file, hereby release it into the
7 // public domain. This applies worldwide. In case this is not legally
8 // possible: I grant anyone the right to use this work for any
9 // purpose, without any conditions, unless such conditions are
14 #include <linux/videodev2.h>
17 // LIBV4L is not needed for MJPEG capture.
23 #include <sys/ioctl.h>
24 #define v4l2_close close
25 #define v4l2_ioctl ioctl
26 #define v4l2_mmap mmap
27 #define v4l2_munmap munmap
28 #define v4l2_open open
31 #define ASSERT_OPEN if(self->fd < 0) \
33 PyErr_SetString(PyExc_ValueError, \
34 "I/O operation on closed file"); \
46 struct buffer
*buffers
;
55 static struct capability capabilities
[] = {
56 { V4L2_CAP_ASYNCIO
, "asyncio" },
57 { V4L2_CAP_AUDIO
, "audio" },
58 { V4L2_CAP_HW_FREQ_SEEK
, "hw_freq_seek" },
59 { V4L2_CAP_RADIO
, "radio" },
60 { V4L2_CAP_RDS_CAPTURE
, "rds_capture" },
61 { V4L2_CAP_READWRITE
, "readwrite" },
62 { V4L2_CAP_SLICED_VBI_CAPTURE
, "sliced_vbi_capture" },
63 { V4L2_CAP_SLICED_VBI_OUTPUT
, "sliced_vbi_output" },
64 { V4L2_CAP_STREAMING
, "streaming" },
65 { V4L2_CAP_TUNER
, "tuner" },
66 { V4L2_CAP_VBI_CAPTURE
, "vbi_capture" },
67 { V4L2_CAP_VBI_OUTPUT
, "vbi_output" },
68 { V4L2_CAP_VIDEO_CAPTURE
, "video_capture" },
69 { V4L2_CAP_VIDEO_OUTPUT
, "video_output" },
70 { V4L2_CAP_VIDEO_OUTPUT_OVERLAY
, "video_output_overlay" },
71 { V4L2_CAP_VIDEO_OVERLAY
, "video_overlay" }
74 static int my_ioctl(int fd
, int request
, void *arg
)
76 // Retry ioctl until it returns without being interrupted.
80 int result
= v4l2_ioctl(fd
, request
, arg
);
89 PyErr_SetFromErrno(PyExc_IOError
);
95 static void Video_device_unmap(Video_device
*self
)
99 for(i
= 0; i
< self
->buffer_count
; i
++)
101 v4l2_munmap(self
->buffers
[i
].start
, self
->buffers
[i
].length
);
104 self
->buffers
= NULL
;
107 static void Video_device_dealloc(Video_device
*self
)
113 Video_device_unmap(self
);
116 v4l2_close(self
->fd
);
119 self
->ob_type
->tp_free((PyObject
*)self
);
122 static int Video_device_init(Video_device
*self
, PyObject
*args
,
125 const char *device_path
;
127 if(!PyArg_ParseTuple(args
, "s", &device_path
))
132 int fd
= v4l2_open(device_path
, O_RDWR
| O_NONBLOCK
);
136 PyErr_SetFromErrnoWithFilename(PyExc_IOError
, (char *)device_path
);
141 self
->buffers
= NULL
;
142 self
->buffer_count
= 0;
146 static PyObject
*Video_device_close(Video_device
*self
)
152 Video_device_unmap(self
);
155 v4l2_close(self
->fd
);
162 static PyObject
*Video_device_fileno(Video_device
*self
)
165 return PyInt_FromLong(self
->fd
);
168 static PyObject
*Video_device_get_info(Video_device
*self
)
171 struct v4l2_capability caps
;
173 if(my_ioctl(self
->fd
, VIDIOC_QUERYCAP
, &caps
))
178 PyObject
*set
= PySet_New(NULL
);
185 struct capability
*capability
= capabilities
;
187 while((void *)capability
< (void *)capabilities
+ sizeof(capabilities
))
189 if(caps
.capabilities
& capability
->id
)
191 PyObject
*s
= PyString_FromString(capability
->name
);
205 return Py_BuildValue("sssO", caps
.driver
, caps
.card
, caps
.bus_info
, set
);
208 static PyObject
*Video_device_set_format(Video_device
*self
, PyObject
*args
)
212 if(!PyArg_ParseTuple(args
, "ii", &size_x
, &size_y
))
217 struct v4l2_format format
;
218 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
219 format
.fmt
.pix
.width
= size_x
;
220 format
.fmt
.pix
.height
= size_y
;
221 format
.fmt
.pix
.pixelformat
= V4L2_PIX_FMT_MJPEG
;
222 format
.fmt
.pix
.field
= V4L2_FIELD_NONE
;
223 format
.fmt
.pix
.bytesperline
= 0;
225 if(my_ioctl(self
->fd
, VIDIOC_S_FMT
, &format
))
230 return Py_BuildValue("ii", format
.fmt
.pix
.width
, format
.fmt
.pix
.height
);
233 static PyObject
*Video_device_set_fps(Video_device
*self
, PyObject
*args
)
236 if(!PyArg_ParseTuple(args
, "i", &fps
))
240 struct v4l2_streamparm setfps
;
241 memset(&setfps
, 0, sizeof(struct v4l2_streamparm
));
242 setfps
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
243 setfps
.parm
.capture
.timeperframe
.numerator
= 1;
244 setfps
.parm
.capture
.timeperframe
.denominator
= fps
;
245 if(my_ioctl(self
->fd
, VIDIOC_S_PARM
, &setfps
)){
248 return Py_BuildValue("i",setfps
.parm
.capture
.timeperframe
.denominator
);
251 static PyObject
*Video_device_start(Video_device
*self
)
254 enum v4l2_buf_type type
;
255 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
257 if(my_ioctl(self
->fd
, VIDIOC_STREAMON
, &type
))
265 static PyObject
*Video_device_stop(Video_device
*self
)
268 enum v4l2_buf_type type
;
269 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
271 if(my_ioctl(self
->fd
, VIDIOC_STREAMOFF
, &type
))
279 static PyObject
*Video_device_create_buffers(Video_device
*self
, PyObject
*args
)
283 if(!PyArg_ParseTuple(args
, "I", &buffer_count
))
292 PyErr_SetString(PyExc_ValueError
, "Buffers are already created");
296 struct v4l2_requestbuffers reqbuf
;
297 reqbuf
.count
= buffer_count
;
298 reqbuf
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
299 reqbuf
.memory
= V4L2_MEMORY_MMAP
;
301 if(my_ioctl(self
->fd
, VIDIOC_REQBUFS
, &reqbuf
))
308 PyErr_SetString(PyExc_IOError
, "Not enough buffer memory");
312 self
->buffers
= malloc(reqbuf
.count
* sizeof(struct buffer
));
322 for(i
= 0; i
< reqbuf
.count
; i
++)
324 struct v4l2_buffer buffer
;
326 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
327 buffer
.memory
= V4L2_MEMORY_MMAP
;
329 if(my_ioctl(self
->fd
, VIDIOC_QUERYBUF
, &buffer
))
334 self
->buffers
[i
].length
= buffer
.length
;
335 self
->buffers
[i
].start
= v4l2_mmap(NULL
, buffer
.length
,
336 PROT_READ
| PROT_WRITE
, MAP_SHARED
, self
->fd
, buffer
.m
.offset
);
338 if(self
->buffers
[i
].start
== MAP_FAILED
)
340 PyErr_SetFromErrno(PyExc_IOError
);
341 Video_device_unmap(self
);
344 ++self
->buffer_count
;
350 static PyObject
*Video_device_queue_all_buffers(Video_device
*self
)
355 PyErr_SetString(PyExc_ValueError
, "Buffers have not been created");
360 int buffer_count
= self
->buffer_count
;
362 for(i
= 0; i
< buffer_count
; i
++)
364 struct v4l2_buffer buffer
;
366 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
367 buffer
.memory
= V4L2_MEMORY_MMAP
;
369 if(my_ioctl(self
->fd
, VIDIOC_QBUF
, &buffer
))
378 static PyObject
*Video_device_read_internal(Video_device
*self
, int queue
)
383 PyErr_SetString(PyExc_ValueError
, "Buffers have not been created");
387 struct v4l2_buffer buffer
;
388 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
389 buffer
.memory
= V4L2_MEMORY_MMAP
;
391 if(my_ioctl(self
->fd
, VIDIOC_DQBUF
, &buffer
))
396 PyObject
*result
= PyString_FromStringAndSize(
397 self
->buffers
[buffer
.index
].start
, buffer
.bytesused
);
404 if(queue
&& my_ioctl(self
->fd
, VIDIOC_QBUF
, &buffer
))
412 static PyObject
*Video_device_read(Video_device
*self
)
414 return Video_device_read_internal(self
, 0);
417 static PyObject
*Video_device_read_and_queue(Video_device
*self
)
419 return Video_device_read_internal(self
, 1);
422 static PyMethodDef Video_device_methods
[] = {
423 {"close", (PyCFunction
)Video_device_close
, METH_NOARGS
,
425 "Close video device. Subsequent calls to other methods will fail."},
426 {"fileno", (PyCFunction
)Video_device_fileno
, METH_NOARGS
,
427 "fileno() -> integer \"file descriptor\".\n\n"
428 "This enables video devices to be passed select.select for waiting "
429 "until a frame is available for reading."},
430 {"get_info", (PyCFunction
)Video_device_get_info
, METH_NOARGS
,
431 "get_info() -> driver, card, bus_info, capabilities\n\n"
432 "Returns three strings with information about the video device, and one "
433 "set containing strings identifying the capabilities of the video "
435 {"set_format", (PyCFunction
)Video_device_set_format
, METH_VARARGS
,
436 "set_format(size_x, size_y) -> size_x, size_y\n\n"
437 "Request the video device to set image size and format. The device may "
438 "choose another size than requested and will return its choice. The "
439 "image format will be MJPEG."},
440 {"set_fps", (PyCFunction
)Video_device_set_fps
, METH_VARARGS
,
441 "set_fps(fps) -> fps \n\n"
442 "Request the video device to set frame per seconds.The device may "
443 "choose another frame rate than requested and will return its choice. " },
444 {"start", (PyCFunction
)Video_device_start
, METH_NOARGS
,
446 "Start video capture."},
447 {"stop", (PyCFunction
)Video_device_stop
, METH_NOARGS
,
449 "Stop video capture."},
450 {"create_buffers", (PyCFunction
)Video_device_create_buffers
, METH_VARARGS
,
451 "create_buffers(count)\n\n"
452 "Create buffers used for capturing image data. Can only be called once "
453 "for each video device object."},
454 {"queue_all_buffers", (PyCFunction
)Video_device_queue_all_buffers
,
456 "queue_all_buffers()\n\n"
457 "Let the video device fill all buffers created."},
458 {"read", (PyCFunction
)Video_device_read
, METH_NOARGS
,
459 "read() -> string\n\n"
460 "Reads image data from a buffer that has been filled by the video "
461 "device. The image data is in MJPEG format. "
462 "The buffer is removed from the queue. Fails if no buffer "
463 "is filled. Use select.select to check for filled buffers."},
464 {"read_and_queue", (PyCFunction
)Video_device_read_and_queue
, METH_NOARGS
,
465 "read_and_queue()\n\n"
466 "Same as 'read', but adds the buffer back to the queue so the video "
467 "device can fill it again."},
471 static PyTypeObject Video_device_type
= {
472 PyObject_HEAD_INIT(NULL
)
473 0, "v4l2capture.Video_device", sizeof(Video_device
), 0,
474 (destructor
)Video_device_dealloc
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
475 0, Py_TPFLAGS_DEFAULT
, "Video_device(path)\n\nOpens the video device at "
476 "the given path and returns an object that can capture images. The "
477 "constructor and all methods except close may raise IOError.", 0, 0, 0,
478 0, 0, 0, Video_device_methods
, 0, 0, 0, 0, 0, 0, 0,
479 (initproc
)Video_device_init
482 static PyMethodDef module_methods
[] = {
486 PyMODINIT_FUNC
initv4l2capture(void)
488 Video_device_type
.tp_new
= PyType_GenericNew
;
490 if(PyType_Ready(&Video_device_type
) < 0)
495 PyObject
*module
= Py_InitModule3("v4l2capture", module_methods
,
496 "Capture video with video4linux2.");
503 Py_INCREF(&Video_device_type
);
504 PyModule_AddObject(module
, "Video_device", (PyObject
*)&Video_device_type
);