videoclock.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "precompile.h"
  2. #include "videoclock.h"
  3. #define TIMER_RESOLUTION 1
  4. struct videoclock
  5. {
  6. get_frame_cb get_frame;
  7. put_frame_cb put_frame;
  8. clockdbg_cb dbglog;
  9. int fps_num;
  10. int fps_den;
  11. void *put_user_data;
  12. void *get_user_data;
  13. int frame_width;
  14. int frame_height;
  15. int frame_format;
  16. HANDLE exit_evt;
  17. HANDLE thread_run;
  18. volatile int *nVideoSendFreq;
  19. };
  20. static void clockDbg(videoclock_t clock, const char* fmt, ...)
  21. {
  22. va_list arg;
  23. va_start(arg, fmt);
  24. if (clock->dbglog) {
  25. (clock->dbglog)(clock, fmt, arg);
  26. }
  27. else {
  28. int n = _vscprintf(fmt, arg);
  29. if (n > 0) {
  30. char* buf = (char*)malloc((size_t)(n + 3));
  31. vsprintf(buf, fmt, arg);
  32. strcat(buf, "\r\n");
  33. printf(buf);
  34. free(buf);
  35. }
  36. }
  37. va_end(arg);
  38. }
  39. static __inline void GetTick(LARGE_INTEGER *last, LARGE_INTEGER *lt)
  40. {
  41. DWORD dwNow = GetTickCount();
  42. if (last->LowPart > dwNow) {
  43. lt->LowPart = dwNow;
  44. lt->HighPart = last->HighPart + 1;
  45. } else {
  46. lt->LowPart = dwNow;
  47. lt->HighPart = last->HighPart;
  48. }
  49. }
  50. static unsigned int __stdcall worker_thread_proc(void* param)
  51. {
  52. struct videoclock *clock = (struct videoclock*)param;
  53. video_frame frame;
  54. LARGE_INTEGER start_tick;
  55. DWORD dwTimeout = 0;
  56. LARGE_INTEGER seq = {0};
  57. LARGE_INTEGER tick = {0};
  58. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  59. if (video_frame_alloc(clock->frame_width, clock->frame_height, clock->frame_format, &frame) != 0)
  60. goto on_error;
  61. start_tick.LowPart = GetTickCount();
  62. start_tick.HighPart = 0;
  63. seq.LowPart = 1;
  64. for (;;) {
  65. DWORD dwRet = WaitForSingleObject(clock->exit_evt, dwTimeout);
  66. if (dwRet == WAIT_TIMEOUT) {
  67. clock->get_frame(clock->get_user_data, &frame);
  68. clock->put_frame(clock->put_user_data, &frame);
  69. seq.LowPart++;
  70. if (seq.LowPart == 0) {
  71. seq.HighPart ++;
  72. }
  73. GetTick(&tick, &tick);
  74. //no support VideoSendFreq(req dynamics fps)
  75. #if 1
  76. if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
  77. dwTimeout = 0;
  78. } else {
  79. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
  80. }
  81. #else
  82. if (*clock->nVideoSendFreq!= 0)
  83. {
  84. if (seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)< tick.QuadPart - start_tick.QuadPart) {
  85. dwTimeout = 0;
  86. } else {
  87. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)- (tick.QuadPart - start_tick.QuadPart));
  88. }
  89. }
  90. else if(*clock->nVideoSendFreq== -1)
  91. {
  92. //暂停发送视频
  93. dwTimeout = 200000;
  94. }
  95. else if(*clock->nVideoSendFreq== 0)
  96. {
  97. if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
  98. dwTimeout = 0;
  99. } else {
  100. dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
  101. }
  102. }
  103. #endif
  104. } else {
  105. break;
  106. }
  107. }
  108. video_frame_free(&frame);
  109. on_error:
  110. _endthreadex(0);
  111. return 0;
  112. }
  113. int videoclock_create(int fps_num,
  114. int fps_den,
  115. int video_width,
  116. int video_height,
  117. int frame_format,
  118. put_frame_cb put,
  119. void *put_user_data,
  120. get_frame_cb get,
  121. void *get_user_data,
  122. videoclock_t *p_clock,
  123. volatile int*nFps,
  124. clockdbg_cb dbgfunc)
  125. {
  126. struct videoclock *clock;
  127. /* check ... */
  128. if (!p_clock)
  129. return -1;
  130. if (!put || !get)
  131. return -1;
  132. if (frame_format != VIDEO_FORMAT_I420 &&
  133. frame_format != VIDEO_FORMAT_RGB24)
  134. return -1;
  135. if (NULL == dbgfunc) {
  136. return -1;
  137. }
  138. clock = malloc(sizeof(struct videoclock));
  139. if (!clock)
  140. return -1;
  141. memset(clock, 0, sizeof(struct videoclock));
  142. clock->exit_evt = CreateEvent(NULL, FALSE, FALSE, NULL);
  143. if (!clock->exit_evt)
  144. goto on_error;
  145. clock->fps_num = fps_num;
  146. clock->nVideoSendFreq = fps_num;
  147. clock->fps_den = fps_den;
  148. clock->frame_format = frame_format;
  149. clock->frame_width = video_width;
  150. clock->frame_height = video_height;
  151. clock->get_frame = get;
  152. clock->get_user_data = get_user_data;
  153. clock->put_frame = put;
  154. clock->put_user_data = put_user_data;
  155. clock->nVideoSendFreq = nFps;
  156. clock->dbglog = dbgfunc;
  157. *p_clock = clock;
  158. return 0;
  159. on_error:
  160. clockDbg(clock,"videoclock_create failed for %s.", strerror(errno));
  161. CloseHandle(clock->exit_evt);
  162. free(clock);
  163. return -1;
  164. }
  165. void videoclock_destroy(videoclock_t vc)
  166. {
  167. if (vc) {
  168. CloseHandle(vc->exit_evt);
  169. free(vc);
  170. }
  171. }
  172. int videoclock_start(videoclock_t vc)
  173. {
  174. if (!vc)
  175. return -1;
  176. ResetEvent(vc->exit_evt);
  177. vc->thread_run = (HANDLE)_beginthreadex(NULL, 0, &worker_thread_proc, vc, 0, NULL);
  178. if (!vc->thread_run)
  179. return -1;
  180. return 0;
  181. }
  182. int videoclock_stop(videoclock_t vc)
  183. {
  184. if (!vc)
  185. return -1;
  186. if (vc->exit_evt) {
  187. SetEvent(vc->exit_evt);
  188. }
  189. if (vc->thread_run) {
  190. WaitForSingleObject(vc->thread_run, INFINITE);
  191. CloseHandle(vc->thread_run);
  192. vc->thread_run = NULL;
  193. }
  194. return 0;
  195. }