• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // python-v4l2capture
2 // Python extension to capture video with video4linux2
3 //
4 // 2009, 2010, 2011 Fredrik Portstrom
5 //
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
10 // required by law.
11 
12 #include <Python.h>
13 #include <fcntl.h>
14 #include <linux/videodev2.h>
15 #include <sys/mman.h>
16 
17 // LIBV4L is not needed for MJPEG capture.
18 #undef USE_LIBV4L
19 
20 #ifdef USE_LIBV4L
21 #include <libv4l2.h>
22 #else
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
29 #endif
30 
31 #define ASSERT_OPEN if(self->fd < 0)                                    \
32     {                                                                   \
33       PyErr_SetString(PyExc_ValueError,                                 \
34           "I/O operation on closed file");                              \
35       return NULL;                                                      \
36     }
37 
38 struct buffer {
39   void *start;
40   size_t length;
41 };
42 
43 typedef struct {
44   PyObject_HEAD
45   int fd;
46   struct buffer *buffers;
47   int buffer_count;
48 } Video_device;
49 
50 struct capability {
51   int id;
52   const char *name;
53 };
54 
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" }
72 };
73 
my_ioctl(int fd,int request,void * arg)74 static int my_ioctl(int fd, int request, void *arg)
75 {
76   // Retry ioctl until it returns without being interrupted.
77 
78   for(;;)
79     {
80       int result = v4l2_ioctl(fd, request, arg);
81 
82       if(!result)
83         {
84           return 0;
85         }
86 
87       if(errno != EINTR)
88         {
89           PyErr_SetFromErrno(PyExc_IOError);
90           return 1;
91         }
92     }
93 }
94 
Video_device_unmap(Video_device * self)95 static void Video_device_unmap(Video_device *self)
96 {
97   int i;
98 
99   for(i = 0; i < self->buffer_count; i++)
100     {
101       v4l2_munmap(self->buffers[i].start, self->buffers[i].length);
102     }
103   free(self->buffers);
104   self->buffers = NULL;
105 }
106 
Video_device_dealloc(Video_device * self)107 static void Video_device_dealloc(Video_device *self)
108 {
109   if(self->fd >= 0)
110     {
111       if(self->buffers)
112         {
113           Video_device_unmap(self);
114         }
115 
116       v4l2_close(self->fd);
117     }
118 
119   self->ob_type->tp_free((PyObject *)self);
120 }
121 
Video_device_init(Video_device * self,PyObject * args,PyObject * kwargs)122 static int Video_device_init(Video_device *self, PyObject *args,
123     PyObject *kwargs)
124 {
125   const char *device_path;
126 
127   if(!PyArg_ParseTuple(args, "s", &device_path))
128     {
129       return -1;
130     }
131 
132   int fd = v4l2_open(device_path, O_RDWR | O_NONBLOCK);
133 
134   if(fd < 0)
135     {
136       PyErr_SetFromErrnoWithFilename(PyExc_IOError, (char *)device_path);
137       return -1;
138     }
139 
140   self->fd = fd;
141   self->buffers = NULL;
142   self->buffer_count = 0;
143   return 0;
144 }
145 
Video_device_close(Video_device * self)146 static PyObject *Video_device_close(Video_device *self)
147 {
148   if(self->fd >= 0)
149     {
150       if(self->buffers)
151         {
152           Video_device_unmap(self);
153         }
154 
155       v4l2_close(self->fd);
156       self->fd = -1;
157     }
158 
159   Py_RETURN_NONE;
160 }
161 
Video_device_fileno(Video_device * self)162 static PyObject *Video_device_fileno(Video_device *self)
163 {
164   ASSERT_OPEN;
165   return PyInt_FromLong(self->fd);
166 }
167 
Video_device_get_info(Video_device * self)168 static PyObject *Video_device_get_info(Video_device *self)
169 {
170   ASSERT_OPEN;
171   struct v4l2_capability caps;
172 
173   if(my_ioctl(self->fd, VIDIOC_QUERYCAP, &caps))
174     {
175       return NULL;
176     }
177 
178   PyObject *set = PySet_New(NULL);
179 
180   if(!set)
181     {
182       return NULL;
183     }
184 
185   struct capability *capability = capabilities;
186 
187   while((void *)capability < (void *)capabilities + sizeof(capabilities))
188     {
189       if(caps.capabilities & capability->id)
190         {
191           PyObject *s = PyString_FromString(capability->name);
192 
193           if(!s)
194             {
195               Py_DECREF(set);
196               return NULL;
197             }
198 
199           PySet_Add(set, s);
200         }
201 
202       capability++;
203     }
204 
205   return Py_BuildValue("sssO", caps.driver, caps.card, caps.bus_info, set);
206 }
207 
Video_device_set_format(Video_device * self,PyObject * args)208 static PyObject *Video_device_set_format(Video_device *self, PyObject *args)
209 {
210   int size_x;
211   int size_y;
212   if(!PyArg_ParseTuple(args, "ii", &size_x, &size_y))
213     {
214       return NULL;
215     }
216 
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;
224 
225   if(my_ioctl(self->fd, VIDIOC_S_FMT, &format))
226     {
227       return NULL;
228     }
229 
230   return Py_BuildValue("ii", format.fmt.pix.width, format.fmt.pix.height);
231 }
232 
Video_device_set_fps(Video_device * self,PyObject * args)233 static PyObject *Video_device_set_fps(Video_device *self, PyObject *args)
234 {
235   int fps;
236   if(!PyArg_ParseTuple(args, "i", &fps))
237     {
238       return NULL;
239     }
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)){
246         return NULL;
247   }
248   return Py_BuildValue("i",setfps.parm.capture.timeperframe.denominator);
249 }
250 
Video_device_start(Video_device * self)251 static PyObject *Video_device_start(Video_device *self)
252 {
253   ASSERT_OPEN;
254   enum v4l2_buf_type type;
255   type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
256 
257   if(my_ioctl(self->fd, VIDIOC_STREAMON, &type))
258     {
259       return NULL;
260     }
261 
262   Py_RETURN_NONE;
263 }
264 
Video_device_stop(Video_device * self)265 static PyObject *Video_device_stop(Video_device *self)
266 {
267   ASSERT_OPEN;
268   enum v4l2_buf_type type;
269   type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
270 
271   if(my_ioctl(self->fd, VIDIOC_STREAMOFF, &type))
272     {
273       return NULL;
274     }
275 
276   Py_RETURN_NONE;
277 }
278 
Video_device_create_buffers(Video_device * self,PyObject * args)279 static PyObject *Video_device_create_buffers(Video_device *self, PyObject *args)
280 {
281   int buffer_count;
282 
283   if(!PyArg_ParseTuple(args, "I", &buffer_count))
284     {
285       return NULL;
286     }
287 
288   ASSERT_OPEN;
289 
290   if(self->buffers)
291     {
292       PyErr_SetString(PyExc_ValueError, "Buffers are already created");
293       return NULL;
294     }
295 
296   struct v4l2_requestbuffers reqbuf;
297   reqbuf.count = buffer_count;
298   reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
299   reqbuf.memory = V4L2_MEMORY_MMAP;
300 
301   if(my_ioctl(self->fd, VIDIOC_REQBUFS, &reqbuf))
302     {
303       return NULL;
304     }
305 
306   if(!reqbuf.count)
307     {
308       PyErr_SetString(PyExc_IOError, "Not enough buffer memory");
309       return NULL;
310     }
311 
312   self->buffers = malloc(reqbuf.count * sizeof(struct buffer));
313 
314   if(!self->buffers)
315     {
316       PyErr_NoMemory();
317       return NULL;
318     }
319 
320   int i;
321 
322   for(i = 0; i < reqbuf.count; i++)
323     {
324       struct v4l2_buffer buffer;
325       buffer.index = i;
326       buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
327       buffer.memory = V4L2_MEMORY_MMAP;
328 
329       if(my_ioctl(self->fd, VIDIOC_QUERYBUF, &buffer))
330         {
331           return NULL;
332         }
333 
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);
337 
338       if(self->buffers[i].start == MAP_FAILED)
339         {
340           PyErr_SetFromErrno(PyExc_IOError);
341           Video_device_unmap(self);
342           return NULL;
343         }
344       ++self->buffer_count;
345     }
346 
347   Py_RETURN_NONE;
348 }
349 
Video_device_queue_all_buffers(Video_device * self)350 static PyObject *Video_device_queue_all_buffers(Video_device *self)
351 {
352   if(!self->buffers)
353     {
354       ASSERT_OPEN;
355       PyErr_SetString(PyExc_ValueError, "Buffers have not been created");
356       return NULL;
357     }
358 
359   int i;
360   int buffer_count = self->buffer_count;
361 
362   for(i = 0; i < buffer_count; i++)
363     {
364       struct v4l2_buffer buffer;
365       buffer.index = i;
366       buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
367       buffer.memory = V4L2_MEMORY_MMAP;
368 
369       if(my_ioctl(self->fd, VIDIOC_QBUF, &buffer))
370         {
371           return NULL;
372         }
373     }
374 
375   Py_RETURN_NONE;
376 }
377 
Video_device_read_internal(Video_device * self,int queue)378 static PyObject *Video_device_read_internal(Video_device *self, int queue)
379 {
380   if(!self->buffers)
381     {
382       ASSERT_OPEN;
383       PyErr_SetString(PyExc_ValueError, "Buffers have not been created");
384       return NULL;
385     }
386 
387   struct v4l2_buffer buffer;
388   buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
389   buffer.memory = V4L2_MEMORY_MMAP;
390 
391   if(my_ioctl(self->fd, VIDIOC_DQBUF, &buffer))
392     {
393       return NULL;
394     }
395 
396   PyObject *result = PyString_FromStringAndSize(
397       self->buffers[buffer.index].start, buffer.bytesused);
398 
399   if(!result)
400     {
401       return NULL;
402     }
403 
404   if(queue && my_ioctl(self->fd, VIDIOC_QBUF, &buffer))
405     {
406       return NULL;
407     }
408 
409   return result;
410 }
411 
Video_device_read(Video_device * self)412 static PyObject *Video_device_read(Video_device *self)
413 {
414   return Video_device_read_internal(self, 0);
415 }
416 
Video_device_read_and_queue(Video_device * self)417 static PyObject *Video_device_read_and_queue(Video_device *self)
418 {
419   return Video_device_read_internal(self, 1);
420 }
421 
422 static PyMethodDef Video_device_methods[] = {
423   {"close", (PyCFunction)Video_device_close, METH_NOARGS,
424        "close()\n\n"
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 "
434        "device."},
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,
445        "start()\n\n"
446        "Start video capture."},
447   {"stop", (PyCFunction)Video_device_stop, METH_NOARGS,
448        "stop()\n\n"
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,
455        METH_NOARGS,
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."},
468   {NULL}
469 };
470 
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
480 };
481 
482 static PyMethodDef module_methods[] = {
483   {NULL}
484 };
485 
initv4l2capture(void)486 PyMODINIT_FUNC initv4l2capture(void)
487 {
488   Video_device_type.tp_new = PyType_GenericNew;
489 
490   if(PyType_Ready(&Video_device_type) < 0)
491     {
492       return;
493     }
494 
495   PyObject *module = Py_InitModule3("v4l2capture", module_methods,
496       "Capture video with video4linux2.");
497 
498   if(!module)
499     {
500       return;
501     }
502 
503   Py_INCREF(&Video_device_type);
504   PyModule_AddObject(module, "Video_device", (PyObject *)&Video_device_type);
505 }
506