123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- #include "precompile.h"
- #include "videoclock.h"
- #ifdef RVC_OS_WIN
- #else
- #include <pthread.h>
- #include <semaphore.h>
- #endif
- #define TIMER_RESOLUTION 1
- struct videoclock
- {
- get_frame_cb get_frame;
- put_frame_cb put_frame;
- clockdbg_cb dbglog;
- int fps_num;
- int fps_den;
- void *put_user_data;
- void *get_user_data;
- int frame_width;
- int frame_height;
- int frame_format;
- #ifdef RVC_OS_WIN
- HANDLE exit_evt;
- HANDLE thread_run;
- #else
- sem_t exit_sem;
- pthread_t thread_id;
- #endif
- volatile int *nVideoSendFreq;
- };
- static void clockDbg(videoclock_t clock, const char* fmt, ...)
- {
- int n;
- va_list arg;
- va_start(arg, fmt);
- if (clock->dbglog) {
- (clock->dbglog)(clock, fmt, arg);
- }
- else {
- n = vscprintf(fmt, arg);
- if (n > 0) {
- char* buf = (char*)malloc((size_t)(n + 3));
- vsprintf(buf, fmt, arg);
- strcat(buf, "\r\n");
- printf(buf);
- }
- }
- va_end(arg);
- }
- #ifdef RVC_OS_WIN
- static __inline void GetTick(LARGE_INTEGER *last, LARGE_INTEGER *lt)
- {
- DWORD dwNow = GetTickCount();
- if (last->LowPart > dwNow) {
- lt->LowPart = dwNow;
- lt->HighPart = last->HighPart + 1;
- } else {
- lt->LowPart = dwNow;
- lt->HighPart = last->HighPart;
- }
- }
- static unsigned int __stdcall worker_thread_proc(void* param)
- {
- struct videoclock *clock = (struct videoclock*)param;
- video_frame frame;
- LARGE_INTEGER start_tick;
- DWORD dwTimeout = 0;
- LARGE_INTEGER seq = {0};
- LARGE_INTEGER tick = {0};
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
-
- if (video_frame_alloc(clock->frame_width, clock->frame_height, clock->frame_format, &frame) != 0)
- goto on_error;
- start_tick.LowPart = GetTickCount();
- start_tick.HighPart = 0;
- seq.LowPart = 1;
- for (;;) {
- DWORD dwRet = WaitForSingleObject(clock->exit_evt, dwTimeout);
- if (dwRet == WAIT_TIMEOUT) {
- clock->get_frame(clock->get_user_data, &frame);
- clock->put_frame(clock->put_user_data, &frame);
- seq.LowPart++;
- if (seq.LowPart == 0) {
- seq.HighPart ++;
- }
- GetTick(&tick, &tick);
- //no support VideoSendFreq(req dynamics fps)
- #if 1
- if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
- dwTimeout = 0;
- } else {
- dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
- }
- #else
- if (*clock->nVideoSendFreq!= 0)
- {
- if (seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)< tick.QuadPart - start_tick.QuadPart) {
- dwTimeout = 0;
- } else {
- dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / (*clock->nVideoSendFreq)- (tick.QuadPart - start_tick.QuadPart));
- }
- }
- else if(*clock->nVideoSendFreq== -1)
- {
- //暂停发送视频
- dwTimeout = 200000;
- }
- else if(*clock->nVideoSendFreq== 0)
- {
- if (seq.QuadPart * clock->fps_den * 1000 / clock->fps_num < tick.QuadPart - start_tick.QuadPart) {
- dwTimeout = 0;
- } else {
- dwTimeout = (DWORD)(seq.QuadPart * clock->fps_den * 1000 / clock->fps_num - (tick.QuadPart - start_tick.QuadPart));
- }
- }
- #endif
- } else {
- break;
- }
- }
- video_frame_free(&frame);
- on_error:
- _endthreadex(0);
- return 0;
- }
- #else
- void* local_video_sendfunc(void* param)
- {
- struct videoclock* clock = (struct videoclock*)param;
- video_frame frame;
- int dwTimeout = 1000/clock->fps_num;
- if (video_frame_alloc(clock->frame_width, clock->frame_height, clock->frame_format, &frame) != 0){
- goto on_error;
- }
- for (;;) {
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- long unsec = ts.tv_nsec + (1000 * 1000 * dwTimeout * 2);
- ts.tv_sec += (unsec / 1000000000);
- ts.tv_nsec = (unsec % 1000000000);
- if (0 != sem_timedwait(&clock->exit_sem, &ts) && (ETIMEDOUT == errno))
- {
- clock->get_frame(clock->get_user_data, &frame);
- clock->put_frame(clock->put_user_data, &frame);
- }
- else {
- break;
- }
- }
- video_frame_free(&frame);
- on_error:
- return 0;
- }
- #endif
- int videoclock_create(int fps_num,
- int fps_den,
- int video_width,
- int video_height,
- int frame_format,
- put_frame_cb put,
- void *put_user_data,
- get_frame_cb get,
- void *get_user_data,
- videoclock_t *p_clock,
- volatile int*nFps,
- clockdbg_cb dbgfunc)
- {
- struct videoclock *clock;
- /* check ... */
- if (!p_clock)
- return -1;
- if (!put || !get)
- return -1;
- if (frame_format != VIDEO_FORMAT_I420 &&
- frame_format != VIDEO_FORMAT_RGB24)
- return -1;
- if (NULL == dbgfunc) {
- return -1;
- }
- clock = malloc(sizeof(struct videoclock));
- if (!clock)
- return -1;
- memset(clock, 0, sizeof(struct videoclock));
- #ifdef RVC_OS_WIN
- clock->exit_evt = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!clock->exit_evt)
- goto on_error;
- #else
- if (0 != sem_init(&clock->exit_sem, 0, 0)){
- goto on_error;
- }
- #endif
- clock->fps_num = fps_num;
- //clock->nVideoSendFreq = fps_num;
- clock->fps_den = fps_den;
- clock->frame_format = frame_format;
- clock->frame_width = video_width;
- clock->frame_height = video_height;
- clock->get_frame = get;
- clock->get_user_data = get_user_data;
- clock->put_frame = put;
- clock->put_user_data = put_user_data;
- clock->nVideoSendFreq = nFps;
- clock->dbglog = dbgfunc;
- *p_clock = clock;
-
- return 0;
- on_error:
- clockDbg(clock,"videoclock_create failed for %s.", strerror(errno));
- free(clock);
- return -1;
- }
- void videoclock_destroy(videoclock_t vc)
- {
- if (vc) {
- #ifdef RVC_OS_WIN
- CloseHandle(vc->exit_evt);
- #else
- sem_destroy(&vc->exit_sem);
- #endif
- free(vc);
- }
- }
- int videoclock_start(videoclock_t vc)
- {
- if (!vc)
- return -1;
- #ifdef RVC_OS_WIN
- ResetEvent(vc->exit_evt);
- vc->thread_run = (HANDLE)_beginthreadex(NULL, 0, &worker_thread_proc, vc, 0, NULL);
- if (!vc->thread_run)
- return -1;
- #else
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- struct sched_param param;
- param.sched_priority = sched_get_priority_max(SCHED_RR);
- pthread_attr_setschedpolicy(&attr, SCHED_RR);
- pthread_attr_setschedparam(&attr, ¶m);
- pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
- int err = pthread_create(&vc->thread_id, NULL, local_video_sendfunc, vc);
- if (0 != err) {
- clockDbg(vc,"pthread create failed for %s.", strerror(errno));
- return -1;
- }
- #endif
- return 0;
- }
- int videoclock_stop(videoclock_t vc)
- {
- if (!vc)
- return -1;
- #ifdef RVC_OS_WIN
- if (vc->exit_evt) {
- SetEvent(vc->exit_evt);
- }
- if (vc->thread_run) {
- WaitForSingleObject(vc->thread_run, INFINITE);
- CloseHandle(vc->thread_run);
- vc->thread_run = NULL;
- }
- #else
- sem_post(&vc->exit_sem);
- if (vc->thread_id > 0){
- pthread_join(vc->thread_id, NULL);
- }
- #endif
- return 0;
- }
|