2013-09-30 19:37:13 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <windows.h>
|
|
|
|
|
2013-11-26 22:07:27 -08:00
|
|
|
#include <util/base.h>
|
2014-04-19 20:50:59 -07:00
|
|
|
#include <graphics/vec2.h>
|
2013-11-26 22:07:27 -08:00
|
|
|
#include <media-io/audio-resampler.h>
|
|
|
|
#include <obs.h>
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2013-10-14 12:37:52 -07:00
|
|
|
#include <intrin.h>
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
static const int cx = 800;
|
|
|
|
static const int cy = 600;
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
|
|
|
class SourceContext {
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_source_t *source;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
public:
|
2014-09-25 17:44:05 -07:00
|
|
|
inline SourceContext(obs_source_t *source) : source(source) {}
|
2013-11-20 14:00:16 -08:00
|
|
|
inline ~SourceContext() {obs_source_release(source);}
|
2014-09-25 17:44:05 -07:00
|
|
|
inline operator obs_source_t*() {return source;}
|
2013-09-30 19:37:13 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
|
|
|
class SceneContext {
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_scene_t *scene;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
public:
|
2014-09-25 17:44:05 -07:00
|
|
|
inline SceneContext(obs_scene_t *scene) : scene(scene) {}
|
2013-12-29 07:54:06 -08:00
|
|
|
inline ~SceneContext() {obs_scene_release(scene);}
|
2014-09-25 17:44:05 -07:00
|
|
|
inline operator obs_scene_t*() {return scene;}
|
2013-09-30 19:37:13 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
2015-08-12 20:30:02 -07:00
|
|
|
class DisplayContext {
|
|
|
|
obs_display_t *display;
|
|
|
|
|
|
|
|
public:
|
|
|
|
inline DisplayContext(obs_display_t *display) : display(display) {}
|
|
|
|
inline ~DisplayContext() {obs_display_destroy(display);}
|
|
|
|
inline operator obs_display_t*() {return display;}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
static LRESULT CALLBACK sceneProc(HWND hwnd, UINT message, WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (message) {
|
|
|
|
|
|
|
|
case WM_CLOSE:
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-14 04:02:11 -07:00
|
|
|
static void do_log(int log_level, const char *msg, va_list args, void *param)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
char bla[4096];
|
|
|
|
vsnprintf(bla, 4095, msg, args);
|
|
|
|
|
|
|
|
OutputDebugStringA(bla);
|
|
|
|
OutputDebugStringA("\n");
|
2013-10-14 12:37:52 -07:00
|
|
|
|
2015-08-12 20:30:02 -07:00
|
|
|
if (log_level < LOG_WARNING)
|
2013-10-29 06:01:19 -07:00
|
|
|
__debugbreak();
|
2014-04-14 04:02:11 -07:00
|
|
|
|
|
|
|
UNUSED_PARAMETER(param);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2013-10-14 12:37:52 -07:00
|
|
|
static void CreateOBS(HWND hwnd)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2013-10-16 23:31:18 -07:00
|
|
|
RECT rc;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
|
2015-08-09 05:09:07 -07:00
|
|
|
if (!obs_startup("en-US", nullptr, nullptr))
|
2013-09-30 19:37:13 -07:00
|
|
|
throw "Couldn't create OBS";
|
2013-11-20 14:00:16 -08:00
|
|
|
|
|
|
|
struct obs_video_info ovi;
|
|
|
|
ovi.adapter = 0;
|
|
|
|
ovi.base_width = rc.right;
|
|
|
|
ovi.base_height = rc.bottom;
|
|
|
|
ovi.fps_num = 30000;
|
|
|
|
ovi.fps_den = 1001;
|
2015-01-09 11:19:22 -08:00
|
|
|
ovi.graphics_module = DL_OPENGL;
|
2013-11-20 14:00:16 -08:00
|
|
|
ovi.output_format = VIDEO_FORMAT_RGBA;
|
|
|
|
ovi.output_width = rc.right;
|
|
|
|
ovi.output_height = rc.bottom;
|
|
|
|
|
2014-07-20 17:40:57 -07:00
|
|
|
if (obs_reset_video(&ovi) != 0)
|
2013-11-20 14:00:16 -08:00
|
|
|
throw "Couldn't initialize video";
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2015-08-12 20:30:02 -07:00
|
|
|
static DisplayContext CreateDisplay(HWND hwnd)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
|
|
|
|
gs_init_data info = {};
|
|
|
|
info.cx = rc.right;
|
|
|
|
info.cy = rc.bottom;
|
|
|
|
info.format = GS_RGBA;
|
|
|
|
info.zsformat = GS_ZS_NONE;
|
|
|
|
info.window.hwnd = hwnd;
|
|
|
|
|
|
|
|
return obs_display_create(&info);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static void AddTestItems(obs_scene_t *scene, obs_source_t *source)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_sceneitem_t *item = NULL;
|
2014-04-19 20:50:59 -07:00
|
|
|
struct vec2 scale;
|
|
|
|
|
|
|
|
vec2_set(&scale, 20.0f, 20.0f);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2013-10-14 12:37:52 -07:00
|
|
|
item = obs_scene_add(scene, source);
|
2014-08-03 14:39:19 -07:00
|
|
|
obs_sceneitem_set_scale(item, &scale);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static HWND CreateTestWindow(HINSTANCE instance)
|
|
|
|
{
|
|
|
|
WNDCLASS wc;
|
|
|
|
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
2014-01-20 07:58:58 -08:00
|
|
|
wc.lpszClassName = TEXT("bla");
|
2013-09-30 19:37:13 -07:00
|
|
|
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
|
|
|
wc.hInstance = instance;
|
|
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wc.lpfnWndProc = (WNDPROC)sceneProc;
|
|
|
|
|
|
|
|
if (!RegisterClass(&wc))
|
|
|
|
return 0;
|
|
|
|
|
Revamp API and start using doxygen
The API used to be designed in such a way to where it would expect
exports for each individual source/output/encoder/etc. You would export
functions for each and it would automatically load those functions based
on a specific naming scheme from the module.
The idea behind this was that I wanted to limit the usage of structures
in the API so only functions could be used. It was an interesting idea
in theory, but this idea turned out to be flawed in a number of ways:
1.) Requiring exports to create sources/outputs/encoders/etc meant that
you could not create them by any other means, which meant that
things like faruton's .net plugin would become difficult.
2.) Export function declarations could not be checked, therefore if you
created a function with the wrong parameters and parameter types,
the compiler wouldn't know how to check for that.
3.) Required overly complex load functions in libobs just to handle it.
It makes much more sense to just have a load function that you call
manually. Complexity is the bane of all good programs.
4.) It required that you have functions of specific names, which looked
and felt somewhat unsightly.
So, to fix these issues, I replaced it with a more commonly used API
scheme, seen commonly in places like kernels and typical C libraries
with abstraction. You simply create a structure that contains the
callback definitions, and you pass it to a function to register that
definition (such as obs_register_source), which you call in the
obs_module_load of the module.
It will also automatically check the structure size and ensure that it
only loads the required values if the structure happened to add new
values in an API change.
The "main" source file for each module must include obs-module.h, and
must use OBS_DECLARE_MODULE() within that source file.
Also, started writing some doxygen documentation in to the main library
headers. Will add more detailed documentation as I go.
2014-02-12 07:04:50 -08:00
|
|
|
return CreateWindow(TEXT("bla"), TEXT("bla"),
|
|
|
|
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
|
2013-09-30 19:37:13 -07:00
|
|
|
1920/2 - cx/2, 1080/2 - cy/2, cx, cy,
|
|
|
|
NULL, NULL, instance, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
2014-04-14 14:10:47 -07:00
|
|
|
static void RenderWindow(void *data, uint32_t cx, uint32_t cy)
|
|
|
|
{
|
|
|
|
obs_render_main_view();
|
|
|
|
|
|
|
|
UNUSED_PARAMETER(data);
|
|
|
|
UNUSED_PARAMETER(cx);
|
|
|
|
UNUSED_PARAMETER(cy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------- */
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine,
|
|
|
|
int numCmd)
|
|
|
|
{
|
|
|
|
HWND hwnd = NULL;
|
2014-04-14 04:02:11 -07:00
|
|
|
base_set_log_handler(do_log, nullptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
try {
|
|
|
|
hwnd = CreateTestWindow(instance);
|
|
|
|
if (!hwnd)
|
|
|
|
throw "Couldn't create main window";
|
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
/* create OBS */
|
2013-10-14 12:37:52 -07:00
|
|
|
CreateOBS(hwnd);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
(API Change) Refactor module handling
Changed API:
- char *obs_find_plugin_file(const char *sub_path);
Changed to: char *obs_module_file(const char *file);
Cahnge it so you no longer need to specify a sub-path such as:
obs_find_plugin_file("module_name/file.ext")
Instead, now automatically handle the module data path so all you need
to do is:
obs_module_file("file.ext")
- int obs_load_module(const char *name);
Changed to: int obs_open_module(obs_module_t *module,
const char *path,
const char *data_path);
bool obs_init_module(obs_module_t module);
Change the module loading API so that if the front-end chooses, it can
load modules directly from a specified path, and associate a data
directory with it on the spot.
The module will not be initialized immediately; obs_init_module must
be called on the module pointer in order to fully initialize the
module. This is done so a module can be disabled by the front-end if
the it so chooses.
New API:
- void obs_add_module_path(const char *bin, const char *data);
These functions allow you to specify new module search paths to add,
and allow you to search through them, or optionally just load all
modules from them. If the string %module% is included, it will
replace it with the module's name when that string is used as a
lookup. Data paths are now directly added to the module's internal
storage structure, and when obs_find_module_file is used, it will look
up the pointer to the obs_module structure and get its data directory
that way.
Example:
obs_add_module_path("/opt/obs/my-modules/%module%/bin",
"/opt/obs/my-modules/%module%/data");
This would cause it to additionally look for the binary of a
hypthetical module named "foo" at /opt/obs/my-modules/foo/bin/foo.so
(or libfoo.so), and then look for the data in
/opt/obs/my-modules/foo/data.
This gives the front-end more flexibility for handling third-party
plugin modules, or handling all plugin modules in a custom way.
- void obs_find_modules(obs_find_module_callback_t callback, void
*param);
This searches the existing paths for modules and calls the callback
function when any are found. Useful for plugin management and custom
handling of the paths by the front-end if desired.
- void obs_load_all_modules(void);
Search through the paths and both loads and initializes all modules
automatically without custom handling.
- void obs_enum_modules(obs_enum_module_callback_t callback,
void *param);
Enumerates currently opened modules.
2014-07-27 12:00:11 -07:00
|
|
|
/* load modules */
|
|
|
|
obs_load_all_modules();
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
/* create source */
|
2015-12-29 15:25:45 -08:00
|
|
|
SourceContext source = obs_source_create("random",
|
|
|
|
"some randon source", NULL, nullptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!source)
|
|
|
|
throw "Couldn't create random test source";
|
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
/* create filter */
|
2015-12-29 15:25:45 -08:00
|
|
|
SourceContext filter = obs_source_create("test_filter",
|
|
|
|
"a nice green filter", NULL, nullptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!filter)
|
|
|
|
throw "Couldn't create test filter";
|
2013-10-14 12:37:52 -07:00
|
|
|
obs_source_filter_add(source, filter);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
/* create scene and add source to scene (twice) */
|
2013-12-28 04:33:16 -08:00
|
|
|
SceneContext scene = obs_scene_create("test scene");
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!scene)
|
|
|
|
throw "Couldn't create scene";
|
|
|
|
|
|
|
|
AddTestItems(scene, source);
|
|
|
|
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
/* set the scene as the primary draw source and go */
|
2014-08-04 08:41:15 -07:00
|
|
|
obs_set_output_source(0, obs_scene_get_source(scene));
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-04-14 14:10:47 -07:00
|
|
|
/* ------------------------------------------------------ */
|
2015-08-12 20:30:02 -07:00
|
|
|
/* create display for output and set the output render callback */
|
|
|
|
DisplayContext display = CreateDisplay(hwnd);
|
|
|
|
obs_display_add_draw_callback(display, RenderWindow, nullptr);
|
2014-04-14 14:10:47 -07:00
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
MSG msg;
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (char *error) {
|
|
|
|
MessageBoxA(NULL, error, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2013-10-14 12:37:52 -07:00
|
|
|
obs_shutdown();
|
|
|
|
|
2015-02-09 01:19:46 -08:00
|
|
|
blog(LOG_INFO, "Number of memory leaks: %ld", bnum_allocs());
|
2013-09-30 19:37:13 -07:00
|
|
|
DestroyWindow(hwnd);
|
|
|
|
|
2014-06-25 02:05:17 -07:00
|
|
|
UNUSED_PARAMETER(prevInstance);
|
|
|
|
UNUSED_PARAMETER(cmdLine);
|
|
|
|
UNUSED_PARAMETER(numCmd);
|
2013-09-30 19:37:13 -07:00
|
|
|
return 0;
|
|
|
|
}
|