add uvc code for test.
This commit is contained in:
		
							parent
							
								
									e95a5e6b1d
								
							
						
					
					
						commit
						b102e5ae19
					
				
							
								
								
									
										490
									
								
								src/mynteye/uvc/utlist_osx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										490
									
								
								src/mynteye/uvc/utlist_osx.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,490 @@ | ||||
| /*
 | ||||
| Copyright (c) 2007-2010, Troy D. Hanson   http://uthash.sourceforge.net
 | ||||
| All rights reserved. | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
|     * Redistributions of source code must retain the above copyright | ||||
|       notice, this list of conditions and the following disclaimer. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||||
| IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||||
| TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||||
| PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||||
| OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||||
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||||
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef UTLIST_H | ||||
| #define UTLIST_H | ||||
| 
 | ||||
| #define UTLIST_VERSION 1.9.1 | ||||
| 
 | ||||
| /* 
 | ||||
|  * This file contains macros to manipulate singly and doubly-linked lists. | ||||
|  * | ||||
|  * 1. LL_ macros:  singly-linked lists. | ||||
|  * 2. DL_ macros:  doubly-linked lists. | ||||
|  * 3. CDL_ macros: circular doubly-linked lists. | ||||
|  * | ||||
|  * To use singly-linked lists, your structure must have a "next" pointer. | ||||
|  * To use doubly-linked lists, your structure must "prev" and "next" pointers. | ||||
|  * Either way, the pointer to the head of the list must be initialized to NULL. | ||||
|  *  | ||||
|  * ----------------.EXAMPLE ------------------------- | ||||
|  * struct item { | ||||
|  *      int id; | ||||
|  *      struct item *prev, *next; | ||||
|  * } | ||||
|  * | ||||
|  * struct item *list = NULL: | ||||
|  * | ||||
|  * int main() { | ||||
|  *      struct item *item; | ||||
|  *      ... allocate and populate item ... | ||||
|  *      DL_APPEND(list, item); | ||||
|  * } | ||||
|  * -------------------------------------------------- | ||||
|  * | ||||
|  * For doubly-linked lists, the append and delete macros are O(1) | ||||
|  * For singly-linked lists, append and delete are O(n) but prepend is O(1) | ||||
|  * The sort macro is O(n log(n)) for all types of single/double/circular lists. | ||||
|  */ | ||||
| 
 | ||||
| /* These macros use decltype or the earlier __typeof GNU extension.
 | ||||
|    As decltype is only available in newer compilers (VS2010 or gcc 4.3+ | ||||
|    when compiling c++ code), this code uses whatever method is needed | ||||
|    or, for VS2008 where neither is available, uses casting workarounds. */ | ||||
| #ifdef _MSC_VER            /* MS compiler */ | ||||
| #if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */ | ||||
| #define LDECLTYPE(x) decltype(x) | ||||
| #else                     /* VS2008 or older (or VS2010 in C mode) */ | ||||
| #define NO_DECLTYPE | ||||
| #define LDECLTYPE(x) char* | ||||
| #endif | ||||
| #else                      /* GNU, Sun and other compilers */ | ||||
| #define LDECLTYPE(x) __typeof(x) | ||||
| #endif | ||||
| 
 | ||||
| /* for VS2008 we use some workarounds to get around the lack of decltype,
 | ||||
|  * namely, we always reassign our tmp variable to the list head if we need | ||||
|  * to dereference its prev/next pointers, and save/restore the real head.*/ | ||||
| #ifdef NO_DECLTYPE | ||||
| #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } | ||||
| #define _NEXT(elt,list) ((char*)((list)->next)) | ||||
| #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } | ||||
| #define _PREV(elt,list) ((char*)((list)->prev)) | ||||
| #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } | ||||
| #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } | ||||
| #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } | ||||
| #else  | ||||
| #define _SV(elt,list) | ||||
| #define _NEXT(elt,list) ((elt)->next) | ||||
| #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) | ||||
| #define _PREV(elt,list) ((elt)->prev) | ||||
| #define _PREVASGN(elt,list,to) ((elt)->prev)=(to) | ||||
| #define _RS(list) | ||||
| #define _CASTASGN(a,b) (a)=(b) | ||||
| #endif | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    * | ||||
|  * Unwieldy variable names used here to avoid shadowing passed-in variables.  * | ||||
|  *****************************************************************************/ | ||||
| #define LL_SORT(list, cmp)                                                                     \ | ||||
| do {                                                                                           \ | ||||
|   LDECLTYPE(list) _ls_p;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_q;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_e;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_tail;                                                                    \ | ||||
|   LDECLTYPE(list) _ls_oldhead;                                                                 \ | ||||
|   LDECLTYPE(list) _tmp;                                                                        \ | ||||
|   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \ | ||||
|   if (list) {                                                                                  \ | ||||
|     _ls_insize = 1;                                                                            \ | ||||
|     _ls_looping = 1;                                                                           \ | ||||
|     while (_ls_looping) {                                                                      \ | ||||
|       _CASTASGN(_ls_p,list);                                                                   \ | ||||
|       _CASTASGN(_ls_oldhead,list);                                                             \ | ||||
|       list = NULL;                                                                             \ | ||||
|       _ls_tail = NULL;                                                                         \ | ||||
|       _ls_nmerges = 0;                                                                         \ | ||||
|       while (_ls_p) {                                                                          \ | ||||
|         _ls_nmerges++;                                                                         \ | ||||
|         _ls_q = _ls_p;                                                                         \ | ||||
|         _ls_psize = 0;                                                                         \ | ||||
|         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \ | ||||
|           _ls_psize++;                                                                         \ | ||||
|           _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list);                               \ | ||||
|           if (!_ls_q) break;                                                                   \ | ||||
|         }                                                                                      \ | ||||
|         _ls_qsize = _ls_insize;                                                                \ | ||||
|         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \ | ||||
|           if (_ls_psize == 0) {                                                                \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|           } else if (_ls_qsize == 0 || !_ls_q) {                                               \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|           } else {                                                                             \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|           }                                                                                    \ | ||||
|           if (_ls_tail) {                                                                      \ | ||||
|             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \ | ||||
|           } else {                                                                             \ | ||||
|             _CASTASGN(list,_ls_e);                                                             \ | ||||
|           }                                                                                    \ | ||||
|           _ls_tail = _ls_e;                                                                    \ | ||||
|         }                                                                                      \ | ||||
|         _ls_p = _ls_q;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list);                            \ | ||||
|       if (_ls_nmerges <= 1) {                                                                  \ | ||||
|         _ls_looping=0;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _ls_insize *= 2;                                                                         \ | ||||
|     }                                                                                          \ | ||||
|   } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define DL_SORT(list, cmp)                                                                     \ | ||||
| do {                                                                                           \ | ||||
|   LDECLTYPE(list) _ls_p;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_q;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_e;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_tail;                                                                    \ | ||||
|   LDECLTYPE(list) _ls_oldhead;                                                                 \ | ||||
|   LDECLTYPE(list) _tmp;                                                                        \ | ||||
|   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \ | ||||
|   if (list) {                                                                                  \ | ||||
|     _ls_insize = 1;                                                                            \ | ||||
|     _ls_looping = 1;                                                                           \ | ||||
|     while (_ls_looping) {                                                                      \ | ||||
|       _CASTASGN(_ls_p,list);                                                                   \ | ||||
|       _CASTASGN(_ls_oldhead,list);                                                             \ | ||||
|       list = NULL;                                                                             \ | ||||
|       _ls_tail = NULL;                                                                         \ | ||||
|       _ls_nmerges = 0;                                                                         \ | ||||
|       while (_ls_p) {                                                                          \ | ||||
|         _ls_nmerges++;                                                                         \ | ||||
|         _ls_q = _ls_p;                                                                         \ | ||||
|         _ls_psize = 0;                                                                         \ | ||||
|         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \ | ||||
|           _ls_psize++;                                                                         \ | ||||
|           _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list);                               \ | ||||
|           if (!_ls_q) break;                                                                   \ | ||||
|         }                                                                                      \ | ||||
|         _ls_qsize = _ls_insize;                                                                \ | ||||
|         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \ | ||||
|           if (_ls_psize == 0) {                                                                \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|           } else if (_ls_qsize == 0 || !_ls_q) {                                               \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|           } else {                                                                             \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|           }                                                                                    \ | ||||
|           if (_ls_tail) {                                                                      \ | ||||
|             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \ | ||||
|           } else {                                                                             \ | ||||
|             _CASTASGN(list,_ls_e);                                                             \ | ||||
|           }                                                                                    \ | ||||
|           _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list);                          \ | ||||
|           _ls_tail = _ls_e;                                                                    \ | ||||
|         }                                                                                      \ | ||||
|         _ls_p = _ls_q;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _CASTASGN(list->prev, _ls_tail);                                                         \ | ||||
|       _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list);                            \ | ||||
|       if (_ls_nmerges <= 1) {                                                                  \ | ||||
|         _ls_looping=0;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _ls_insize *= 2;                                                                         \ | ||||
|     }                                                                                          \ | ||||
|   } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define CDL_SORT(list, cmp)                                                                    \ | ||||
| do {                                                                                           \ | ||||
|   LDECLTYPE(list) _ls_p;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_q;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_e;                                                                       \ | ||||
|   LDECLTYPE(list) _ls_tail;                                                                    \ | ||||
|   LDECLTYPE(list) _ls_oldhead;                                                                 \ | ||||
|   LDECLTYPE(list) _tmp;                                                                        \ | ||||
|   LDECLTYPE(list) _tmp2;                                                                       \ | ||||
|   int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \ | ||||
|   if (list) {                                                                                  \ | ||||
|     _ls_insize = 1;                                                                            \ | ||||
|     _ls_looping = 1;                                                                           \ | ||||
|     while (_ls_looping) {                                                                      \ | ||||
|       _CASTASGN(_ls_p,list);                                                                   \ | ||||
|       _CASTASGN(_ls_oldhead,list);                                                             \ | ||||
|       list = NULL;                                                                             \ | ||||
|       _ls_tail = NULL;                                                                         \ | ||||
|       _ls_nmerges = 0;                                                                         \ | ||||
|       while (_ls_p) {                                                                          \ | ||||
|         _ls_nmerges++;                                                                         \ | ||||
|         _ls_q = _ls_p;                                                                         \ | ||||
|         _ls_psize = 0;                                                                         \ | ||||
|         for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \ | ||||
|           _ls_psize++;                                                                         \ | ||||
|           _SV(_ls_q,list);                                                                     \ | ||||
|           if (_NEXT(_ls_q,list) == _ls_oldhead) {                                              \ | ||||
|             _ls_q = NULL;                                                                      \ | ||||
|           } else {                                                                             \ | ||||
|             _ls_q = _NEXT(_ls_q,list);                                                         \ | ||||
|           }                                                                                    \ | ||||
|           _RS(list);                                                                           \ | ||||
|           if (!_ls_q) break;                                                                   \ | ||||
|         }                                                                                      \ | ||||
|         _ls_qsize = _ls_insize;                                                                \ | ||||
|         while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \ | ||||
|           if (_ls_psize == 0) {                                                                \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|             if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \ | ||||
|           } else if (_ls_qsize == 0 || !_ls_q) {                                               \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|             if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \ | ||||
|           } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ | ||||
|             _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ | ||||
|             if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \ | ||||
|           } else {                                                                             \ | ||||
|             _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ | ||||
|             if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \ | ||||
|           }                                                                                    \ | ||||
|           if (_ls_tail) {                                                                      \ | ||||
|             _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list);                     \ | ||||
|           } else {                                                                             \ | ||||
|             _CASTASGN(list,_ls_e);                                                             \ | ||||
|           }                                                                                    \ | ||||
|           _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list);                          \ | ||||
|           _ls_tail = _ls_e;                                                                    \ | ||||
|         }                                                                                      \ | ||||
|         _ls_p = _ls_q;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _CASTASGN(list->prev,_ls_tail);                                                          \ | ||||
|       _CASTASGN(_tmp2,list);                                                                   \ | ||||
|       _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list);                           \ | ||||
|       if (_ls_nmerges <= 1) {                                                                  \ | ||||
|         _ls_looping=0;                                                                         \ | ||||
|       }                                                                                        \ | ||||
|       _ls_insize *= 2;                                                                         \ | ||||
|     }                                                                                          \ | ||||
|   } else _tmp=NULL; /* quiet gcc unused variable warning */                                    \ | ||||
| } while (0) | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  * singly linked list macros (non-circular)                                   * | ||||
|  *****************************************************************************/ | ||||
| #define LL_PREPEND(head,add)                                                                   \ | ||||
| do {                                                                                           \ | ||||
|   (add)->next = head;                                                                          \ | ||||
|   head = add;                                                                                  \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define LL_APPEND(head,add)                                                                    \ | ||||
| do {                                                                                           \ | ||||
|   LDECLTYPE(head) _tmp;                                                                        \ | ||||
|   (add)->next=NULL;                                                                            \ | ||||
|   if (head) {                                                                                  \ | ||||
|     _tmp = head;                                                                               \ | ||||
|     while (_tmp->next) { _tmp = _tmp->next; }                                                  \ | ||||
|     _tmp->next=(add);                                                                          \ | ||||
|   } else {                                                                                     \ | ||||
|     (head)=(add);                                                                              \ | ||||
|   }                                                                                            \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define LL_DELETE(head,del)                                                                    \ | ||||
| do {                                                                                           \ | ||||
|   LDECLTYPE(head) _tmp;                                                                        \ | ||||
|   if ((head) == (del)) {                                                                       \ | ||||
|     (head)=(head)->next;                                                                       \ | ||||
|   } else {                                                                                     \ | ||||
|     _tmp = head;                                                                               \ | ||||
|     while (_tmp->next && (_tmp->next != (del))) {                                              \ | ||||
|       _tmp = _tmp->next;                                                                       \ | ||||
|     }                                                                                          \ | ||||
|     if (_tmp->next) {                                                                          \ | ||||
|       _tmp->next = ((del)->next);                                                              \ | ||||
|     }                                                                                          \ | ||||
|   }                                                                                            \ | ||||
| } while (0) | ||||
| 
 | ||||
| /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ | ||||
| #define LL_APPEND_VS2008(head,add)                                                             \ | ||||
| do {                                                                                           \ | ||||
|   if (head) {                                                                                  \ | ||||
|     (add)->next = head;     /* use add->next as a temp variable */                             \ | ||||
|     while ((add)->next->next) { (add)->next = (add)->next->next; }                             \ | ||||
|     (add)->next->next=(add);                                                                   \ | ||||
|   } else {                                                                                     \ | ||||
|     (head)=(add);                                                                              \ | ||||
|   }                                                                                            \ | ||||
|   (add)->next=NULL;                                                                            \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define LL_DELETE_VS2008(head,del)                                                             \ | ||||
| do {                                                                                           \ | ||||
|   if ((head) == (del)) {                                                                       \ | ||||
|     (head)=(head)->next;                                                                       \ | ||||
|   } else {                                                                                     \ | ||||
|     char *_tmp = (char*)(head);                                                                \ | ||||
|     while (head->next && (head->next != (del))) {                                              \ | ||||
|       head = head->next;                                                                       \ | ||||
|     }                                                                                          \ | ||||
|     if (head->next) {                                                                          \ | ||||
|       head->next = ((del)->next);                                                              \ | ||||
|     }                                                                                          \ | ||||
|     {                                                                                          \ | ||||
|       char **_head_alias = (char**)&(head);                                                    \ | ||||
|       *_head_alias = _tmp;                                                                     \ | ||||
|     }                                                                                          \ | ||||
|   }                                                                                            \ | ||||
| } while (0) | ||||
| #ifdef NO_DECLTYPE | ||||
| #undef LL_APPEND | ||||
| #define LL_APPEND LL_APPEND_VS2008 | ||||
| #undef LL_DELETE | ||||
| #define LL_DELETE LL_DELETE_VS2008 | ||||
| #endif | ||||
| /* end VS2008 replacements */ | ||||
| 
 | ||||
| #define LL_FOREACH(head,el)                                                                    \ | ||||
|     for(el=head;el;el=el->next) | ||||
| 
 | ||||
| #define LL_FOREACH_SAFE(head,el,tmp)                                                           \ | ||||
|   for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||||
| 
 | ||||
| #define LL_SEARCH_SCALAR(head,out,field,val)                                                   \ | ||||
| do {                                                                                           \ | ||||
|     LL_FOREACH(head,out) {                                                                     \ | ||||
|       if ((out)->field == (val)) break;                                                        \ | ||||
|     }                                                                                          \ | ||||
| } while(0)  | ||||
| 
 | ||||
| #define LL_SEARCH(head,out,elt,cmp)                                                            \ | ||||
| do {                                                                                           \ | ||||
|     LL_FOREACH(head,out) {                                                                     \ | ||||
|       if ((cmp(out,elt))==0) break;                                                            \ | ||||
|     }                                                                                          \ | ||||
| } while(0)  | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  * doubly linked list macros (non-circular)                                   * | ||||
|  *****************************************************************************/ | ||||
| #define DL_PREPEND(head,add)                                                                   \ | ||||
| do {                                                                                           \ | ||||
|  (add)->next = head;                                                                           \ | ||||
|  if (head) {                                                                                   \ | ||||
|    (add)->prev = (head)->prev;                                                                 \ | ||||
|    (head)->prev = (add);                                                                       \ | ||||
|  } else {                                                                                      \ | ||||
|    (add)->prev = (add);                                                                        \ | ||||
|  }                                                                                             \ | ||||
|  (head) = (add);                                                                               \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define DL_APPEND(head,add)                                                                    \ | ||||
| do {                                                                                           \ | ||||
|   if (head) {                                                                                  \ | ||||
|       (add)->prev = (head)->prev;                                                              \ | ||||
|       (head)->prev->next = (add);                                                              \ | ||||
|       (head)->prev = (add);                                                                    \ | ||||
|       (add)->next = NULL;                                                                      \ | ||||
|   } else {                                                                                     \ | ||||
|       (head)=(add);                                                                            \ | ||||
|       (head)->prev = (head);                                                                   \ | ||||
|       (head)->next = NULL;                                                                     \ | ||||
|   }                                                                                            \ | ||||
| } while (0); | ||||
| 
 | ||||
| #define DL_DELETE(head,del)                                                                    \ | ||||
| do {                                                                                           \ | ||||
|   if ((del)->prev == (del)) {                                                                  \ | ||||
|       (head)=NULL;                                                                             \ | ||||
|   } else if ((del)==(head)) {                                                                  \ | ||||
|       (del)->next->prev = (del)->prev;                                                         \ | ||||
|       (head) = (del)->next;                                                                    \ | ||||
|   } else {                                                                                     \ | ||||
|       (del)->prev->next = (del)->next;                                                         \ | ||||
|       if ((del)->next) {                                                                       \ | ||||
|           (del)->next->prev = (del)->prev;                                                     \ | ||||
|       } else {                                                                                 \ | ||||
|           (head)->prev = (del)->prev;                                                          \ | ||||
|       }                                                                                        \ | ||||
|   }                                                                                            \ | ||||
| } while (0); | ||||
| 
 | ||||
| 
 | ||||
| #define DL_FOREACH(head,el)                                                                    \ | ||||
|     for(el=head;el;el=el->next) | ||||
| 
 | ||||
| /* this version is safe for deleting the elements during iteration */ | ||||
| #define DL_FOREACH_SAFE(head,el,tmp)                                                           \ | ||||
|   for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) | ||||
| 
 | ||||
| /* these are identical to their singly-linked list counterparts */ | ||||
| #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR | ||||
| #define DL_SEARCH LL_SEARCH | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
|  * circular doubly linked list macros                                         * | ||||
|  *****************************************************************************/ | ||||
| #define CDL_PREPEND(head,add)                                                                  \ | ||||
| do {                                                                                           \ | ||||
|  if (head) {                                                                                   \ | ||||
|    (add)->prev = (head)->prev;                                                                 \ | ||||
|    (add)->next = (head);                                                                       \ | ||||
|    (head)->prev = (add);                                                                       \ | ||||
|    (add)->prev->next = (add);                                                                  \ | ||||
|  } else {                                                                                      \ | ||||
|    (add)->prev = (add);                                                                        \ | ||||
|    (add)->next = (add);                                                                        \ | ||||
|  }                                                                                             \ | ||||
| (head)=(add);                                                                                  \ | ||||
| } while (0) | ||||
| 
 | ||||
| #define CDL_DELETE(head,del)                                                                   \ | ||||
| do {                                                                                           \ | ||||
|   if ( ((head)==(del)) && ((head)->next == (head))) {                                          \ | ||||
|       (head) = 0L;                                                                             \ | ||||
|   } else {                                                                                     \ | ||||
|      (del)->next->prev = (del)->prev;                                                          \ | ||||
|      (del)->prev->next = (del)->next;                                                          \ | ||||
|      if ((del) == (head)) (head)=(del)->next;                                                  \ | ||||
|   }                                                                                            \ | ||||
| } while (0); | ||||
| 
 | ||||
| #define CDL_FOREACH(head,el)                                                                   \ | ||||
|     for(el=head;el;el=(el->next==head ? 0L : el->next))  | ||||
| 
 | ||||
| #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \ | ||||
|   for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \ | ||||
|       (el) && ((tmp2)=(el)->next, 1);                                                          \ | ||||
|       ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) | ||||
| 
 | ||||
| #define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \ | ||||
| do {                                                                                           \ | ||||
|     CDL_FOREACH(head,out) {                                                                    \ | ||||
|       if ((out)->field == (val)) break;                                                        \ | ||||
|     }                                                                                          \ | ||||
| } while(0)  | ||||
| 
 | ||||
| #define CDL_SEARCH(head,out,elt,cmp)                                                           \ | ||||
| do {                                                                                           \ | ||||
|     CDL_FOREACH(head,out) {                                                                    \ | ||||
|       if ((cmp(out,elt))==0) break;                                                            \ | ||||
|     }                                                                                          \ | ||||
| } while(0)  | ||||
| 
 | ||||
| #endif /* UTLIST_H */ | ||||
| 
 | ||||
| @ -11,11 +11,16 @@ | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| #include "mynteye/uvc/uvc.h" | ||||
| 
 | ||||
| #include <libuvc/libuvc.h> | ||||
| 
 | ||||
| #include <thread> | ||||
| #include <vector> | ||||
| #include <atomic> | ||||
| #include <mutex> | ||||
| #include "mynteye/logger.h" | ||||
| #include "mynteye/uvc/uvc.h" | ||||
| #include "libuvc/libuvc.h" | ||||
| 
 | ||||
| #include "mynteye/uvc/uvc_osx_internal.h" | ||||
| 
 | ||||
| // #define ENABLE_DEBUG_SPAM
 | ||||
| 
 | ||||
| @ -27,6 +32,8 @@ static void check(const char *call, uvc_error_t status) { | ||||
|   LOG_IF(FATAL, status < 0) | ||||
|       << call << "(...) returned " << uvc_strerror(status); | ||||
| } | ||||
| 
 | ||||
| #define CALL_UVC_WITHOUT_CHECK(name, ...) name(__VA_ARGS__) | ||||
| #define CALL_UVC(name, ...) check(#name, name(__VA_ARGS__)) | ||||
| 
 | ||||
| struct context { | ||||
| @ -44,13 +51,41 @@ struct context { | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /** UVC request code (A.8) */ | ||||
| enum uvc_req_code { | ||||
|     UVC_RC_UNDEFINED = 0x00, | ||||
|     UVC_SET_CUR = 0x01, | ||||
|     UVC_GET_CUR = 0x81, | ||||
|     UVC_GET_MIN = 0x82, | ||||
|     UVC_GET_MAX = 0x83, | ||||
|     UVC_GET_RES = 0x84, | ||||
|     UVC_GET_LEN = 0x85, | ||||
|     UVC_GET_INFO = 0x86, | ||||
|     UVC_GET_DEF = 0x87, | ||||
|     UVC_REQ_TYPE_GET = 0xa1, | ||||
|     UVC_REQ_TYPE_SET = 0x21 | ||||
| }; | ||||
| 
 | ||||
| struct device; | ||||
| 
 | ||||
| struct device { | ||||
|   const std::shared_ptr<context> parent; | ||||
| 
 | ||||
|   uvc_device_t *uvcdevice = nullptr; | ||||
|   uvc_device_handle_t *handle = nullptr; | ||||
| 
 | ||||
|   /** Serial number (null if unavailable) */ | ||||
|   std::string serialNumber = ""; | ||||
|   /** Device-reported manufacturer name (or null) */ | ||||
|   std::string manufacturer = ""; | ||||
|   /** Device-reporter product name (or null) */ | ||||
|   std::string product = ""; | ||||
|   uvc_device_info_t info; | ||||
|   int width, height, format, fps; | ||||
|   int vid, pid; | ||||
|   video_channel_callback callback = nullptr; | ||||
|   static std::vector <struct device*> s_devices; | ||||
| 
 | ||||
|   std::mutex _devices_mutex; | ||||
| 
 | ||||
|   device(std::shared_ptr<context> parent, uvc_device_t *uvcdevice) | ||||
|       : parent(parent), uvcdevice(uvcdevice) { | ||||
| @ -59,9 +94,16 @@ struct device { | ||||
| 
 | ||||
|     uvc_device_descriptor_t *desc; | ||||
|     CALL_UVC(uvc_get_device_descriptor, uvcdevice, &desc); | ||||
| 
 | ||||
|     serialNumber = std::string(desc->serialNumber); | ||||
|     manufacturer = std::string(desc->manufacturer); | ||||
|     product = std::string(desc->product); | ||||
| 
 | ||||
|     vid = desc->idVendor; | ||||
|     pid = desc->idProduct; | ||||
|     uvc_free_device_descriptor(desc); | ||||
|     std::lock_guard<std::mutex> lock(_devices_mutex); | ||||
|     s_devices.push_back(this); | ||||
|   } | ||||
| 
 | ||||
|   ~device() { | ||||
| @ -70,14 +112,83 @@ struct device { | ||||
|       uvc_close(handle); | ||||
|     if (uvcdevice) | ||||
|       uvc_unref_device(uvcdevice); | ||||
|     std::lock_guard<std::mutex> lock(_devices_mutex); | ||||
|     for(unsigned long i = 0 ; i < s_devices.size() ; i++) { | ||||
|       if(this == s_devices[i]) { | ||||
|         s_devices.erase(s_devices.begin()+i); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void open() { | ||||
|     if (!handle) | ||||
|       CALL_UVC(uvc_open, uvcdevice, &handle); | ||||
|   } | ||||
| 
 | ||||
|   void set_format( | ||||
|       int width, int height, int format, int fps, | ||||
|       video_channel_callback callback) { | ||||
|     this->width = width; | ||||
|     this->height = height; | ||||
|     this->format = format; | ||||
|     this->fps = fps; | ||||
|     this->callback = callback; | ||||
|   } | ||||
| 
 | ||||
|   static void uvc_frame_callback (struct uvc_frame *frame, void *user_ptr) | ||||
|   { | ||||
|     for(unsigned long i = 0 ; i < s_devices.size() ; i++) { | ||||
|       if(user_ptr == (void*)s_devices[i]) { | ||||
|         printf("bingo\n"); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // int32_t get_data_usb( uvc_req_code action, int control, int unit) const {
 | ||||
|   //     unsigned char buffer[4];
 | ||||
| 
 | ||||
|   //     int status = libusb_control_transfer(handle->usb_devh,
 | ||||
|   //                                           UVC_REQ_TYPE_GET,
 | ||||
|   //                                           action,
 | ||||
|   //                                           control << 8,
 | ||||
|   //                                           unit << 8 | (1),// _interface
 | ||||
|   //                                           buffer,
 | ||||
|   //                                           sizeof(int32_t), 0);
 | ||||
|   //     MYNTEYE_UNUSED(status);
 | ||||
|   //     if (status < 0) throw std::runtime_error(
 | ||||
|   //                 to_string() << "libusb_control_transfer(...) returned "
 | ||||
|   //                             << libusb_error_name(status));
 | ||||
| 
 | ||||
|   //     if (status != sizeof(int32_t))
 | ||||
|   //         throw std::runtime_error("insufficient data read from USB");
 | ||||
| 
 | ||||
|   //     return DW_TO_INT(buffer);
 | ||||
|   // }
 | ||||
| 
 | ||||
|   // void set_data_usb( uvc_req_code action, int control, int unit, int value) const {
 | ||||
|   //     unsigned char buffer[4];
 | ||||
| 
 | ||||
|   //     INT_TO_DW(value, buffer);
 | ||||
| 
 | ||||
|   //     int status = libusb_control_transfer(handle->usb_devh,
 | ||||
|   //                                           UVC_REQ_TYPE_SET,
 | ||||
|   //                                           action,
 | ||||
|   //                                           control << 8,
 | ||||
|   //                                           unit << 8 | (1),// _interface
 | ||||
|   //                                           buffer,
 | ||||
|   //                                           sizeof(int32_t), 0);
 | ||||
| 
 | ||||
|   //     if (status < 0) throw std::runtime_error(
 | ||||
|   //                 to_string() << "libusb_control_transfer(...) returned "
 | ||||
|   //                             << libusb_error_name(status));
 | ||||
| 
 | ||||
|   //     if (status != sizeof(int32_t))
 | ||||
|   //         throw std::runtime_error("insufficient data writen to USB");
 | ||||
|   // }
 | ||||
| }; | ||||
| 
 | ||||
| std::vector <struct device*> device::s_devices; | ||||
| 
 | ||||
| std::shared_ptr<context> create_context() { | ||||
|   return std::make_shared<context>(); | ||||
| } | ||||
| @ -112,17 +223,48 @@ int get_product_id(const device &device) { | ||||
| } | ||||
| 
 | ||||
| std::string get_name(const device &device) { | ||||
|   // TODO(JohnZhao)
 | ||||
|   MYNTEYE_UNUSED(device) | ||||
|   return ""; | ||||
|   return device.serialNumber + "/" + device.manufacturer + "/" + device.product; | ||||
| } | ||||
| 
 | ||||
| std::string get_video_name(const device &device) { | ||||
|   // TODO(JohnZhao)
 | ||||
|   MYNTEYE_UNUSED(device) | ||||
|   return ""; | ||||
|   return device.serialNumber + "/" + device.manufacturer + "/" + device.product; | ||||
| } | ||||
| 
 | ||||
| // class uvc_device
 | ||||
| //         {
 | ||||
| //         public:
 | ||||
| //             virtual void probe_and_commit(stream_profile profile, frame_callback callback, int buffers = DEFAULT_V4L2_FRAME_BUFFERS) = 0;
 | ||||
| //             virtual void stream_on(std::function<void(const notification& n)> error_handler = [](const notification& n){}) = 0;
 | ||||
| //             virtual void start_callbacks() = 0;
 | ||||
| //             virtual void stop_callbacks() = 0;
 | ||||
| //             virtual void close(stream_profile profile) = 0;
 | ||||
| 
 | ||||
| //             virtual void set_power_state(power_state state) = 0;
 | ||||
| //             virtual power_state get_power_state() const = 0;
 | ||||
| 
 | ||||
| //             virtual void init_xu(const extension_unit& xu) = 0;
 | ||||
| //             virtual bool set_xu(const extension_unit& xu, uint8_t ctrl, const uint8_t* data, int len) = 0;
 | ||||
| //             virtual bool get_xu(const extension_unit& xu, uint8_t ctrl, uint8_t* data, int len) const = 0;
 | ||||
| //             virtual control_range get_xu_range(const extension_unit& xu, uint8_t ctrl, int len) const = 0;
 | ||||
| 
 | ||||
| //             virtual bool get_pu(rs2_option opt, int32_t& value) const = 0;
 | ||||
| //             virtual bool set_pu(rs2_option opt, int32_t value) = 0;
 | ||||
| //             virtual control_range get_pu_range(rs2_option opt) const = 0;
 | ||||
| 
 | ||||
| //             virtual std::vector<stream_profile> get_profiles() const = 0;
 | ||||
| 
 | ||||
| //             virtual void lock() const = 0;
 | ||||
| //             virtual void unlock() const = 0;
 | ||||
| 
 | ||||
| //             virtual std::string get_device_location() const = 0;
 | ||||
| //             virtual usb_spec  get_usb_specification() const = 0;
 | ||||
| 
 | ||||
| //             virtual ~uvc_device() = default;
 | ||||
| 
 | ||||
| //         protected:
 | ||||
| //             std::function<void(const notification& n)> _error_handler;
 | ||||
| //         };
 | ||||
| 
 | ||||
| bool pu_control_range( | ||||
|     const device &device, Option option, int32_t *min, int32_t *max, | ||||
|     int32_t *def) { | ||||
| @ -132,6 +274,7 @@ bool pu_control_range( | ||||
|   MYNTEYE_UNUSED(min) | ||||
|   MYNTEYE_UNUSED(max) | ||||
|   MYNTEYE_UNUSED(def) | ||||
|   // device.uvcdevice -> set_pu(option, *def);
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| @ -173,26 +316,112 @@ bool xu_control_query( | ||||
| } | ||||
| 
 | ||||
| void set_device_mode( | ||||
|     device &device, int width, int height, int fourcc, int fps,  // NOLINT
 | ||||
|     device &device, int width, int height, int format, int fps,  // NOLINT
 | ||||
|     video_channel_callback callback) { | ||||
|   // TODO(JohnZhao)
 | ||||
|   MYNTEYE_UNUSED(device) | ||||
|   MYNTEYE_UNUSED(width) | ||||
|   MYNTEYE_UNUSED(height) | ||||
|   MYNTEYE_UNUSED(fourcc) | ||||
|   MYNTEYE_UNUSED(fps) | ||||
|   MYNTEYE_UNUSED(callback) | ||||
|   device.set_format(width, height, format, fps, callback); | ||||
| } | ||||
| 
 | ||||
| void start_streaming(device &device, int num_transfer_bufs) {  // NOLINT
 | ||||
|   // TODO(JohnZhao)
 | ||||
|   MYNTEYE_UNUSED(device) | ||||
|   MYNTEYE_UNUSED(num_transfer_bufs) | ||||
|   // MYNTEYE_UNUSED(device)
 | ||||
|   // MYNTEYE_UNUSED(num_transfer_bufs)
 | ||||
| 
 | ||||
| //   typedef struct uvc_stream_ctrl {
 | ||||
| //   uint16_t bmHint;
 | ||||
| //   uint8_t bFormatIndex;
 | ||||
| //   uint8_t bFrameIndex;
 | ||||
| //   uint32_t dwFrameInterval;
 | ||||
| //   uint16_t wKeyFrameRate;
 | ||||
| //   uint16_t wPFrameRate;
 | ||||
| //   uint16_t wCompQuality;
 | ||||
| //   uint16_t wCompWindowSize;
 | ||||
| //   uint16_t wDelay;
 | ||||
| //   uint32_t dwMaxVideoFrameSize;
 | ||||
| //   uint32_t dwMaxPayloadTransferSize;
 | ||||
| //   uint32_t dwClockFrequency;
 | ||||
| //   uint8_t bmFramingInfo;
 | ||||
| //   uint8_t bPreferredVersion;
 | ||||
| //   uint8_t bMinVersion;
 | ||||
| //   uint8_t bMaxVersion;
 | ||||
| //   uint8_t bInterfaceNumber;
 | ||||
| // } uvc_stream_ctrl_t;
 | ||||
| 
 | ||||
|   // uvc_error_t uvc_get_stream_ctrl_format_size(
 | ||||
|   //   uvc_device_handle_t *devh,
 | ||||
|   //   uvc_stream_ctrl_t *ctrl,
 | ||||
|   //   enum uvc_frame_format format,
 | ||||
|   //   int width, int height,
 | ||||
|   //   int fps
 | ||||
|   //   );
 | ||||
| 
 | ||||
|   uvc_stream_ctrl_t ctrl_st = {}; | ||||
| 
 | ||||
|   /** Color coding of stream, transport-independent
 | ||||
|  * @ingroup streaming | ||||
|  */ | ||||
| // enum uvc_frame_format {
 | ||||
| //   UVC_FRAME_FORMAT_UNKNOWN = 0,
 | ||||
| //   /** Any supported format */
 | ||||
| //   UVC_FRAME_FORMAT_ANY = 0,
 | ||||
| //   UVC_FRAME_FORMAT_UNCOMPRESSED,
 | ||||
| //   UVC_FRAME_FORMAT_COMPRESSED,
 | ||||
| //   /** YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and
 | ||||
| //    * one UV (chrominance) pair for every two pixels.
 | ||||
| //    */
 | ||||
| //   UVC_FRAME_FORMAT_YUYV,
 | ||||
| //   UVC_FRAME_FORMAT_UYVY,
 | ||||
| //   /** 24-bit RGB */
 | ||||
| //   UVC_FRAME_FORMAT_RGB,
 | ||||
| //   UVC_FRAME_FORMAT_BGR,
 | ||||
| //   /** Motion-JPEG (or JPEG) encoded images */
 | ||||
| //   UVC_FRAME_FORMAT_MJPEG,
 | ||||
| //   /** Greyscale images */
 | ||||
| //   UVC_FRAME_FORMAT_GRAY8,
 | ||||
| //   UVC_FRAME_FORMAT_GRAY16,
 | ||||
| //   /* Raw colour mosaic images */
 | ||||
| //   UVC_FRAME_FORMAT_BY8,
 | ||||
| //   UVC_FRAME_FORMAT_BA81,
 | ||||
| //   UVC_FRAME_FORMAT_SGRBG8,
 | ||||
| //   UVC_FRAME_FORMAT_SGBRG8,
 | ||||
| //   UVC_FRAME_FORMAT_SRGGB8,
 | ||||
| //   UVC_FRAME_FORMAT_SBGGR8,
 | ||||
| //   /** Number of formats understood */
 | ||||
| //   UVC_FRAME_FORMAT_COUNT,
 | ||||
| // };
 | ||||
|   CALL_UVC(uvc_get_stream_ctrl_format_size, | ||||
|           device.handle, | ||||
|           &ctrl_st, | ||||
|           UVC_FRAME_FORMAT_ANY, // UVC_FRAME_FORMAT_YUYV, //(enum uvc_frame_format)device.format,
 | ||||
|           device.width, | ||||
|           device.height, | ||||
|           device.fps); | ||||
| 
 | ||||
|  /** A callback function to handle incoming assembled UVC frames
 | ||||
|  * @ingroup streaming | ||||
|  */ | ||||
| // typedef void(uvc_frame_callback_t)(struct uvc_frame *frame, void *user_ptr);
 | ||||
|   // uvc_frame_callback_t *cb = nullptr;
 | ||||
| 
 | ||||
|   CALL_UVC(uvc_start_streaming, | ||||
|           device.handle, | ||||
|           &ctrl_st, | ||||
|           device::uvc_frame_callback, | ||||
|           &device, | ||||
|           num_transfer_bufs); | ||||
|    | ||||
|   printf("begin\n"); | ||||
| 
 | ||||
| //   uvc_error_t uvc_start_streaming(
 | ||||
| //     uvc_device_handle_t *devh,
 | ||||
| //     uvc_stream_ctrl_t *ctrl,
 | ||||
| //     uvc_frame_callback_t *cb,
 | ||||
| //     void *user_ptr,
 | ||||
| //     uint8_t flags);
 | ||||
| } | ||||
| 
 | ||||
| void stop_streaming(device &device) {  // NOLINT
 | ||||
|   // TODO(JohnZhao)
 | ||||
|   MYNTEYE_UNUSED(device) | ||||
|   // MYNTEYE_UNUSED(device)
 | ||||
| 
 | ||||
|   CALL_UVC_WITHOUT_CHECK(uvc_stop_streaming, device.handle); | ||||
| } | ||||
| 
 | ||||
| }  // namespace uvc
 | ||||
|  | ||||
							
								
								
									
										326
									
								
								src/mynteye/uvc/uvc_osx_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								src/mynteye/uvc/uvc_osx_internal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,326 @@ | ||||
| /** @file libuvc_internal.h
 | ||||
|   * @brief Implementation-specific UVC constants and structures. | ||||
|   * @cond include_hidden | ||||
|   */ | ||||
| #ifndef UVC_OSX_INTERNAL_H | ||||
| #define UVC_OSX_INTERNAL_H | ||||
| 
 | ||||
| #include <assert.h> | ||||
| #include <atomic> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <stdint.h> | ||||
| #include <thread> | ||||
| #include <mutex> | ||||
| #include <condition_variable> | ||||
| #include <signal.h> | ||||
| #include "mynteye/uvc/utlist_osx.h" | ||||
| 
 | ||||
| #pragma GCC diagnostic ignored "-Wpedantic" | ||||
| #include <libusb-1.0/libusb.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 unaligned eight-byte little-endian integer into an int64 */ | ||||
| #define QW_TO_QUAD(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24) |  \ | ||||
|                        ((p)[4] << 32) |((p)[5] << 40) |((p)[6] << 48) |((p)[7] << 56)) | ||||
| 
 | ||||
| /** 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; | ||||
| 
 | ||||
| /** Converts an int64 into an unaligned eight-byte little-endian integer */ | ||||
| #define QUAD_TO_QW(i, p) \ | ||||
|   (p)[0] = (i); \ | ||||
|   (p)[1] = (i) >> 8; \ | ||||
|   (p)[2] = (i) >> 16; \ | ||||
|   (p)[3] = (i) >> 24; \ | ||||
|   (p)[4] = (i) >> 32; \ | ||||
|   (p)[5] = (i) >> 40; \ | ||||
|   (p)[6] = (i) >> 48; \ | ||||
|   (p)[7] = (i) >> 56; \ | ||||
| 
 | ||||
| /** 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> | ||||
| #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__) | ||||
| #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; | ||||
| } 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; | ||||
|     int interface; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
|     /** Store the interface for multiple UVCs on a single VID/PID device (Intel RealSense, VF200, e.g) */ | ||||
|     int camera_number; | ||||
| } 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). | ||||
|   We could/should change this to allow reduce it to, say, 5 by default | ||||
|   and then allow the user to change the number of buffers as required. | ||||
|  */ | ||||
| #define LIBUVC_NUM_TRANSFER_BUFS 1 | ||||
| 
 | ||||
| #define LIBUVC_XFER_BUF_SIZE	( 16 * 1024 * 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) */ | ||||
|     std::atomic<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; | ||||
|     uint8_t *metadata_buf; | ||||
|     size_t metadata_bytes,metadata_size; | ||||
|     size_t got_bytes, hold_bytes; | ||||
|     uint8_t *outbuf, *holdbuf; | ||||
|     std::mutex cb_mutex; | ||||
|     std::condition_variable cb_cond; | ||||
|     std::thread 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]; | ||||
|     std::condition_variable transfer_cancel[LIBUVC_NUM_TRANSFER_BUFS]; | ||||
|     struct uvc_frame frame; | ||||
|     enum uvc_frame_format frame_format; | ||||
| }; | ||||
| 
 | ||||
| /** 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; | ||||
| }; | ||||
| 
 | ||||
| /** 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; | ||||
|     std::thread 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(UVC_OSX_INTERNAL_H)
 | ||||
| /** @endcond */ | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user