#include #include #include #include #import #import #import #include #include static const int cx = 800; static const int cy = 600; /* --------------------------------------------------- */ template struct OBSUniqueHandle : std::unique_ptr> { using base = std::unique_ptr>; explicit OBSUniqueHandle(T *obj = nullptr) : base(obj, D) {} operator T *() { return base::get(); } }; #define DECLARE_DELETER(x) decltype(x), x using SourceContext = OBSUniqueHandle; using SceneContext = OBSUniqueHandle; using DisplayContext = OBSUniqueHandle; #undef DECLARE_DELETER /* --------------------------------------------------- */ static void CreateOBS() { if (!obs_startup("en", nullptr, nullptr)) throw "Couldn't create OBS"; struct obs_video_info ovi; ovi.adapter = 0; ovi.fps_num = 30000; ovi.fps_den = 1001; ovi.graphics_module = DL_OPENGL; ovi.output_format = VIDEO_FORMAT_RGBA; ovi.base_width = cx; ovi.base_height = cy; ovi.output_width = cx; ovi.output_height = cy; if (obs_reset_video(&ovi) != 0) throw "Couldn't initialize video"; } static DisplayContext CreateDisplay(NSView *view) { gs_init_data info = {}; info.cx = cx; info.cy = cy; info.format = GS_RGBA; info.zsformat = GS_ZS_NONE; info.window.view = view; return DisplayContext{obs_display_create(&info, 0)}; } static SceneContext SetupScene() { /* ------------------------------------------------------ */ /* load modules */ obs_load_all_modules(); /* ------------------------------------------------------ */ /* create source */ SourceContext source{ obs_source_create("random", "a test source", nullptr, nullptr)}; if (!source) throw "Couldn't create random test source"; /* ------------------------------------------------------ */ /* create scene and add source to scene */ SceneContext scene{obs_scene_create("test scene")}; if (!scene) throw "Couldn't create scene"; obs_scene_add(scene, source); /* ------------------------------------------------------ */ /* set the scene as the primary draw source and go */ obs_set_output_source(0, obs_scene_get_source(scene)); return scene; } @interface OBSTest : NSObject { NSWindow *win; NSView *view; DisplayContext display; SceneContext scene; } - (void)applicationDidFinishLaunching:(NSNotification *)notification; - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app; - (void)windowWillClose:(NSNotification *)notification; @end @implementation OBSTest - (void)applicationDidFinishLaunching:(NSNotification *)notification { UNUSED_PARAMETER(notification); try { NSRect content_rect = NSMakeRect(0, 0, cx, cy); win = [[NSWindow alloc] initWithContentRect:content_rect styleMask:NSTitledWindowMask | NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO]; if (!win) throw "Could not create window"; view = [[NSView alloc] initWithFrame:content_rect]; if (!view) throw "Could not create view"; CreateOBS(); win.title = @"foo"; win.delegate = self; win.contentView = view; [win orderFrontRegardless]; [win center]; [win makeMainWindow]; display = CreateDisplay(view); scene = SetupScene(); obs_display_add_draw_callback( display.get(), [](void *, uint32_t, uint32_t) { obs_render_main_texture(); }, nullptr); } catch (char const *error) { NSLog(@"%s\n", error); [NSApp terminate:nil]; } } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app { UNUSED_PARAMETER(app); return YES; } - (void)windowWillClose:(NSNotification *)notification { UNUSED_PARAMETER(notification); obs_set_output_source(0, nullptr); scene.reset(); display.reset(); obs_shutdown(); NSLog(@"Number of memory leaks: %lu", bnum_allocs()); } @end /* --------------------------------------------------- */ int main() { @autoreleasepool { NSApplication *app = [NSApplication sharedApplication]; OBSTest *test = [[OBSTest alloc] init]; app.delegate = test; [app run]; } return 0; }