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