dc-capture.c 4.6 KB

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