From 4fd4b12c842908e0b9acda8d4485963e063d6041 Mon Sep 17 00:00:00 2001 From: Palana Date: Fri, 17 Jan 2014 02:38:35 +0100 Subject: [PATCH] Add example monitor capture for OSX (need to clean up (CMake) files) --- CMakeLists.txt | 4 +- .../obs-plugins/test-input/draw_rect.effect | 35 ++++ test/test-input/CMakeLists.txt | 15 +- test/test-input/test-desktop.h | 34 ++++ test/test-input/test-desktop.m | 174 ++++++++++++++++++ test/test-input/test-input.c | 2 +- 6 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 build/data/obs-plugins/test-input/draw_rect.effect create mode 100644 test/test-input/test-desktop.h create mode 100644 test/test-input/test-desktop.m diff --git a/CMakeLists.txt b/CMakeLists.txt index a9f829d9f..8749d5bd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,6 @@ endif() set(LIBRARY_OUTPUT_PATH ${obs_BINARY_DIR}/plugins) set(RUNTIME_OUTPUT_PATH ${obs_BINARY_DIR}/plugins) -add_subdirectory(obs) - add_subdirectory(test) + +add_subdirectory(obs) diff --git a/build/data/obs-plugins/test-input/draw_rect.effect b/build/data/obs-plugins/test-input/draw_rect.effect new file mode 100644 index 000000000..2816b7dc1 --- /dev/null +++ b/build/data/obs-plugins/test-input/draw_rect.effect @@ -0,0 +1,35 @@ +uniform float4x4 ViewProj; +uniform texture_rect diffuse; + +sampler_state texSampler { + AddressU = Clamp; + AddressV = Clamp; + Filter = Linear; +}; + +struct VertexInOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertexInOut VShader(VertexInOut vert_in) +{ + VertexInOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = vert_in.uv; + return vert_out; +} + +float4 PShader(VertexInOut fragment_in) : TARGET +{ + return diffuse.Sample(texSampler, fragment_in.uv); +} + +technique Default +{ + pass + { + vertex_shader = VShader(vert_in); + pixel_shader = PShader(fragment_in); + } +} diff --git a/test/test-input/CMakeLists.txt b/test/test-input/CMakeLists.txt index abc564407..51b8a0d4f 100644 --- a/test/test-input/CMakeLists.txt +++ b/test/test-input/CMakeLists.txt @@ -1,16 +1,27 @@ include_directories(SYSTEM ${obs_SOURCE_DIR}/libobs) add_library(test-input MODULE + test-desktop.m test-filter.c test-input.c test-sinewave.c test-random.c) +set_source_files_properties(test-desktop.m + PROPERTIES LANGUAGE C + COMPILE_FLAGS "-fobjc-arc") + +find_library(IOSURF IOSurface) + + target_link_libraries(test-input - libobs) + libobs + ${IOSURF}) obs_add_plugin(test-input) obs_add_data_source(/data/obs-plugins/test-input/ + ${obs_SOURCE_DIR}/build/data/obs-plugins/test-input/draw_rect.effect ${obs_SOURCE_DIR}/build/data/obs-plugins/test-input/draw.effect - ${obs_SOURCE_DIR}/build/data/obs-plugins/test-input/test.effect) + ${obs_SOURCE_DIR}/build/data/obs-plugins/test-input/test.effect + ) diff --git a/test/test-input/test-desktop.h b/test/test-input/test-desktop.h new file mode 100644 index 000000000..41c59202f --- /dev/null +++ b/test/test-input/test-desktop.h @@ -0,0 +1,34 @@ +#pragma once + +#include "obs.h" +#import + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +struct desktop_tex { + samplerstate_t sampler; + effect_t whatever; + CGDisplayStreamRef disp; + uint32_t width, height; +}; + +EXPORT const char *desktop_getname(const char *locale); + +EXPORT struct desktop_tex *desktop_create(const char *settings, obs_source_t source); +EXPORT void desktop_destroy(struct desktop_tex *rt); +EXPORT uint32_t desktop_get_output_flags(struct desktop_tex *rt); +EXPORT void desktop_video_tick(struct desktop_tex *rt, float dt); + +EXPORT void desktop_video_render(struct desktop_tex *rt, obs_source_t filter_target); + +EXPORT uint32_t desktop_getwidth(struct desktop_tex *rt); +EXPORT uint32_t desktop_getheight(struct desktop_tex *rt); + +#ifdef __cplusplus +} +#endif diff --git a/test/test-input/test-desktop.m b/test/test-input/test-desktop.m new file mode 100644 index 000000000..c570292cc --- /dev/null +++ b/test/test-input/test-desktop.m @@ -0,0 +1,174 @@ +#include +#include "test-desktop.h" + +#import +#import +#import +#import +#import +#import +#include + + +const char *desktop_getname(const char *locale) +{ + return "OSX Monitor Capture"; +} + +static IOSurfaceRef current = NULL, + prev = NULL; +static texture_t tex = NULL; +static pthread_mutex_t c_mutex; + +struct desktop_tex *desktop_create(const char *settings, obs_source_t source) +{ + struct desktop_tex *rt = bmalloc(sizeof(struct desktop_tex)); + char *effect_file; + + memset(rt, 0, sizeof(struct desktop_tex)); + + 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); + + 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 (!rt->whatever) { + desktop_destroy(rt); + return NULL; + } + + if ([[NSScreen screens] count] < 1) { + desktop_destroy(rt); + return NULL; + } + + NSScreen *screen = [NSScreen screens][0]; + + NSRect frame = [screen convertRectToBacking:[screen frame]]; + + rt->width = frame.size.width; + rt->height = frame.size.height; + + printf("%u %u\n", rt->width, rt->height); + + pthread_mutex_init(&c_mutex, NULL); + + NSDictionary *dict = @{ + (__bridge NSString*)kCGDisplayStreamSourceRect: + (__bridge NSDictionary*)CGRectCreateDictionaryRepresentation( + CGRectMake(0, 0, rt->width, rt->height)), + (__bridge NSString*)kCGDisplayStreamQueueDepth: @5 + }; + + rt->disp = CGDisplayStreamCreateWithDispatchQueue(CGMainDisplayID(), + rt->width, rt->height, 'BGRA', + (__bridge CFDictionaryRef)dict, + dispatch_queue_create("dispstream", NULL), + ^(CGDisplayStreamFrameStatus status, uint64_t + displayTime, IOSurfaceRef frameSurface, + CGDisplayStreamUpdateRef updateRef) + { + if (!frameSurface || + pthread_mutex_trylock(&c_mutex)) + return; + + if (current) { + IOSurfaceDecrementUseCount(current); + CFRelease(current); + current = NULL; + } + + current = frameSurface; + CFRetain(current); + IOSurfaceIncrementUseCount(current); + pthread_mutex_unlock(&c_mutex); + } + ); + + gs_leavecontext(); + + if (CGDisplayStreamStart(rt->disp)) { + desktop_destroy(rt); + return NULL; + } + + return rt; +} + +void desktop_destroy(struct desktop_tex *rt) +{ + if (rt) { + pthread_mutex_lock(&c_mutex); + gs_entercontext(obs_graphics()); + + if (current) { + IOSurfaceDecrementUseCount(current); + CFRelease(current); + } + if (rt->sampler) + samplerstate_destroy(rt->sampler); + if (tex) + texture_destroy(tex); + CGDisplayStreamStop(rt->disp); + effect_destroy(rt->whatever); + bfree(rt); + + gs_leavecontext(); + pthread_mutex_unlock(&c_mutex); + } +} + +uint32_t desktop_get_output_flags(struct desktop_tex *rt) +{ + return SOURCE_VIDEO; +} + +void desktop_video_render(struct desktop_tex *rt, obs_source_t filter_target) +{ + pthread_mutex_lock(&c_mutex); + + if (prev != current) { + if (tex) + texture_rebind_iosurface(tex, current); + else + tex = gs_create_texture_from_iosurface(current); + prev = current; + } + + if (!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), + tex); + technique_begin(tech); + technique_beginpass(tech, 0); + + gs_draw_sprite(tex, 0, 0, 0); + + technique_endpass(tech); + technique_end(tech); + +fail: + pthread_mutex_unlock(&c_mutex); +} + +uint32_t desktop_getwidth(struct desktop_tex *rt) +{ + return rt->width; +} + +uint32_t desktop_getheight(struct desktop_tex *rt) +{ + return rt->height; +} diff --git a/test/test-input/test-input.c b/test/test-input/test-input.c index c1d79eb4a..496e9e844 100644 --- a/test/test-input/test-input.c +++ b/test/test-input/test-input.c @@ -1,7 +1,7 @@ #include #include "test-input-exports.h" -const char *inputs[] = {"random", "sinewave"}; +const char *inputs[] = {"desktop", "random", "sinewave"}; const char *filters[] = {"test"}; uint32_t module_version(uint32_t in_version)