├── .gitignore ├── README.md ├── v4l2obj.h ├── setup.py ├── LICENSE ├── testme.py ├── v4l2.c └── v4l2obj.c /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyv4l2 2 | v4l2 (Video 4 Linux 2) interface to python, & camera access. 3 | -------------------------------------------------------------------------------- /v4l2obj.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: v4l2obj.h 3 | * Date: 2015-04-17 4 | * Author: gashero 5 | */ 6 | 7 | #ifndef V4L2OBJ_H 8 | #define V4L2OBJ_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | PyAPI_DATA(PyTypeObject) V4L2Type; 15 | 16 | #define V4L2_Check(op) (Py_TYPE(op)==&V4L2Type) 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # File: setup.py 4 | # Date: 2015-04-17 5 | # Author: gashero 6 | 7 | """ 8 | setup.py for pyv4l2 9 | """ 10 | 11 | import os 12 | 13 | from distutils.core import setup,Extension 14 | 15 | mod_v4l2=Extension('v4l2',sources=[ 16 | 'v4l2.c','v4l2obj.c',]) 17 | 18 | extmodlist=[mod_v4l2,] 19 | 20 | setup(name='pyv4l2', 21 | version='1.0', 22 | description='pyv4l2, V4L2 interface for Python', 23 | author='gashero', 24 | author_email='harry.python@gmail.com', 25 | packages=[], 26 | ext_modules=extmodlist, 27 | ) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Harry Liu. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /testme.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # File: testme.py 4 | # Date: 2015-04-17 5 | # Author: gashero 6 | 7 | """ 8 | manual test entry. 9 | """ 10 | 11 | import os 12 | import sys 13 | import select 14 | import time 15 | import traceback 16 | 17 | import v4l2 18 | 19 | def fn_time(): 20 | """make a filename with time now""" 21 | ts=time.time() 22 | dn_dir=time.strftime('%Y%m%d_%H%M',time.localtime(ts)) 23 | if not os.path.exists(dn_dir): 24 | os.mkdir(dn_dir) 25 | ms='%.03f'%(ts-int(ts)) 26 | fn=time.strftime('img_%Y%m%d_%H%M%S_')+ms[2:]+'.jpg' 27 | return os.path.join(dn_dir,fn) 28 | 29 | def main(): 30 | vo=v4l2.V4L2('/dev/video0', 31 | v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE, 32 | v4l2.V4L2_MEMORY_MMAP 33 | #v4l2.V4L2_MEMORY_USERPTR 34 | ) 35 | print 'querycap()=',vo.querycap() 36 | print 'enum_fmt()=',vo.enum_fmt() 37 | vo.s_fmt( 38 | 1280,720, 39 | v4l2.V4L2_PIX_FMT_MJPEG, 40 | v4l2.V4L2_FIELD_ANY) 41 | print 'enuminput()=',vo.enuminput() 42 | print 'enumaudio()=',vo.enumaudio() 43 | vo.s_input(0) 44 | print 'g_input()=',vo.g_input() 45 | print 'enumstd()=',vo.enumstd() 46 | #print 'queryctrl(V4L2_CID_GAIN)',vo.queryctrl(v4l2.V4L2_CID_GAIN) 47 | #print 'g_ctrl(V4L2_CID_MIN_BUFFERS_FOR_CAPTURE)',vo.g_ctrl(v4l2.V4L2_CID_MIN_BUFFERS_FOR_CAPTURE) 48 | #print 'g_ctrl(V4L2_CID_GAIN)',vo.g_ctrl(v4l2.V4L2_CID_GAIN) 49 | buffercount=vo.reqbufs(4) 50 | assert buffercount==4,buffercount 51 | bufmap={} 52 | for bufidx in range(buffercount): 53 | bufinfo=vo.querybuf(bufidx) 54 | addr=vo.mmap(bufinfo['offset'],bufinfo['length']) 55 | bufmap[bufidx]=(addr,bufinfo['length']) 56 | vo.qbuf(bufinfo['index']) 57 | vo.streamon() 58 | for i in range(2): #Jump out 2 frame 59 | assert ([vo.fileno()],[],[])==select.select([vo.fileno()],[],[],2) 60 | bufidx=vo.dqbuf() 61 | vo.qbuf(bufidx) 62 | while True: 63 | try: 64 | assert ([vo.fileno()],[],[])==select.select([vo.fileno()],[],[],2) 65 | bufidx=vo.dqbuf() 66 | vo.qbuf(bufidx) 67 | bufinfo=vo.querybuf(bufidx) 68 | data=vo.getjpeg(*bufmap[bufidx]) 69 | fn=fn_time() 70 | f=open(fn,'w') 71 | f.write(data) 72 | f.close() 73 | assert data[-2:]=='\xff\xd9',repr(data[-256:]) 74 | except KeyboardInterrupt: 75 | break 76 | except Exception,ex: 77 | flog=open('error.log','a+') 78 | flog.write(traceback.format_exc()+'\n') 79 | flog.close() 80 | vo.streamoff() 81 | for (bufidx,(addr,length)) in bufmap.items(): 82 | vo.munmap(addr,length) 83 | return 84 | 85 | if __name__=='__main__': 86 | main() 87 | print '---- finished ----' 88 | -------------------------------------------------------------------------------- /v4l2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: v4l2.c 3 | * Date: 2015-04-17 4 | * Author: gashero 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "v4l2obj.h" 24 | 25 | // Uilt functions -------------------------------------------------------------- 26 | 27 | /*static int eioctl(int fd, int request, void *argp, char *errmsg) { 28 | int ret; 29 | ret=ioctl(fd, request, argp); 30 | if (ret<0) { 31 | PyErr_Format(PyExc_OSError, "ERROR[%d]=\"%s\", %s", 32 | errno, strerror(errno), errmsg); 33 | } 34 | return ret; 35 | }*/ 36 | 37 | // Module leve functions ------------------------------------------------------- 38 | 39 | static PyMethodDef v4l2_methods[] = { 40 | {NULL} 41 | }; 42 | 43 | struct kvlong { 44 | char *key; 45 | long value; 46 | }; 47 | 48 | static struct kvlong const_kvlong[] = { 49 | // enum v4l2_buf_type 50 | {"V4L2_BUF_TYPE_VIDEO_CAPTURE", V4L2_BUF_TYPE_VIDEO_CAPTURE}, 51 | {"V4L2_BUF_TYPE_VIDEO_OUTPUT", V4L2_BUF_TYPE_VIDEO_OUTPUT}, 52 | {"V4L2_BUF_TYPE_VIDEO_OVERLAY", V4L2_BUF_TYPE_VIDEO_OVERLAY}, 53 | {"V4L2_BUF_TYPE_VBI_CAPTURE", V4L2_BUF_TYPE_VBI_CAPTURE}, 54 | {"V4L2_BUF_TYPE_VBI_OUTPUT", V4L2_BUF_TYPE_VBI_OUTPUT}, 55 | {"V4L2_BUF_TYPE_SLICED_VBI_CAPTURE",V4L2_BUF_TYPE_SLICED_VBI_CAPTURE}, 56 | {"V4L2_BUF_TYPE_SLICED_VBI_OUTPUT", V4L2_BUF_TYPE_SLICED_VBI_OUTPUT}, 57 | {"V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE", V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE}, 58 | {"V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE", V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE}, 59 | {"V4L2_BUF_TYPE_PRIVATE", V4L2_BUF_TYPE_PRIVATE}, 60 | // enum v4l2_field, not complete 61 | {"V4L2_FIELD_ANY", V4L2_FIELD_ANY}, 62 | {"V4L2_FIELD_NONE", V4L2_FIELD_NONE}, 63 | {"V4L2_FIELD_TOP", V4L2_FIELD_TOP}, 64 | {"V4L2_FIELD_BOTTOM", V4L2_FIELD_BOTTOM}, 65 | {"V4L2_FIELD_INTERLACED", V4L2_FIELD_INTERLACED}, 66 | // v4l2_pix_fmt, not complete 67 | {"V4L2_PIX_FMT_YUYV", V4L2_PIX_FMT_YUYV}, 68 | {"V4L2_PIX_FMT_MJPEG", V4L2_PIX_FMT_MJPEG}, 69 | // v4l2_memory 70 | {"V4L2_MEMORY_MMAP", V4L2_MEMORY_MMAP}, 71 | {"V4L2_MEMORY_USERPTR", V4L2_MEMORY_USERPTR}, 72 | {"V4L2_MEMORY_OVERLAY", V4L2_MEMORY_OVERLAY}, 73 | //{"V4L2_MEMORY_DMABUF", V4L2_MEMORY_DMABUF}, 74 | // other constant I interest. 75 | {"V4L2_CID_BRIGHTNESS", V4L2_CID_BRIGHTNESS}, 76 | {"V4L2_CID_GAIN", V4L2_CID_GAIN}, 77 | {"V4L2_CID_AUTOBRIGHTNESS", V4L2_CID_AUTOBRIGHTNESS}, 78 | {"V4L2_CID_AUDIO_MUTE", V4L2_CID_AUDIO_MUTE}, 79 | {"V4L2_CID_MIN_BUFFERS_FOR_CAPTURE",V4L2_CID_MIN_BUFFERS_FOR_CAPTURE}, 80 | {"V4L2_STD_PAL_BG", V4L2_STD_PAL_BG}, 81 | {NULL} 82 | }; 83 | 84 | PyMODINIT_FUNC initv4l2(void) { 85 | PyObject *m; 86 | errno=0; 87 | m=Py_InitModule3("v4l2", v4l2_methods, "v4l2 module"); 88 | struct kvlong *_kv; 89 | for (_kv=const_kvlong; _kv->key!=NULL; _kv++) { 90 | if (PyModule_AddIntConstant(m, _kv->key, _kv->value)<0) 91 | return; 92 | } 93 | if (PyType_Ready(&V4L2Type)<0) 94 | return; 95 | Py_INCREF(&V4L2Type); 96 | PyModule_AddObject(m, "V4L2", (PyObject*)&V4L2Type); 97 | } 98 | -------------------------------------------------------------------------------- /v4l2obj.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: v4l2obj.c 3 | * Date: 2015-04-17 4 | * Author: gashero 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "v4l2obj.h" 26 | 27 | typedef struct { 28 | PyObject_HEAD 29 | int fd; 30 | uint32_t type; 31 | uint32_t memory; 32 | } V4L2Object; 33 | 34 | static int eioctl(int fd, int request, void *argp, char *errmsg) { 35 | int ret; 36 | Py_BEGIN_ALLOW_THREADS; 37 | ret=ioctl(fd, request, argp); 38 | Py_END_ALLOW_THREADS; 39 | if (ret<0) { 40 | PyErr_Format(PyExc_OSError, "ERROR[%d]=\"%s\", %s", 41 | errno, strerror(errno), errmsg); 42 | } 43 | return ret; 44 | } 45 | 46 | // Object system methods ------------------------------------------------------- 47 | 48 | static void V4L2_dealloc(V4L2Object *self) { 49 | self->ob_type->tp_free((PyObject*)self); 50 | close(self->fd); 51 | } 52 | 53 | static PyObject *V4L2_New(PyTypeObject *type, PyObject *args, PyObject *kwds) { 54 | V4L2Object *self; 55 | self=(V4L2Object*)type->tp_alloc(type,0); 56 | if (self!=NULL) { 57 | //创建其他成员 58 | } 59 | return (PyObject*)self; 60 | } 61 | 62 | static int V4L2_Init(V4L2Object *self, PyObject *args, PyObject *kwds) { 63 | char *devname; 64 | if (!PyArg_ParseTuple(args, "sII", 65 | &devname, 66 | &self->type, 67 | &self->memory)) { 68 | return -1; 69 | } 70 | self->fd=open(devname,O_RDWR); 71 | return 0; 72 | } 73 | 74 | // Object methods -------------------------------------------------------------- 75 | 76 | static PyObject *V4L2_querycap(V4L2Object *self) { 77 | struct v4l2_capability cap; 78 | if (eioctl(self->fd, VIDIOC_QUERYCAP, &cap, "ioctl(VIDIOC_QUERYCAP)")<0) { 79 | return NULL; 80 | } 81 | return Py_BuildValue("{s:s,s:s,s:s,s:I,s:I,s:I}", 82 | "driver", cap.driver, 83 | "card", cap.card, 84 | "bus_info", cap.bus_info, 85 | "version", cap.version, 86 | "capabilities", cap.capabilities 87 | //"device_caps", cap.device_caps 88 | ); 89 | } 90 | 91 | static PyObject *V4L2_enum_fmt(V4L2Object *self) { 92 | struct v4l2_fmtdesc fmtdesc; 93 | fmtdesc.index=0; 94 | PyObject *fmtlist, *fmtinfo; 95 | fmtdesc.type=self->type; 96 | fmtlist=PyList_New(0); 97 | while(ioctl(self->fd, VIDIOC_ENUM_FMT, &fmtdesc)!=-1) { 98 | fmtinfo=Py_BuildValue("{s:I,s:I,s:I,s:s,s:I}", 99 | "index", fmtdesc.index, 100 | "type", fmtdesc.type, 101 | "flags", fmtdesc.flags, 102 | "description", fmtdesc.description, 103 | "pixelformat", fmtdesc.pixelformat 104 | ); 105 | PyList_Append(fmtlist, fmtinfo); 106 | Py_XDECREF(fmtinfo); 107 | fmtdesc.index++; 108 | } 109 | errno=0; 110 | return fmtlist; 111 | } 112 | 113 | static PyObject *V4L2_s_fmt(V4L2Object *self, PyObject *args) { 114 | struct v4l2_format format; 115 | if (!PyArg_ParseTuple(args, "IIII", 116 | &format.fmt.pix.width, 117 | &format.fmt.pix.height, 118 | &format.fmt.pix.pixelformat, 119 | &format.fmt.pix.field)) { 120 | return NULL; 121 | } 122 | format.type=self->type; 123 | if (eioctl(self->fd, VIDIOC_S_FMT, &format, "ioctl(VIDIOC_S_FMT)")<0) { 124 | return NULL; 125 | } 126 | Py_RETURN_NONE; 127 | } 128 | 129 | static PyObject *V4L2_enuminput(V4L2Object *self) { 130 | struct v4l2_input input; 131 | memset(&input, 0, sizeof(struct v4l2_input)); 132 | PyObject *inputlist, *inputinfo; 133 | input.index=0; 134 | inputlist=PyList_New(0); 135 | while(ioctl(self->fd, VIDIOC_ENUMINPUT, &input)!=-1) { 136 | inputinfo=Py_BuildValue( 137 | "{s:I,s:s,s:I,s:I,s:I,s:K,s:I,s:I}", 138 | "index", input.index, 139 | "name", input.name, 140 | "type", input.type, 141 | "audioset", input.audioset, 142 | "tuner", input.tuner, 143 | "std", input.std, 144 | "status", input.status, 145 | "capabilities",input.capabilities 146 | ); 147 | PyList_Append(inputlist, inputinfo); 148 | Py_XDECREF(inputinfo); 149 | input.index++; 150 | } 151 | errno=0; 152 | return inputlist; 153 | } 154 | 155 | static PyObject *V4L2_enumaudio(V4L2Object *self) { 156 | struct v4l2_audio audio; 157 | memset(&audio, 0, sizeof(struct v4l2_audio)); 158 | PyObject *audiolist, *audioinfo; 159 | audio.index=0; 160 | audiolist=PyList_New(0); 161 | while(ioctl(self->fd, VIDIOC_ENUMAUDIO, &audio)!=-1) { 162 | audioinfo=Py_BuildValue( 163 | "{s:I,s:s,s:I,s:I}", 164 | "index", audio.index, 165 | "name", audio.name, 166 | "capability", audio.capability, 167 | "mode", audio.mode 168 | ); 169 | PyList_Append(audiolist, audioinfo); 170 | Py_XDECREF(audioinfo); 171 | audio.index++; 172 | } 173 | errno=0; 174 | return audiolist; 175 | } 176 | 177 | static PyObject *V4L2_s_input(V4L2Object *self, PyObject *args) { 178 | int inputnum; 179 | if (!PyArg_ParseTuple(args, "i", 180 | &inputnum)) { 181 | return NULL; 182 | } 183 | if (eioctl(self->fd, VIDIOC_S_INPUT, &inputnum, "ioctl(VIDIOC_S_INPUT")<0) { 184 | return NULL; 185 | } 186 | Py_RETURN_NONE; 187 | } 188 | 189 | static PyObject *V4L2_g_input(V4L2Object *self) { 190 | uint32_t inputnum; 191 | if (eioctl(self->fd, VIDIOC_G_INPUT, &inputnum, "ioctl(VIDIOC_G_INPUT)")<0) { 192 | return NULL; 193 | } 194 | return Py_BuildValue("I", inputnum); 195 | } 196 | 197 | static PyObject *V4L2_enumstd(V4L2Object *self) { 198 | struct v4l2_standard std; 199 | memset(&std, 0, sizeof(struct v4l2_standard)); 200 | PyObject *stdlist, *stdinfo; 201 | std.index=0; 202 | stdlist=PyList_New(0); 203 | while(ioctl(self->fd, VIDIOC_ENUMSTD, &std)!=-1) { 204 | stdinfo=Py_BuildValue( 205 | "{s:I,s:K,s:s,s:I,s:{s:I,s:I}}", 206 | "index", std.index, 207 | "id", std.id, 208 | "name", std.name, 209 | "framelines", std.framelines, 210 | "frameperiod", 211 | "numerator", std.frameperiod.numerator, 212 | "denominator", std.frameperiod.denominator 213 | ); 214 | PyList_Append(stdlist, stdinfo); 215 | Py_XDECREF(stdinfo); 216 | std.index++; 217 | } 218 | errno=0; 219 | return stdlist; 220 | } 221 | 222 | static PyObject *V4L2_g_std(V4L2Object *self) { 223 | v4l2_std_id std_id; 224 | if (eioctl(self->fd, VIDIOC_G_STD, &std_id, 225 | "ioctl(VIDIOC_G_STD)")<0) { 226 | return NULL; 227 | } 228 | return Py_BuildValue("K",std_id); 229 | } 230 | 231 | static PyObject *V4L2_s_std(V4L2Object *self, PyObject *args) { 232 | v4l2_std_id std_id=0; 233 | if (!PyArg_ParseTuple(args, "K", 234 | &std_id)) { 235 | return NULL; 236 | } 237 | if (eioctl(self->fd, VIDIOC_S_STD, &std_id, 238 | "ioctl(VIDIOC_S_STD)")<0) { 239 | return NULL; 240 | } 241 | Py_RETURN_NONE; 242 | } 243 | 244 | // s_std() 245 | // g_std() 246 | 247 | static PyObject *V4L2_reqbufs(V4L2Object *self, PyObject *args) { 248 | struct v4l2_requestbuffers reqbufs; 249 | memset(&reqbufs, 0, sizeof(struct v4l2_requestbuffers)); 250 | if (!PyArg_ParseTuple(args, "I", 251 | &reqbufs.count)) { 252 | return NULL; 253 | } 254 | reqbufs.type=self->type; 255 | reqbufs.memory=self->memory; 256 | if (eioctl(self->fd, VIDIOC_REQBUFS, &reqbufs, 257 | "ioctl(VIDIOC_REQBUFS)")<0) { 258 | return NULL; 259 | } 260 | return Py_BuildValue("i", reqbufs.count); 261 | } 262 | 263 | static PyObject *V4L2_querybuf(V4L2Object *self, PyObject *args) { 264 | struct v4l2_buffer buf; 265 | memset(&buf, 0, sizeof(struct v4l2_buffer)); 266 | PyObject *bufinfo; 267 | if (!PyArg_ParseTuple(args, "I", 268 | &buf.index)) { 269 | return NULL; 270 | } 271 | buf.type=self->type; 272 | buf.memory=self->memory; 273 | if (eioctl(self->fd, VIDIOC_QUERYBUF, &buf, 274 | "ioctl(VIDIOC_QUERYBUF)")<0) { 275 | return NULL; 276 | } 277 | bufinfo=Py_BuildValue( 278 | "{s:I,s:I,s:I,s:I,s:I,s:{s:I,s:I},s:{s:I,s:I,s:I,s:I,s:I,s:I},s:I,s:I,s:I,s:I}", 279 | "index", buf.index, 280 | "type", buf.type, 281 | "bytesused", buf.bytesused, 282 | "flags", buf.flags, 283 | "field", buf.field, 284 | "timestamp", 285 | "tv_sec", buf.timestamp.tv_sec, 286 | "tv_usec", buf.timestamp.tv_usec, 287 | "timecode", 288 | "type", buf.timecode.type, 289 | "flags", buf.timecode.flags, 290 | "frames", buf.timecode.frames, 291 | "seconds", buf.timecode.seconds, 292 | "minutes", buf.timecode.minutes, 293 | "hours", buf.timecode.hours, 294 | //"userbits", buf.timecode.userbits, 4, 295 | "sequence", buf.sequence, 296 | "memory", buf.memory, 297 | "offset", buf.m.offset, 298 | "length", buf.length 299 | //"input", buf.input // can not work in linux-3.12-1-amd64 300 | ); 301 | return bufinfo; 302 | } 303 | 304 | static PyObject *V4L2_mmap(V4L2Object *self, PyObject *args) { 305 | long offset; 306 | uint64_t length; 307 | void *addr; 308 | if (!PyArg_ParseTuple(args, "lI", 309 | &offset, &length)) { 310 | return NULL; 311 | } 312 | addr=mmap(NULL, length, 313 | PROT_READ|PROT_WRITE, 314 | MAP_SHARED, 315 | self->fd, 316 | offset); 317 | if (addr==NULL || addr==MAP_FAILED) { 318 | PyErr_Format(PyExc_OSError, "ERROR[%d]=\"%s\", %s", 319 | errno, strerror(errno), "mmap()"); 320 | errno=0; 321 | return NULL; 322 | } 323 | return Py_BuildValue("k",addr); 324 | } 325 | 326 | static PyObject *V4L2_munmap(V4L2Object *self, PyObject *args) { 327 | uint64_t length; 328 | void *addr; 329 | if (!PyArg_ParseTuple(args, "II", 330 | &addr, &length)) { 331 | return NULL; 332 | } 333 | munmap(addr,length); 334 | Py_RETURN_NONE; 335 | } 336 | 337 | static PyObject *V4L2_qbuf(V4L2Object *self, PyObject *args) { 338 | struct v4l2_buffer buf; 339 | memset(&buf, 0, sizeof(struct v4l2_buffer)); 340 | if (!PyArg_ParseTuple(args, "I", 341 | &buf.index)) { 342 | return NULL; 343 | } 344 | buf.type=self->type; 345 | buf.memory=self->memory; 346 | if (eioctl(self->fd, VIDIOC_QBUF, &buf, 347 | "ioctl(VIDIOC_QBUF)")<0) { 348 | return NULL; 349 | } 350 | Py_RETURN_NONE; 351 | } 352 | 353 | static PyObject *V4L2_streamon(V4L2Object *self) { 354 | enum v4l2_buf_type type=self->type; 355 | if (eioctl(self->fd, VIDIOC_STREAMON, &type, 356 | "ioctl(VIDIOC_STREAMON)")<0) { 357 | return NULL; 358 | } 359 | Py_RETURN_NONE; 360 | } 361 | 362 | static PyObject *V4L2_streamoff(V4L2Object *self) { 363 | enum v4l2_buf_type type=self->type; 364 | if (eioctl(self->fd, VIDIOC_STREAMOFF, &type, 365 | "ioctl(VIDIOC_STREAMOFF)")<0) { 366 | return NULL; 367 | } 368 | Py_RETURN_NONE; 369 | } 370 | 371 | static PyObject *V4L2_dqbuf(V4L2Object *self) { 372 | struct v4l2_buffer buf; 373 | memset(&buf, 0, sizeof(struct v4l2_buffer)); 374 | buf.type=self->type; 375 | buf.memory=self->memory; 376 | if (eioctl(self->fd, VIDIOC_DQBUF, &buf, 377 | "ioctl(VIDIOC_DQBUF)")<0) { 378 | return NULL; 379 | } 380 | return Py_BuildValue("I", buf.index); 381 | } 382 | 383 | static PyObject *V4L2_getbuffer(V4L2Object *self, PyObject *args) { 384 | uint8_t *addr; 385 | Py_ssize_t length; 386 | if (!PyArg_ParseTuple(args, "li", 387 | &addr, &length)) { 388 | return NULL; 389 | } 390 | return PyBuffer_FromMemory(addr, length); 391 | } 392 | 393 | static PyObject *V4L2_getjpeg(V4L2Object *self, PyObject *args) { 394 | uint8_t *addr; 395 | Py_ssize_t length; 396 | if (!PyArg_ParseTuple(args, "ki", 397 | &addr, &length)) { 398 | return NULL; 399 | } 400 | uint32_t i; 401 | /*for (i=length-1; i>=0 ; i--) { 402 | if (addr[i] != 0) { 403 | break; 404 | } 405 | } 406 | return PyBuffer_FromMemory(addr, i+1);*/ 407 | //i=length-1; 408 | for (i=0; ifd); 418 | } 419 | 420 | static PyObject *V4L2_queryctrl(V4L2Object *self, PyObject *args) { 421 | struct v4l2_queryctrl queryctrl; 422 | memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl)); 423 | if (!PyArg_ParseTuple(args, "I", 424 | &queryctrl.id)) { 425 | return NULL; 426 | } 427 | if (eioctl(self->fd, VIDIOC_QUERYCTRL, &queryctrl, 428 | "ioctl(VIDIOC_QUERYCTRL)")<0) { 429 | return NULL; 430 | } 431 | return Py_BuildValue( 432 | "{s:I,s:I,s:s,s:i,s:i,s:i,s:i,s:I}", 433 | "id", queryctrl.id, 434 | "type", queryctrl.type, 435 | "name", queryctrl.name, 436 | "minimum", queryctrl.minimum, 437 | "maximum", queryctrl.maximum, 438 | "step", queryctrl.step, 439 | "default_value", queryctrl.default_value, 440 | "flags", queryctrl.flags 441 | ); 442 | } 443 | 444 | static PyObject *V4L2_querymenu(V4L2Object *self, PyObject *args) { 445 | struct v4l2_querymenu querymenu; 446 | memset(&querymenu, 0, sizeof(struct v4l2_querymenu)); 447 | if (!PyArg_ParseTuple(args, "I", 448 | &querymenu.id)) { 449 | return NULL; 450 | } 451 | if (eioctl(self->fd, VIDIOC_QUERYMENU, &querymenu, 452 | "ioctl(VIDIOC_QUERYMENU)")<0) { 453 | return NULL; 454 | } 455 | return Py_BuildValue( 456 | "{s:I,s:I,s:s}", 457 | "id", querymenu.id, 458 | "index", querymenu.index, 459 | "name", querymenu.name 460 | ); 461 | } 462 | 463 | static PyObject *V4L2_g_ctrl(V4L2Object *self, PyObject *args) { 464 | struct v4l2_control ctrl; 465 | memset(&ctrl, 0, sizeof(struct v4l2_control)); 466 | if (!PyArg_ParseTuple(args, "I", 467 | &ctrl.id)) { 468 | return NULL; 469 | } 470 | if (eioctl(self->fd, VIDIOC_G_CTRL, &ctrl, 471 | "ioctl(VIDIOC_G_CTRL)")<0) { 472 | return NULL; 473 | } 474 | return Py_BuildValue( 475 | "{s:I,s:i}", 476 | "id", ctrl.id, 477 | "value", ctrl.value 478 | ); 479 | } 480 | 481 | static PyObject *V4L2_s_ctrl(V4L2Object *self, PyObject *args) { 482 | struct v4l2_control ctrl; 483 | memset(&ctrl, 0, sizeof(struct v4l2_control)); 484 | if (!PyArg_ParseTuple(args, "Ii", 485 | &ctrl.id, &ctrl.value)) { 486 | return NULL; 487 | } 488 | if (eioctl(self->fd, VIDIOC_S_CTRL, &ctrl, 489 | "ioctl(VIDIOC_S_CTRL)")<0) { 490 | return NULL; 491 | } 492 | Py_RETURN_NONE; 493 | } 494 | 495 | // Module level members -------------------------------------------------------- 496 | 497 | static PyMethodDef V4L2_methods[] = { 498 | {"querycap", (PyCFunction)V4L2_querycap, METH_NOARGS, 499 | "querycap()"}, 500 | {"enum_fmt", (PyCFunction)V4L2_enum_fmt, METH_NOARGS, 501 | "enum_fmt(type)"}, 502 | {"s_fmt", (PyCFunction)V4L2_s_fmt, METH_VARARGS, 503 | "s_fmt(width,height,pixelformat,field)"}, 504 | {"enuminput", (PyCFunction)V4L2_enuminput, METH_NOARGS, 505 | "enuminput()"}, 506 | {"enumaudio", (PyCFunction)V4L2_enumaudio, METH_NOARGS, 507 | "enumaudio()"}, 508 | {"s_input", (PyCFunction)V4L2_s_input, METH_VARARGS, 509 | "s_input(inputnum)"}, 510 | {"g_input", (PyCFunction)V4L2_g_input, METH_VARARGS, 511 | "g_input()"}, 512 | {"enumstd", (PyCFunction)V4L2_enumstd, METH_NOARGS, 513 | "enumstd()"}, 514 | {"g_std", (PyCFunction)V4L2_g_std, METH_NOARGS, 515 | "g_std()"}, 516 | {"s_std", (PyCFunction)V4L2_s_std, METH_VARARGS, 517 | "s_std(std_id)"}, 518 | {"reqbufs", (PyCFunction)V4L2_reqbufs, METH_VARARGS, 519 | "reqbufs(count,type,memory)"}, 520 | {"querybuf", (PyCFunction)V4L2_querybuf, METH_VARARGS, 521 | "querybuf(bufidx,type,memory)"}, 522 | {"mmap", (PyCFunction)V4L2_mmap, METH_VARARGS, 523 | "mmap(offset,length)"}, 524 | {"munmap", (PyCFunction)V4L2_munmap, METH_VARARGS, 525 | "munmap(addr,length)"}, 526 | {"qbuf", (PyCFunction)V4L2_qbuf, METH_VARARGS, 527 | "qbuf(bufidx)"}, 528 | {"streamon", (PyCFunction)V4L2_streamon, METH_NOARGS, 529 | "stream()"}, 530 | {"streamoff", (PyCFunction)V4L2_streamoff, METH_NOARGS, 531 | "streamoff()"}, 532 | {"dqbuf", (PyCFunction)V4L2_dqbuf, METH_NOARGS, 533 | "dqbuf()"}, 534 | {"getbuffer", (PyCFunction)V4L2_getbuffer, METH_VARARGS, 535 | "getbuffer(addr,length)"}, 536 | {"getjpeg", (PyCFunction)V4L2_getjpeg, METH_VARARGS, 537 | "getjpeg(addr,length)"}, 538 | {"fileno", (PyCFunction)V4L2_fileno, METH_NOARGS, 539 | "fileno()"}, 540 | {"queryctrl", (PyCFunction)V4L2_queryctrl, METH_VARARGS, 541 | "queryctrl(ctrl_id)"}, 542 | {"querymenu", (PyCFunction)V4L2_querymenu, METH_VARARGS, 543 | "querymenu(menu_id)"}, 544 | {"g_ctrl", (PyCFunction)V4L2_g_ctrl, METH_VARARGS, 545 | "g_ctrl(ctrl_id)"}, 546 | {"s_ctrl", (PyCFunction)V4L2_s_ctrl, METH_VARARGS, 547 | "s_ctrl(ctrl_id,value)"}, 548 | {NULL} 549 | }; 550 | 551 | static PyMemberDef V4L2_members[] = { 552 | {NULL} 553 | }; 554 | 555 | PyTypeObject V4L2Type= { 556 | PyVarObject_HEAD_INIT(&PyType_Type,0) 557 | "V4L2", //tp_name,类型名字,注意同时包含模块名,以点分隔 558 | sizeof(V4L2Object), //tp_basicsize,调用PyObject_New()时需要分配多少内存 559 | 0, //tp_itemsize,对列表和字符串,这里是可变长度,暂时忽略 560 | (destructor)V4L2_dealloc, //tp_dealloc 561 | 0,0,0,0,0, //tp_print,tp_getattr,tp_setattr,tp_compare,tp_repr 562 | 0,0,0,0,0, //tp_as_number,tp_as_sequence,tp_as_mapping,tp_as_hash,tp_call 563 | 0,0,0,0, //tp_str,tp_getattro,tp_setattro,tp_as_buffer 564 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,//tp_flags 565 | "V4L2 Objecct", //tp_doc 566 | 0,0,0,0, //tp_traverse,tp_clear,tp_richcompare,tp_weaklistoffset 567 | 0,0, //tp_iter,tp_iternext 568 | V4L2_methods, //struct PyMethodDef *tp_methods 569 | V4L2_members, //struct PyMemberDef *tp_members 570 | 0,0,0,0,0, //tp_getset,tp_base,tp_dict,tp_descr_get,tp_descr_set 571 | 0, //tp_dictoffset 572 | (initproc)V4L2_Init, //tp_init 573 | 0, //tp_alloc 574 | V4L2_New, //tp_new 575 | 0,0,0,0,0, //tp_free,tp_is_gc,tp_bases,tp_mro,tp_cache 576 | 0,0,0,0, //tp_subclasses,tp_weaklist,tp_del,tp_version_tag 577 | }; 578 | --------------------------------------------------------------------------------