videoclock.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "precompile.h"
  2. #include "videoclock.h"
  3. #ifdef RVC_OS_WIN
  4. #else
  5. #include <pthread.h>
  6. #include <semaphore.h>
  7. #endif
  8. #define TIMER_RESOLUTION 1
  9. struct videoclock
  10. {
  11. get_frame_cb get_frame;
  12. put_frame_cb put_frame;
  13. clockdbg_cb dbglog;
  14. int fps_num;
  15. int fps_den;
  16. void *put_user_data;
  17. void *get_user_data;
  18. int frame_width;
  19. int frame_height;
  20. int frame_format;
  21. #ifdef RVC_OS_WIN
  22. HANDLE exit_evt;
  23. HANDLE thread_run;
  24. #else
  25. sem_t exit_sem;
  26. pthread_t thread_id;
  27. #endif
  28. volatile int *nVideoSendFreq;
  29. };
  30. static void clockDbg(videoclock_t clock, const char* fmt, ...)
  31. {
  32. int n;
  33. va_list arg;
  34. va_start(arg, fmt);
  35. if (clock->dbglog) {
  36. (clock->dbglog)(clock, fmt, arg);
  37. }
  38. else {
  39. n = vscprintf(fmt, arg);
  40. if (n > 0) {
  41. char* buf = (char*)malloc((size_t)(n + 3));
  42. vsprintf(buf, fmt, arg);
  43. strcat(buf, "\r\n");
  44. printf(buf);
  45. }
  46. }
  47. va_end(arg);
  48. }
  49. #ifdef RVC_OS_WIN
  50. static __inline void GetTick(LARGE_INTEGER *last, LARGE_INTEGER *lt)
  51. {
  52. DWORD dwNow = GetTickCount();
  53. if (last->LowPart > dwNow) {
  54. lt->LowPart = dwNow;
  55. lt->HighPart = last->HighPart + 1;
  56. } else {
  57. lt->LowPart = dwNow;
  58. lt->HighPart = last->HighPart;
  59. }
  60. }
  61. static unsigned int __stdcall worker_thread_proc(void* param)
  62. {
  63. struct videoclock *clock = (struct videoclock*)param;
  64. video_frame frame;
  65. LARGE_INTEGER start_tick;
  66. DWORD dwTimeout = 0;
  67. LARGE_INTEGER seq = {0};
  68. LARGE_INTEGER tick = {0};
  69. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  70. if (video_frame_alloc(clock->frame_width, clock->frame_height, clock->frame_format, &frame) != 0)
  71. goto on_error;
  72. start_tick.LowPart = GetTickCount();
  73. start_tick.HighPart = 0;
  74. seq.LowPart = 1;
  75. for (;;) {
  76. DWORD dwRet = WaitForSingleObject(clock->exit_evt, dwTimeout);
  77. if (dwRet == WAIT_TIMEOUT) {
  78. clock->get_frame(clock->get_user_data, &frame);
  79. clock->put_frame(clock->put_user_data, &frame);
  80. seq.LowPart++;
  81. if (seq.LowPart == 0) {
  82. seq.HighPart ++;
  83. }
  84. GetTick(&tick, &tick);
  85. //no support VideoSendFreq(req dynamics fps)
  86. #if 1
  87. if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
  88. dwTimeout = 0;
  89. } else {
  90. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
  91. }
  92. #else
  93. if (*clock->nVideoSendFreq!= 0)
  94. {
  95. if (seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)< tick.QuadPart - start_tick.QuadPart) {
  96. dwTimeout = 0;
  97. } else {
  98. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)- (tick.QuadPart - start_tick.QuadPart));
  99. }
  100. }
  101. else if(*clock->nVideoSendFreq== -1)
  102. {
  103. //暂停发送视频
  104. dwTimeout = 200000;
  105. }
  106. else if(*clock->nVideoSendFreq== 0)
  107. {
  108. if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
  109. dwTimeout = 0;
  110. } else {
  111. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
  112. }
  113. }
  114. #endif
  115. } else {
  116. break;
  117. }
  118. }
  119. video_frame_free(&frame);
  120. on_error:
  121. _endthreadex(0);
  122. return 0;
  123. }
  124. #else
  125. void* local_video_sendfunc(void* param)
  126. {
  127. struct videoclock* clock = (struct videoclock*)param;
  128. video_frame frame;
  129. int dwTimeout = 1000/clock->fps_num;
  130. if (video_frame_alloc(clock->frame_width, clock->frame_height, clock->frame_format, &frame) != 0){
  131. goto on_error;
  132. }
  133. for (;;) {
  134. struct timespec ts;
  135. clock_gettime(CLOCK_REALTIME, &ts);
  136. long unsec = ts.tv_nsec + (1000 * 1000 * dwTimeout * 2);
  137. ts.tv_sec += (unsec / 1000000000);
  138. ts.tv_nsec = (unsec % 1000000000);
  139. if (0 != sem_timedwait(&clock->exit_sem, &ts) && (ETIMEDOUT == errno))
  140. {
  141. clock->get_frame(clock->get_user_data, &frame);
  142. clock->put_frame(clock->put_user_data, &frame);
  143. }
  144. else {
  145. break;
  146. }
  147. }
  148. video_frame_free(&frame);
  149. on_error:
  150. return 0;
  151. }
  152. #endif
  153. int videoclock_create(int fps_num,
  154. int fps_den,
  155. int video_width,
  156. int video_height,
  157. int frame_format,
  158. put_frame_cb put,
  159. void *put_user_data,
  160. get_frame_cb get,
  161. void *get_user_data,
  162. videoclock_t *p_clock,
  163. volatile int*nFps,
  164. clockdbg_cb dbgfunc)
  165. {
  166. struct videoclock *clock;
  167. /* check ... */
  168. if (!p_clock)
  169. return -1;
  170. if (!put || !get)
  171. return -1;
  172. if (frame_format != VIDEO_FORMAT_I420 &&
  173. frame_format != VIDEO_FORMAT_RGB24)
  174. return -1;
  175. if (NULL == dbgfunc) {
  176. return -1;
  177. }
  178. clock = malloc(sizeof(struct videoclock));
  179. if (!clock)
  180. return -1;
  181. memset(clock, 0, sizeof(struct videoclock));
  182. #ifdef RVC_OS_WIN
  183. clock->exit_evt = CreateEvent(NULL, FALSE, FALSE, NULL);
  184. if (!clock->exit_evt)
  185. goto on_error;
  186. #else
  187. if (0 != sem_init(&clock->exit_sem, 0, 0)){
  188. goto on_error;
  189. }
  190. #endif
  191. clock->fps_num = fps_num;
  192. //clock->nVideoSendFreq = fps_num;
  193. clock->fps_den = fps_den;
  194. clock->frame_format = frame_format;
  195. clock->frame_width = video_width;
  196. clock->frame_height = video_height;
  197. clock->get_frame = get;
  198. clock->get_user_data = get_user_data;
  199. clock->put_frame = put;
  200. clock->put_user_data = put_user_data;
  201. clock->nVideoSendFreq = nFps;
  202. clock->dbglog = dbgfunc;
  203. *p_clock = clock;
  204. return 0;
  205. on_error:
  206. clockDbg(clock,"videoclock_create failed for %s.", strerror(errno));
  207. free(clock);
  208. return -1;
  209. }
  210. void videoclock_destroy(videoclock_t vc)
  211. {
  212. if (vc) {
  213. #ifdef RVC_OS_WIN
  214. CloseHandle(vc->exit_evt);
  215. #else
  216. sem_destroy(&vc->exit_sem);
  217. #endif
  218. free(vc);
  219. }
  220. }
  221. int videoclock_start(videoclock_t vc)
  222. {
  223. if (!vc)
  224. return -1;
  225. #ifdef RVC_OS_WIN
  226. ResetEvent(vc->exit_evt);
  227. vc->thread_run = (HANDLE)_beginthreadex(NULL, 0, &worker_thread_proc, vc, 0, NULL);
  228. if (!vc->thread_run)
  229. return -1;
  230. #else
  231. pthread_attr_t attr;
  232. pthread_attr_init(&attr);
  233. struct sched_param param;
  234. param.sched_priority = sched_get_priority_max(SCHED_RR);
  235. pthread_attr_setschedpolicy(&attr, SCHED_RR);
  236. pthread_attr_setschedparam(&attr, &param);
  237. pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
  238. int err = pthread_create(&vc->thread_id, NULL, local_video_sendfunc, vc);
  239. if (0 != err) {
  240. clockDbg(vc,"pthread create failed for %s.", strerror(errno));
  241. return -1;
  242. }
  243. #endif
  244. return 0;
  245. }
  246. int videoclock_stop(videoclock_t vc)
  247. {
  248. if (!vc)
  249. return -1;
  250. #ifdef RVC_OS_WIN
  251. if (vc->exit_evt) {
  252. SetEvent(vc->exit_evt);
  253. }
  254. if (vc->thread_run) {
  255. WaitForSingleObject(vc->thread_run, INFINITE);
  256. CloseHandle(vc->thread_run);
  257. vc->thread_run = NULL;
  258. }
  259. #else
  260. sem_post(&vc->exit_sem);
  261. if (vc->thread_id > 0){
  262. pthread_join(vc->thread_id, NULL);
  263. }
  264. #endif
  265. return 0;
  266. }