197 lines
4.4 KiB
C
197 lines
4.4 KiB
C
#include "dc-capture.h"
|
|
|
|
#define WIN32_MEAN_AND_LEAN
|
|
#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) {
|
|
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;
|
|
|
|
capture->hdc = CreateCompatibleDC(NULL);
|
|
capture->bmp = CreateDIBSection(capture->hdc, &bi,
|
|
DIB_RGB_COLORS, (void**)&capture->bits,
|
|
NULL, 0);
|
|
capture->old_bmp = SelectObject(capture->hdc, capture->bmp);
|
|
}
|
|
}
|
|
|
|
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->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;
|
|
|
|
DrawIcon(hdc, pos.x, pos.y, icon);
|
|
|
|
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;
|
|
}
|
|
|
|
static void draw_texture(struct dc_capture *capture, gs_effect_t *effect)
|
|
{
|
|
gs_texture_t *texture = capture->texture;
|
|
gs_technique_t *tech = gs_effect_get_technique(effect, "Draw");
|
|
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
|
size_t passes;
|
|
|
|
gs_effect_set_texture(image, texture);
|
|
|
|
passes = gs_technique_begin(tech);
|
|
for (size_t i = 0; i < passes; i++) {
|
|
if (gs_technique_begin_pass(tech, i)) {
|
|
if (capture->compatibility)
|
|
gs_draw_sprite(texture, GS_FLIP_V, 0, 0);
|
|
else
|
|
gs_draw_sprite(texture, 0, 0, 0);
|
|
|
|
gs_technique_end_pass(tech);
|
|
}
|
|
}
|
|
gs_technique_end(tech);
|
|
}
|
|
|
|
void dc_capture_render(struct dc_capture *capture, gs_effect_t *effect)
|
|
{
|
|
if (capture->valid && capture->texture_written)
|
|
draw_texture(capture, effect);
|
|
}
|