test-desktop.m 6.3 KB
Newer Older
1
#include <stdlib.h>
J
jp9000 已提交
2
#include <obs.h>
P
Palana 已提交
3
#include <util/threading.h>
J
jp9000 已提交
4
#include <pthread.h>
5

J
jp9000 已提交
6
#import <CoreGraphics/CGDisplayStream.h>
7 8
#import <Cocoa/Cocoa.h>

P
Palana 已提交
9
struct display_capture {
J
jp9000 已提交
10
	samplerstate_t sampler;
P
Palana 已提交
11 12
	effect_t draw_effect;
	texture_t tex;
13

P
Palana 已提交
14
	unsigned display;
J
jp9000 已提交
15 16
	uint32_t width, height;

P
Palana 已提交
17 18
	os_event_t disp_finished;
	CGDisplayStreamRef disp;
J
jp9000 已提交
19
	IOSurfaceRef current, prev;
P
Palana 已提交
20 21

	pthread_mutex_t mutex;
J
jp9000 已提交
22
};
23

P
Palana 已提交
24
static void destroy_display_stream(struct display_capture *dc)
J
jp9000 已提交
25
{
P
Palana 已提交
26 27 28 29
	if (dc->disp) {
		CGDisplayStreamStop(dc->disp);
		os_event_wait(dc->disp_finished);
	}
J
jp9000 已提交
30

P
Palana 已提交
31 32 33
	if (dc->tex) {
		texture_destroy(dc->tex);
		dc->tex = NULL;
J
jp9000 已提交
34
	}
P
Palana 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47

	if (dc->current) {
		IOSurfaceDecrementUseCount(dc->current);
		CFRelease(dc->current);
		dc->current = NULL;
	}

	if (dc->disp) {
		CFRelease(dc->disp);
		dc->disp = NULL;
	}

	os_event_destroy(dc->disp_finished);
J
jp9000 已提交
48 49
}

P
Palana 已提交
50
static void display_capture_destroy(void *data)
51
{
P
Palana 已提交
52 53 54 55
	struct display_capture *dc = data;

	if (!dc)
		return;
56

P
Palana 已提交
57
	pthread_mutex_lock(&dc->mutex);
58 59
	gs_entercontext(obs_graphics());

P
Palana 已提交
60
	destroy_display_stream(dc);
61

P
Palana 已提交
62 63 64 65
	if (dc->sampler)
		samplerstate_destroy(dc->sampler);
	if (dc->draw_effect)
		effect_destroy(dc->draw_effect);
66

P
Palana 已提交
67
	gs_leavecontext();
68

P
Palana 已提交
69 70 71 72 73 74 75 76
	pthread_mutex_destroy(&dc->mutex);
	bfree(dc);
}

static bool init_display_stream(struct display_capture *dc)
{
	if (dc->display >= [NSScreen screens].count)
		return false;
77

P
Palana 已提交
78
	NSScreen *screen = [NSScreen screens][dc->display];
79

P
Palana 已提交
80
	NSRect frame = [screen convertRectToBacking:screen.frame];
81

P
Palana 已提交
82 83
	dc->width = frame.size.width;
	dc->height = frame.size.height;
84

P
Palana 已提交
85 86
	NSNumber *screen_num = screen.deviceDescription[@"NSScreenNumber"];
	CGDirectDisplayID disp_id = (CGDirectDisplayID)screen_num.pointerValue;
87 88 89 90

	NSDictionary *dict = @{
		(__bridge NSString*)kCGDisplayStreamSourceRect:
		(__bridge NSDictionary*)CGRectCreateDictionaryRepresentation(
P
Palana 已提交
91
				CGRectMake(0, 0, dc->width, dc->height)),
92 93 94
		(__bridge NSString*)kCGDisplayStreamQueueDepth: @5
	};

P
Palana 已提交
95 96 97 98
	os_event_init(&dc->disp_finished, OS_EVENT_TYPE_MANUAL);

	dc->disp = CGDisplayStreamCreateWithDispatchQueue(disp_id,
			dc->width, dc->height, 'BGRA',
99
			(__bridge CFDictionaryRef)dict,
100
			dispatch_queue_create(NULL, NULL),
101 102 103 104
			^(CGDisplayStreamFrameStatus status, uint64_t
				displayTime, IOSurfaceRef frameSurface,
				CGDisplayStreamUpdateRef updateRef)
			{
P
Palana 已提交
105 106 107 108 109 110 111 112 113
				UNUSED_PARAMETER(displayTime);
				UNUSED_PARAMETER(updateRef);

				if (status ==
					kCGDisplayStreamFrameStatusStopped) {
					os_event_signal(dc->disp_finished);
					return;
				}

114
				if (!frameSurface ||
P
Palana 已提交
115
					pthread_mutex_trylock(&dc->mutex))
116 117
					return;

P
Palana 已提交
118 119 120 121
				if (dc->current) {
					IOSurfaceDecrementUseCount(dc->current);
					CFRelease(dc->current);
					dc->current = NULL;
122 123
				}

P
Palana 已提交
124 125 126 127
				dc->current = frameSurface;
				CFRetain(dc->current);
				IOSurfaceIncrementUseCount(dc->current);
				pthread_mutex_unlock(&dc->mutex);
128 129 130
			}
	);

P
Palana 已提交
131 132
	return !CGDisplayStreamStart(dc->disp);
}
133

P
Palana 已提交
134 135 136
static void *display_capture_create(obs_data_t settings,
		obs_source_t source)
{
J
jp9000 已提交
137 138
	UNUSED_PARAMETER(source);
	UNUSED_PARAMETER(settings);
P
Palana 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

	struct display_capture *dc = bzalloc(sizeof(struct display_capture));

	gs_entercontext(obs_graphics());

	struct gs_sampler_info info = {
		.filter = GS_FILTER_LINEAR,
		.address_u = GS_ADDRESS_CLAMP,
		.address_v = GS_ADDRESS_CLAMP,
		.address_w = GS_ADDRESS_CLAMP,
		.max_anisotropy = 1,
	};
	dc->sampler = gs_create_samplerstate(&info);
	if (!dc->sampler)
		goto fail;

	char *effect_file = obs_find_plugin_file("test-input/draw_rect.effect");
	dc->draw_effect = gs_create_effect_from_file(effect_file, NULL);
	bfree(effect_file);
	if (!dc->draw_effect)
		goto fail;

	gs_leavecontext();

	dc->display = obs_data_getint(settings, "display");
	pthread_mutex_init(&dc->mutex, NULL);

	if (!init_display_stream(dc))
		goto fail;

	return dc;

fail:
	gs_leavecontext();
	display_capture_destroy(dc);
	return NULL;
175 176
}

P
Palana 已提交
177
static void display_capture_video_render(void *data, effect_t effect)
178
{
P
Palana 已提交
179 180 181
	UNUSED_PARAMETER(effect);

	struct display_capture *dc = data;
J
jp9000 已提交
182

P
Palana 已提交
183
	pthread_mutex_lock(&dc->mutex);
184

P
Palana 已提交
185 186 187
	if (dc->prev != dc->current) {
		if (dc->tex)
			texture_rebind_iosurface(dc->tex, dc->current);
188
		else
P
Palana 已提交
189 190 191
			dc->tex = gs_create_texture_from_iosurface(
					dc->current);
		dc->prev = dc->current;
192 193
	}

P
Palana 已提交
194
	if (!dc->tex) goto fail;
195

P
Palana 已提交
196 197 198 199 200
	gs_load_samplerstate(dc->sampler, 0);
	technique_t tech = effect_gettechnique(dc->draw_effect, "Default");
	effect_settexture(dc->draw_effect,
			effect_getparambyidx(dc->draw_effect, 1),
			dc->tex);
201 202 203
	technique_begin(tech);
	technique_beginpass(tech, 0);

P
Palana 已提交
204
	gs_draw_sprite(dc->tex, 0, 0, 0);
205 206 207 208 209

	technique_endpass(tech);
	technique_end(tech);

fail:
P
Palana 已提交
210 211
	pthread_mutex_unlock(&dc->mutex);
}
J
jp9000 已提交
212

P
Palana 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
static const char *display_capture_getname(const char *locale)
{
	UNUSED_PARAMETER(locale);
	return "Display Capture";
}

static uint32_t display_capture_getwidth(void *data)
{
	struct display_capture *dc = data;
	return dc->width;
}

static uint32_t display_capture_getheight(void *data)
{
	struct display_capture *dc = data;
	return dc->height;
}

static void display_capture_defaults(obs_data_t settings)
{
	obs_data_set_default_int(settings, "display", 0);
234 235
}

P
Palana 已提交
236
static void display_capture_update(void *data, obs_data_t settings)
237
{
P
Palana 已提交
238 239 240 241 242 243 244 245 246 247 248 249
	struct display_capture *dc = data;
	unsigned display = obs_data_getint(settings, "display");
	if (dc->display == display)
		return;

	gs_entercontext(obs_graphics());

	destroy_display_stream(dc);
	dc->display = display;
	init_display_stream(dc);

	gs_leavecontext();
250 251
}

P
Palana 已提交
252
static obs_properties_t display_capture_properties(char const *locale)
253
{
P
Palana 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	UNUSED_PARAMETER(locale);
	obs_properties_t props = obs_properties_create();

	obs_property_t list = obs_properties_add_list(props,
			"display", "Display",
			OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);

	for (unsigned i = 0; i < [NSScreen screens].count; i++)
	{
		char buf[10];
		sprintf(buf, "%u", i);
		obs_property_list_add_item(list, buf, buf);
	}

	return props;
269
}
J
jp9000 已提交
270

P
Palana 已提交
271 272
struct obs_source_info display_capture_info = {
	.id           = "display_capture",
J
jp9000 已提交
273
	.type         = OBS_SOURCE_TYPE_INPUT,
P
Palana 已提交
274 275 276 277 278
	.getname      = display_capture_getname,

	.create       = display_capture_create,
	.destroy      = display_capture_destroy,

J
jp9000 已提交
279
	.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW,
P
Palana 已提交
280 281 282 283 284 285 286 287
	.video_render = display_capture_video_render,

	.getwidth     = display_capture_getwidth,
	.getheight    = display_capture_getheight,

	.defaults     = display_capture_defaults,
	.properties   = display_capture_properties,
	.update       = display_capture_update,
J
jp9000 已提交
288
};