最近作一个小软件须要用到虚拟摄像头,在网上找了找虚拟摄像头软件 发现 Vcam 软件有个API 能够用,有API固然是最好的啦,可是这个API只有C++和C#的。都说 **“人生苦短,得用python”**能用Python解决的事情尽可能别用C++,因而萌生了本身写个模块的想法。
值得庆幸的是以前研究过一段时间C++。
先贴两个python官方文档连接 C API 第三方模块开发指南html
创建win32 DLL工程
python
调整工程属性ios
头文件windows
写Python的C++扩展必须包含Python.h 和 structmember.h两个头文件api
#include <windows.h> #include <iostream> #include <sstream> #include <Python.h> #include <structmember.h>
API文件导入略过数据结构
首先建立一个struct 用来存放类的各项属性.ide
struct IVCamRenderer; # 这个IVCamRenderer在VCam API文件里面有定义 这里从新声明下 typedef struct _VCam { PyObject_HEAD // 结构体的第一个元素必须是 PyObject_HEAD 宏 IBaseFilter * __vcam_renderer; //VCam类的第一个成员 IVCamRenderer * __my_vcam; //第二个成员 因为要处理图片用到了GDI+ 此属性用来存放 }VCam; static PyMemberDef VCam_DataMembers[] = { //类/结构的数据成员类说明 表. 根据官方文档说明此类表必需要要以一个元素全为NULL的数据结构结尾,后面还有一个Method 表也是如此 { "__vcam_renderer", T_OBJECT, offsetof(VCam, __vcam_renderer), 0, "The vcam_renderer of instance" }, { "__my_vcam", T_OBJECT, offsetof(VCam, __my_vcam), 0, "The vcam of instance." }, { NULL, NULL, NULL, 0, NULL } };
咱们来看一下PyMemberDef 的定义函数
/* An array of PyMemberDef structures defines the name, type and offset of selected members of a C structure. These can be read by PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY flag is set). The array must be terminated with an entry whose name pointer is NULL. */ typedef struct PyMemberDef { char *name; // 在Python中显示的名称 int type; // 变量类型 Py_ssize_t offset; // offset 变量在前面为模块类定义的模块中的offset int flags; //读写权限标记 char *doc; //帮助文档内容 } PyMemberDef; /* Types */ #define T_SHORT 0 #define T_INT 1 #define T_LONG 2 #define T_FLOAT 3 #define T_DOUBLE 4 #define T_STRING 5 #define T_OBJECT 6 /* XXX the ordering here is weird for binary compatibility */ #define T_CHAR 7 /* 1-character string */ #define T_BYTE 8 /* 8-bit signed int */ /* unsigned variants: */ #define T_UBYTE 9 #define T_USHORT 10 #define T_UINT 11 #define T_ULONG 12 /* Added by Jack: strings contained in the structure */ #define T_STRING_INPLACE 13 /* Added by Lillo: bools contained in the structure (assumed char) */ #define T_BOOL 14 #define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError when the value is NULL, instead of converting to None. */ #define T_LONGLONG 17 #define T_ULONGLONG 18 #define T_PYSSIZET 19 /* Py_ssize_t */ #define T_NONE 20 /* Value is always None */ /* Flags */ #define READONLY 1 #define READ_RESTRICTED 2 #define PY_WRITE_RESTRICTED 4 #define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED)
写两个函数用来处理python类初始化资源申请和和类析构时资源释放工具
初始化函数ui
static void VCam_init(VCam* Self, PyObject* pArgs) //构造方法. { Self->__vcam_renderer = nullptr; Self->__my_vcam = nullptr; HRESULT hr=::CoInitialize(nullptr); if (FAILED(hr = CoCreateInstance(CLSID_VCamRenderer, NULL, CLSCTX_INPROC, IID_IBaseFilter, reinterpret_cast<void**>(&(Self->__vcam_renderer))))) { PyErr_SetString(PyExc_OSError, "driver not installed!"); return; } // get [IVCamRender] interface from VCam Renderer filter if (FAILED(hr = Self->__vcam_renderer->QueryInterface(&(Self->__my_vcam)))) { PyErr_SetString(PyExc_OSError, "driver not installed!"); return; } }
请不要在乎构造函数中一堆乱七八糟的代码 那些代码是VcamAPI初始化取对象的代码 正常简单点写就是假如类体内声明 一个 成员
XXType * instance;
构造时将其实例化一下申请一块内存
self->instance = new xxx;
析构函数
static void VCam_Destruct(VCam* Self) //析构方法. { if (Self->__my_vcam) Self->__my_vcam->SetConnectionNotificationEvent(reinterpret_cast<__int64>(nullptr)); if (Self->__vcam_renderer) Self->__vcam_renderer->Release(), Self->__vcam_renderer = nullptr; if (Self->__my_vcam) Self->__my_vcam->Release(), Self->__my_vcam = nullptr; Py_TYPE(Self)->tp_free((PyObject*)Self); //释放对象/实例. }
析构时候 shift键构造时候申请的内存防止内存泄漏便可
delete self->instance; self->instance = nullptr;
最后须要掉将Python对象释放
Py_TYPE(Self)->tp_free((PyObject*)Self); //释放对象/
写供Python调用的类中的各类方法
举例:写一个将虚拟摄像头显示 调整为镜像显示的方法
static PyObject* VCam_Mirror(VCam* Self, PyObject* Argvs) { Py_INCREF(Py_None); int mode=1; if (!PyArg_ParseTuple(Argvs, "|i", &mode)) { cout << "Parse the argument FAILED! You should pass correct values!" << endl; return Py_None; } Self->__my_vcam->SetMirror(mode); //Mirror the output video (0: no mirror, others: mirror), non-persistent. return Py_None; }
看完引用计数问题感受有点明白了 CPython 垃圾回收机制原理了有没有
先写到这 后面再开一篇 如何用C++ 写Python模块扩展(二)