videorender.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #include "precompile.h"
  2. #include "videorender.h"
  3. #define av_always_inline __inline
  4. #define inline __inline
  5. #include <libswscale\swscale.h>
  6. #include <vfw.h>
  7. #include "video_common/ffmpeg_api_adapter.h"
  8. //#pragma comment(lib, "ffmpeg\\libswscale.lib")
  9. //#pragma comment(lib, "Winmm.lib")
  10. //#pragma comment(lib, "Vfw32.lib")
  11. #define DEFAULT_MAX_QUEUE_SIZE 16
  12. #define TIMER_RESOLUTION 1
  13. #define CMB_VIDEOVIEW _T("cmb_videoview")
  14. struct render_window
  15. {
  16. volatile HWND hWnd;
  17. HANDLE ui_thread;
  18. struct videorender *render;
  19. };
  20. struct videorender
  21. {
  22. volatile LONG quit;
  23. HANDLE thread_run;
  24. struct SwsContext *sws_context;
  25. CRITICAL_SECTION q_cs;
  26. HANDLE q_full_sem;
  27. HANDLE q_empty_sem;
  28. HANDLE q_exit_evt;
  29. video_frame** frame;
  30. video_timestamp* time;
  31. int q_head;
  32. int q_tail;
  33. int q_size;
  34. struct render_window *own_hwnd; /* if hWnd is null, we will create our own window */
  35. HWND hWnd;
  36. int top;
  37. int left;
  38. int width;
  39. int height;
  40. unsigned char *rgb;
  41. void (*free_frame_cb)(video_frame *frame);
  42. HDRAWDIB hdib;
  43. };
  44. static void display_frame(struct videorender *pr, video_frame *frame)
  45. {
  46. int dstFormat;
  47. int srcFormat;
  48. int dstStride[4] = {0};
  49. if (frame->format == VIDEO_FORMAT_RGB24) {
  50. srcFormat = PIX_FMT_RGB24;
  51. } else if (frame->format == VIDEO_FORMAT_I420) {
  52. srcFormat = PIX_FMT_YUV420P;
  53. } else {
  54. return;
  55. }
  56. dstFormat = PIX_FMT_RGB24;
  57. dstStride[0] = pr->width * 3;
  58. /* prepare sws_context */
  59. pr->sws_context = sws_getCachedContext(pr->sws_context, frame->width, frame->height, srcFormat,
  60. pr->width, pr->height, dstFormat, SWS_FAST_BILINEAR, NULL, NULL, NULL);
  61. if (!pr->sws_context)
  62. return;
  63. /* color space convert and image scale */
  64. {
  65. unsigned char *data[4] = {pr->rgb, 0, 0, 0};
  66. sws_scale(pr->sws_context, frame->data, frame->linesize, 0, frame->height, data, dstStride);
  67. }
  68. /* draw */
  69. {
  70. HDC hdc;
  71. BITMAPINFOHEADER bmpheader = {sizeof(BITMAPINFOHEADER)};
  72. bmpheader.biPlanes = 1;
  73. bmpheader.biBitCount = 24;//pr->bpp;
  74. bmpheader.biCompression = BI_RGB;
  75. bmpheader.biHeight = pr->height;
  76. bmpheader.biWidth = pr->width;
  77. hdc = GetDC(pr->hWnd);
  78. DrawDibDraw(pr->hdib, hdc, 0, 0, -1, -1, &bmpheader, pr->rgb, 0, 0, pr->width, pr->height, DDF_SAME_DRAW|DDF_SAME_HDC);
  79. ReleaseDC(pr->hWnd, hdc);
  80. }
  81. }
  82. static LRESULT CALLBACK UIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  83. {
  84. switch (msg) {
  85. case WM_DESTROY:
  86. PostQuitMessage(0);
  87. break;
  88. case WM_CLOSE:
  89. DestroyWindow(hWnd);
  90. break;
  91. default:
  92. return DefWindowProc(hWnd, msg, wParam, lParam);
  93. }
  94. return 0;
  95. }
  96. static unsigned __stdcall ui_proc(void *param)
  97. {
  98. struct render_window *win = (struct render_window *)param;
  99. MSG msg;
  100. WNDCLASS wc;
  101. int width, height;
  102. //CoInitialize(NULL);
  103. /* register class */
  104. wc.cbClsExtra = 0;
  105. wc.cbWndExtra = 0;
  106. wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  107. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  108. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  109. wc.hInstance = NULL;
  110. wc.style = CS_HREDRAW|CS_VREDRAW|CS_NOCLOSE;
  111. wc.lpszMenuName = NULL;
  112. wc.lpszClassName = CMB_VIDEOVIEW;
  113. wc.lpfnWndProc = &UIWndProc;
  114. RegisterClass(&wc);
  115. height = win->render->height + 2*GetSystemMetrics(SM_CYBORDER) +
  116. 2*GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CYCAPTION);
  117. width = win->render->width + 2*GetSystemMetrics(SM_CXBORDER) +
  118. 2*GetSystemMetrics(SM_CXEDGE);
  119. win->hWnd = CreateWindowEx(WS_EX_TOPMOST,
  120. CMB_VIDEOVIEW, _T("cmb video view"),
  121. WS_CAPTION|WS_POPUPWINDOW|WS_VISIBLE,
  122. CW_USEDEFAULT, CW_USEDEFAULT, width, height,
  123. NULL, NULL, NULL, NULL);
  124. //SetWindowPos(win->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
  125. while (GetMessage(&msg, 0, 0, 0)) {
  126. TranslateMessage(&msg);
  127. DispatchMessage(&msg);
  128. }
  129. //CoUninitialize();
  130. _endthreadex(0);
  131. return 0;
  132. }
  133. unsigned __stdcall run(void *param)
  134. {
  135. struct videorender *pr;
  136. video_timestamp ts_freq;
  137. HANDLE wait_evt;
  138. HANDLE hwait[3];
  139. if (video_get_timestamp_freq(&ts_freq) != 0) {
  140. _endthreadex(0);
  141. return 0;
  142. }
  143. if (!(wait_evt = CreateEvent(NULL, FALSE, FALSE, NULL))) {
  144. _endthreadex(0);
  145. return 0;
  146. }
  147. /* set time resolution */
  148. {
  149. TIMECAPS tc;
  150. timeGetDevCaps(&tc, sizeof(TIMECAPS));
  151. timeBeginPeriod(min(max(TIMER_RESOLUTION ,tc.wPeriodMin) ,tc.wPeriodMax));
  152. }
  153. /* set affinity mask */
  154. {
  155. SYSTEM_INFO si;
  156. GetSystemInfo(&si);
  157. if (si.dwNumberOfProcessors > 1)
  158. SetThreadAffinityMask(GetCurrentThread(), 0x01 << rand()%si.dwNumberOfProcessors);
  159. }
  160. pr = (struct videorender*)param;
  161. hwait[0] = pr->q_full_sem;
  162. hwait[1] = pr->q_exit_evt;
  163. hwait[2] = wait_evt;
  164. while (!pr->quit) {
  165. DWORD dwResult = WaitForMultipleObjects(2, &hwait[0], FALSE, INFINITE) - WAIT_OBJECT_0;
  166. if (dwResult == 0) {
  167. video_timestamp now;
  168. video_frame *disp_frame;
  169. video_timestamp disp_ts;
  170. EnterCriticalSection(&pr->q_cs);
  171. disp_frame = pr->frame[pr->q_head];
  172. disp_ts = pr->time[pr->q_head];
  173. pr->q_head = (pr->q_head+1)%pr->q_size;
  174. LeaveCriticalSection(&pr->q_cs);
  175. video_get_timestamp(&now);
  176. if (disp_ts.u64 > now.u64) { /* too early */
  177. UINT delay = (UINT)(1000*(disp_ts.u64 - now.u64)/ts_freq.u64);
  178. timeSetEvent(delay, TIMER_RESOLUTION, (LPTIMECALLBACK)wait_evt, 0, TIME_CALLBACK_EVENT_SET|TIME_ONESHOT);
  179. dwResult = WaitForMultipleObjects(2, &hwait[1], FALSE, INFINITE) - WAIT_OBJECT_0;
  180. if (dwResult == 1) /* wait finished */
  181. display_frame(pr, disp_frame);
  182. } else {
  183. display_frame(pr, disp_frame);
  184. }
  185. if (pr->free_frame_cb) {
  186. pr->free_frame_cb(disp_frame);
  187. }
  188. ReleaseSemaphore(pr->q_empty_sem, 1, NULL);
  189. }
  190. }
  191. /* exit, need to clear all queue frames */
  192. if (pr->free_frame_cb) {
  193. while (WaitForSingleObject(pr->q_full_sem, 0) == WAIT_OBJECT_0) {
  194. pr->free_frame_cb(pr->frame[pr->q_head]);
  195. pr->q_head = (pr->q_head + 1)%pr->q_size;
  196. }
  197. }
  198. /* end timer period */
  199. {
  200. TIMECAPS tc;
  201. timeGetDevCaps(&tc, sizeof(TIMECAPS));
  202. timeEndPeriod(min(max(TIMER_RESOLUTION ,tc.wPeriodMin) ,tc.wPeriodMax));
  203. }
  204. CloseHandle(wait_evt);
  205. _endthreadex(0);
  206. return 0;
  207. }
  208. int videorender_create(HWND hWnd,
  209. int top,
  210. int left,
  211. int width,
  212. int height,
  213. int q_max_size,
  214. void (*free_frame_cb)(video_frame *frame),
  215. videorender_t *p_render)
  216. {
  217. struct videorender *pr;
  218. if (width%2 != 0)
  219. return -1;
  220. if (height%2 != 0)
  221. return -1;
  222. if (hWnd && !IsWindow(hWnd))
  223. return -1;
  224. pr = (struct videorender *)malloc(sizeof(struct videorender));
  225. if (!pr)
  226. return -1;
  227. memset(pr, 0, sizeof(struct videorender));
  228. pr->top = top;
  229. pr->width = width;
  230. pr->height = height;
  231. pr->q_size = q_max_size;
  232. if (!hWnd) {
  233. struct render_window *win = malloc(sizeof(struct render_window));
  234. if (!win)
  235. goto on_error;
  236. win->hWnd = NULL;
  237. win->render = pr;
  238. win->ui_thread = (HANDLE)_beginthreadex(NULL, 0, &ui_proc, win, 0, 0);
  239. if (!win->ui_thread) {
  240. free(win);
  241. goto on_error;
  242. }
  243. while (win->hWnd == NULL)
  244. Sleep(1);
  245. pr->own_hwnd = win;
  246. hWnd = win->hWnd;
  247. }
  248. pr->hWnd = hWnd;
  249. pr->frame = malloc(sizeof(video_frame*)*q_max_size);
  250. if (!pr->frame)
  251. goto on_error;
  252. pr->time = malloc(sizeof(video_timestamp)*q_max_size);
  253. if (!pr->time)
  254. goto on_error;
  255. pr->q_full_sem = CreateSemaphore(NULL, 0, q_max_size, NULL);
  256. if (!pr->q_full_sem)
  257. goto on_error;
  258. pr->q_empty_sem = CreateSemaphore(NULL, q_max_size, q_max_size, NULL);
  259. if (!pr->q_empty_sem)
  260. goto on_error;
  261. pr->q_exit_evt = CreateEvent(NULL, FALSE, FALSE, NULL);
  262. if (!pr->q_exit_evt)
  263. goto on_error;
  264. pr->rgb = malloc(3 * pr->width * pr->height);
  265. if (!pr->rgb)
  266. goto on_error;
  267. /* setup drawdib */
  268. {
  269. HDC hdc;
  270. BITMAPINFOHEADER bmpheader = {sizeof(BITMAPINFOHEADER)};
  271. bmpheader.biPlanes = 1;
  272. bmpheader.biBitCount = 24;
  273. bmpheader.biCompression = BI_RGB;
  274. bmpheader.biHeight = pr->height;
  275. bmpheader.biWidth = pr->width;
  276. pr->hdib = DrawDibOpen();
  277. if (!pr->hdib)
  278. goto on_error;
  279. hdc = GetDC(hWnd);
  280. if (!DrawDibBegin(pr->hdib, hdc, pr->width, pr->height, &bmpheader,
  281. pr->width, pr->height, DDF_SAME_DRAW|DDF_SAME_HDC)) {
  282. DrawDibClose(pr->hdib);
  283. pr->hdib = NULL;
  284. ReleaseDC(hWnd, hdc);
  285. goto on_error;
  286. }
  287. ReleaseDC(hWnd, hdc);
  288. }
  289. pr->free_frame_cb = free_frame_cb;
  290. /* start working thread */
  291. pr->thread_run = (HANDLE)_beginthreadex(NULL, 0, &run, pr, 0, 0);
  292. if (!pr->thread_run)
  293. goto on_error;
  294. InitializeCriticalSection(&pr->q_cs);
  295. *p_render = pr;
  296. return 0;
  297. on_error:
  298. if (pr->frame)
  299. free(pr->frame);
  300. if (pr->time)
  301. free(pr->time);
  302. if (pr->q_full_sem)
  303. CloseHandle(pr->q_full_sem);
  304. if (pr->q_empty_sem)
  305. CloseHandle(pr->q_empty_sem);
  306. if (pr->q_exit_evt)
  307. CloseHandle(pr->q_exit_evt);
  308. if (pr->rgb)
  309. free(pr->rgb);
  310. if (pr->hdib) {
  311. DrawDibEnd(pr->hdib);
  312. DrawDibClose(pr->hdib);
  313. }
  314. if (pr->own_hwnd) {
  315. PostMessage(pr->own_hwnd->hWnd, WM_CLOSE, 0, 0);
  316. WaitForSingleObject(pr->own_hwnd->ui_thread, INFINITE);
  317. CloseHandle(pr->own_hwnd->ui_thread);
  318. free(pr->own_hwnd);
  319. }
  320. if (pr->thread_run)
  321. CloseHandle(pr->thread_run);
  322. free(pr);
  323. return -1;
  324. }
  325. void videorender_destroy(videorender_t render)
  326. {
  327. if (!render)
  328. return;
  329. /* change quit flag to true and force mem fence */
  330. InterlockedExchange(&render->quit, 1);
  331. /* signal exit event */
  332. SetEvent(render->q_exit_evt);
  333. WaitForSingleObject(render->thread_run, INFINITE);
  334. CloseHandle(render->q_exit_evt);
  335. CloseHandle(render->thread_run);
  336. CloseHandle(render->q_full_sem);
  337. CloseHandle(render->q_empty_sem);
  338. DeleteCriticalSection(&render->q_cs);
  339. free(render->frame);
  340. free(render->time);
  341. if (render->sws_context)
  342. sws_freeContext(render->sws_context);
  343. free(render->rgb);
  344. DrawDibEnd(render->hdib);
  345. DrawDibClose(render->hdib);
  346. if (render->own_hwnd) {
  347. PostMessage(render->own_hwnd->hWnd, WM_CLOSE, 0, 0);
  348. WaitForSingleObject(render->own_hwnd->ui_thread, INFINITE);
  349. CloseHandle(render->own_hwnd->ui_thread);
  350. free(render->own_hwnd);
  351. }
  352. free(render);
  353. return;
  354. }
  355. int videorender_queue_frame(videorender_t render, video_frame *frame, video_timestamp *disp_ts)
  356. {
  357. DWORD dwResult;
  358. if (!frame || !disp_ts)
  359. return 0;
  360. if (render->quit)
  361. return -1;
  362. dwResult = WaitForSingleObject(render->q_empty_sem, 0);
  363. if (dwResult == WAIT_OBJECT_0) {
  364. EnterCriticalSection(&render->q_cs);
  365. render->frame[render->q_tail] = frame;
  366. render->time[render->q_tail].u64 = disp_ts->u64;
  367. render->q_tail = (render->q_tail+1)%render->q_size;
  368. LeaveCriticalSection(&render->q_cs);
  369. ReleaseSemaphore(render->q_full_sem, 1, NULL);
  370. return 0;
  371. } else {
  372. return -1; /* no empty slot */
  373. }
  374. }