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 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 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 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 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 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 162 static PyObject *Video_device_fileno(Video_device *self) 163 { 164 ASSERT_OPEN; 165 return PyInt_FromLong(self->fd); 166 } 167 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 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 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 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 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 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 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 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 412 static PyObject *Video_device_read(Video_device *self) 413 { 414 return Video_device_read_internal(self, 0); 415 } 416 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 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