duplicator-monitor-capture.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #include <windows.h>
  2. #include <obs-module.h>
  3. #include <util/dstr.h>
  4. #include "cursor-capture.h"
  5. #define do_log(level, format, ...) \
  6. blog(level, "[duplicator-monitor-capture: '%s'] " format, \
  7. obs_source_get_name(capture->source), ##__VA_ARGS__)
  8. #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
  9. #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
  10. #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
  11. #define TEXT_MONITOR_CAPTURE obs_module_text("MonitorCapture")
  12. #define TEXT_CAPTURE_CURSOR obs_module_text("CaptureCursor")
  13. #define TEXT_COMPATIBILITY obs_module_text("Compatibility")
  14. #define TEXT_MONITOR obs_module_text("Monitor")
  15. #define TEXT_PRIMARY_MONITOR obs_module_text("PrimaryMonitor")
  16. #define RESET_INTERVAL_SEC 3.0f
  17. struct duplicator_capture {
  18. obs_source_t *source;
  19. int monitor;
  20. bool capture_cursor;
  21. long x;
  22. long y;
  23. int rot;
  24. uint32_t width;
  25. uint32_t height;
  26. gs_duplicator_t *duplicator;
  27. float reset_timeout;
  28. struct cursor_data cursor_data;
  29. };
  30. /* ------------------------------------------------------------------------- */
  31. static inline void update_settings(struct duplicator_capture *capture,
  32. obs_data_t *settings)
  33. {
  34. capture->monitor = (int)obs_data_get_int(settings, "monitor");
  35. capture->capture_cursor = obs_data_get_bool(settings, "capture_cursor");
  36. obs_enter_graphics();
  37. gs_duplicator_destroy(capture->duplicator);
  38. capture->duplicator = gs_duplicator_create(capture->monitor);
  39. capture->width = 0;
  40. capture->height = 0;
  41. capture->x = 0;
  42. capture->y = 0;
  43. capture->rot = 0;
  44. capture->reset_timeout = 0.0f;
  45. obs_leave_graphics();
  46. }
  47. /* ------------------------------------------------------------------------- */
  48. static const char *duplicator_capture_getname(void *unused)
  49. {
  50. UNUSED_PARAMETER(unused);
  51. return TEXT_MONITOR_CAPTURE;
  52. }
  53. static void duplicator_capture_destroy(void *data)
  54. {
  55. struct duplicator_capture *capture = data;
  56. obs_enter_graphics();
  57. gs_duplicator_destroy(capture->duplicator);
  58. cursor_data_free(&capture->cursor_data);
  59. obs_leave_graphics();
  60. bfree(capture);
  61. }
  62. static void duplicator_capture_defaults(obs_data_t *settings)
  63. {
  64. obs_data_set_default_int(settings, "monitor", 0);
  65. obs_data_set_default_bool(settings, "capture_cursor", true);
  66. }
  67. static void duplicator_capture_update(void *data, obs_data_t *settings)
  68. {
  69. struct duplicator_capture *mc = data;
  70. update_settings(mc, settings);
  71. }
  72. static void *duplicator_capture_create(obs_data_t *settings,
  73. obs_source_t *source)
  74. {
  75. struct duplicator_capture *capture;
  76. capture = bzalloc(sizeof(struct duplicator_capture));
  77. capture->source = source;
  78. update_settings(capture, settings);
  79. return capture;
  80. }
  81. static void reset_capture_data(struct duplicator_capture *capture)
  82. {
  83. struct gs_monitor_info monitor_info = {0};
  84. gs_texture_t *texture = gs_duplicator_get_texture(capture->duplicator);
  85. gs_get_duplicator_monitor_info(capture->monitor, &monitor_info);
  86. capture->width = gs_texture_get_width(texture);
  87. capture->height = gs_texture_get_height(texture);
  88. capture->x = monitor_info.x;
  89. capture->y = monitor_info.y;
  90. capture->rot = monitor_info.rotation_degrees;
  91. }
  92. static void duplicator_capture_tick(void *data, float seconds)
  93. {
  94. struct duplicator_capture *capture = data;
  95. if (!obs_source_showing(capture->source))
  96. return;
  97. obs_enter_graphics();
  98. if (!capture->duplicator) {
  99. capture->reset_timeout += seconds;
  100. if (capture->reset_timeout >= RESET_INTERVAL_SEC) {
  101. capture->duplicator =
  102. gs_duplicator_create(capture->monitor);
  103. capture->reset_timeout = 0.0f;
  104. }
  105. }
  106. if (!!capture->duplicator) {
  107. if (capture->capture_cursor)
  108. cursor_capture(&capture->cursor_data);
  109. if (!gs_duplicator_update_frame(capture->duplicator)) {
  110. gs_duplicator_destroy(capture->duplicator);
  111. capture->duplicator = NULL;
  112. capture->width = 0;
  113. capture->height = 0;
  114. capture->x = 0;
  115. capture->y = 0;
  116. capture->rot = 0;
  117. capture->reset_timeout = 0.0f;
  118. } else if (capture->width == 0) {
  119. reset_capture_data(capture);
  120. }
  121. }
  122. obs_leave_graphics();
  123. UNUSED_PARAMETER(seconds);
  124. }
  125. static uint32_t duplicator_capture_width(void *data)
  126. {
  127. struct duplicator_capture *capture = data;
  128. return capture->rot % 180 == 0 ? capture->width : capture->height;
  129. }
  130. static uint32_t duplicator_capture_height(void *data)
  131. {
  132. struct duplicator_capture *capture = data;
  133. return capture->rot % 180 == 0 ? capture->height : capture->width;
  134. }
  135. static void draw_cursor(struct duplicator_capture *capture)
  136. {
  137. cursor_draw(&capture->cursor_data, -capture->x, -capture->y,
  138. 1.0f, 1.0f,
  139. capture->rot % 180 == 0 ? capture->width : capture->height,
  140. capture->rot % 180 == 0 ? capture->height : capture->width);
  141. }
  142. static void duplicator_capture_render(void *data, gs_effect_t *effect)
  143. {
  144. struct duplicator_capture *capture = data;
  145. gs_texture_t *texture;
  146. int rot;
  147. if (!capture->duplicator)
  148. return;
  149. texture = gs_duplicator_get_texture(capture->duplicator);
  150. if (!texture)
  151. return;
  152. effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
  153. rot = capture->rot;
  154. while (gs_effect_loop(effect, "Draw")) {
  155. if (rot != 0) {
  156. float x = 0.0f;
  157. float y = 0.0f;
  158. switch (rot) {
  159. case 90:
  160. x = (float)capture->height;
  161. break;
  162. case 180:
  163. x = (float)capture->width;
  164. y = (float)capture->height;
  165. break;
  166. case 270:
  167. y = (float)capture->width;
  168. break;
  169. }
  170. gs_matrix_push();
  171. gs_matrix_translate3f(x, y, 0.0f);
  172. gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD((float)rot));
  173. }
  174. obs_source_draw(texture, 0, 0, 0, 0, false);
  175. if (rot != 0)
  176. gs_matrix_pop();
  177. }
  178. if (capture->capture_cursor) {
  179. effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
  180. while (gs_effect_loop(effect, "Draw")) {
  181. draw_cursor(capture);
  182. }
  183. }
  184. }
  185. static bool get_monitor_props(obs_property_t *monitor_list, int monitor_idx)
  186. {
  187. struct dstr monitor_desc = {0};
  188. struct gs_monitor_info info;
  189. if (!gs_get_duplicator_monitor_info(monitor_idx, &info))
  190. return false;
  191. dstr_catf(&monitor_desc, "%s %d: %ldx%ld @ %ld,%ld",
  192. TEXT_MONITOR, monitor_idx,
  193. info.cx, info.cy, info.x, info.y);
  194. obs_property_list_add_int(monitor_list, monitor_desc.array,
  195. monitor_idx);
  196. dstr_free(&monitor_desc);
  197. return true;
  198. }
  199. static obs_properties_t *duplicator_capture_properties(void *unused)
  200. {
  201. int monitor_idx = 0;
  202. UNUSED_PARAMETER(unused);
  203. obs_properties_t *props = obs_properties_create();
  204. obs_property_t *monitors = obs_properties_add_list(props,
  205. "monitor", TEXT_MONITOR,
  206. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
  207. obs_properties_add_bool(props, "capture_cursor", TEXT_CAPTURE_CURSOR);
  208. obs_enter_graphics();
  209. while (get_monitor_props(monitors, monitor_idx++));
  210. obs_leave_graphics();
  211. return props;
  212. }
  213. struct obs_source_info duplicator_capture_info = {
  214. .id = "monitor_capture",
  215. .type = OBS_SOURCE_TYPE_INPUT,
  216. .output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW,
  217. .get_name = duplicator_capture_getname,
  218. .create = duplicator_capture_create,
  219. .destroy = duplicator_capture_destroy,
  220. .video_render = duplicator_capture_render,
  221. .video_tick = duplicator_capture_tick,
  222. .update = duplicator_capture_update,
  223. .get_width = duplicator_capture_width,
  224. .get_height = duplicator_capture_height,
  225. .get_defaults = duplicator_capture_defaults,
  226. .get_properties = duplicator_capture_properties
  227. };