videoclock.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. //int ivalue = -1;
  136. clock_gettime(CLOCK_REALTIME, &ts);
  137. long unsec = ts.tv_nsec + (1000 * 1000 * dwTimeout * 2);
  138. ts.tv_sec += (unsec / 1000000000);
  139. ts.tv_nsec = (unsec % 1000000000);
  140. //sem_getvalue(&clock->exit_sem, &ivalue);
  141. //clockDbg(clock, "%s:%d sem value is %d", __FUNCTION__, __LINE__, ivalue);
  142. if (0 != sem_timedwait(&clock->exit_sem, &ts) && (ETIMEDOUT == errno))
  143. {
  144. //clockDbg(clock, "%s:%d last errno = %d for %s", __FUNCTION__, __LINE__, errno, strerror(errno));
  145. clock->get_frame(clock->get_user_data, &frame);
  146. clock->put_frame(clock->put_user_data, &frame);
  147. }
  148. else {
  149. clockDbg(clock, "%s:%d exit local video send thread.", __FUNCTION__, __LINE__);
  150. break;
  151. }
  152. }
  153. //clockDbg(clock, "%s:%d exit local_video_sendfunc", __FUNCTION__, __LINE__);
  154. video_frame_free(&frame);
  155. on_error:
  156. return 0;
  157. }
  158. #endif
  159. int videoclock_create(int fps_num,
  160. int fps_den,
  161. int video_width,
  162. int video_height,
  163. int frame_format,
  164. put_frame_cb put,
  165. void *put_user_data,
  166. get_frame_cb get,
  167. void *get_user_data,
  168. videoclock_t *p_clock,
  169. volatile int*nFps,
  170. clockdbg_cb dbgfunc)
  171. {
  172. struct videoclock *clock;
  173. /* check ... */
  174. if (!p_clock)
  175. return -1;
  176. if (!put || !get)
  177. return -1;
  178. if (frame_format != VIDEO_FORMAT_I420 &&
  179. frame_format != VIDEO_FORMAT_RGB24)
  180. return -1;
  181. if (NULL == dbgfunc) {
  182. return -1;
  183. }
  184. clock = malloc(sizeof(struct videoclock));
  185. if (!clock)
  186. return -1;
  187. memset(clock, 0, sizeof(struct videoclock));
  188. #ifdef RVC_OS_WIN
  189. clock->exit_evt = CreateEvent(NULL, FALSE, FALSE, NULL);
  190. if (!clock->exit_evt)
  191. goto on_error;
  192. #else
  193. if (0 != sem_init(&clock->exit_sem, 0, 0)){
  194. goto on_error;
  195. }
  196. #endif
  197. clock->fps_num = fps_num;
  198. //clock->nVideoSendFreq = fps_num;
  199. clock->fps_den = fps_den;
  200. clock->frame_format = frame_format;
  201. clock->frame_width = video_width;
  202. clock->frame_height = video_height;
  203. clock->get_frame = get;
  204. clock->get_user_data = get_user_data;
  205. clock->put_frame = put;
  206. clock->put_user_data = put_user_data;
  207. clock->nVideoSendFreq = nFps;
  208. clock->dbglog = dbgfunc;
  209. *p_clock = clock;
  210. return 0;
  211. on_error:
  212. clockDbg(clock,"videoclock_create failed for %s.", strerror(errno));
  213. free(clock);
  214. return -1;
  215. }
  216. void videoclock_destroy(videoclock_t vc)
  217. {
  218. if (vc) {
  219. #ifdef RVC_OS_WIN
  220. CloseHandle(vc->exit_evt);
  221. #else
  222. sem_destroy(&vc->exit_sem);
  223. #endif
  224. free(vc);
  225. }
  226. }
  227. int videoclock_start(videoclock_t vc)
  228. {
  229. if (!vc)
  230. return -1;
  231. #ifdef RVC_OS_WIN
  232. ResetEvent(vc->exit_evt);
  233. vc->thread_run = (HANDLE)_beginthreadex(NULL, 0, &worker_thread_proc, vc, 0, NULL);
  234. if (!vc->thread_run)
  235. return -1;
  236. #else
  237. pthread_attr_t attr;
  238. pthread_attr_init(&attr);
  239. struct sched_param param;
  240. param.sched_priority = sched_get_priority_max(SCHED_RR);
  241. pthread_attr_setschedpolicy(&attr, SCHED_RR);
  242. pthread_attr_setschedparam(&attr, &param);
  243. pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
  244. int err = pthread_create(&vc->thread_id, NULL, local_video_sendfunc, vc);
  245. if (0 != err) {
  246. clockDbg(vc,"pthread create failed for %s.", strerror(errno));
  247. return -1;
  248. }
  249. #endif
  250. return 0;
  251. }
  252. int videoclock_stop(videoclock_t vc)
  253. {
  254. if (!vc)
  255. return -1;
  256. #ifdef RVC_OS_WIN
  257. if (vc->exit_evt) {
  258. SetEvent(vc->exit_evt);
  259. }
  260. if (vc->thread_run) {
  261. WaitForSingleObject(vc->thread_run, INFINITE);
  262. CloseHandle(vc->thread_run);
  263. vc->thread_run = NULL;
  264. }
  265. #else
  266. sem_post(&vc->exit_sem);
  267. if (vc->thread_id > 0){
  268. pthread_join(vc->thread_id, NULL);
  269. }
  270. #endif
  271. return 0;
  272. }