dc-capture.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "dc-capture.h"
  2. #define WIN32_MEAN_AND_LEAN
  3. #include <windows.h>
  4. static inline void init_textures(struct dc_capture *capture)
  5. {
  6. if (capture->compatibility)
  7. capture->texture = gs_texture_create(
  8. capture->width, capture->height,
  9. GS_BGRA, 1, NULL, GS_DYNAMIC);
  10. else
  11. capture->texture = gs_texture_create_gdi(
  12. capture->width, capture->height);
  13. if (!capture->texture) {
  14. blog(LOG_WARNING, "[dc_capture_init] Failed to "
  15. "create textures");
  16. return;
  17. }
  18. capture->valid = true;
  19. }
  20. void dc_capture_init(struct dc_capture *capture, int x, int y,
  21. uint32_t width, uint32_t height, bool cursor,
  22. bool compatibility)
  23. {
  24. memset(capture, 0, sizeof(struct dc_capture));
  25. capture->x = x;
  26. capture->y = y;
  27. capture->width = width;
  28. capture->height = height;
  29. capture->capture_cursor = cursor;
  30. obs_enter_graphics();
  31. if (!gs_gdi_texture_available())
  32. compatibility = true;
  33. capture->compatibility = compatibility;
  34. init_textures(capture);
  35. obs_leave_graphics();
  36. if (!capture->valid)
  37. return;
  38. if (compatibility) {
  39. BITMAPINFO bi = {0};
  40. BITMAPINFOHEADER *bih = &bi.bmiHeader;
  41. bih->biSize = sizeof(BITMAPINFOHEADER);
  42. bih->biBitCount = 32;
  43. bih->biWidth = width;
  44. bih->biHeight = height;
  45. bih->biPlanes = 1;
  46. capture->hdc = CreateCompatibleDC(NULL);
  47. capture->bmp = CreateDIBSection(capture->hdc, &bi,
  48. DIB_RGB_COLORS, (void**)&capture->bits,
  49. NULL, 0);
  50. capture->old_bmp = SelectObject(capture->hdc, capture->bmp);
  51. }
  52. }
  53. void dc_capture_free(struct dc_capture *capture)
  54. {
  55. if (capture->hdc) {
  56. SelectObject(capture->hdc, capture->old_bmp);
  57. DeleteDC(capture->hdc);
  58. DeleteObject(capture->bmp);
  59. }
  60. obs_enter_graphics();
  61. gs_texture_destroy(capture->texture);
  62. obs_leave_graphics();
  63. memset(capture, 0, sizeof(struct dc_capture));
  64. }
  65. static void draw_cursor(struct dc_capture *capture, HDC hdc, HWND window)
  66. {
  67. HICON icon;
  68. ICONINFO ii;
  69. CURSORINFO *ci = &capture->ci;
  70. POINT win_pos = {capture->x, capture->y};
  71. if (!(capture->ci.flags & CURSOR_SHOWING))
  72. return;
  73. icon = CopyIcon(capture->ci.hCursor);
  74. if (!icon)
  75. return;
  76. if (GetIconInfo(icon, &ii)) {
  77. POINT pos;
  78. if (window)
  79. ClientToScreen(window, &win_pos);
  80. pos.x = ci->ptScreenPos.x - (int)ii.xHotspot - win_pos.x;
  81. pos.y = ci->ptScreenPos.y - (int)ii.yHotspot - win_pos.y;
  82. DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL,
  83. DI_NORMAL);
  84. DeleteObject(ii.hbmColor);
  85. DeleteObject(ii.hbmMask);
  86. }
  87. DestroyIcon(icon);
  88. }
  89. static inline HDC dc_capture_get_dc(struct dc_capture *capture)
  90. {
  91. if (!capture->valid)
  92. return NULL;
  93. if (capture->compatibility)
  94. return capture->hdc;
  95. else
  96. return gs_texture_get_dc(capture->texture);
  97. }
  98. static inline void dc_capture_release_dc(struct dc_capture *capture)
  99. {
  100. if (capture->compatibility) {
  101. gs_texture_set_image(capture->texture,
  102. capture->bits, capture->width*4, false);
  103. } else {
  104. gs_texture_release_dc(capture->texture);
  105. }
  106. }
  107. void dc_capture_capture(struct dc_capture *capture, HWND window)
  108. {
  109. HDC hdc_target;
  110. HDC hdc;
  111. if (capture->capture_cursor) {
  112. memset(&capture->ci, 0, sizeof(CURSORINFO));
  113. capture->ci.cbSize = sizeof(CURSORINFO);
  114. capture->cursor_captured = GetCursorInfo(&capture->ci);
  115. }
  116. hdc = dc_capture_get_dc(capture);
  117. if (!hdc) {
  118. blog(LOG_WARNING, "[capture_screen] Failed to get "
  119. "texture DC");
  120. return;
  121. }
  122. hdc_target = GetDC(window);
  123. BitBlt(hdc, 0, 0, capture->width, capture->height,
  124. hdc_target, capture->x, capture->y, SRCCOPY);
  125. ReleaseDC(NULL, hdc_target);
  126. if (capture->cursor_captured && !capture->cursor_hidden)
  127. draw_cursor(capture, hdc, window);
  128. dc_capture_release_dc(capture);
  129. capture->texture_written = true;
  130. }
  131. static void draw_texture(struct dc_capture *capture, gs_effect_t *effect)
  132. {
  133. gs_texture_t *texture = capture->texture;
  134. gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
  135. gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
  136. size_t passes;
  137. gs_effect_set_texture(image, texture);
  138. passes = gs_technique_begin(tech);
  139. for (size_t i = 0; i < passes; i++) {
  140. if (gs_technique_begin_pass(tech, i)) {
  141. if (capture->compatibility)
  142. gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
  143. else
  144. gs_draw_sprite(texture, 0, 0, 0);
  145. gs_technique_end_pass(tech);
  146. }
  147. }
  148. gs_technique_end(tech);
  149. }
  150. void dc_capture_render(struct dc_capture *capture, gs_effect_t *effect)
  151. {
  152. if (capture->valid && capture->texture_written)
  153. draw_texture(capture, effect);
  154. }