videoview.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #include "precompile.h"
  2. #include "videoview.h"
  3. #include <vfw.h>
  4. #define MAX_VIEW_ENTRY 8
  5. #define BUFFER_COUNT 4
  6. #define CMB_VIDEOVIEW _T("cmb_videoview")
  7. #define WM_VIDEO (WM_APP+0x03)
  8. struct videoview {
  9. HWND hwnd;
  10. int own;
  11. WNDPROC lpfnOrigin;/* use when hwnd != NULL, for subclass window */
  12. char *buf[BUFFER_COUNT]; /* backgournd buffer */
  13. volatile LONG buf_use[BUFFER_COUNT];
  14. int buf_size;
  15. int offset_x;
  16. int offset_y;
  17. int height;
  18. int width;
  19. HDRAWDIB hDrawDib;
  20. /* use when own == TRUE */
  21. HANDLE hevtnotify; /* set when user call videoview_create with hwnd == null */
  22. HANDLE uithread;
  23. };
  24. static struct {
  25. HWND hwnd;
  26. struct videoview *pvv;
  27. } _map[MAX_VIEW_ENTRY] = {0};
  28. static LRESULT CALLBACK SubclassWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  29. {
  30. int i;
  31. struct videoview *pvv = NULL;
  32. for (i = 0; i < MAX_VIEW_ENTRY; ++i) {
  33. if (_map[i].hwnd == hWnd) {
  34. pvv = _map[i].pvv;
  35. break;
  36. }
  37. }
  38. if (i == MAX_VIEW_ENTRY) {
  39. /* bug */
  40. return DefWindowProc(hWnd, msg, wParam, lParam);
  41. }
  42. if (msg == WM_VIDEO) {
  43. int idx = (int)wParam;
  44. if (idx >= 0 && idx < BUFFER_COUNT && pvv->hDrawDib) {
  45. HDC hdc = GetDC(hWnd);
  46. BITMAPINFOHEADER bmiHeader = {sizeof(BITMAPINFOHEADER)};
  47. bmiHeader.biBitCount = 24;
  48. bmiHeader.biWidth = pvv->width;
  49. bmiHeader.biHeight = pvv->height;
  50. bmiHeader.biPlanes = 1;
  51. bmiHeader.biCompression = BI_RGB;
  52. DrawDibDraw(pvv->hDrawDib, hdc, pvv->offset_x, pvv->offset_y, -1, -1,
  53. &bmiHeader, pvv->buf[idx], 0, 0, pvv->width, pvv->height, DDF_SAME_DRAW);
  54. InterlockedExchange(&pvv->buf_use[idx], 0);/* clear use flag */
  55. ReleaseDC(hWnd, hdc);
  56. } else if (idx == -1) { /* create drawdib */
  57. if (pvv->hDrawDib == NULL) {
  58. if ((pvv->hDrawDib = DrawDibOpen()) != NULL) {
  59. HDC hdc = GetDC(hWnd);
  60. BITMAPINFOHEADER bmiHeader = {sizeof(BITMAPINFOHEADER)};
  61. bmiHeader.biBitCount = 24;
  62. bmiHeader.biWidth = pvv->width;
  63. bmiHeader.biHeight = pvv->height;
  64. bmiHeader.biPlanes = 1;
  65. bmiHeader.biCompression = BI_RGB;
  66. if (DrawDibBegin(pvv->hDrawDib, hdc, -1, -1, &bmiHeader, pvv->width,
  67. pvv->height, 0) == FALSE) {
  68. DrawDibClose(pvv->hDrawDib);
  69. pvv->hDrawDib = NULL;
  70. } else {
  71. UINT u = DrawDibRealize(pvv->hDrawDib, hdc, 0);
  72. pvv->hDrawDib;
  73. }
  74. ReleaseDC(hWnd, hdc);
  75. }
  76. }
  77. return (LRESULT)pvv->hDrawDib;
  78. } else if (idx == -2) { /* destroy drawdib */
  79. if (pvv->hDrawDib) {
  80. DrawDibEnd(pvv->hDrawDib);
  81. DrawDibClose(pvv->hDrawDib);
  82. pvv->hDrawDib = NULL;
  83. }
  84. } else if (idx == -3) { /* destroy window */
  85. DestroyWindow(hWnd);
  86. PostQuitMessage(0);
  87. }
  88. return 0;
  89. }
  90. if (pvv->own) {
  91. if (msg == WM_CLOSE)
  92. return 0;
  93. }
  94. if (pvv->lpfnOrigin)
  95. return (*pvv->lpfnOrigin)(hWnd, msg, wParam, lParam);
  96. return DefWindowProc(hWnd, msg, wParam, lParam);
  97. }
  98. static BOOL InitDrawDib(videoview_t vv)
  99. {
  100. if (vv && vv->hwnd)
  101. return (BOOL)SendMessage(vv->hwnd, WM_VIDEO, (WPARAM)-1, 0); /* -1 for init */
  102. return -1;
  103. }
  104. static void DeinitDrawDib(videoview_t vv)
  105. {
  106. SendMessage(vv->hwnd, WM_VIDEO, (WPARAM)-2, 0); /* -2 for destroy */
  107. }
  108. static unsigned __stdcall VideoViewUIThreadProc(void *param)
  109. {
  110. MSG msg;
  111. WNDCLASS wc;
  112. struct videoview * pvv = (struct videoview*)param;
  113. int width, height;
  114. CoInitialize(NULL);
  115. /* register class */
  116. wc.cbClsExtra = 0;
  117. wc.cbWndExtra = 0;
  118. wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  119. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  120. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  121. wc.hInstance = NULL;
  122. wc.style = CS_HREDRAW|CS_VREDRAW|CS_NOCLOSE;
  123. wc.lpszMenuName = NULL;
  124. wc.lpszClassName = CMB_VIDEOVIEW;
  125. wc.lpfnWndProc = &SubclassWndProc;
  126. RegisterClass(&wc);
  127. /* create window */
  128. height = pvv->height + 2*GetSystemMetrics(SM_CYBORDER) +
  129. 2*GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CYCAPTION);
  130. width = pvv->width + 2*GetSystemMetrics(SM_CXBORDER) + 2*GetSystemMetrics(SM_CXEDGE);
  131. pvv->hwnd = CreateWindow(CMB_VIDEOVIEW, _T("cmb video view"),
  132. WS_MINIMIZE|WS_CAPTION|WS_POPUPWINDOW|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
  133. width, height, NULL, NULL, NULL, NULL);
  134. /* notify caller's thread, ui thread window is ready */
  135. SetEvent(pvv->hevtnotify);
  136. while (GetMessage(&msg, 0, 0, 0)) {
  137. TranslateMessage(&msg);
  138. DispatchMessage(&msg);
  139. }
  140. CoUninitialize();
  141. _endthreadex(0);
  142. return 0;
  143. }
  144. int videoview_create(videoview_t *pvv, HWND hWnd, int off_x, int off_y, int pic_width, int pic_height)
  145. {
  146. int i;
  147. struct videoview *p;
  148. if (!pvv)
  149. return -1;
  150. for (i = 0; i < MAX_VIEW_ENTRY; ++i)
  151. if (_map[i].hwnd == NULL)
  152. break;
  153. if (i == MAX_VIEW_ENTRY)
  154. return -1;
  155. p = (struct videoview*)malloc(sizeof(struct videoview));
  156. if (p == NULL)
  157. return -1;
  158. ZeroMemory(p, sizeof(struct videoview));
  159. p->height = pic_height;
  160. p->width = pic_width;
  161. p->buf_size = pic_width * pic_height * 3;
  162. p->offset_x = off_x;
  163. p->offset_y = off_y;
  164. p->buf[0] = malloc(BUFFER_COUNT*p->buf_size);
  165. if (p->buf[0] == NULL) {
  166. free(p);
  167. return -1;
  168. }
  169. for (i = 1; i < BUFFER_COUNT; ++i)
  170. p->buf[i] = p->buf[0] + i*p->buf_size;
  171. if (hWnd) {
  172. if (!IsWindow(hWnd)) {
  173. free(p->buf[0]);
  174. free(p);
  175. return -1;
  176. }
  177. p->own = FALSE;
  178. p->hwnd = hWnd;
  179. p->lpfnOrigin = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)SubclassWndProc);
  180. _map[i].hwnd = p->hwnd;
  181. *pvv = _map[i].pvv = p;
  182. if (!InitDrawDib(p)) {
  183. SetWindowLong(hWnd, GWL_WNDPROC, (LONG)p->lpfnOrigin);
  184. free(p->buf[0]);
  185. free(p);
  186. _map[i].hwnd = NULL;
  187. _map[i].pvv = NULL;
  188. return -1;
  189. }
  190. } else {
  191. p->own = TRUE;
  192. p->hevtnotify = CreateEvent(NULL, FALSE, FALSE, NULL);
  193. p->uithread = (HANDLE)_beginthreadex(0, 0, &VideoViewUIThreadProc, p, 0, NULL);
  194. WaitForSingleObject(p->hevtnotify, INFINITE);
  195. _map[i].hwnd = p->hwnd;
  196. *pvv = _map[i].pvv = p;
  197. if (!InitDrawDib(p)) {
  198. PostMessage(p->hwnd, WM_CLOSE, 0, 0);
  199. WaitForSingleObject(p->uithread, INFINITE);
  200. CloseHandle(p->uithread);
  201. CloseHandle(p->hevtnotify);
  202. free(p->buf[0]);
  203. free(p);
  204. _map[i].hwnd = NULL;
  205. _map[i].pvv = NULL;
  206. return -1;
  207. }
  208. }
  209. return 0;
  210. }
  211. void videoview_destroy(videoview_t vv)
  212. {
  213. if (!vv || !vv->hwnd)
  214. return;
  215. if (vv->hDrawDib)
  216. DeinitDrawDib(vv);
  217. if (vv->own) {
  218. int i;
  219. for (i = 0; i < MAX_VIEW_ENTRY; ++i)
  220. if (_map[i].pvv == vv)
  221. break;
  222. if (i == MAX_VIEW_ENTRY)
  223. return;
  224. PostMessage(vv->hwnd, WM_VIDEO, (WPARAM)-3, 0);
  225. WaitForSingleObject(vv->uithread, INFINITE);
  226. CloseHandle(vv->uithread);
  227. CloseHandle(vv->hevtnotify);
  228. _map[i].hwnd = NULL;
  229. _map[i].pvv = NULL;
  230. } else {
  231. if (vv->lpfnOrigin)
  232. SetWindowLong(vv->hwnd, GWL_WNDPROC, (LONG)vv->lpfnOrigin);
  233. }
  234. free(vv->buf[0]);
  235. free(vv);
  236. }
  237. int videoview_put(videoview_t vv, void *buf, int len, unsigned int ts_rtp/*for later usage*/)
  238. {
  239. int i;
  240. if (!vv || !vv->hwnd || !buf || len != vv->buf_size)
  241. return -1;
  242. for (i = 0; i < BUFFER_COUNT; ++i) {
  243. if (vv->buf_use[i] == 0) { /* first try */
  244. if (InterlockedCompareExchange(&vv->buf_use[i], 1, 0) == 0) { /* second try, ok */
  245. memcpy(vv->buf[i], buf, len);
  246. PostMessage(vv->hwnd, WM_VIDEO, (WPARAM)i, (LPARAM)ts_rtp);
  247. return 0;
  248. }
  249. }
  250. }
  251. return -1; /* not enough slot */
  252. }