Skip to content

Commit 009148a

Browse files
authored
Merge pull request #1 from shagren/threading-gil-releasing
Release GIL in device_get_capture
2 parents e6f43bd + 29716b2 commit 009148a

File tree

2 files changed

+93
-13
lines changed

2 files changed

+93
-13
lines changed

pyk4a/pyk4a.cpp

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,75 @@ extern "C" {
1919
k4a_transformation_t transformation_handle;
2020
k4a_calibration_t calibration_handle;
2121
k4a_device_t device;
22+
short thread_safe;
2223
} device_container;
2324
#define MAX_DEVICES 32
2425
device_container devices[MAX_DEVICES];
2526

27+
static PyThreadState* _gil_release(uint32_t device_id) {
28+
return NULL;
29+
PyThreadState *thread_state = NULL;
30+
if (devices[device_id].thread_safe == 0) {
31+
thread_state = PyEval_SaveThread();
32+
}
33+
return thread_state;
34+
}
35+
36+
static void _gil_restore(PyThreadState *thread_state) {
37+
if (thread_state != NULL) {
38+
PyEval_RestoreThread(thread_state);
39+
}
40+
}
41+
2642
static PyObject* device_open(PyObject* self, PyObject* args){
2743
uint32_t device_id;
28-
PyArg_ParseTuple(args, "I", &device_id);
29-
k4a_result_t result = k4a_device_open(device_id, &devices[device_id].device);
44+
short thread_safe;
45+
PyThreadState *thread_state;
46+
PyArg_ParseTuple(args, "IH", &device_id, &thread_safe);
3047

48+
devices[device_id].thread_safe = thread_safe;
49+
thread_state = _gil_release(device_id);
50+
k4a_result_t result = k4a_device_open(device_id, &devices[device_id].device);
51+
_gil_restore(thread_state);
3152
return Py_BuildValue("I", result);
3253
}
3354

3455
static PyObject* device_close(PyObject* self, PyObject* args){
3556
uint32_t device_id;
57+
PyThreadState *thread_state;
3658
PyArg_ParseTuple(args, "I", &device_id);
59+
60+
thread_state = _gil_release(device_id);
3761
k4a_device_close(devices[device_id].device);
62+
_gil_restore(thread_state);
63+
3864
return Py_BuildValue("I", K4A_RESULT_SUCCEEDED);
3965
}
4066

4167
static PyObject* device_get_sync_jack(PyObject* self, PyObject* args){
4268
uint32_t device_id;
69+
PyThreadState *thread_state;
4370
bool in_jack = 0;
4471
bool out_jack = 0;
4572
PyArg_ParseTuple(args, "I", &device_id);
46-
73+
74+
thread_state = _gil_release(device_id);
4775
k4a_result_t result = k4a_device_get_sync_jack(devices[device_id].device, &in_jack, &out_jack);
76+
_gil_restore(thread_state);
4877

4978
return Py_BuildValue("III", result, in_jack, out_jack);
5079
}
5180

5281
static PyObject* device_get_color_control(PyObject* self, PyObject* args){
5382
uint32_t device_id;
83+
PyThreadState *thread_state;
5484
k4a_color_control_command_t command;
5585
k4a_color_control_mode_t mode;
5686
int32_t value = 0;
5787
PyArg_ParseTuple(args, "II", &device_id, &command);
58-
88+
thread_state = _gil_release(device_id);
5989
k4a_result_t result = k4a_device_get_color_control(devices[device_id].device, command, &mode, &value);
90+
_gil_restore(thread_state);
6091
if (result == K4A_RESULT_FAILED) {
6192
return Py_BuildValue("III", 0, 0, 0);
6293
}
@@ -65,12 +96,15 @@ extern "C" {
6596

6697
static PyObject* device_set_color_control(PyObject* self, PyObject* args){
6798
uint32_t device_id;
99+
PyThreadState *thread_state;
68100
k4a_color_control_command_t command = K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE;
69101
k4a_color_control_mode_t mode = K4A_COLOR_CONTROL_MODE_MANUAL;
70102
int32_t value = 0;
71103
PyArg_ParseTuple(args, "IIII", &device_id, &command, &mode, &value);
72104

105+
thread_state = _gil_release(device_id);
73106
k4a_result_t result = k4a_device_set_color_control(devices[device_id].device, command, mode, value);
107+
_gil_restore(thread_state);
74108
if (result == K4A_RESULT_FAILED) {
75109
return Py_BuildValue("I", K4A_RESULT_FAILED);
76110
}
@@ -79,6 +113,7 @@ extern "C" {
79113

80114
static PyObject* device_get_color_control_capabilities(PyObject* self, PyObject* args){
81115
uint32_t device_id;
116+
PyThreadState *thread_state;
82117
k4a_color_control_command_t command;
83118
bool supports_auto;
84119
int32_t min_value;
@@ -88,8 +123,9 @@ extern "C" {
88123
k4a_color_control_mode_t default_mode;
89124
PyArg_ParseTuple(args, "II", &device_id, &command);
90125

91-
126+
thread_state = _gil_release(device_id);
92127
k4a_result_t result = k4a_device_get_color_control_capabilities(devices[device_id].device, command, &supports_auto, &min_value, &max_value, &step_value, &default_value, &default_mode);
128+
_gil_restore(thread_state);
93129
if (result == K4A_RESULT_FAILED) {
94130
return Py_BuildValue("IIIIIII", 0, 0, 0, 0, 0, 0, 0);
95131
}
@@ -98,6 +134,7 @@ extern "C" {
98134

99135
static PyObject* device_start_cameras(PyObject* self, PyObject* args){
100136
uint32_t device_id;
137+
PyThreadState *thread_state;
101138
k4a_device_configuration_t config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
102139
PyArg_ParseTuple(args, "IIIIIIIIII", &device_id,
103140
&config.color_format,
@@ -108,45 +145,57 @@ extern "C" {
108145
&config.disable_streaming_indicator);
109146

110147
k4a_result_t result;
148+
thread_state = _gil_release(device_id);
111149
result = k4a_device_get_calibration(devices[device_id].device, config.depth_mode, config.color_resolution, &devices[device_id].calibration_handle);
112150
if (result == K4A_RESULT_FAILED) {
151+
_gil_restore(thread_state);
113152
return Py_BuildValue("I", K4A_RESULT_FAILED);
114153
}
115154
devices[device_id].transformation_handle = k4a_transformation_create(&devices[device_id].calibration_handle);
116155
if (devices[device_id].transformation_handle == NULL) {
156+
_gil_restore(thread_state);
117157
return Py_BuildValue("I", K4A_RESULT_FAILED);
118158
}
119159
result = k4a_device_start_cameras(devices[device_id].device, &config);
160+
_gil_restore(thread_state);
120161
return Py_BuildValue("I", result);
121162
}
122163

123164
static PyObject* device_stop_cameras(PyObject* self, PyObject* args){
124165
uint32_t device_id;
166+
PyThreadState *thread_state;
125167
PyArg_ParseTuple(args, "I", &device_id);
168+
thread_state = _gil_release(device_id);
126169
if (devices[device_id].transformation_handle) {
127170
k4a_transformation_destroy(devices[device_id].transformation_handle);
128171
}
129172
if (devices[device_id].capture) {
130173
k4a_capture_release(devices[device_id].capture);
131174
}
132175
k4a_device_stop_cameras(devices[device_id].device);
176+
_gil_restore(thread_state);
133177
return Py_BuildValue("I", K4A_RESULT_SUCCEEDED);
134178
}
135179

136180
static PyObject* device_get_capture(PyObject* self, PyObject* args){
137181
uint32_t device_id;
182+
PyThreadState *thread_state;
138183
int32_t timeout;
139184
PyArg_ParseTuple(args, "II", &device_id, &timeout);
185+
thread_state = _gil_release(device_id);
140186
if (devices[device_id].capture) {
141187
k4a_capture_release(devices[device_id].capture);
142188
}
143189
k4a_capture_create(&devices[device_id].capture);
144-
k4a_wait_result_t result = k4a_device_get_capture(devices[device_id].device, &devices[device_id].capture, timeout);
190+
k4a_wait_result_t result;
191+
result = k4a_device_get_capture(devices[device_id].device, &devices[device_id].capture, timeout);
192+
_gil_restore(thread_state);
145193
return Py_BuildValue("I", result);
146194
}
147195

148196
static PyObject* calibration_set_from_raw(PyObject* self, PyObject* args){
149197
uint32_t device_id;
198+
PyThreadState *thread_state;
150199
char * raw_calibration;
151200
k4a_device_configuration_t config = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
152201
PyArg_ParseTuple(args, "IsIIIIIIIII", &device_id,
@@ -159,37 +208,44 @@ extern "C" {
159208
size_t raw_calibration_size = strlen(raw_calibration) + 1;
160209
k4a_result_t result;
161210

211+
thread_state = _gil_release(device_id);
162212
result = k4a_calibration_get_from_raw(raw_calibration,
163213
raw_calibration_size, config.depth_mode,
164214
config.color_resolution, &devices[device_id].calibration_handle);
165215
if (result == K4A_RESULT_FAILED) {
216+
_gil_restore(thread_state);
166217
return Py_BuildValue("I", K4A_RESULT_FAILED);
167218
}
168219
if (devices[device_id].transformation_handle) {
169220
k4a_transformation_destroy(devices[device_id].transformation_handle);
170221
}
171222
devices[device_id].transformation_handle = k4a_transformation_create(&devices[device_id].calibration_handle);
223+
_gil_restore(thread_state);
172224
return Py_BuildValue("I", K4A_RESULT_SUCCEEDED);
173225
}
174226

175227
static PyObject* device_get_calibration(PyObject* self, PyObject* args){
176228
uint32_t device_id;
229+
PyThreadState *thread_state;
177230
k4a_buffer_result_t result;
178231
size_t data_size;
179232
PyArg_ParseTuple(args, "I", &device_id);
180-
233+
thread_state = _gil_release(device_id);
181234
result = k4a_device_get_raw_calibration(devices[device_id].device, NULL, &data_size);
182235
if (result == K4A_BUFFER_RESULT_FAILED) {
236+
_gil_restore(thread_state);
183237
return Py_BuildValue("");
184238
}
185239
uint8_t* data = (uint8_t*) malloc(data_size);
186240
result = k4a_device_get_raw_calibration(devices[device_id].device, data, &data_size);
187241
if (result == K4A_BUFFER_RESULT_FAILED) {
242+
_gil_restore(thread_state);
188243
return Py_BuildValue("");
189244
}
190245

191246
PyObject* res = Py_BuildValue("s", data);
192247
free(data);
248+
_gil_restore(thread_state);
193249
return res;
194250
}
195251

@@ -255,11 +311,13 @@ extern "C" {
255311
static PyObject* transformation_depth_image_to_color_camera(
256312
PyObject* self, PyObject* args){
257313
uint32_t device_id;
314+
PyThreadState *thread_state;
258315
k4a_result_t res;
259316
PyArrayObject *in_array;
260317
k4a_color_resolution_t color_resolution;
261318
PyArg_ParseTuple(args, "IO!I", &device_id, &PyArray_Type, &in_array, &color_resolution);
262319

320+
thread_state = _gil_release(device_id);
263321
k4a_image_t* depth_image_transformed = (k4a_image_t*) malloc(sizeof(k4a_image_t));
264322

265323
k4a_image_t depth_image;
@@ -287,18 +345,22 @@ extern "C" {
287345
}
288346

289347
if (K4A_RESULT_SUCCEEDED == res) {
348+
_gil_restore(thread_state);
290349
return PyArray_Return(np_depth_image);
291350
}
292351
else {
293352
free(depth_image_transformed);
353+
_gil_restore(thread_state);
294354
return Py_BuildValue("");
295355
}
296356
}
297357

298358
static PyObject* device_get_color_image(PyObject* self, PyObject* args){
299359
uint32_t device_id;
360+
PyThreadState *thread_state;
300361
PyArg_ParseTuple(args, "I", &device_id);
301362
k4a_result_t res;
363+
thread_state = _gil_release(device_id);
302364
k4a_image_t* color_image = (k4a_image_t*) malloc(sizeof(k4a_image_t));
303365
*color_image = k4a_capture_get_color_image(devices[device_id].capture);
304366
PyArrayObject* np_color_image;
@@ -307,18 +369,23 @@ extern "C" {
307369
}
308370

309371
if (K4A_RESULT_SUCCEEDED == res) {
372+
_gil_restore(thread_state);
310373
return PyArray_Return(np_color_image);
311374
}
312375
else {
313376
free(color_image);
377+
_gil_restore(thread_state);
314378
return Py_BuildValue("");
315379
}
316380
}
317381

318382
static PyObject* device_get_depth_image(PyObject* self, PyObject* args){
319383
k4a_result_t res;
320384
uint32_t device_id;
385+
PyThreadState *thread_state;
321386
PyArg_ParseTuple(args, "I", &device_id);
387+
388+
thread_state = _gil_release(device_id);
322389
k4a_image_t* depth_image = (k4a_image_t*) malloc(sizeof(k4a_image_t));
323390
*depth_image = k4a_capture_get_depth_image(devices[device_id].capture);
324391

@@ -328,18 +395,23 @@ extern "C" {
328395
}
329396

330397
if (K4A_RESULT_SUCCEEDED == res) {
398+
_gil_restore(thread_state);
331399
return PyArray_Return(np_depth_image);
332400
}
333401
else {
334402
free(depth_image);
403+
_gil_restore(thread_state);
335404
return Py_BuildValue("");
336405
}
337406
}
338407

339408
static PyObject* device_get_ir_image(PyObject* self, PyObject* args){
340409
k4a_result_t res;
341410
uint32_t device_id;
411+
PyThreadState *thread_state;
342412
PyArg_ParseTuple(args, "I", &device_id);
413+
414+
thread_state = _gil_release(device_id);
343415
k4a_image_t* ir_image = (k4a_image_t*) malloc(sizeof(k4a_image_t));
344416
*ir_image = k4a_capture_get_ir_image(devices[device_id].capture);
345417

@@ -349,16 +421,19 @@ extern "C" {
349421
}
350422

351423
if (K4A_RESULT_SUCCEEDED == res) {
424+
_gil_restore(thread_state);
352425
return PyArray_Return(np_ir_image);
353426
}
354427
else {
355428
free(ir_image);
429+
_gil_restore(thread_state);
356430
return Py_BuildValue("");
357431
}
358432
}
359433

360434
static PyObject* calibration_3d_to_3d(PyObject* self, PyObject *args){
361435
uint32_t device_id;
436+
PyThreadState *thread_state;
362437
k4a_result_t res;
363438
k4a_float3_t source_point3d_mm;
364439
k4a_float3_t target_point3d_mm;
@@ -375,7 +450,8 @@ extern "C" {
375450
&source_point_z,
376451
&source_camera,
377452
&target_camera);
378-
453+
454+
thread_state = _gil_release(device_id);
379455
source_point3d_mm.xyz.x = source_point_x;
380456
source_point3d_mm.xyz.y = source_point_y;
381457
source_point3d_mm.xyz.z = source_point_z;
@@ -386,7 +462,7 @@ extern "C" {
386462
source_camera,
387463
target_camera,
388464
&target_point3d_mm);
389-
465+
_gil_restore(thread_state);
390466
if (res == K4A_RESULT_FAILED ) {
391467
return Py_BuildValue("I", K4A_RESULT_FAILED);
392468
}
@@ -396,6 +472,7 @@ extern "C" {
396472

397473
static PyObject* calibration_2d_to_3d(PyObject* self, PyObject *args){
398474
uint32_t device_id;
475+
PyThreadState *thread_state;
399476
int source_point_x;
400477
int source_point_y;
401478
float source_depth_mm;
@@ -413,7 +490,8 @@ extern "C" {
413490
&source_depth_mm,
414491
&source_camera,
415492
&target_camera);
416-
493+
494+
thread_state = _gil_release(device_id);
417495
source_point2d.xy.x = source_point_x;
418496
source_point2d.xy.y = source_point_y;
419497

@@ -425,7 +503,7 @@ extern "C" {
425503
target_camera,
426504
&target_point3d_mm,
427505
&valid);
428-
506+
_gil_restore(thread_state);
429507
if (res == K4A_RESULT_FAILED ) {
430508
return Py_BuildValue("I", K4A_RESULT_FAILED);
431509
}

0 commit comments

Comments
 (0)