-
Notifications
You must be signed in to change notification settings - Fork 526
/
Copy pathlibuvc_internal.h
320 lines (284 loc) · 9.92 KB
/
libuvc_internal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/** @file libuvc_internal.h
* @brief Implementation-specific UVC constants and structures.
* @cond include_hidden
*/
#ifndef LIBUVC_INTERNAL_H
#define LIBUVC_INTERNAL_H
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <libusb.h>
#include "utlist.h"
/** Converts an unaligned four-byte little-endian integer into an int32 */
#define DW_TO_INT(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24))
/** Converts an unaligned two-byte little-endian integer into an int16 */
#define SW_TO_SHORT(p) ((p)[0] | ((p)[1] << 8))
/** Converts an int16 into an unaligned two-byte little-endian integer */
#define SHORT_TO_SW(s, p) \
(p)[0] = (s); \
(p)[1] = (s) >> 8;
/** Converts an int32 into an unaligned four-byte little-endian integer */
#define INT_TO_DW(i, p) \
(p)[0] = (i); \
(p)[1] = (i) >> 8; \
(p)[2] = (i) >> 16; \
(p)[3] = (i) >> 24;
/** Selects the nth item in a doubly linked list. n=-1 selects the last item. */
#define DL_NTH(head, out, n) \
do { \
int dl_nth_i = 0; \
LDECLTYPE(head) dl_nth_p = (head); \
if ((n) < 0) { \
while (dl_nth_p && dl_nth_i > (n)) { \
dl_nth_p = dl_nth_p->prev; \
dl_nth_i--; \
} \
} else { \
while (dl_nth_p && dl_nth_i < (n)) { \
dl_nth_p = dl_nth_p->next; \
dl_nth_i++; \
} \
} \
(out) = dl_nth_p; \
} while (0);
#ifdef UVC_DEBUGGING
#include <libgen.h>
#ifdef __ANDROID__
#include <android/log.h>
#define UVC_DEBUG(format, ...) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define UVC_ENTER() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
#define UVC_EXIT(code) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
#define UVC_EXIT_VOID() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
#else
#define UVC_DEBUG(format, ...) fprintf(stderr, "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define UVC_ENTER() fprintf(stderr, "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
#define UVC_EXIT(code) fprintf(stderr, "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
#define UVC_EXIT_VOID() fprintf(stderr, "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
#endif
#else
#define UVC_DEBUG(format, ...)
#define UVC_ENTER()
#define UVC_EXIT_VOID()
#define UVC_EXIT(code)
#endif
/* http://stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers */
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0))
/** Video interface subclass code (A.2) */
enum uvc_int_subclass_code {
UVC_SC_UNDEFINED = 0x00,
UVC_SC_VIDEOCONTROL = 0x01,
UVC_SC_VIDEOSTREAMING = 0x02,
UVC_SC_VIDEO_INTERFACE_COLLECTION = 0x03
};
/** Video interface protocol code (A.3) */
enum uvc_int_proto_code {
UVC_PC_PROTOCOL_UNDEFINED = 0x00
};
/** VideoControl interface descriptor subtype (A.5) */
enum uvc_vc_desc_subtype {
UVC_VC_DESCRIPTOR_UNDEFINED = 0x00,
UVC_VC_HEADER = 0x01,
UVC_VC_INPUT_TERMINAL = 0x02,
UVC_VC_OUTPUT_TERMINAL = 0x03,
UVC_VC_SELECTOR_UNIT = 0x04,
UVC_VC_PROCESSING_UNIT = 0x05,
UVC_VC_EXTENSION_UNIT = 0x06
};
/** UVC endpoint descriptor subtype (A.7) */
enum uvc_ep_desc_subtype {
UVC_EP_UNDEFINED = 0x00,
UVC_EP_GENERAL = 0x01,
UVC_EP_ENDPOINT = 0x02,
UVC_EP_INTERRUPT = 0x03
};
/** VideoControl interface control selector (A.9.1) */
enum uvc_vc_ctrl_selector {
UVC_VC_CONTROL_UNDEFINED = 0x00,
UVC_VC_VIDEO_POWER_MODE_CONTROL = 0x01,
UVC_VC_REQUEST_ERROR_CODE_CONTROL = 0x02
};
/** Terminal control selector (A.9.2) */
enum uvc_term_ctrl_selector {
UVC_TE_CONTROL_UNDEFINED = 0x00
};
/** Selector unit control selector (A.9.3) */
enum uvc_su_ctrl_selector {
UVC_SU_CONTROL_UNDEFINED = 0x00,
UVC_SU_INPUT_SELECT_CONTROL = 0x01
};
/** Extension unit control selector (A.9.6) */
enum uvc_xu_ctrl_selector {
UVC_XU_CONTROL_UNDEFINED = 0x00
};
/** VideoStreaming interface control selector (A.9.7) */
enum uvc_vs_ctrl_selector {
UVC_VS_CONTROL_UNDEFINED = 0x00,
UVC_VS_PROBE_CONTROL = 0x01,
UVC_VS_COMMIT_CONTROL = 0x02,
UVC_VS_STILL_PROBE_CONTROL = 0x03,
UVC_VS_STILL_COMMIT_CONTROL = 0x04,
UVC_VS_STILL_IMAGE_TRIGGER_CONTROL = 0x05,
UVC_VS_STREAM_ERROR_CODE_CONTROL = 0x06,
UVC_VS_GENERATE_KEY_FRAME_CONTROL = 0x07,
UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL = 0x08,
UVC_VS_SYNC_DELAY_CONTROL = 0x09
};
/** Status packet type (2.4.2.2) */
enum uvc_status_type {
UVC_STATUS_TYPE_CONTROL = 1,
UVC_STATUS_TYPE_STREAMING = 2
};
/** Payload header flags (2.4.3.3) */
#define UVC_STREAM_EOH (1 << 7)
#define UVC_STREAM_ERR (1 << 6)
#define UVC_STREAM_STI (1 << 5)
#define UVC_STREAM_RES (1 << 4)
#define UVC_STREAM_SCR (1 << 3)
#define UVC_STREAM_PTS (1 << 2)
#define UVC_STREAM_EOF (1 << 1)
#define UVC_STREAM_FID (1 << 0)
/** Control capabilities (4.1.2) */
#define UVC_CONTROL_CAP_GET (1 << 0)
#define UVC_CONTROL_CAP_SET (1 << 1)
#define UVC_CONTROL_CAP_DISABLED (1 << 2)
#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3)
#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4)
struct uvc_streaming_interface;
struct uvc_device_info;
/** VideoStream interface */
typedef struct uvc_streaming_interface {
struct uvc_device_info *parent;
struct uvc_streaming_interface *prev, *next;
/** Interface number */
uint8_t bInterfaceNumber;
/** Video formats that this interface provides */
struct uvc_format_desc *format_descs;
/** USB endpoint to use when communicating with this interface */
uint8_t bEndpointAddress;
uint8_t bTerminalLink;
uint8_t bStillCaptureMethod;
} uvc_streaming_interface_t;
/** VideoControl interface */
typedef struct uvc_control_interface {
struct uvc_device_info *parent;
struct uvc_input_terminal *input_term_descs;
// struct uvc_output_terminal *output_term_descs;
struct uvc_selector_unit *selector_unit_descs;
struct uvc_processing_unit *processing_unit_descs;
struct uvc_extension_unit *extension_unit_descs;
uint16_t bcdUVC;
uint32_t dwClockFrequency;
uint8_t bEndpointAddress;
/** Interface number */
uint8_t bInterfaceNumber;
} uvc_control_interface_t;
struct uvc_stream_ctrl;
struct uvc_device {
struct uvc_context *ctx;
int ref;
libusb_device *usb_dev;
};
typedef struct uvc_device_info {
/** Configuration descriptor for USB device */
struct libusb_config_descriptor *config;
/** VideoControl interface provided by device */
uvc_control_interface_t ctrl_if;
/** VideoStreaming interfaces on the device */
uvc_streaming_interface_t *stream_ifs;
} uvc_device_info_t;
/*
set a high number of transfer buffers. This uses a lot of ram, but
avoids problems with scheduling delays on slow boards causing missed
transfers. A better approach may be to make the transfer thread FIFO
scheduled (if we have root).
Default number of transfer buffers can be overwritten by defining
this macro.
*/
#ifndef LIBUVC_NUM_TRANSFER_BUFS
#if defined(__APPLE__) && defined(__MACH__)
#define LIBUVC_NUM_TRANSFER_BUFS 20
#else
#define LIBUVC_NUM_TRANSFER_BUFS 100
#endif
#endif
#define LIBUVC_XFER_META_BUF_SIZE ( 4 * 1024 )
struct uvc_stream_handle {
struct uvc_device_handle *devh;
struct uvc_stream_handle *prev, *next;
struct uvc_streaming_interface *stream_if;
/** if true, stream is running (streaming video to host) */
uint8_t running;
/** Current control block */
struct uvc_stream_ctrl cur_ctrl;
/* listeners may only access hold*, and only when holding a
* lock on cb_mutex (probably signaled with cb_cond) */
uint8_t fid;
uint32_t seq, hold_seq;
uint32_t pts, hold_pts;
uint32_t last_scr, hold_last_scr;
size_t got_bytes, hold_bytes;
uint8_t *outbuf, *holdbuf;
pthread_mutex_t cb_mutex;
pthread_cond_t cb_cond;
pthread_t cb_thread;
uint32_t last_polled_seq;
uvc_frame_callback_t *user_cb;
void *user_ptr;
struct libusb_transfer *transfers[LIBUVC_NUM_TRANSFER_BUFS];
uint8_t *transfer_bufs[LIBUVC_NUM_TRANSFER_BUFS];
struct uvc_frame frame;
enum uvc_frame_format frame_format;
struct timespec capture_time_finished;
/* raw metadata buffer if available */
uint8_t *meta_outbuf, *meta_holdbuf;
size_t meta_got_bytes, meta_hold_bytes;
};
/** Handle on an open UVC device
*
* @todo move most of this into a uvc_device struct?
*/
struct uvc_device_handle {
struct uvc_device *dev;
struct uvc_device_handle *prev, *next;
/** Underlying USB device handle */
libusb_device_handle *usb_devh;
struct uvc_device_info *info;
struct libusb_transfer *status_xfer;
uint8_t status_buf[32];
/** Function to call when we receive status updates from the camera */
uvc_status_callback_t *status_cb;
void *status_user_ptr;
/** Function to call when we receive button events from the camera */
uvc_button_callback_t *button_cb;
void *button_user_ptr;
uvc_stream_handle_t *streams;
/** Whether the camera is an iSight that sends one header per frame */
uint8_t is_isight;
uint32_t claimed;
};
/** Context within which we communicate with devices */
struct uvc_context {
/** Underlying context for USB communication */
struct libusb_context *usb_ctx;
/** True iff libuvc initialized the underlying USB context */
uint8_t own_usb_ctx;
/** List of open devices in this context */
uvc_device_handle_t *open_devices;
pthread_t handler_thread;
int kill_handler_thread;
};
uvc_error_t uvc_query_stream_ctrl(
uvc_device_handle_t *devh,
uvc_stream_ctrl_t *ctrl,
uint8_t probe,
enum uvc_req_code req);
void uvc_start_handler_thread(uvc_context_t *ctx);
uvc_error_t uvc_claim_if(uvc_device_handle_t *devh, int idx);
uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx);
#endif // !def(LIBUVC_INTERNAL_H)
/** @endcond */