dc-capture.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. DrawIcon(hdc, pos.x, pos.y, icon);
  83. DeleteObject(ii.hbmColor);
  84. DeleteObject(ii.hbmMask);
  85. }
  86. DestroyIcon(icon);
  87. }
  88. static inline HDC dc_capture_get_dc(struct dc_capture *capture)
  89. {
  90. if (!capture->valid)
  91. return NULL;
  92. if (capture->compatibility)
  93. return capture->hdc;
  94. else
  95. return gs_texture_get_dc(capture->texture);
  96. }
  97. static inline void dc_capture_release_dc(struct dc_capture *capture)
  98. {
  99. if (capture->compatibility) {
  100. gs_texture_set_image(capture->texture,
  101. capture->bits, capture->width*4, false);
  102. } else {
  103. gs_texture_release_dc(capture->texture);
  104. }
  105. }
  106. void dc_capture_capture(struct dc_capture *capture, HWND window)
  107. {
  108. HDC hdc_target;
  109. HDC hdc;
  110. if (capture->capture_cursor) {
  111. memset(&capture->ci, 0, sizeof(CURSORINFO));
  112. capture->ci.cbSize = sizeof(CURSORINFO);
  113. capture->cursor_captured = GetCursorInfo(&capture->ci);
  114. }
  115. hdc = dc_capture_get_dc(capture);
  116. if (!hdc) {
  117. blog(LOG_WARNING, "[capture_screen] Failed to get "
  118. "texture DC");
  119. return;
  120. }
  121. hdc_target = GetDC(window);
  122. BitBlt(hdc, 0, 0, capture->width, capture->height,
  123. hdc_target, capture->x, capture->y, SRCCOPY);
  124. ReleaseDC(NULL, hdc_target);
  125. if (capture->cursor_captured && !capture->cursor_hidden)
  126. draw_cursor(capture, hdc, window);
  127. dc_capture_release_dc(capture);
  128. capture->texture_written = true;
  129. }
  130. static void draw_texture(struct dc_capture *capture, gs_effect_t *effect)
  131. {
  132. gs_texture_t *texture = capture->texture;
  133. gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
  134. gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
  135. size_t passes;
  136. gs_effect_set_texture(image, texture);
  137. passes = gs_technique_begin(tech);
  138. for (size_t i = 0; i < passes; i++) {
  139. if (gs_technique_begin_pass(tech, i)) {
  140. if (capture->compatibility)
  141. gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
  142. else
  143. gs_draw_sprite(texture, 0, 0, 0);
  144. gs_technique_end_pass(tech);
  145. }
  146. }
  147. gs_technique_end(tech);
  148. }
  149. void dc_capture_render(struct dc_capture *capture, gs_effect_t *effect)
  150. {
  151. if (capture->valid && capture->texture_written)
  152. draw_texture(capture, effect);
  153. }