dc-capture.c 5.6 KB

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