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