diff --git a/test/test-input/test-desktop.m b/test/test-input/test-desktop.m index bdfa756cf7aff90662e0519cce5cf637be5cf82c..41026e31e324d24b6208c2091ea15b2a92f9f2a7 100644 --- a/test/test-input/test-desktop.m +++ b/test/test-input/test-desktop.m @@ -1,200 +1,288 @@ #include #include +#include #include #import #import -#import -#import -#import -#import -#import -struct desktop_tex { +struct display_capture { samplerstate_t sampler; - effect_t whatever; + effect_t draw_effect; + texture_t tex; - CGDisplayStreamRef disp; + unsigned display; uint32_t width, height; - texture_t tex; - pthread_mutex_t mutex; + os_event_t disp_finished; + CGDisplayStreamRef disp; IOSurfaceRef current, prev; + + pthread_mutex_t mutex; }; -static const char *osx_desktop_test_getname(const char *locale) +static void destroy_display_stream(struct display_capture *dc) { - UNUSED_PARAMETER(locale); - return "OSX Monitor Capture"; -} + if (dc->disp) { + CGDisplayStreamStop(dc->disp); + os_event_wait(dc->disp_finished); + } -static void osx_desktop_test_destroy(void *data) -{ - struct desktop_tex *rt = data; - - if (rt) { - pthread_mutex_lock(&rt->mutex); - gs_entercontext(obs_graphics()); - - if (rt->current) { - IOSurfaceDecrementUseCount(rt->current); - CFRelease(rt->current); - } - if (rt->sampler) - samplerstate_destroy(rt->sampler); - if (rt->tex) - texture_destroy(rt->tex); - CGDisplayStreamStop(rt->disp); - effect_destroy(rt->whatever); - bfree(rt); - - gs_leavecontext(); - pthread_mutex_unlock(&rt->mutex); + if (dc->tex) { + texture_destroy(dc->tex); + dc->tex = NULL; } + + 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); } -static void *osx_desktop_test_create(obs_data_t settings, obs_source_t source) +static void display_capture_destroy(void *data) { - struct desktop_tex *rt = bzalloc(sizeof(struct desktop_tex)); - char *effect_file; + struct display_capture *dc = data; + + if (!dc) + return; + pthread_mutex_lock(&dc->mutex); 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, - }; - rt->sampler = gs_create_samplerstate(&info); + destroy_display_stream(dc); - effect_file = obs_find_plugin_file("test-input/draw_rect.effect"); - rt->whatever = gs_create_effect_from_file(effect_file, NULL); - bfree(effect_file); + if (dc->sampler) + samplerstate_destroy(dc->sampler); + if (dc->draw_effect) + effect_destroy(dc->draw_effect); - if (!rt->whatever) { - osx_desktop_test_destroy(rt); - return NULL; - } + gs_leavecontext(); - if ([[NSScreen screens] count] < 1) { - osx_desktop_test_destroy(rt); - return NULL; - } + pthread_mutex_destroy(&dc->mutex); + bfree(dc); +} + +static bool init_display_stream(struct display_capture *dc) +{ + if (dc->display >= [NSScreen screens].count) + return false; - NSScreen *screen = [NSScreen screens][0]; + NSScreen *screen = [NSScreen screens][dc->display]; - NSRect frame = [screen convertRectToBacking:[screen frame]]; + NSRect frame = [screen convertRectToBacking:screen.frame]; - rt->width = frame.size.width; - rt->height = frame.size.height; + dc->width = frame.size.width; + dc->height = frame.size.height; - pthread_mutex_init(&rt->mutex, NULL); + NSNumber *screen_num = screen.deviceDescription[@"NSScreenNumber"]; + CGDirectDisplayID disp_id = (CGDirectDisplayID)screen_num.pointerValue; NSDictionary *dict = @{ (__bridge NSString*)kCGDisplayStreamSourceRect: (__bridge NSDictionary*)CGRectCreateDictionaryRepresentation( - CGRectMake(0, 0, rt->width, rt->height)), + CGRectMake(0, 0, dc->width, dc->height)), (__bridge NSString*)kCGDisplayStreamQueueDepth: @5 }; - rt->disp = CGDisplayStreamCreateWithDispatchQueue(CGMainDisplayID(), - rt->width, rt->height, 'BGRA', + os_event_init(&dc->disp_finished, OS_EVENT_TYPE_MANUAL); + + dc->disp = CGDisplayStreamCreateWithDispatchQueue(disp_id, + dc->width, dc->height, 'BGRA', (__bridge CFDictionaryRef)dict, dispatch_queue_create(NULL, NULL), ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { + UNUSED_PARAMETER(displayTime); + UNUSED_PARAMETER(updateRef); + + if (status == + kCGDisplayStreamFrameStatusStopped) { + os_event_signal(dc->disp_finished); + return; + } + if (!frameSurface || - pthread_mutex_trylock(&rt->mutex)) + pthread_mutex_trylock(&dc->mutex)) return; - if (rt->current) { - IOSurfaceDecrementUseCount(rt->current); - CFRelease(rt->current); - rt->current = NULL; + if (dc->current) { + IOSurfaceDecrementUseCount(dc->current); + CFRelease(dc->current); + dc->current = NULL; } - rt->current = frameSurface; - CFRetain(rt->current); - IOSurfaceIncrementUseCount(rt->current); - pthread_mutex_unlock(&rt->mutex); - - UNUSED_PARAMETER(status); - UNUSED_PARAMETER(displayTime); - UNUSED_PARAMETER(updateRef); + dc->current = frameSurface; + CFRetain(dc->current); + IOSurfaceIncrementUseCount(dc->current); + pthread_mutex_unlock(&dc->mutex); } ); - gs_leavecontext(); - - if (CGDisplayStreamStart(rt->disp)) { - osx_desktop_test_destroy(rt); - return NULL; - } + return !CGDisplayStreamStart(dc->disp); +} +static void *display_capture_create(obs_data_t settings, + obs_source_t source) +{ UNUSED_PARAMETER(source); UNUSED_PARAMETER(settings); - return rt; + + 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; } -static void osx_desktop_test_video_render(void *data, effect_t effect) +static void display_capture_video_render(void *data, effect_t effect) { - struct desktop_tex *rt = data; + UNUSED_PARAMETER(effect); + + struct display_capture *dc = data; - pthread_mutex_lock(&rt->mutex); + pthread_mutex_lock(&dc->mutex); - if (rt->prev != rt->current) { - if (rt->tex) - texture_rebind_iosurface(rt->tex, rt->current); + if (dc->prev != dc->current) { + if (dc->tex) + texture_rebind_iosurface(dc->tex, dc->current); else - rt->tex = gs_create_texture_from_iosurface( - rt->current); - rt->prev = rt->current; + dc->tex = gs_create_texture_from_iosurface( + dc->current); + dc->prev = dc->current; } - if (!rt->tex) goto fail; + if (!dc->tex) goto fail; - gs_load_samplerstate(rt->sampler, 0); - technique_t tech = effect_gettechnique(rt->whatever, "Default"); - effect_settexture(rt->whatever, effect_getparambyidx(rt->whatever, 1), - rt->tex); + 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); technique_begin(tech); technique_beginpass(tech, 0); - gs_draw_sprite(rt->tex, 0, 0, 0); + gs_draw_sprite(dc->tex, 0, 0, 0); technique_endpass(tech); technique_end(tech); fail: - pthread_mutex_unlock(&rt->mutex); + pthread_mutex_unlock(&dc->mutex); +} - UNUSED_PARAMETER(effect); +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); } -static uint32_t osx_desktop_test_getwidth(void *data) +static void display_capture_update(void *data, obs_data_t settings) { - struct desktop_tex *rt = data; - return rt->width; + 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(); } -static uint32_t osx_desktop_test_getheight(void *data) +static obs_properties_t display_capture_properties(char const *locale) { - struct desktop_tex *rt = data; - return rt->height; + 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; } -struct obs_source_info osx_desktop = { - .id = "osx_desktop", +struct obs_source_info display_capture_info = { + .id = "display_capture", .type = OBS_SOURCE_TYPE_INPUT, + .getname = display_capture_getname, + + .create = display_capture_create, + .destroy = display_capture_destroy, + .output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW, - .getname = osx_desktop_test_getname, - .create = osx_desktop_test_create, - .destroy = osx_desktop_test_destroy, - .video_render = osx_desktop_test_video_render, - .getwidth = osx_desktop_test_getwidth, - .getheight = osx_desktop_test_getheight, + .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, }; diff --git a/test/test-input/test-input.c b/test/test-input/test-input.c index 01a004b7fb0875e7b98db4fd0f8426c9ffaa76fd..a1883202732d320c603f8c7070f8a0a2daba71c3 100644 --- a/test/test-input/test-input.c +++ b/test/test-input/test-input.c @@ -7,7 +7,7 @@ extern struct obs_source_info test_sinewave; extern struct obs_source_info test_filter; #ifdef __APPLE__ -extern struct obs_source_info osx_desktop; +extern struct obs_source_info display_capture_info; #endif bool obs_module_load(uint32_t libobs_version) @@ -17,7 +17,7 @@ bool obs_module_load(uint32_t libobs_version) obs_register_source(&test_filter); #ifdef __APPLE__ - obs_register_source(&osx_desktop); + obs_register_source(&display_capture_info); #endif UNUSED_PARAMETER(libobs_version);