23
23
* Binary distributions must follow the binary distribution requirements of
24
24
* either License.
25
25
*/
26
- #include <stdio.h >
27
- #include <pthread.h >
28
- #include <string.h >
29
- #include <stdlib.h >
30
- #include <assert.h >
26
+ #include < cassert >
27
+ #include < condition_variable >
28
+ #include < iostream >
29
+ #include < thread >
30
+ #include < mutex >
31
31
#include " libfreenect_registration.h"
32
32
#include " libfreenect_sync.h"
33
33
34
+ using std::cerr;
35
+ using std::endl;
36
+ using Mutex = std::mutex;
37
+ using UniqueLock = std::unique_lock<Mutex>;
38
+ using LockGuard = std::lock_guard<Mutex>;
39
+ using ConditionVariable = std::condition_variable;
40
+ using Thread = std::thread;
41
+
42
+ namespace
43
+ {
44
+ void FN_WARN_INVALID_INDEX (const int index)
45
+ {
46
+ cerr << " Error: Invalid index [" << index << " ]" << endl;
47
+ }
48
+ }
49
+
50
+
34
51
typedef struct buffer_ring {
35
- pthread_mutex_t lock ;
36
- pthread_cond_t cb_cond ;
52
+ Mutex mutex ;
53
+ ConditionVariable cb_cond;
37
54
void *bufs[3 ];
38
55
uint32_t timestamp;
39
- int valid ; // True if middle buffer is valid
56
+ bool valid; // True if middle buffer is valid
40
57
int fmt;
41
58
int res;
42
59
} buffer_ring_t ;
@@ -47,102 +64,113 @@ typedef struct sync_kinect {
47
64
buffer_ring_t depth;
48
65
} sync_kinect_t ;
49
66
67
+ struct AutomaticShutdownThread : public Thread
68
+ {
69
+ using Thread::thread;
70
+
71
+ virtual ~AutomaticShutdownThread ()
72
+ {
73
+ freenect_sync_stop ();
74
+ }
75
+
76
+ AutomaticShutdownThread& operator =(Thread&& other)
77
+ {
78
+ Thread::operator =(std::move (other));
79
+ return *this ;
80
+ }
81
+ };
82
+
50
83
typedef int (*set_buffer_t )(freenect_device *dev, void *buf);
51
84
52
85
#define MAX_KINECTS 64
53
86
static sync_kinect_t *kinects[MAX_KINECTS] = { 0 };
54
87
static freenect_context *ctx;
55
- static int thread_running = 0 ;
56
- static pthread_t thread ;
57
- static pthread_mutex_t runloop_lock = PTHREAD_MUTEX_INITIALIZER ;
88
+ static bool thread_running = false ;
89
+ static AutomaticShutdownThread thread;
90
+ static Mutex runloop_mutex ;
58
91
static int pending_runloop_tasks = 0 ;
59
- static pthread_mutex_t pending_runloop_tasks_lock = PTHREAD_MUTEX_INITIALIZER ;
60
- static pthread_cond_t pending_runloop_tasks_cond = PTHREAD_COND_INITIALIZER ;
61
-
62
- /* Locking Convention
63
- Rules:
64
- - if you need more than one lock on a line, get them from left to right
65
- - do not mix locks on different lines
66
- - if you need to change the lock rules, make sure you check everything and update this
67
- Lock Families:
68
- - pending_runloop_tasks_lock
69
- - runloop_lock, buffer_ring_t.lock (NOTE: You may only have one)
92
+ static Mutex pending_runloop_tasks_mutex;
93
+ static ConditionVariable pending_runloop_tasks_cond;
94
+
95
+ /* Lock Families:
96
+ - pending_runloop_tasks_mutex
97
+ - runloop_mutex, buffer_ring_t.mutex (NOTE: You may only have one)
70
98
*/
71
99
72
100
static int alloc_buffer_ring_video (freenect_resolution res, freenect_video_format fmt, buffer_ring_t *buf)
73
101
{
74
- int sz , i ;
102
+ int size ;
75
103
switch (fmt) {
76
104
case FREENECT_VIDEO_RGB:
77
105
case FREENECT_VIDEO_BAYER:
78
106
case FREENECT_VIDEO_IR_8BIT:
79
107
case FREENECT_VIDEO_IR_10BIT:
80
108
case FREENECT_VIDEO_IR_10BIT_PACKED:
81
- sz = freenect_find_video_mode (res , fmt ).bytes ;
109
+ size = freenect_find_video_mode (res, fmt).bytes ;
82
110
break ;
83
111
default :
84
- printf ( "Invalid video format %d\n" , fmt ) ;
112
+ cerr << " Invalid video format " << fmt << endl ;
85
113
return -1 ;
86
114
}
87
- for (i = 0 ; i < 3 ; ++ i )
88
- buf -> bufs [i ] = malloc (sz );
115
+ for (short i = 0 ; i < 3 ; ++i) {
116
+ buf->bufs [i] = malloc (size);
117
+ }
89
118
buf->timestamp = 0 ;
90
- buf -> valid = 0 ;
119
+ buf->valid = false ;
91
120
buf->fmt = fmt;
92
121
buf->res = res;
93
122
return 0 ;
94
123
}
95
124
96
125
static int alloc_buffer_ring_depth (freenect_resolution res, freenect_depth_format fmt, buffer_ring_t *buf)
97
126
{
98
- int sz , i ;
127
+ int size ;
99
128
switch (fmt) {
100
129
case FREENECT_DEPTH_11BIT:
101
130
case FREENECT_DEPTH_10BIT:
102
131
case FREENECT_DEPTH_11BIT_PACKED:
103
132
case FREENECT_DEPTH_10BIT_PACKED:
104
133
case FREENECT_DEPTH_REGISTERED:
105
134
case FREENECT_DEPTH_MM:
106
- sz = freenect_find_depth_mode (res , fmt ).bytes ;
135
+ size = freenect_find_depth_mode (res, fmt).bytes ;
107
136
break ;
108
137
default :
109
- printf ( "Invalid depth format %d\n" , fmt ) ;
138
+ cerr << " Invalid depth format " << fmt << endl ;
110
139
return -1 ;
111
140
}
112
- for (i = 0 ; i < 3 ; ++ i )
113
- buf -> bufs [i ] = malloc (sz );
141
+ for (short i = 0 ; i < 3 ; ++i) {
142
+ buf->bufs [i] = malloc (size);
143
+ }
114
144
buf->timestamp = 0 ;
115
- buf -> valid = 0 ;
145
+ buf->valid = false ;
116
146
buf->fmt = fmt;
117
147
buf->res = res;
118
148
return 0 ;
119
149
}
120
150
121
151
static void free_buffer_ring (buffer_ring_t *buf)
122
152
{
123
- int i ;
124
- for (i = 0 ; i < 3 ; ++ i ) {
153
+ for (short i = 0 ; i < 3 ; ++i) {
125
154
free (buf->bufs [i]);
126
- buf -> bufs [i ] = NULL ;
155
+ buf->bufs [i] = nullptr ;
127
156
}
128
157
buf->timestamp = 0 ;
129
- buf -> valid = 0 ;
158
+ buf->valid = false ;
130
159
buf->fmt = -1 ;
131
160
buf->res = -1 ;
132
161
}
133
162
134
163
static void producer_cb_inner (freenect_device *dev, void *data, uint32_t timestamp, buffer_ring_t *buf, set_buffer_t set_buffer)
135
164
{
136
- pthread_mutex_lock ( & buf -> lock );
165
+ UniqueLock buffer_lock ( buf->mutex );
137
166
assert (data == buf->bufs [2 ]);
138
167
void *temp_buf = buf->bufs [1 ];
139
168
buf->bufs [1 ] = buf->bufs [2 ];
140
169
buf->bufs [2 ] = temp_buf;
141
170
set_buffer (dev, temp_buf);
142
171
buf->timestamp = timestamp;
143
- buf -> valid = 1 ;
144
- pthread_cond_signal (& buf -> cb_cond );
145
- pthread_mutex_unlock (& buf -> lock );
172
+ buf->valid = true ;
173
+ buf->cb_cond .notify_one ();
146
174
}
147
175
148
176
static void video_producer_cb (freenect_device *dev, void *data, uint32_t timestamp)
@@ -155,71 +183,69 @@ static void depth_producer_cb(freenect_device *dev, void *data, uint32_t timesta
155
183
producer_cb_inner (dev, data, timestamp, &((sync_kinect_t *)freenect_get_user (dev))->depth , freenect_set_depth_buffer);
156
184
}
157
185
158
- /* You should only use these functions to manipulate the pending_runloop_tasks_lock */
186
+ /* You should only use these functions to manipulate the pending_runloop_tasks_mutex */
159
187
static void pending_runloop_tasks_inc (void )
160
188
{
161
- pthread_mutex_lock ( & pending_runloop_tasks_lock );
189
+ LockGuard lock (pending_runloop_tasks_mutex );
162
190
assert (pending_runloop_tasks >= 0 );
163
191
++pending_runloop_tasks;
164
- pthread_mutex_unlock (& pending_runloop_tasks_lock );
165
192
}
166
193
167
194
static void pending_runloop_tasks_dec (void )
168
195
{
169
- pthread_mutex_lock ( & pending_runloop_tasks_lock );
196
+ LockGuard lock (pending_runloop_tasks_mutex );
170
197
--pending_runloop_tasks;
171
198
assert (pending_runloop_tasks >= 0 );
172
- if (!pending_runloop_tasks )
173
- pthread_cond_signal ( & pending_runloop_tasks_cond );
174
- pthread_mutex_unlock ( & pending_runloop_tasks_lock );
199
+ if (!pending_runloop_tasks) {
200
+ pending_runloop_tasks_cond. notify_one ( );
201
+ }
175
202
}
176
203
177
204
static void pending_runloop_tasks_wait_zero (void )
178
205
{
179
- pthread_mutex_lock ( & pending_runloop_tasks_lock );
180
- while (pending_runloop_tasks )
181
- pthread_cond_wait ( & pending_runloop_tasks_cond , & pending_runloop_tasks_lock );
182
- pthread_mutex_unlock ( & pending_runloop_tasks_lock );
206
+ UniqueLock lock (pending_runloop_tasks_mutex );
207
+ while (pending_runloop_tasks) {
208
+ pending_runloop_tasks_cond. wait (lock );
209
+ }
183
210
}
184
211
185
- static void * init ( void * unused )
212
+ static void runloop ( )
186
213
{
187
214
pending_runloop_tasks_wait_zero ();
188
- pthread_mutex_lock (& runloop_lock );
215
+ UniqueLock runloop_lock (runloop_mutex);
216
+
189
217
while (thread_running && freenect_process_events (ctx) >= 0 ) {
190
- pthread_mutex_unlock (& runloop_lock );
191
218
// NOTE: This lets you run tasks while process_events isn't running
219
+ runloop_lock.unlock ();
192
220
pending_runloop_tasks_wait_zero ();
193
- pthread_mutex_lock ( & runloop_lock );
221
+ runloop_lock. lock ( );
194
222
}
195
223
// Go through each device, call stop video, close device
196
- int i ;
197
- for (i = 0 ; i < MAX_KINECTS ; ++ i ) {
224
+ for (short i = 0 ; i < MAX_KINECTS; ++i) {
198
225
if (kinects[i]) {
199
226
freenect_stop_video (kinects[i]->dev );
200
227
freenect_stop_depth (kinects[i]->dev );
201
- freenect_set_user (kinects [i ]-> dev , NULL );
228
+ freenect_set_user (kinects[i]->dev , nullptr );
202
229
freenect_close_device (kinects[i]->dev );
203
230
free_buffer_ring (&kinects[i]->video );
204
231
free_buffer_ring (&kinects[i]->depth );
205
232
free (kinects[i]);
206
- kinects [i ] = NULL ;
233
+ kinects[i] = nullptr ;
207
234
}
208
235
}
209
236
freenect_shutdown (ctx);
210
- pthread_mutex_unlock (& runloop_lock );
211
- return NULL ;
212
237
}
213
238
214
239
static void init_thread (void )
215
240
{
216
- thread_running = 1 ;
241
+ assert (!thread_running);
242
+ thread_running = true ;
217
243
freenect_init (&ctx, 0 );
218
244
// We claim both the motor and the camera, because we can't know in advance
219
245
// which devices the caller will want, and the c_sync interface doesn't
220
246
// support audio, so there's no reason to claim the device needlessly.
221
247
freenect_select_subdevices (ctx, (freenect_device_flags)(FREENECT_DEVICE_MOTOR | FREENECT_DEVICE_CAMERA));
222
- pthread_create ( & thread , NULL , init , NULL );
248
+ thread = Thread (runloop );
223
249
}
224
250
225
251
static int change_video_format (sync_kinect_t *kinect, freenect_resolution res, freenect_video_format fmt)
@@ -248,124 +274,116 @@ static int change_depth_format(sync_kinect_t *kinect, freenect_resolution res, f
248
274
249
275
static sync_kinect_t *alloc_kinect (int index)
250
276
{
251
- sync_kinect_t * kinect = ( sync_kinect_t * ) malloc ( sizeof ( sync_kinect_t ) );
277
+ sync_kinect_t * kinect = new sync_kinect_t ( );
252
278
if (freenect_open_device (ctx, &kinect->dev , index)) {
253
- free ( kinect ) ;
254
- return NULL ;
279
+ delete kinect;
280
+ return nullptr ;
255
281
}
256
- int i ;
257
- for (i = 0 ; i < 3 ; ++ i ) {
258
- kinect -> video .bufs [i ] = NULL ;
259
- kinect -> depth .bufs [i ] = NULL ;
282
+ for (short i = 0 ; i < 3 ; ++i) {
283
+ kinect->video .bufs [i] = nullptr ;
284
+ kinect->depth .bufs [i] = nullptr ;
260
285
}
261
286
kinect->video .fmt = -1 ;
262
287
kinect->video .res = -1 ;
263
288
kinect->depth .fmt = -1 ;
264
289
kinect->depth .res = -1 ;
265
290
freenect_set_video_callback (kinect->dev , video_producer_cb);
266
291
freenect_set_depth_callback (kinect->dev , depth_producer_cb);
267
- pthread_mutex_init (& kinect -> video .lock , NULL );
268
- pthread_mutex_init (& kinect -> depth .lock , NULL );
269
- pthread_cond_init (& kinect -> video .cb_cond , NULL );
270
- pthread_cond_init (& kinect -> depth .cb_cond , NULL );
271
292
return kinect;
272
293
}
273
294
274
295
static int setup_kinect (int index, int res, int fmt, int is_depth)
275
296
{
276
297
pending_runloop_tasks_inc ();
277
- pthread_mutex_lock (& runloop_lock );
278
- int thread_running_prev = thread_running ;
298
+ UniqueLock runloop_lock (runloop_mutex);
299
+
300
+ bool thread_running_prev = thread_running;
279
301
if (!thread_running)
280
302
init_thread ();
281
303
if (!kinects[index]) {
282
304
kinects[index] = alloc_kinect (index);
283
305
}
284
306
if (!kinects[index]) {
285
- printf ( "Error: Invalid index [%d]\n" , index );
307
+ FN_WARN_INVALID_INDEX ( index);
286
308
// If we started the thread, we need to bring it back
287
309
if (!thread_running_prev) {
288
- thread_running = 0 ;
289
- pthread_mutex_unlock ( & runloop_lock );
310
+ thread_running = false ;
311
+ runloop_lock. unlock ( );
290
312
pending_runloop_tasks_dec ();
291
- pthread_join ( thread , NULL );
313
+ thread. join ( );
292
314
} else {
293
- pthread_mutex_unlock ( & runloop_lock );
315
+ runloop_lock. unlock ( );
294
316
pending_runloop_tasks_dec ();
295
317
}
296
318
return -1 ;
297
319
}
298
320
freenect_set_user (kinects[index]->dev , kinects[index]);
299
- buffer_ring_t * buf ;
300
- if (is_depth )
301
- buf = & kinects [index ]-> depth ;
302
- else
303
- buf = & kinects [index ]-> video ;
304
- pthread_mutex_lock (& buf -> lock );
321
+ buffer_ring_t *buf = is_depth ? &kinects[index]->depth : &kinects[index]->video ;
322
+
323
+ UniqueLock buffer_lock (buf->mutex );
305
324
if ((buf->fmt != fmt) || (buf->res != res))
306
325
{
307
326
if (is_depth)
308
327
change_depth_format (kinects[index], (freenect_resolution)res, (freenect_depth_format)fmt);
309
328
else
310
329
change_video_format (kinects[index], (freenect_resolution)res, (freenect_video_format)fmt);
311
330
}
312
- pthread_mutex_unlock (& buf -> lock );
313
- pthread_mutex_unlock (& runloop_lock );
331
+ buffer_lock.unlock ();
314
332
pending_runloop_tasks_dec ();
315
333
return 0 ;
316
334
}
317
335
318
336
static int sync_get (void **data, uint32_t *timestamp, buffer_ring_t *buf)
319
337
{
320
- pthread_mutex_lock ( & buf -> lock );
338
+ UniqueLock buffer_lock ( buf->mutex );
321
339
// If there isn't a frame ready for us
322
- while (!buf -> valid )
323
- pthread_cond_wait (& buf -> cb_cond , & buf -> lock );
340
+ while (!buf->valid ) {
341
+ buf->cb_cond .wait (buffer_lock);
342
+ }
324
343
void *temp_buf = buf->bufs [0 ];
325
344
*data = buf->bufs [0 ] = buf->bufs [1 ];
326
345
buf->bufs [1 ] = temp_buf;
327
- buf -> valid = 0 ;
346
+ buf->valid = false ;
328
347
*timestamp = buf->timestamp ;
329
- pthread_mutex_unlock (& buf -> lock );
330
348
return 0 ;
331
349
}
332
350
333
351
334
- /*
352
+ /*
335
353
Use this to make sure the runloop is locked and no one is in it. Then you can
336
354
call arbitrary functions from libfreenect.h in a safe way. If the kinect with
337
- this index has not been initialized yet, then it will try to set it up. If
355
+ this index has not been initialized yet, then it will try to set it up. If
338
356
this function is successful, then you can access kinects[index]. Don't forget
339
357
to unlock the runloop when you're done.
340
-
358
+
341
359
Returns 0 if successful, nonzero if kinect[index] is unvailable
342
- */
360
+ */
343
361
static int runloop_enter (int index)
344
362
{
345
363
if (index < 0 || index >= MAX_KINECTS) {
346
- printf ( "Error: Invalid index [%d]\n" , index );
364
+ FN_WARN_INVALID_INDEX ( index);
347
365
return -1 ;
348
366
}
349
367
if (!thread_running || !kinects[index])
350
368
if (setup_kinect (index, FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT, 1 ))
351
369
return -1 ;
352
-
370
+
353
371
pending_runloop_tasks_inc ();
354
- pthread_mutex_lock ( & runloop_lock );
372
+ runloop_mutex. lock ( );
355
373
return 0 ;
356
374
}
357
375
358
376
static void runloop_exit ()
359
377
{
360
- pthread_mutex_unlock ( & runloop_lock );
378
+ runloop_mutex. unlock ( );
361
379
pending_runloop_tasks_dec ();
362
380
}
363
381
364
382
int freenect_sync_get_video_with_res (void **video, uint32_t *timestamp, int index,
365
383
freenect_resolution res, freenect_video_format fmt)
366
384
{
367
385
if (index < 0 || index >= MAX_KINECTS) {
368
- printf ( "Error: Invalid index [%d]\n" , index );
386
+ FN_WARN_INVALID_INDEX ( index);
369
387
return -1 ;
370
388
}
371
389
if (!thread_running || !kinects[index] || kinects[index]->video .fmt != fmt || kinects[index]->video .res != res)
@@ -384,7 +402,7 @@ int freenect_sync_get_depth_with_res(void **depth, uint32_t *timestamp, int inde
384
402
freenect_resolution res, freenect_depth_format fmt)
385
403
{
386
404
if (index < 0 || index >= MAX_KINECTS) {
387
- printf ( "Error: Invalid index [%d]\n" , index );
405
+ FN_WARN_INVALID_INDEX ( index);
388
406
return -1 ;
389
407
}
390
408
if (!thread_running || !kinects[index] || kinects[index]->depth .fmt != fmt
@@ -404,7 +422,7 @@ int freenect_sync_get_tilt_state(freenect_raw_tilt_state **state, int index)
404
422
{
405
423
if (runloop_enter (index)) return -1 ;
406
424
freenect_update_tilt_state (kinects[index]->dev );
407
- * state = freenect_get_tilt_state (kinects [index ]-> dev );
425
+ *state = freenect_get_tilt_state (kinects[index]->dev );
408
426
runloop_exit ();
409
427
return 0 ;
410
428
}
@@ -433,7 +451,7 @@ int freenect_sync_camera_to_world(int cx, int cy, int wz, double* wx, double* wy
433
451
void freenect_sync_stop (void )
434
452
{
435
453
if (thread_running) {
436
- thread_running = 0 ;
437
- pthread_join ( thread , NULL );
454
+ thread_running = false ;
455
+ thread. join ( );
438
456
}
439
457
}
0 commit comments