123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- #include "dc-capture.h"
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- static inline void init_textures(struct dc_capture *capture)
- {
- if (capture->compatibility) {
- capture->texture = gs_texture_create(capture->width, capture->height, GS_BGRA, 1, NULL, GS_DYNAMIC);
- } else {
- capture->texture = gs_texture_create_gdi(capture->width, capture->height);
- if (capture->texture) {
- capture->extra_texture =
- gs_texture_create(capture->width, capture->height, GS_BGRA, 1, NULL, 0);
- if (!capture->extra_texture) {
- blog(LOG_WARNING, "[dc_capture_init] Failed to "
- "create textures");
- gs_texture_destroy(capture->texture);
- capture->texture = NULL;
- }
- }
- }
- if (!capture->texture) {
- blog(LOG_WARNING, "[dc_capture_init] Failed to "
- "create textures");
- return;
- }
- capture->valid = true;
- }
- void dc_capture_init(struct dc_capture *capture, int x, int y, uint32_t width, uint32_t height, bool cursor,
- bool compatibility)
- {
- memset(capture, 0, sizeof(struct dc_capture));
- capture->x = x;
- capture->y = y;
- capture->width = width;
- capture->height = height;
- capture->capture_cursor = cursor;
- obs_enter_graphics();
- if (!gs_gdi_texture_available())
- compatibility = true;
- capture->compatibility = compatibility;
- init_textures(capture);
- obs_leave_graphics();
- if (!capture->valid)
- return;
- if (compatibility) {
- BITMAPINFO bi = {0};
- BITMAPINFOHEADER *bih = &bi.bmiHeader;
- bih->biSize = sizeof(BITMAPINFOHEADER);
- bih->biBitCount = 32;
- bih->biWidth = width;
- bih->biHeight = height;
- bih->biPlanes = 1;
- const HDC hdc = CreateCompatibleDC(NULL);
- if (hdc) {
- const HBITMAP bmp =
- CreateDIBSection(capture->hdc, &bi, DIB_RGB_COLORS, (void **)&capture->bits, NULL, 0);
- if (bmp) {
- capture->hdc = hdc;
- capture->bmp = bmp;
- capture->old_bmp = SelectObject(capture->hdc, capture->bmp);
- } else {
- DeleteDC(hdc);
- }
- }
- }
- }
- void dc_capture_free(struct dc_capture *capture)
- {
- if (capture->hdc) {
- SelectObject(capture->hdc, capture->old_bmp);
- DeleteDC(capture->hdc);
- DeleteObject(capture->bmp);
- }
- obs_enter_graphics();
- gs_texture_destroy(capture->extra_texture);
- gs_texture_destroy(capture->texture);
- obs_leave_graphics();
- memset(capture, 0, sizeof(struct dc_capture));
- }
- static void draw_cursor(struct dc_capture *capture, HDC hdc, HWND window)
- {
- HICON icon;
- ICONINFO ii;
- CURSORINFO *ci = &capture->ci;
- POINT win_pos = {capture->x, capture->y};
- if (!(capture->ci.flags & CURSOR_SHOWING))
- return;
- icon = CopyIcon(capture->ci.hCursor);
- if (!icon)
- return;
- if (GetIconInfo(icon, &ii)) {
- POINT pos;
- if (window)
- ClientToScreen(window, &win_pos);
- pos.x = ci->ptScreenPos.x - (int)ii.xHotspot - win_pos.x;
- pos.y = ci->ptScreenPos.y - (int)ii.yHotspot - win_pos.y;
- DrawIconEx(hdc, pos.x, pos.y, icon, 0, 0, 0, NULL, DI_NORMAL);
- DeleteObject(ii.hbmColor);
- DeleteObject(ii.hbmMask);
- }
- DestroyIcon(icon);
- }
- static inline HDC dc_capture_get_dc(struct dc_capture *capture)
- {
- if (!capture->valid)
- return NULL;
- if (capture->compatibility)
- return capture->hdc;
- else
- return gs_texture_get_dc(capture->texture);
- }
- static inline void dc_capture_release_dc(struct dc_capture *capture)
- {
- if (capture->compatibility) {
- gs_texture_set_image(capture->texture, capture->bits, capture->width * 4, false);
- } else {
- gs_texture_release_dc(capture->texture);
- }
- }
- void dc_capture_capture(struct dc_capture *capture, HWND window)
- {
- HDC hdc_target;
- HDC hdc;
- if (capture->capture_cursor) {
- memset(&capture->ci, 0, sizeof(CURSORINFO));
- capture->ci.cbSize = sizeof(CURSORINFO);
- capture->cursor_captured = GetCursorInfo(&capture->ci);
- }
- hdc = dc_capture_get_dc(capture);
- if (!hdc) {
- blog(LOG_WARNING, "[capture_screen] Failed to get "
- "texture DC");
- return;
- }
- hdc_target = GetDC(window);
- BitBlt(hdc, 0, 0, capture->width, capture->height, hdc_target, capture->x, capture->y, SRCCOPY);
- ReleaseDC(NULL, hdc_target);
- if (capture->cursor_captured && !capture->cursor_hidden)
- draw_cursor(capture, hdc, window);
- dc_capture_release_dc(capture);
- capture->texture_written = true;
- }
- void dc_capture_render(struct dc_capture *capture, bool texcoords_centered)
- {
- if (capture->valid && capture->texture_written) {
- gs_texture_t *texture = capture->texture;
- const bool compatibility = capture->compatibility;
- bool linear_sample = compatibility;
- if (!linear_sample && !texcoords_centered) {
- gs_texture_t *const extra_texture = capture->extra_texture;
- gs_copy_texture(extra_texture, texture);
- texture = extra_texture;
- linear_sample = true;
- }
- const char *tech_name = "Draw";
- float multiplier = 1.f;
- switch (gs_get_color_space()) {
- case GS_CS_SRGB_16F:
- case GS_CS_709_EXTENDED:
- if (!linear_sample)
- tech_name = "DrawSrgbDecompress";
- break;
- case GS_CS_709_SCRGB:
- if (linear_sample)
- tech_name = "DrawMultiply";
- else
- tech_name = "DrawSrgbDecompressMultiply";
- multiplier = obs_get_video_sdr_white_level() / 80.f;
- }
- gs_effect_t *effect = obs_get_base_effect(OBS_EFFECT_OPAQUE);
- gs_technique_t *tech = gs_effect_get_technique(effect, tech_name);
- gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
- const bool previous = gs_framebuffer_srgb_enabled();
- gs_enable_framebuffer_srgb(linear_sample);
- gs_enable_blending(false);
- if (linear_sample)
- gs_effect_set_texture_srgb(image, texture);
- else
- gs_effect_set_texture(image, texture);
- gs_eparam_t *multiplier_param = gs_effect_get_param_by_name(effect, "multiplier");
- gs_effect_set_float(multiplier_param, multiplier);
- const uint32_t flip = compatibility ? GS_FLIP_V : 0;
- const size_t passes = gs_technique_begin(tech);
- for (size_t i = 0; i < passes; i++) {
- if (gs_technique_begin_pass(tech, i)) {
- gs_draw_sprite(texture, flip, 0, 0);
- gs_technique_end_pass(tech);
- }
- }
- gs_technique_end(tech);
- gs_enable_blending(true);
- gs_enable_framebuffer_srgb(previous);
- }
- }
|