1/* 2 * Customer wrappers for a number of CoreVideo APIs. 3 */ 4#include <Python.h> 5#include "pyobjc-api.h" 6 7#ifdef WITH_CORE_VIDEO 8 9#import <CoreVideo/CoreVideo.h> 10 11static void 12mod_CVPixelBufferReleaseBytesCallback( 13 void *releaseRefCon, const void *baseAddress) 14{ 15 PyObject* info = (PyObject*)releaseRefCon; 16 PyGILState_STATE state = PyGILState_Ensure(); 17 18 if (PyTuple_GET_ITEM(info, 0) != Py_None) { 19 PyObject* r = PyObject_CallFunction( 20 PyTuple_GET_ITEM(info, 0), 21 "O", 22 PyTuple_GET_ITEM(info, 1)); 23 if (r == NULL) { 24 Py_XDECREF(info); 25 PyObjCErr_ToObjCWithGILState(&state); 26 } 27 28 Py_DECREF(r); 29 } 30 31 Py_DECREF(info); 32 PyGILState_Release(state); 33} 34 35static PyObject* 36mod_CVPixelBufferCreateWithBytes( 37 PyObject* self __attribute__((__unused__)), 38 PyObject* args) 39{ 40 CFAllocatorRef allocator; 41 size_t width; 42 size_t height; 43 OSType pixelFormatType; 44 void* baseAddress; 45 size_t bytesPerRow; 46 CFDictionaryRef pixelBufferAttributes; 47 CVPixelBufferRef pixelBuffer; 48 PyObject* py_allocator; 49 PyObject* py_width; 50 PyObject* py_height; 51 PyObject* py_pixelFormatType; 52 PyObject* py_buffer; 53 Py_ssize_t buflen; 54 PyObject* py_bytesPerRow; 55 PyObject* releaseCallback; 56 PyObject* info; 57 PyObject* py_pixelBufferAttributes; 58 PyObject* py_pixelBuffer = Py_None; 59 60 if (!PyArg_ParseTuple(args, "OOOOOOOOO|O", 61 &py_allocator, &py_width, &py_height, &py_pixelFormatType, 62 &py_buffer, &py_bytesPerRow, &releaseCallback, &info, 63 &py_pixelBufferAttributes, &py_pixelBuffer)) { 64 65 return NULL; 66 } 67 68 if (PyObjC_PythonToObjC(@encode(CFAllocatorRef), py_allocator, &allocator) < 0) { 69 return NULL; 70 } 71 if (PyObjC_PythonToObjC(@encode(size_t), py_width, &width) < 0) { 72 return NULL; 73 } 74 if (PyObjC_PythonToObjC(@encode(size_t), py_height, &height) < 0) { 75 return NULL; 76 } 77 if (PyObjC_PythonToObjC(@encode(OSType), py_pixelFormatType, &pixelFormatType) < 0) { 78 return NULL; 79 } 80 if (PyObjC_PythonToObjC(@encode(size_t), py_bytesPerRow, &bytesPerRow) < 0) { 81 return NULL; 82 } 83 if (PyObjC_PythonToObjC(@encode(CFDictionaryRef), py_pixelBufferAttributes, &pixelBufferAttributes) < 0) { 84 return NULL; 85 } 86 87 if (py_pixelBuffer != Py_None) { 88 PyErr_SetString(PyExc_ValueError, "pixelBufferOut must be None"); 89 return NULL; 90 } 91 92 if (PyObject_AsWriteBuffer(py_buffer, &baseAddress, &buflen) < 0) { 93 return NULL; 94 } 95 96 PyObject* real_info = Py_BuildValue("OOO", 97 releaseCallback, info, py_buffer); 98 if (real_info == NULL) { 99 return NULL; 100 } 101 102 CVReturn rv; 103 104 PyObjC_DURING 105 rv = CVPixelBufferCreateWithBytes( 106 allocator, 107 width, 108 height, 109 pixelFormatType, 110 baseAddress, 111 bytesPerRow, 112 mod_CVPixelBufferReleaseBytesCallback, 113 real_info, 114 pixelBufferAttributes, 115 &pixelBuffer); 116 117 PyObjC_HANDLER 118 rv = 0; 119 PyObjCErr_FromObjC(localException); 120 121 PyObjC_ENDHANDLER 122 123 if (PyErr_Occurred()) { 124 Py_DECREF(real_info); 125 return NULL; 126 } 127 128 if (pixelBuffer == NULL) { 129 Py_DECREF(real_info); 130 Py_INCREF(Py_None); 131 return Py_None; 132 } 133 134 py_pixelBuffer = PyObjC_ObjCToPython( 135 @encode(CVPixelBufferRef), 136 &pixelBuffer); 137 CFRelease(pixelBuffer); /* Compensate for create rule */ 138 return py_pixelBuffer; 139} 140 141 142 143static PyMethodDef m_methods[] = { 144 { 145 "CVPixelBufferCreateWithBytes", 146 (PyCFunction)mod_CVPixelBufferCreateWithBytes, 147 METH_VARARGS, 148 NULL 149 }, 150 151 { 0, 0, 0, 0 } 152}; 153 154#else /* ! WITH_CORE_VIDEO */ 155 156static PyMethodDef m_methods[] = { 157 { 0, 0, 0, 0 } 158}; 159 160#endif /* ! WITH_CORE_VIDEO */ 161 162 163 164void init_CVPixelBuffer(void); 165void init_CVPixelBuffer(void) 166{ 167 PyObject* m = Py_InitModule4("_CVPixelBuffer", m_methods, 168 NULL, NULL, PYTHON_API_VERSION); 169 170 if (PyObjC_ImportAPI(m) < 0) { return; } 171} 172