dc-capture.c 5.3 KB

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